1、二值化函数
二值化简而言之就是把图片转换为黑白色,前提是要先把图片变成灰度化之后的图片。
先介绍灰度化的三种方法:
- 加权均值法:对于彩色图像的每个像素【每个像素包含 RGB三通道】,它会按照一定的权重去乘以每个通道的像素值,并将其相加,得到最后的值就是灰度图像中对应位置的像素值,权重的比例为: R乘以0.299,G乘以0.587,B乘以0.114。
- 平均值法:对于彩色图像的每个像素,它会将R、G、B三个通道的像素值全部加起来,然后再除以三,得到的平均值就是灰度图像中对应位置的像素值。
- 最大值法:对于彩色图像的每个像素,它会从R、G、B三个通道的值中选出最大的一个,并将其作为灰度图像中对应位置的像素值。
我们写代码一般直接使用颜色空间转换函数即可转为灰度化的单通道图,或者读取直接转换
img_gray = cv2.imread("./flower.png", cv2.IMREAD_GRAYSCALE)
img = cv2.imread("./flower.png") # 对原图进行灰度化转换
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
接下来进行二值化处理
所谓二值化,就是提前设定一个阈值,由于灰度化之后的图片是单通道图片,我们要拿该值和阈值比较,可选择大于阈值设定为白色(255),小于阈值设定为黑色(0)
可以列出几种二值化:
1、阈值法(THRESH_BINARY)
通过设置一个阈值,将灰度图中的每一个像素值与该阈值进行比较,小于等于阈值的像素就被设置为0(黑),大于阈值的像素就被设置为maxval。
2、反阈值法(THRESH_BINARY_INV)
与阈值法相反。反阈值法是当灰度图的像素值大于阈值时,该像素值将会变成0(黑),当灰度图的像素值小于等于阈值时,该像素值将会变成maxval。
3、截断阈值法(THRESH_TRUNC):
指将灰度图中的所有像素与阈值进行比较,像素值大于阈值的部分将会被修改为阈值,小于等于阈值的部分不变。换句话说,经过截断阈值法处理过的二值化图中的最大像素值就是阈值。
4、低阈值零处理(THRESH_TOZERO)
就是像素值小于等于阈值的部分被置为0(也就是黑色),大于阈值的部分不变。
5、超阈值零处理(THRESH_TOZERO_INV)
就是将灰度图中的每个像素与阈值进行比较,像素值大于阈值的部分置为0(也就是黑色),像素值小于等于阈值的部分不变
6、OTSU阈值法
函数:threshold
功能:用于对图像进行二值化处理
参数:
- src: 输入图像,这应该是一个灰度图像(即单通道图像)。如果你有一个彩色图像,你需要先使用 cv2.cvtColor() 将其转换为灰度图。
- thresh: 阈值,用于将像素划分为两部分。这个值是一个浮点数或整数,取决于图像的数据类型。
- maxVal: 最大值,用于设置高于阈值的像素值。这个值通常是一个整数,表示你想要将高于阈值的像素设置为的具体数值。
- type: 阈值类型,这是一个标志,用于指定如何应用阈值。OpenCV 提供了几种不同的阈值类型,如 cv2.THRESH_BINARY、cv2.THRESH_BINARY_INV、cv2.THRESH_TRUNC、cv2.THRESH_TOZERO 和 cv2.THRESH_TOZERO_INV。
- dst: 输出图像,与输入图像具有相同的大小和类型。这是一个可选参数,如果不提供,函数会创建一个新的图像来存储二值化结果。
函数返回值:
- ret: 实际使用的阈值。在某些情况下(如使用 cv2.THRESH_OTSU 或 cv2.THRESH_TRIANGLE 标志时),这个值可能会与输入的 thresh 不同。
- dst: 二值化后的图像。
下面给出样例图片(图片放在同级目录下)
代码:(常规 设定阈值解释原理)
#导入cv库和numpy库,cv用于图象处理,numpy是多维数组的库
import cv2
import numpy as np
#图片导入
img=cv2.imread('./cat.png')
# 灰度化
img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 创建二值化的多维数组
img_black=np.zeros_like(img_gray)
# 设定阈值
thresh=120
#二值化的遍历过程
for i in range(img_gray.shape[0]): #纵向遍历
for j in range(img_gray.shape[1]): #横向遍历
if img_gray[i,j]<=thresh: #判断单通道值是否小于阈值
img_black[i,j]=0 #若小于阈值设定为白色
else:
img_black[i,j]=255 #否则为黑色
#imshow函数生成原图
cv2.imshow('image',img)
#灰度化的图
cv2.imshow('image_gray',img_gray)
#二值化的图
cv2.imshow('image_black',img_black)
#窗口无限等待
cv2.waitKey(0)
直接调用代码方法(这里用到OTSU阈值法)
import cv2
img=cv2.imread('./cat.png')
img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#ret返回的是使用的阈值,otsu算法用到可能不是你的阈值,img_binary接收二值化的信息
ret,img_binary=cv2.threshold(
img_gray, #灰度化的图
200, #阈值
255, #设定的超阈值后最大值
cv2.THRESH_OTSU #二值化方法
)
cv2.imshow('image',img)
cv2.imshow('image_gray',img_gray)
cv2.imshow('image_binary',img_binary)
cv2.waitKey(0)
效果图如下:
2、自适应二值化
自适应二值化更加适合用在明暗分布不均的图片
函数:adaptiveThreshold
参数:
- src: 输入图像,必须为灰度图像。
- maxValue: 超过或等于阈值的像素值被赋予的值。它可以是任意数值,但通常设置为 255(表示白色)。
- adaptiveMethod: 自适应阈值算法的选择。有两种选择:
- cv2.ADAPTIVE_THRESH_MEAN_C:计算邻域的平均值,然后从平均值中减去常数 C。
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C:计算邻域像素的加权和(使用高斯窗口),然后从加权和中减去常数 C。
- thresholdType: 阈值类型,与固定阈值函数 cv2.threshold() 相同。通常是 cv2.THRESH_BINARY 或 cv2.THRESH_BINARY_INV。
- blockSize: 用于计算阈值的邻域大小(必须是奇数)。
- C: 从计算出的平均值或加权和中减去的常数。
常用的领域(核)大小一般为:1、3、5、7....只要是奇数即可
核设置的越大,越接近于图片整体的阈值
import cv2
img=cv2.imread('./cat.png')
img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img_adaptive_binary=cv2.adaptiveThreshold(img_gray,#tu
255,#zuidazhi
cv2.ADAPTIVE_THRESH_MEAN_C,#adaptivevalue
cv2.THRESH_BINARY,#binarytype
3,#核的size
8) #changshu
cv2.imshow('image',img)
cv2.imshow('image_gray',img_gray)
cv2.imshow('image_binary',img_adaptive_binary)
cv2.waitKey(0)
这里核设置为15,轮廓较明显,常数非默认的0,我设置了8,减少了杂乱的噪点。
3、腐蚀函数
腐蚀操作就是使用核在原图(二值化图)上进行从左到右、从上到下的滑动(也就是从图像的左上角开始,滑动到图像的右下角)。在滑动过程中,令核值为1的区域与被核覆盖的对应区域进行相乘,得到其最小值,该最小值就是卷积核覆盖区域的中心像素点的新像素值,接着继续滑动。由于操作图像为二值图,所以不是黑就是白,这就意味着,在被核值为1覆盖的区域内,只要有黑色(像素值为0),那么该区域的中心像素点必定为黑色(0)。这样做的结果就是会将二值化图像中的白色部分尽可能的压缩,如下图所示,该图经过腐蚀之后,“变瘦”了。
简而言之:腐蚀就是给二值化的图的白色部分‘瘦身’
函数:erode
参数:
- src: 输入图像,这可以是一个二值图像、灰度图像或彩色图像。对于二值图像,通常使用 0 和 255 表示像素值;对于灰度图像和彩色图像,像素值范围可能更广。
- kernel: 结构元素,核。
- (下面的参数用的少)
- dst: 输出图像,是一个可选参数,如果不提供,函数会创建一个新的图像来存储腐蚀结果。
- anchor: 锚点,这是一个可选参数,通常不需要修改。
- iterations: 迭代次数,表示腐蚀操作应该应用的次数。默认值为 1,但你可以通过增加这个值来应用多次腐蚀,从而得到更强的效果。
- borderType: 边界类型,用于指定图像边界的像素外推方法。这通常是一个可选参数,默认值为 cv2.BORDER_DEFAULT,表示使用默认的边界填充方法。
- borderValue: 边界值,当 borderType 为 cv2.BORDER_CONSTANT 时使用,表示边界像素应该被设置的值。这也是一个可选参数。
函数返回值:
- dst: 腐蚀后的图像,这是一个包含腐蚀操作结果的 NumPy 数组。
案例图如下:
在此之前我们引入核的函数构造:
getStructuringElement
功能:生成一个特定形状和尺寸的结构元素(也称为核或掩膜)。
参数:
- shape: 结构元素的形状,这是一个整数标识符,表示你想要生成的结构元素的形状。OpenCV 提供了几种预定义的形状,如矩形(cv2.MORPH_RECT)、椭圆形(cv2.MORPH_ELLIPSE)和十字形(cv2.MORPH_CROSS)。
- ksize: 结构元素的尺寸,这是一个元组,表示结构元素的宽度和高度(通常是相同的,即正方形)。例如,(5, 5) 表示一个 5x5 的结构元素。
- anchor: 锚点,这是一个可选参数,表示结构元素的中心点(或称为锚点)相对于结构元素左上角的偏移量。默认情况下,锚点位于结构元素的中心。
函数返回值:
- 返回一个结构元素,这是一个 NumPy 数组,其数据类型通常为 uint8,并且数组中的元素值通常为 0 或 255(对于二值结构元素)。结构元素的形状和尺寸由 shape 和 ksize 参数决定
代码:
import cv2
img_binary=cv2.imread('./fushi.png')
#核的选择,这里核的参数设置为十字型大小10x10
kernel=cv2.getStructuringElement(cv2.MORPH_CROSS,(10,10))
#腐蚀函数
img_erode=cv2.erode(img_binary,kernel)
cv2.imshow('1',img_binary)
cv2.imshow('2',img_erode)
cv2.waitKey(0)
效果如下:
4、膨胀函数
与腐蚀函数相反,给二值化图像‘增肥’用的
膨胀与腐蚀刚好相反,膨胀操作就是使用核在原图(二值化图)上进行从左到右、从上到下的滑动(也就是从图像的左上角开始,滑动到图像的右下角),在滑动过程中,令核值为1的区域与被核覆盖的对应区域进行相乘,得到其最大值,该最大值就是核覆盖区域的中心像素点的新像素值,接着继续滑动。由于操作图像为二值图,所以不是黑就是白,这就意味着,在卷积核覆盖的区域内,只要有白色(像素值为255),那么该区域的中心像素点必定为白色(255)。这样做的结果就是会将二值化图像中的白色部分尽可能的扩张,如下图所示,该图经过腐蚀之后,“变胖”了。
函数:dilate
参数同腐蚀函数
代码:
import cv2
img_binary=cv2.imread('./fushi.png')
#核的参数设置为椭圆,这样会更圆润
kernel=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(10,10))
img_erode=cv2.dilate(img_binary,kernel)
cv2.imshow('1',img_binary)
cv2.imshow('2',img_erode)
cv2.waitKey(0)
效果图:
那么接下来我们对腐蚀和膨胀结合使用:可以实现去除噪点
5、仿射变换函数
仿射变换(Affine Transformation)的函数,用于对图像的平移、旋转、缩放以及剪切等操作。
引入该函数前,我们要先引出计算二维旋转矩阵的函数
cv2.getRotationMatrix2D(center, angle, scale)
功能:用于计算二维旋转矩阵的函数
参数:
center: 旋转的中心点,通常是一个二元元组 (x, y),表示旋转中心的坐标。
angle: 旋转的角度,以度为单位。正值表示逆时针旋转,负值表示顺时针旋转。
scale: 缩放因子。默认情况下,这个值是 1.0,表示不缩放。如果你想要同时旋转和缩放图像,可以通过调整这个参数来实现。
然后是仿射变换函数
cv2.warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None)
功能:用于对图像进行仿射变换(Affine Transformation)的函数,仿射变换包括平移、旋转、缩放以及剪切等操作。
参数:
src: 输入图像。
M: 变换矩阵,一个 2x3 的数组。这个矩阵是通过其他函数(如 cv2.getRotationMatrix2D())计算得到的,用于描述仿射变换。
dsize: 输出图像的大小,以 (width, height) 的形式表示。这个参数决定了变换后图像的尺寸。
dst: 输出图像,与输入图像有相同的大小和类型。这是一个可选参数,如果提供,则变换的结果会存储在这个图像中;如果未提供,则会创建一个新的图像来存储结果。
flags: 插值方法。常用的插值方法包括 cv2.INTER_LINEAR(线性插值)、cv2.INTER_NEAREST(最近邻插值)、cv2.INTER_CUBIC(三次样条插值)等。这是一个可选参数,如果未提供,则默认使用线性插值。
borderMode: 边缘填充方法。常用的方法包括 cv2.BORDER_CONSTANT(常量填充)、cv2.BORDER_REFLECT(反射)、cv2.BORDER_REFLECT_101(反射101)等。这是一个可选参数,如果未提供,则默认使用常量填充。
borderValue: 边界颜色,当 borderMode 为 cv2.BORDER_CONSTANT 时使用。这个参数是一个表示颜色的元组或数组,如 (255, 255, 255) 表示白色。这是一个可选参数,如果未提供,则默认使用黑色 (0, 0, 0)。
代码:
import cv2
img=cv2.imread('./cat.png')
M=cv2.getRotationMatrix2D((img.shape[1]/2,img.shape[0]/2),45,0.6) #缩放比例为0.6,默认旋转一次45°
#放射变换
img_warp =cv2.warpAffine(img,
M,
(800,800), #窗口设置为800x800
flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_WRAP
)
cv2.imshow('1',img_warp)
cv2.waitKey(0)
这里选择窗口设置为800x800大小,角度45°默认旋转一次,填充方式是BRODER_WRAP
6、透视变换函数
透视变换是把一个图像投影到一个新的视平面的过程,在现实世界中,我们观察到的物体在视觉上会受到透视效果的影响,即远处的物体看起来会比近处的物体小。透视投影是指将三维空间中的物体投影到二维平面上的过程,这个过程会导致物体在图像中出现形变和透视畸变。透视变换可以通过数学模型来校正这种透视畸变,使得图像中的物体看起来更符合我们的直观感受。
同样引入两个函数:
函数:cv2.getPerspectiveTransform(src, dst),返回透视矩阵
参数:
src: 源图像中的四个点,通常是一个形状为 (4, 2) 的 numpy 数组或类似的数据结构,表示四个点的坐标。这四个点应该按照某种顺序排列(例如,顺时针或逆时针),因为变换矩阵的计算依赖于这个顺序。
dst: 目标图像中的四个点,与 src 参数类似,也是一个形状为 (4, 2) 的 numpy 数组或类似的数据结构,表示变换后四个点应该位于的位置。
函数返回一个 3x3 的变换矩阵,可以使用 cv2.warpPerspective() 函数将这个矩阵应用于图像,从而执行透视变换。
函数:cv2.warpPerspective(src, M, dsize, dst=None, flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=None)
功能:用于对图像进行透视变换的函数
参数:
src: 输入图像,即你想要进行透视变换的源图像。
M: 透视变换矩阵,通常是一个 3x3 的矩阵,可以通过 cv2.getPerspectiveTransform() 函数计算得到。这个矩阵定义了源图像中的点如何映射到目标图像中的点。
dsize: 输出图像的尺寸,以 (width, height) 的形式表示。这是变换后图像的尺寸。
dst: 输出图像,这是一个可选参数。
flags: 插值方法。
borderMode: 边界填充方法。
borderValue: 边界颜色【可选】。
给定一个图片,对齐透视变换纠正:
我们可以先用matplotlib库读取图片获取四个角的坐标
代码:
import cv2
import numpy as np
img =cv2.imread('./card.png')
#原图的四个点和目标图的四个点
points1=np.array(([234,125],[672,173],[140,384],[654,438]),dtype=np.float32)
points2=np.array(([0,0],[img.shape[1],0],[0,img.shape[0]],[img.shape[1],img.shape[0]]),dtype=np.float32)
M=cv2.getPerspectiveTransform(points1,points2)
img_warp=cv2.warpPerspective(img,M,(img.shape[1],img.shape[0]))
cv2.imshow('1',img_warp)
cv2.waitKey(0)
透视转换后效果: