一. Pillow处理图片

1.1 Pillow安装

可以使用pip安装也可以通过conda安装

conda install pillow

在这里插入图片描述

1.2 Pillow基本使用

  1. 读取并显示图片
from PIL import Image  #导入图像库
cat=Image.open("./beauty.jpg")
print(type(cat))
cat

在这里插入图片描述
2. 将图像数据转换为numpy数据

from PIL import Image  #导入图像库
import numpy as np
beauty=Image.open("./beauty.jpg")
beauty_data=np.array(beauty)#图像转为ndarray对象
print(type(beauty_data))
print(beauty_data)

在这里插入图片描述
3. 通过numpy对图像进行一些简单操作

from PIL import Image  #导入图像库
import numpy as np
beauty=Image.open("./beauty.jpg")
beauty_data=np.array(beauty)
beauty_data=beauty_data[:,:,::-1] #这里将数据反向打印,所以红绿蓝变成了蓝绿红
beauty2=Image.fromarray(beauty_data) #将array数组转换为图片
beauty2

在这里插入图片描述

二. Matplotlib包中的图像模块

2.1 简介

Matplotlib提供加载,重新缩放和显示图像所需的功能,但是Matplotlib仅支持PNG图像,如果本机读取失败,下面显示的命令将回腿到Pillow

Matplotlib已将每个通道的8位数据重新调整为0.0到1.0之间的浮点数据。Pillow可以使用的唯一数据类型是UTF8.Matplotlib绘图可以处理float32和uint8,但是除PNG之外的任何格式的图像读/写都限于uint8。为什么8位?大多数显示器每个通道只能渲染8位颜色等级。为什么他们只能渲染8位颜色等级?因为那是人眼能看到的。
每个内部列表代表一个像素。这里,对于RGB图像,有3个值。由于它是黑白图像,因此R,G,B都相似。RGBA(其中A是alpha即透明度)每个内部列表具有4个值,并且简单亮度仅具有一个值(因此仅2-D阵列,而不是3-D阵列)。对于RGB和RGBA图像,matplotlib支持float32和uint8数据类型。对于灰度,matplotlib仅支持float32.如果您的阵列数据不符合这些描述之一,则需要重新调整它。

2.2 API简介

