day31和day32图像处理OpenCV
文章目录
- 一、图像预处理
- 10 图像添加水印
- 11 图像噪点消除
- 11.1 均值滤波
- 11.2 方框滤波
- 11.3 高斯滤波
- 11.4 中值滤波
- 11.5 双边滤波
- 11.6 小结
- 12 图像梯度处理
- 12.1 图像梯度
- 12.2 垂直或水平边缘提取
一、图像预处理
10 图像添加水印
本实验中添加水印的概念其实可以理解为将一张图片中的某个物体或者图案提取出来,然后叠加到另一张图片上。具体的操作思想是通过将原始图片转换成灰度图,并进行二值化处理,去除背景部分,得到一个类似掩膜的图像。然后将这个二值化图像与另一张图片中要添加水印的区域进行“与”运算,使得目标物体的形状出现在要添加水印的区域。最后,将得到的目标物体图像与要添加水印的区域进行相加,就完成了添加水印的操作。这样可以实现将一个图像中的某个物体或图案叠加到另一个图像上,从而实现添加水印的效果。就本实验而言,会用到两个新的组件,一个是模板输入,一个是图像融合。如下图:
示例:
import cv2 as cv
import numpy as np
# 读取背景和logo
bg = cv.imread('./images/bg.png')
bg = cv.resize(bg,(300,300))
logo = cv.imread("./images/logohq.png")
# 获取logo大小
h,w,_ = logo.shape# 从背景中切片(和logo大小一样)
rot = bg[0:h,0:w] # 左上角# 二值化处理的是灰度图
gray_logo = cv.cvtColor(logo,cv.COLOR_BGR2GRAY)# 获取黑背景,有颜色的logo / 黑背景白色logo "与" logo# 这里的logo图是白背景红文字,所以需要反阈值法,才能获取到黑背景,白文字(白背景255>阈值,设置为0黑色)
_,white = cv.threshold(gray_logo,170,255,cv.THRESH_BINARY_INV)
v1 = cv.bitwise_and(logo,logo,mask=white)# 获取有背景,没颜色的logo / 白背景黑色logo "与" 切片
_,black = cv.threshold(gray_logo,170,255,cv.THRESH_BINARY)
v2 = cv.bitwise_and(rot,rot,mask=black)
# 将logo和背景拼接 并且 赋值给切分
rot[:] = cv.add(v1,v2)cv.imshow('logo',bg)
cv.waitKey(0)
cv.destroyAllWindows()
11 图像噪点消除
首先介绍一些概念:
噪声:指图像中的一些干扰因素,通常是由图像采集设备、传输信道等因素造成的,表现为图像中随机的亮度,也可以理解为有那么一些点的像素值与周围的像素值格格不入。常见的噪声类型包括高斯噪声和椒盐噪声。高斯噪声是一种分布符合正态分布的噪声,会使图像变得模糊或有噪点。椒盐噪声则是一些黑白色的像素值分布在原图像中。
滤波器:也可以叫做卷积核,与自适应二值化中的核一样,本身是一个小的区域,有着特定的核值,并且工作原理也是在原图上进行滑动并计算中心像素点的像素值。滤波器可分为线性滤波和非线性滤波,线性滤波对邻域中的像素进行线性运算,如在核的范围内进行加权求和,常见的线性滤波器有均值滤波、高斯滤波等。非线性滤波则是利用原始图像与模板之间的一种逻辑关系得到结果,常见的非线性滤波器中有中值滤波器、双边滤波器等。
滤波与模糊联系与区别:
- 它们都属于卷积,不同滤波方法之间只是卷积核不同(对线性滤波而言)
- 低通滤波器是模糊,高通滤波器是锐化
- 低通滤波器就是允许低频信号通过,在图像中边缘和噪点都相当于高频部分,所以低通滤波器用于去除噪点、平滑和模糊图像。高通滤波器则反之,用来增强图像边缘,进行锐化处理。
注意:椒盐噪声可以理解为斑点,随机出现在图像中的黑点或白点;高斯噪声可以理解为拍摄图片时由于光照等原因造成的噪声。
本实验中共提供了五种滤波的方式
11.1 均值滤波
- 采用卷积核从图像左上角开始,逐个计算对应位置的像素值,并从左至右、从上至下滑动卷积核,直至到达图像右下角。
均值滤波是一种最简单的滤波处理,它取的是卷积核区域内元素的均值,如3×3的卷积核:
k e r n e l = 1 9 [ 1 1 1 1 1 1 1 1 1 ] k e r n e l={\frac{1}{9}}{\Bigg[}\begin{array}{l l l}{1}&{1}&{1}\\{1}&{1}&{1}\\{1}&{1}&{1}\end{array}{\Bigg]} kernel=91[111111111]
对于边界的像素点,默认使用borderType=BORDER_REFLECT_101进行边界填充。
- 示例:
big = cv.imread('./images/lvbo2.png')
# 均值滤波器
blur1 = cv.blur(big,(3,3))
cv.imshow('blur1', blur1)
cv.imshow('big', big)
cv.waitKey(0)
cv.destroyAllWindows()
11.2 方框滤波
方框滤波跟均值滤波很像,如3×3的滤波核如下:
k e r n e l = a [ 1 1 1 1 1 1 1 1 1 ] k e r n e l={a}{\Bigg[}\begin{array}{l l l}{1}&{1}&{1}\\{1}&{1}&{1}\\{1}&{1}&{1}\end{array}{\Bigg]} kernel=a[111111111]
- 语法:
blur2 = cv.boxFilter(big,-1,(3,3),normalize=True)
-
参数
-
1.
img
:处理的图片 -
2.
ddepth
:输出图像的深度,-1代表使用原图像的深度。- 图像深度是指在数字图像处理和计算机视觉领域中,每个像素点所使用的位数(bit depth),也就是用来表示图像中每一个像素点的颜色信息所需的二进制位数。图像深度决定了图像能够表达的颜色数量或灰度级。
-
3.
ksize
:代表卷积核的大小,eg:ksize=3,则代表使用3×3的卷积核。 -
4.
normalize
:当normalize为True的时候,方框滤波就是均值滤波,上式中的a就等于1/9;normalize为False的时候,就是方框滤波,a=1,相当于求区域内的像素和
-
其滤波的过程与均值滤波一模一样,都采用卷积核从图像左上角开始,逐个计算对应位置的像素值,并从左至右、从上至下滑动卷积核,直至到达图像右下角,唯一的区别就是核值可能会不同。
11.3 高斯滤波
-
高斯滤波是一种常用的图像处理技术,主要用于平滑图像、去除噪声。它通过使用高斯函数(正态分布)作为卷积核来对图像进行模糊处理。
-
相比上面的两种方法,运算慢,效果好,能保留更多的图像特征。
-
语法
blur3 = cv.GaussianBlur(big,(3,3),sigmaX=0)
- 参数:
ksize=(3,3)
,则代表使用3×3的卷积核sigmaX
:就是高斯函数里的值,σx值越大,模糊效果越明显
11.4 中值滤波
中值又叫中位数,是所有数排序后取中间的值。中值滤波没有核值,而是在原图中从左上角开始,将卷积核区域内的像素值进行排序,并选取中值作为卷积核的中点的像素值。
-
中值滤波就是用区域内的中值来代替本像素值,所以那种孤立的斑点,如0或255很容易消除掉,适用于去除椒盐噪声和斑点噪声。中值是一种非线性操作,效率相比前面几种线性滤波要慢。
-
语法:
blur4 = cv.medianBlur(big,3)
- 参数
- 参数1:处理的图像
- 参数2:卷积核大小
11.5 双边滤波
模糊操作基本都会损失掉图像细节信息,尤其前面介绍的线性滤波器,图像的边缘信息很难保留下来。然而,边缘(edge)信息是图像中很重要的一个特征,所以这才有了双边滤波。
双边滤波的基本思路是同时考虑将要被滤波的像素点的空域信息(周围像素点的位置的权重)和值域信息(周围像素点的像素值的权重)。为什么要添加值域信息呢?是因为假设图像在空间中是缓慢变化的话,那么临近的像素点会更相近,但是这个假设在图像的边缘处会不成立,因为图像的边缘处的像素点必不会相近。因此在边缘处如果只是使用空域信息来进行滤波的话,得到的结果必然是边缘被模糊了,这样我们就丢掉了边缘信息,因此添加了值域信息。
双边滤波采用了两个高斯滤波的结合,一个负责计算空间邻近度的权值(也就是空域信息),也就是上面的高斯滤波器,另一个负责计算像素值相似度的权值(也就是值域信息),也是一个高斯滤波器。
语法:
blur5 = cv.bilateralFilter(img,5,55,55)
参数:
img=big
:处理的图像d=5
:过滤时周围每个像素领域的直径,这里已经设置了核大小。d=5===>5x5sigmaColor=55
:在color space(色彩空间)中过滤sigma。参数越大,那些颜色足够相近的的颜色的影响越大。较大的sigmaColor
值意味着更大的颜色差异将被允许参与到加权平均中,从而使得颜色相近但不完全相同的像素也能够相互影响。
-sigmaSpace=55
:在coordinate space(坐标空间)中过滤sigma。这个参数是坐标空间中的标准差,决定了像素位置对滤波结果的影响程度。它定义了在图像的空间域中,一个像素可以影响周围像素的最大距离。换句话说,它控制着滤波器作用的范围大小。
关于2个sigma参数:
简单起见,可以令2个sigma的值相等;
如果他们很小(小于10),那么滤波器几乎没有什么效果;
如果他们很大(大于150),那么滤波器的效果会很强,使图像显得非常卡通化。
关于参数d:
过大的滤波器(d>5)执行效率低。
对于实时应用,建议取d=5;
对于需要过滤严重噪声的离线应用,可取d=9;
11.6 小结
在不知道用什么滤波器好的时候,优先高斯滤波,然后均值滤波。
斑点和椒盐噪声优先使用中值滤波。
要去除噪点的同时尽可能保留更多的边缘信息,使用双边滤波。
线性滤波方式:均值滤波、方框滤波、高斯滤波(速度相对快)。
非线性滤波方式:中值滤波、双边滤波(速度相对慢)。
12 图像梯度处理
12.1 图像梯度
如果你还记得高数中用一阶导数来求极值的话,就很容易理解了:把图片想象成连续函数,因为边缘部分的像素值是与旁边像素明显有区别的,所以对图片局部求极值,就可以得到整幅图片的边缘信息了。不过图片是二维的离散函数,导数就变成了差分,这个差分就称为图像的梯度。
12.2 垂直或水平边缘提取
滤波是应用卷积来实现的,卷积的关键就是卷积核,我们来考察下面这个卷积核:
- 语法
new_img = cv2.filter2D(src, ddepth, kernel)
-
参数
src
: 输入图像,一般为numpy
数组。ddepth
: 输出图像的深度,可以是负值(表示与原图相同)、正值或其他特定值(常用-1 表示输出与输入具有相同的深度)。kernel
: 卷积核,一个二维数组(通常为奇数大小的方形矩阵),用于计算每个像素周围邻域的加权和。
-
原理:
-
自定义卷积核:提前垂直边缘,使用如下卷积核
k 1 = [ − 1 0 1 − 2 0 2 − 1 0 1 ] k1=\left[\begin{array}{c c c}{{-1}}&{{0}}&{{1}}\\ {{-2}}&{{0}}&{{2}}\\ {{-1}}&{{0}}&{{1}}\end{array}\right] k1= −1−2−1000121 -
把上面那个矩阵转置一下,就是提取水平边缘
k 2 = [ − 1 − 2 − 1 0 0 0 1 2 1 ] k2=\left[\begin{array}{c c c}{{-1}}&{{-2}}&{{-1}}\\ {{0}}&{{0}}&{{0}}\\ {{1}}&{{2}}&{{1}}\end{array}\right] k2= −101−202−101 -
边缘使用的cv.BORDER_REFLECT_101方法填充
-
9个像素点与卷积核的 乘积之和 得到中心位置对应的值
-
示例:
import cv2 as cv
import numpy as np
img = cv.imread('./images/shudu.png')
# 灰度图
img = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 定义卷积核,垂直边缘
kernel=np.array([[-1,0,1],[-2,0,2],[-1,0,1]],dtype=np.float32)
# 水平边缘
kernel2 = kernel.T
# 二维卷积操作
img2 = cv.filter2D(img,-1,kernel)
img3 = cv.filter2D(img,-1,kernel2)
# 打印卷积后的图
cv.imshow('img',img) # 灰度图
cv.imshow('img2',img2) # 垂直边缘
cv.imshow('img3',img3) # 水平边缘
cv.waitKey(0)
cv.destroyAllWindows()
输出:三张图分别灰度图、水平边缘、垂直边缘