imread()
作用:用于读取float32 dtype的ndarray对象中的图像数据(返回值是ndarray对象

import numpy as np
import matplotlib.image as mpimg

data=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
print(type(data))
print(data)

在这里插入图片描述
imshow()
用于将ndarray数据转换为图片格式进行展示

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt

data=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
plt.axis("off") #关闭网格
plt.imshow(data)

在这里插入图片描述
imsave()
用于将ndarray数组保存为本地图片

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt

data=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
plt.imsave("./beauty2.png",data,cmap="gray",origin="lower")#lower实现图像倒着显示

在这里插入图片描述

三. ndarray图像操作练习

3.1 旋转图片

在进行图像操作时我们要清楚,图像的像素矩阵时一个三维矩阵,最外面一层代表有多少行,第二层代表有多少列,最后最里面的列表就是代表像素点的三原色的数值。如果我们想要左右旋转图像要做的就是将第二层的列数据进行反转,最左边的列去最右边的列即可。

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
plt.axis("off") #关闭轴线
data=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
data2=data[::,::-1,::]
plt.imshow(data2)

在这里插入图片描述

3.2 图片打码

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
plt.axis("off") #关闭轴线
data=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
data2=data[::80,::80] #step设置为20,只读了一部分数据
plt.imshow(data2)

在这里插入图片描述

上面我们使用的全局马赛克,现在我们只给人脸打上马赛克

  1. 对图像进形裁剪,获得人脸区域
import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
plt.axis("off") #关闭轴线
data=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
data2=data[200:1800,1300:2500]
plt.imshow(data2)

在这里插入图片描述
2. 打码

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
plt.axis("off") #关闭轴线
data=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
data2=data[200:1800:80,1300:2500:80]
for i in range(20):  #由于data2的维度和data被马赛克替换的那一块的维度大小不一样,所以不能直接将马赛克的脸嵌入
    for j in range(15):
        data[200+i*80:200+80+i*80,1300+j*80:1300+80+j*80]=data2[i,j]
plt.imshow(data)

在这里插入图片描述

3.3 图片拼接

其本质就是将ndarray数组按行拼接(图片就会左右拼接)或按列拼接(图片就是上下拼接)

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
plt.axis("off") #关闭轴线
data1=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
data2=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
data3=np.concatenate([data1,data2],axis=1)
plt.imshow(data3)

在这里插入图片描述

3.4 图片切割

本质上就是切割ndarray数组

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
plt.axis("off") #关闭轴线
data1=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
d1,d2,d3=np.split(data1,indices_or_sections=[400,1800],axis=1) #切割大小为300,500
print(d1.shape,d2.shape,d3.shape)
plt.imshow(d2)

在这里插入图片描述

四. 图像灰度化

4.1 简介

灰度化:在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫做灰度值,因此灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。一般常用的是加权平均法来获取每个像素点的灰度值
灰度化处理:将彩色图片转换称为灰度图像的过程成为图像的灰度化处理
作用:减少颜色所引起的数据量的大幅增加,相当于减少了RGB的三个向量信息,从而减少数据量,加快运算速度

4.2 灰度化方法

  1. 最小值法或者是最大值法(极值法)

在颜色向量中,让所有的值都等于向量中的最小值或最大值

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
plt.axis("off") #关闭轴线
data1=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
data2=data1.min(axis=-1) #axis等于-1对应于最后一个维度,相当于取最后一个维度的最小值
plt.imshow(data2,cmap='gray')

在这里插入图片描述

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
plt.axis("off") #关闭轴线
data1=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
data2=data1.max(axis=-1) #axis等于-1对应于最后一个维度,相当于取最后一个维度的最小值
plt.imshow(data2,cmap='gray')

在这里插入图片描述
2. 平均值法

取颜色向量三个值的平均值作为颜色数值

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
plt.axis("off") #关闭轴线
data1=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
data2=data1.mean(axis=-1) #axis等于-1对应于最后一个维度,相当于取最后一个维度的最小值
plt.imshow(data2,cmap='gray')

在这里插入图片描述
3. 加权平均值法

import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
plt.axis("off") #关闭轴线
weight=[0.299,0.587,0.114]
data1=mpimg.imread("./beauty.png")  #注意这里的png不能是该后缀名得到的png,此外如果导入jpg图片会默认使用pillow模块
data2=np.dot(data1,weight)
plt.imshow(data2,cmap='gray')

在这里插入图片描述

五. OpenCV使用入门

5.1 简介

OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、AndroidMac OS操作系统上。 [1] 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。OpenCV用C++语言编写,它具有C ++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac OS,OpenCV主要倾向于实时视觉应用,并在可用时利用MMX和SSE指令, 如今也提供对于C#、Ch、Ruby,GO的支持。opencv的下载命令:

pip install opencv-python

5.2 OpenCV基本使用

  1. 读取图像
import matplotlib.pyplot as plt
import cv2
data=cv2.imread('./beauty.png')
plt.imshow(data)

在这里插入图片描述

因为opencv读进来的图像默认是brg的而不是rgb所以要对颜色向量进行一个倒置

import matplotlib.pyplot as plt
import cv2
data=cv2.imread('./beauty.png')
b,g,r=cv2.split(data)
data2=cv2.merge([r,g,b])
plt.imshow(data2)

在这里插入图片描述
2. 九种常见的颜色空间,包括BGR、RGB、GRAY、HSV、YCrCb、HLS、XYZ、LAB、YUV展示

BRG转RGB颜色空间

import matplotlib.pyplot as plt
import cv2
data=cv2.imread('./beauty.png')
img_BGR=cv2.imread("./beauty.png")  #默认读进来时BGR
#BGR->RGB 上面也提供了一种常见的转换形式
img_RGB=cv2.cvtColor(img_BGR,cv2.COLOR_BGR2RGB)
plt.imshow(img_RGB)

在这里插入图片描述

灰度化(BGR转GRAY颜色空间)

import matplotlib.pyplot as plt
import cv2
data=cv2.imread('./beauty.png')
img_BGR=cv2.imread("./beauty.png")  #默认读进来时BGR
#BGR->RGB 上面也提供了一种常见的转换形式
img_RGB=cv2.cvtColor(img_BGR,cv2.COLOR_BGR2GRAY)
plt.imshow(img_RGB)

在这里插入图片描述

转为其它颜色空间

image_HSV=cv2.cvtColor(ima_BGR,cv2.COLOR_BGR2HSV)
image_YCrCb=cv2.cvtColor(ima_BGR,cv2.COLOR_BGR2YCrCb)
image_HLS=cv2.cvtColor(ima_BGR,cv2.COLOR_BGR2HLS)
image_XYZ=cv2.cvtColor(ima_BGR,cv2.COLOR_BGR2XYZ)
image_LAB=cv2.cvtColor(ima_BGR,cv2.COLOR_BGR2LAB)
image_YUV=cv2.cvtColor(ima_BGR,cv2.COLOR_BGR2YUV)

5.3 图像灰度化

将彩色图像转化成为灰度图像的过程称为图像的灰度化处理。彩色图像中的每个像素的颜色有R,G,B三个分量决定,而每个分量有255中值可取,这样一个像素点可以1600多万(255255255)的颜色的变化范围。而灰度图像是R、G、B三个分量相同的一种特殊的彩色图像,其一个像素点的变化范围为255种,所以在数字图像处理中一般先将各种格式的图像直接反映了整个图像的整体和局部的色度和亮度等级的分布和特征。图像的灰度化处理可用两种方法来获取。

  1. 直接获取
import matplotlib.pyplot as plt
import cv2
data=cv2.imread('./beauty.png')
img_BGR=cv2.imread("./beauty.png")  #默认读进来时BGR
#BGR->RGB 上面也提供了一种常见的转换形式
img_RGB=cv2.cvtColor(img_BGR,cv2.COLOR_BGR2GRAY)
plt.imshow(img_RGB,'gray')

在这里插入图片描述
2. 同意也可以使用 4.2中介绍的灰度化方法(这里我们使用最小值法)

import matplotlib.pyplot as plt
import cv2
import numpy as np
data=cv2.imread('./beauty.png')
img_BGR=cv2.imread("./beauty.png")  #默认读进来时BGR
#BGR->RGB 上面也提供了一种常见的转换形式
img_RGB=cv2.cvtColor(img_BGR,cv2.COLOR_BGR2RGB)
row,col,channel=img_RGB.shape
for i in range(row):
    for j in range(col):
        img_RGB[i,j]=np.uint8(min(img_RGB[i,j,0],img_RGB[i,j,1],img_RGB[i,j,2]))
plt.imshow(img_RGB)

在这里插入图片描述

5.4 图像二值化

图像的二值化处理就是将图像上的点的灰度置为0或266,也就是将整个图像呈现出明显的黑白效果。即将256个亮度等级的灰度图像通过适当的阈值选取而获得仍然可以反映图像整体和局部特征的二值化图像。在数字图像处理 中,二值图像占有非常重要的地位,特别是在实用的图像处理中,以二值图像处理实现而构成的系统是很多的,要进行二值图像的处理和分析,首先要把灰度图像二值化,得到二值化图像,这样子有利于再对图像做进一步处理时,图像的集合性质只与像素值为0或255的点的位置有关,不再涉及像素额多级值,使处理变得简单,而且数据的处理和压缩量小。为了得到理想的二值图像,一般采用封闭、连通的边界定义不交叠区域。所有灰度大于或等于阈值的像素被判定为属于特定物体,其灰度值为255表示,否则这些像素点被排除在物体区域以外灰度值为0,表示背景或则例外的物体区域。如果某特定物体在内部有均匀一致的灰度值,并且某处在一个具有其他等级灰度值的均匀背景下,使用阈值法就可以得到比较的分割效果。如果物体同背景的差别表现不在灰度值上(比如纹理不同),可以将这个差别特征转化为灰度的差别,然后利用阈值选取技术来分割该图像。动态调节阈值实现图像二值化可动态观察其分割图像的具体结果。
固定阈值cv2.threshold()
原型:threshold(src,thresh,maxval,tyoe[,dst])

参数 说明
src 原图像
thresh 设定阈值
maxval 高于(低于)阈值时所赋予的像素新值
type 选择参数
type值 说明
cv2.THRESH_BINARY 黑白二值
cv2.THRESH_BINARY_INV 黑白二值反转
cv2.THRESH_TRUNC 得到的图像为多像素
cv2.THRESH_TOZERO
cv2.THRESH_TOZERO_INV
返回值 说明
第一个 retval(得到的阈值(在后面一个方法中会用到))
第二个 阈值化后的图像
import matplotlib.pyplot as plt
import cv2
data=cv2.imread("./beauty.png")
data=cv2.cvtColor(data,cv2.COLOR_BGR2GRAY) #二值化之前要将图片转换为灰度图片
ret1,thresh1=cv2.threshold(data,42,255,cv2.THRESH_BINARY)#大于阈值设置为255,小于阈值设置为0,设置合适的阈值才有号的效果
ret2,thresh2=cv2.threshold(data,42,255,cv2.THRESH_BINARY_INV)
ret3,thresh3=cv2.threshold(data,42,255,cv2.THRESH_TRUNC)
ret4,thresh4=cv2.threshold(data,42,255,cv2.THRESH_TOZERO)
ret5,thresh5=cv2.threshold(data,42,255,cv2.THRESH_TOZERO_INV)
titles=['img','THRESH_BINARY','THRESH_BINARY_INV',"THRESH_TRUNC",'THRESH_TOZERO','THRESH_TOZERO_INV']
images=[data,thresh1,thresh2,thresh3,thresh4,thresh5]
for i in range(6):
    plt.subplot(2,3,i+1)
    plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([])
    plt.yticks([])
plt.show()

在这里插入图片描述

自适应阈值cv2.adaptiveThreshold()
前面看到简单的阈值是一种全局性的阈值,只需要规定一个阈值值,整个图像都和这个阈值比较。而自适应阈值可以看成一种局部性的阈值,通过规定一个区域大小,比较这个点与区域大小里面像素点的平均值(或者其他特征)的大小关系确定的这个像素点是属于黑或者白(如果是二值情况)
adaptiveThreshold(src,maxValue,adaptiveMethod,thresholdType,blockSize,C[,dst])
该方法理论上得到的效果更好,相当于在动态自适应的调整属于自己像素点的阈值,而不是整个图片的阈值

参数 说明
src 原图像
maxValue 高于(低于)阈值时赋予的新值
adaptiveMethod 自适应方法
cv2.ADAPTIVE_THRESH_MEAN_C:领域内均值
cv2.ADAPTIVE_THRESH_GAUSSIAN_C:领域内像素点加权和,权重为一个高斯窗口
thresholdType 赋值方法,只有cv2.THRESH_BINARY和cv2.THRESH_BINARY_INV
blockSize 规定领域的大小(一个正方形区域)
C 常数,阈值等于均值或者加权值减去这个常数(为0相当于阈值就是求得领域内均值或者加权值)
import matplotlib.pyplot as plt
import cv2
data=cv2.imread("./beauty.png")
data=cv2.cvtColor(data,cv2.COLOR_BGR2GRAY) #二值化之前要将图片转换为灰度图片
th2=cv2.adaptiveThreshold(data,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,181,2)
th3=cv2.adaptiveThreshold(data,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,181,2)
images=[data,th2,th3]
plt.figure()
for i in range(3):
    plt.subplot(1,3,i+1)
    plt.imshow(images[i],'gray')
plt.show()

在这里插入图片描述
Otsu`s二值化
cv2.threshold()函数是有两个返回值的,前面一直用的第二个返回值,也就是阈值处理后的图像,那么第一个返回值(得到图像的阈值)这里将会用到。前面对于阈值的处理上,我们选择阈值为42,在实际情况下,42其实并不是最好的阈值 ,那么怎么去找最好的阈值?我们需要算法去自己去寻找一个阈值,而Otsu`s就可以自己加找到一个认为最好的阈值,并且Otsu`s非常适合于图像灰度直方图具有双峰的情况,他会在双峰之间找到一个值作为阈值,对于双峰图像,可能并不是最好用,那么经过Otsu`s得到的那个阈值就是函数cv2.threshold的第一个参数了。因为Otsu`s方法会产生一个阈值,那么函数cv2.threshold的第二个参数(设置阈值)就是0了,并且在cv2.threshold的方法参数中还得加上语句cv2.THRESH_OTSU

双峰图像(只能是灰度图像才有):就是图像的灰度统计图中可以明显看出只有两个波峰,比如下面的灰度直方图就是双峰图

import matplotlib.pyplot as plt
import cv2
data=cv2.imread("./beauty.png")
data=cv2.cvtColor(data,cv2.COLOR_BGR2GRAY) #二值化之前要将图片转换为灰度图片
ret1 ,th1=cv2.threshold(data,42,255,cv2.THRESH_BINARY)
ret2,th2=cv2.threshold(data,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print(ret2)

在这里插入图片描述

其认为阈值为61比较合适,查看一下结果,效果确实比我们设定的42好

images=[data,th1,th2]
plt.figure()
for i in range(3):
    plt.subplot(1,3,i+1)
    plt.imshow(images[i],'gray')
plt.show()

在这里插入图片描述

双峰图如下

plt.figure()
plt.hist(data.ravel(),256)
plt.show()

在这里插入图片描述

5.5 图像降噪

过滤是信号和图像处理中基本的任务。其目的是根据应用环境的不同,选择性的提取图像中某些认为是重要的信息。过滤可以移除图像中的噪音、提取感兴趣的可视特征、允许图像重采样等等。频域分析将图像分成从低频到高频的不同部分。低频对应图像强度变化小的区域,而高频是图像强度变化非常大的区域。在频率分析领域的框架中,滤波器是一个用来增强图像中某个波段或频率并阻塞(或降低)其他频率波段的操作。低通滤波器是消除图像中高频部分,但保留低频部分。高通滤波器消除低频部分个人认为模糊操作就是过滤掉图像中的一些特殊噪音

  1. 均值滤波
    概念:个KxK大小的窗口从图像左上角开始,从左到右,从上到下划过整个图像,这个KxK的窗口称为卷积核,卷积核的锚点一般位于窗口的中心位置,所以卷积核的边长一股为奇数。在滑窗的过程中,计算窗口内像素的平均值,用这个平均值来代替锚点的像素值,遍历过后,图像的纹理信息减弱,噪声减弱,图像变得平滑
    边缘处理:当锚点位于图像边缘时,卷积核一部分位于图像外边,这时有两种处理方法一种成为padding操作,即图像上下左右各添加(Ksize-1)/ 2个像素点,这些多出来的像素点初始化的方式有很多种,一般就是初始化成0,当然还有重复、对称等等类型的初始化方法,opencv内部默认为图像做padding操作,这样经过全局卷积操作后图像的大小维持不变。另一种就是边缘的像素点不予考虑,只能从能放下完整卷积核的地方开始滑窗,经过这样的操作后图像的宽、高变为 (Width – Ksize + 1, Height – Ksize +1),即图像变小了
    特点:Ksize越到,图像越平滑,也就是越模糊,是线性滤波器
    函数:res=cv2.blur(image,(ksize,ksize))
    作用:可以作用RGB图像
import matplotlib.pyplot as plt
import cv2
data=cv2.imread('./beauty.png')
data=cv2.cvtColor(data,cv2.COLOR_BGR2RGB)
#均值滤波
data2=cv2.blur(data,(9,9))#9x9卷积核大小
data3=cv2.blur(data,(19,19))
data4=cv2.blur(data,(100,100))
images=[data,data2,data3,data4]
for i in range(4):
    plt.subplot(2,2,i+1)
    plt.imshow(images[i],'gray')
plt.show()#可以看到卷积核越大图片越模糊

在这里插入图片描述
2. 高斯滤波
概念:高斯滤波要比均值滤波效果好很多,考虑到了卷积核内的像素值对最终结果的贡献大小,即赋予卷积核内的像素以一定的权重,每点的权重乘以当前卷积核所对应到原因的像素值相加最后除以权重的和作为输出结果
特点:考虑到卷积核内像素的权重,是线性滤波器。是应用最多最多的平滑滤波器!一般的图像预处理操作都少不了它!!使用频率极高。一般滴,高斯卷积核越大,方差越大,图像就越模糊函数:
res=cv2.GaussianBlur(image_data, (size, size), sigmaX, sigmaY)
说明:sigmax和sigmaY代表了横轴与纵轴权重的标准差,若为0就是让opencv帮你自动推算方差大小。可作用于RGB图像

import matplotlib.pyplot as plt
import cv2
data=cv2.imread('./beauty.png')
data=cv2.cvtColor(data,cv2.COLOR_BGR2RGB)
#均值滤波
data2=cv2.GaussianBlur(data,(9,9),0)#9x9卷积核大小
data3=cv2.GaussianBlur(data,(51,51),0)
data4=cv2.GaussianBlur(data,(101,101),0)
images=[data,data2,data3,data4]
for i in range(4):
    plt.subplot(2,2,i+1)
    plt.imshow(images[i],'gray')
plt.show()#可以看到卷积核越大图片越模糊

在这里插入图片描述
3. 中值滤波
概念:中值滤波后代替锚点的像素值为卷积核内像素灰度值的中值
特点:是一种非线性滤波器,能够很好的消除椒盐噪声(图像会更清晰),而线性滤波器对椒盐噪声毫无办法!只能让椒盐噪声点变大(原因很简单)
tip:椒盐噪声分为椒噪声(pepper)和盐噪声(salt)。椒嗓声点处灰度值为0,盐嗓声点处灰度值为255
函数:cv2.medianBlur(image, Ksize)
注意:这里的第二个参数不是元组了,是一个整数,代表了(Ksize,Ksize),所以意义是一 样的。能够作用于RGB图像

往图像中人为添加椒盐噪声

import numpy as np
def make_sp_noise(image,ratio):
    """人为的为图像添加椒盐噪声,ratia规定了噪声点占全局像素的比例"""
    h,w=image.shape[:2]
    image_copy=image.copy()
    nums=int(h*w*ratio) #椒盐噪声点占比
    for i in range(nums):
        row=np.random.randint(0,h)
        col=np.random.randint(0,w)
        if i%2==0:
            image_copy[row,col]=255
        else:
            image_copy[row,col]=0  
    return image_copy
import matplotlib.pyplot as plt
import cv2
data=cv2.imread('./beauty.png')
data=cv2.cvtColor(data,cv2.COLOR_BGR2RGB)
data2=make_sp_noise(data,0.6)#添加椒盐噪音
plt.imshow(data2)

在这里插入图片描述

中值滤波解决椒盐噪音(会让图像质量下降)

import matplotlib.pyplot as plt
import cv2
data=cv2.imread('./beauty.png')
data=cv2.cvtColor(data,cv2.COLOR_BGR2RGB)
data=make_sp_noise(data,0.6)
data2=cv2.medianBlur(data,1)#9x9卷积核大小
data3=cv2.medianBlur(data,3)
data4=cv2.medianBlur(data,5)
plt.figure(figsize=(12,6))
images=[data,data2,data3,data4]
for i in range(4):
    plt.subplot(2,2,i+1)
    plt.imshow(images[i],'gray')
plt.show()

在这里插入图片描述
4. 双边滤波
前面说过算法在降噪的同时也会削弱边缘、纹理等信息。有没有什么平滑滤波器能够在平滑图像(降噪)的同时,还能保留明显的边缘信息呢?这就是要说的双边滤波了。双边滤波不仅考虑卷积核内像素点位置信息的权重,还考虑了卷积核内像素点除锚点外的各点与锚点灰度差值的权重!也就是说系数由两个二维高斯函数的乘积联合确定
特点:比如ps的磨皮、人物卡通化都是通过双边滤波实现的。该算法复杂度高,耗时长
函数:cv2.bilaterFilter(image, ksize, sigmacolor, sigmaspace)
说明:ksize是一个整数,代表了卷积核的大小,sigmacolor是灰度差值权重的标准差,sigmaspace是位置权重的标准差,和前面的高斯滤波的权重是一致的,这两个标准差越大,滤波能力越强,同时还能较好的保留边缘信息。能够作用于RGB图像

下面使用双边滤波实现磨皮

import matplotlib.pyplot as plt
import cv2
data=cv2.imread('./beauty23.png')
data=cv2.cvtColor(data,cv2.COLOR_BGR2RGB)
data2=cv2.bilateralFilter(data,0,21,21)
data3=cv2.bilateralFilter(data,0,41,41)
data4=cv2.bilateralFilter(data,0,101,101)
plt.figure(figsize=(12,6))
images=[data,data2,data3,data4]
for i in range(4):
    plt.subplot(2,2,i+1)
    plt.imshow(images[i])
plt.show()

在这里插入图片描述