目录
操作以下步骤时都应该先读取图片,具体操作看连接文章:
本篇内容超多~~~ 请耐心阅读~~~ 🌹🌷🌼🌻🌸💮🪻🏵️🥰🤍🩶🖤🤎🩵🩷❤️❤️🔥💕
一、图像翻转
图像翻转是 OpenCV 中一种简单却常用的预处理操作,它可以改变图像的方向,满足不同场景下的需求。
- 语法:
cv2.flip(img,flipcode)
- 参数:
img:要翻转的图像
filpcode:指定翻转类型的标志
flipcode=0: 垂直翻转,图片像素点沿x轴翻转
flipcode>0: 水平翻转,图片像素点沿y轴翻转
flipcode<0: 水平垂直翻转,水平翻转和垂直翻转的结合
- 示例:
import cv2 as cv
# 读取图片
flower = cv.imread('../images/flower2.png')
# 图像翻转(镜像旋转,以图象中心为原点) cv.flip(img, flipcode)
# 当flipcode = 0时沿着x轴垂直翻转 上下翻转
flip_0 = cv.flip(flower, 0)
cv.imshow('flip_0', flip_0)
# 当flipcode > 0时沿着y轴水平翻转 左右翻转
flip_1 = cv.flip(flower, 1)
cv.imshow('flip_1', flip_1)
# 当flipcode < 0时水平垂直翻转
flip_2 = cv.flip(flower, -2)
cv.imshow('flip_2', flip_2)
cv.waitKey(0)
cv.destroyAllWindows()
二、图像仿射变换
- cv2.warpAffine()函数 -- 仿射变换函数
语法:
cv2.warpAffine(img,M,dsize)
参数:
img:输入图像。
M:2x3的变换矩阵,类型为
np.float32。dsize:输出图像的尺寸,形式为
(width,height)。
1. 单点旋转和平移
首先举一个例子,这是一个最简单的点的旋转,令旋转中心坐标系中心为O(0,0);假设有一点p0(x0,y0)离旋转中心O的距离为r,p0与坐标轴x轴的夹角为α,p0绕O顺时针旋转Θ角后对应点为p(x,y)。

那么我们可以得到如下关系:

用矩阵来表示就是:


被称作旋转矩阵。然而我们所要的不仅仅是可以围绕图像左上角进行旋转,而是可以围绕任意点进行旋转。那么我们可以将其转化成绕原点的旋转,其过程为:
-
首先将旋转点移到原点
-
按照上面的旋转矩阵进行旋转得到新的坐标点
-
再将得到的旋转点移回原来的位置
也就是说,在以任意点为旋转中心时,除了要进行旋转之外,还要进行平移操作。那么当点经过平移后得到P点时,如下图所示:

那么我们就可以得到:

写成矩阵的形式为:

我们将原始的旋转矩阵也扩展到3*3的形式:

仿射变换(Affine Transformation)是一种线性变换,保持了点之间的相对距离不变。

2. 图像旋转
旋转图像可以将图像绕着某个点旋转一定的角度。
- cv2.getRotationMatrix2D()函数 -- 获取旋转矩阵
语法:
cv2.getRotationMatrix2D(center,angle,scale)
参数:
center:旋转中心点的坐标,格式为
(x,y)。angle:旋转角度,单位为度,正值表示逆时针旋转负值表示顺时针旋转。
scale:缩放比例,若设为1,则不缩放。
返回值:M,2x3的旋转矩阵。
示例:
import cv2 as cv
# 读图
flower = cv.imread('../images/flower2.png')
# 获取旋转矩阵 cv2.getRotationMatrix2D(center,angle,scale)
# center:旋转中心点的坐标,格式为`(x,y)`
# center 的作用是先将图像原点平移到该点,旋转后再平移回原坐标系,因此最终结果包含了旋转和平移的复合变换
# angle:旋转角度,单位为度,正值表示逆时针旋转负值表示顺时针旋转。
# scale:缩放比例,若设为1,则不缩放。
# 返回一个2*3的旋转矩阵
M = cv.getRotationMatrix2D((30, 30), 45, 1)
# 仿射变换函数 cv2.warpAffine(img, M, dsize) (w,h)
# dsize:输出图像的尺寸,格式为 (width, height)(宽 × 高)
dst = cv.warpAffine(flower, M, (flower.shape[1], flower.shape[0]))
cv.imshow('flower', flower)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
3. 图像平移
移操作可以将图像中的每个点沿着某个方向移动一定的距离。

- 首先定义平移量
- 然后定义平移矩阵
示例
import cv2 as cv
import numpy as np
# 读取图片
flower = cv.imread('../images/flower2.png')
# 定义平移量
tx = 80
ty = 180
# 定义平移矩阵
M = np.float32([[1, 0, tx], [0, 1, ty]])
dst = cv.warpAffine(flower, M, (flower.shape[1] + tx, flower.shape[0] + ty))
cv.imshow('flower', flower)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
4. 图像缩放
缩放操作可以改变图片的大小。

- 定义缩放因子
- 定义缩放矩阵
示例:
import cv2 as cv
import numpy as np
# 读取图片
flower = cv.imread('../images/flower2.png')
# 定义缩放因子
sx = 0.6
sy = 0.6
# 定义缩放矩阵
M = np.float32([[sx, 0, 0], [0, sy, 0]])
dst = cv.warpAffine(flower, M, (flower.shape[1], flower.shape[0]))
cv.imshow('flower', flower)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
5. 图像剪切
剪切操作可以改变图形的形状,以便其在某个方向上倾斜,它将对象的形状改变为斜边平行四边形,而不改变其面积。
1.水平剪切(沿 x 轴方向)

2.垂直剪切(沿 y 轴方向)

3.示例
假设原图中有一个顶点为(0,0)、(2,0)、(2,2)、(0,2)的正方形:
- 若对其进行水平剪切(k=1),变换后顶点坐标为(0,0)、(2,0)、(4,2)、(2,2),形成一个平行四边形;
- 若进行垂直剪切(k=1),变换后顶点坐标为(0,0)、(2,2)、(2,4)、(0,2),同样形成平行四边形。
三、图像色彩空间
1.RGB颜色空间
RGB是一种用于表示和显示彩色图像的一种颜色模型。RGB代表红色(Red)、绿色(Green)和蓝色(Blue)。
RGB颜色模型基于笛卡尔坐标系,如下图所示,RGB原色值位于3个角上,二次色青色、红色和黄色位于另外三个角上,黑色位于原点处,白色位于离原点最远的角上。因为黑色在RGB三通道中表现为(0,0,0),所以映射到这里就是原点;而白色是(255,255,255),所以映射到这里就是三个坐标为最大值的点。
注意:在OpenCV中,颜色是以BGR的方式进行存储的,而不是RGB,这也是上面红色的像素值是(0,0,255)而不是(255,0,0)的原因。

2.颜色加法和加权加法
2.1 颜色加法
- 使用OpenCV的cv.add()函数把两幅图像相加
- 简单的通过Numpy添加两个图像(两个图像应该具有相同的大小和类型)
OpenCV加法和Numpy加法之间存在差异。OpenCV的加法是饱和操作,而Numpy添加是模运算。
import cv2 as cv
import numpy as np
# 读图
pig = cv.imread('../images/pig.png')
cao = cv.imread('../images/cao.png')
# 饱和操作 cv.add(img1,img2) np.uint8 0~255 250+10 =255
dst1 = cv.add(cao, pig)
cv.imshow('dst1', dst1)
# numpy直接相加 取模运算 对256取模 250+10 = 4
# numpy两个数组相加时,形状要一致
dst2 = cao + pig
cv.imshow('dst2',dst2)
# 举个例子
x = np.uint8([250])
y = np.uint8([10])
xy1 = cv.add(x,y) # [[255]]
xy2 = x + y # [[4]]
cv.waitKey(0)
cv.destroyAllWindows()
2.2 颜色加权加法
其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉。
- 语法
cv2.addWeighted(src1,alpha,src2,deta,gamma)
- 参数
src1、src2:输入图像。
alpha、beta:两张图象权重。
gamma:亮度调整值。
gamma > 0,图像会变亮。
gamma < 0,图像会变暗。
gamma = 0,则没有额外的亮度调整。
第一幅图的权重是0.7,第二幅图的权重是0.3。函数cv2.addWeighted()可以按下面的公式对图片进行混合操作。α + β = 1
dst = α⋅img1 + β⋅img2 + γ
- 示例
import cv2 as cv
import numpy as np
# 读图
pig = cv.imread('../images/pig.png')
cao = cv.imread('../images/cao.png')
# 颜色加权加法,cv.addWeighted(img1,α,img2,β,γ)
# dst = α⋅img1 + β⋅img2 + γ
dst = cv.addWeighted(cao, 0.5, pig, 0.5, 10)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
3.RGB转Gray(灰度)
3.1 什么是Gray(灰度)
灰度图像是一种单通道图像,每个像素的亮度用一个灰度值表示,取值范围通常为 0-255,0 表示黑色,255 表示白色。灰度图像去除了颜色信息,仅保留亮度信息,能减少数据量,简化计算。
3.2 RGB转Gray
RGB 转 Gray 最常用的是加权平均法,在 OpenCV 中,使用cv2.cvtColor()函数,将转换标志设为cv2.COLOR_BGR2GRAY即可实现转换。
-
语法
cv2.cvtColor(img,code)
-
参数
img:输入图像,可以是一个Numpy数组绘着一个OpenCV的Mat对象
Mat是一个核心的数据结构,主要用于存储图像和矩阵数据。在 Python 中使用 OpenCV 时,通常直接处理的是 NumPy 数组,cv2模块自动将Mat对象转换为 NumPy 数组。二者之间的转换是透明且自动完成的。例如,当你使用cv2.imread()函数读取图像时,返回的是一个 NumPy 数组,但在C++中则是Mat对象。
code:指定转换的类型,可以使用预定义的转换代码。
例如
cv2.COLOR_RGB2GRAY表示从rgb到灰度图像的转换。
-
示例
import cv2 as cv
# 读取图像
img = cv.imread('../images/1.jpg')
# 颜色转换 cv.cvtColor(img, code)
# 转灰度图
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow('gray', gray)
cv.waitKey(0)
cv.destroyAllWindows()
4.实现灰度图的方法
4.1 最大值法
对于彩色图像的每个像素,它会从R、G、B三个通道的值中选出最大的一个,并将其作为灰度图像中对应位置的像素值。

- 示例:
import cv2 as cv
import numpy as np
# 读取图像
img = cv.imread('../images/flower2.png')
# 创建一个跟img一样大小的图片
img1 = np.zeros((img.shape[0],img.shape[1]), dtype=np.uint8)
# 循环遍历行列,img.shape拿到的是元组(w,h,c)
# img[行,列,[b,g,r]]
for i in range(img.shape[0]):
for j in range(img.shape[1]):
img1[i, j] = max(img[i, j, 0], img[i, j, 1], img[i, j, 2])
cv.imshow('img1', img1)
cv.waitKey(0)
cv.destroyAllWindows()
4.2 平均值法
对于彩色图像的每个像素,它会将R、G、B三个通道的像素值全部加起来,然后再除以三,得到的平均值就是灰度图像中对应位置的像素值。

- 示例:
import cv2 as cv
import numpy as np
# 读取图像
img = cv.imread('../images/flower2.png')
# 创建一个跟img一样大小的图片
img1 = np.zeros((img.shape[0],img.shape[1]), dtype=np.uint8)
# 循环遍历行列,img.shape拿到的是元组(w,h,c)
# img[行,列,[b,g,r]]
for i in range(img.shape[0]):
for j in range(img.shape[1]):
# int():转为更大的数据类型,防止溢出
img1[i, j] = (int(img[i, j, 0]) + int(img[i, j, 1]) + int(img[i, j, 2]))//3
cv.imshow('img1', img1)
cv.waitKey(0)
cv.destroyAllWindows()
4.3 加权平均值法
对于彩色图像的每个像素,它会按照一定的权重去乘以每个通道的像素值,并将其相加,得到最后的值就是灰度图像中对应位置的像素值。本实验中,权重的比例为: R乘以0.299,G乘以0.587,B乘以0.114,这是经过大量实验得到的一个权重比例,也是一个比较常用的权重比例。
所使用的权重之和应该等于1。这是为了确保生成的灰度图像素值保持在合理的亮度范围内,并且不会因为权重的比例不当导致整体过亮或过暗。

- 示例:
import cv2 as cv
import numpy as np
# 读取图像
img = cv.imread('../images/flower2.png')
# 创建一个跟img一样大小的图片
img1 = np.zeros((img.shape[0], img.shape[1]), dtype=np.uint8)
# 循环遍历行列,img.shape拿到的是元组(w,h,c)
# img[行,列,[b,g,r]]
# 给每一个rgb定义权重
wb, wg, wr = 0.114, 0.587, 0.299
for i in range(img.shape[0]):
for j in range(img.shape[1]):
# int():转为更大的数据类型,防止溢出
img1[i, j] = round(wb * img[i, j, 0] + wg * img[i, j, 1] + wr * img[i, j, 2])
cv.imshow('img1', img1)
cv.waitKey(0)
cv.destroyAllWindows()
五、图像二值化处理
二值图像:
一幅二值图像的二维矩阵仅由0、1两个值构成,“0”代表黑色,“1”代白色。由于每一像素(矩阵中每一元素)取值仅有0、1两种可能,所以计算机中二值图像的数据类型通常为1个二进制位。二值图像通常用于文字、线条图的扫描识别(OCR)和掩膜图像的存储。

其操作的图像也必须是灰度图。也就是说,二值化的过程,就是将一张灰度图上的像素根据某种规则修改为0和maxval(maxval表示最大值,一般为255,显示白色)两种像素值,使图像呈现黑白的效果,能够帮助我们更好地分析图像中的形状、边缘和轮廓等特征。
- 语法:
_,binary = cv2.threshold(img,thresh,maxval,type)
- 参数:
img:输入图像,要进行二值化处理的灰度图。
thresh:设定的阈值。当像素值大于(或小于,取决于阈值类型)thresh时,该像素被赋予的值。
type:阈值处理的类型。返回值:
第一个值(通常用下划线表示):计算出的阈值,若使用自适应阈值法,会根据算法自动计算出这个值。
第二个值(binary):二值化后的图像矩阵。与输入图像尺寸相同。
1.阈值法和反阈值法
- 阈值法(THRESH_BINARY)
阈值法就是通过设置一个阈值,将灰度图中的每一个像素值与该阈值进行比较,小于等于阈值的像素就被设置为0(通常代表背景),大于阈值的像素就被设置为maxval(通常代表前景)。对于我们的8位图像(0~255)来说,通常是设置为255。


示例:
import cv2 as cv
# 读取图片
flower2 = cv.imread('../images/flower.png')
# 灰度图
gary = cv.cvtColor(flower2, cv.COLOR_BGR2GRAY)
gary = cv.resize(gary, (gary.shape[1]//2, gary.shape[0]//2))
# 二值化_阈值法 cv.THRESH_BINARY
_, binary = cv.threshold(gary, 120, 255, cv.THRESH_BINARY)
cv.imshow('gary', binary)
cv.waitKey(0)
cv.destroyAllWindows()
- 反阈值法(THRESH_BINARY_INV)
顾名思义,就是与阈值法相反。反阈值法是当灰度图的像素值大于阈值时,该像素值将会变成0(黑),当灰度图的像素值小于等于阈值时,该像素值将会变成maxval。


示例:
import cv2 as cv
# 读取图片
flower2 = cv.imread('../images/flower.png')
# 灰度图
gary = cv.cvtColor(flower2, cv.COLOR_BGR2GRAY)
gary = cv.resize(gary, (gary.shape[1]//2, gary.shape[0]//2))
# 二值化_反阈值法 cv.THRESH_BINARY_INV
_, binary_inv = cv.threshold(gary, 120, 255, cv.THRESH_BINARY_INV)
cv.imshow('gary_inv', binary_inv)
cv.waitKey(0)
cv.destroyAllWindows()
2.截断阈值法
截断阈值法,指将灰度图中的所有像素与阈值进行比较,像素值大于阈值的部分将会被修改为阈值,小于等于阈值的部分不变。
换句话说,经过截断阈值法处理过的二值化图中的最大像素值就是阈值。


示例:
import cv2 as cv
# 读取图片
flower2 = cv.imread('../images/flower.png')
# 灰度图
gary = cv.cvtColor(flower2, cv.COLOR_BGR2GRAY)
gary = cv.resize(gary, (gary.shape[1]//2, gary.shape[0]//2))
# 二值化_截断阈值法 大于阈值的直接最大值,小于阈值不变 cv.THRESH_TRUNC
_, trunc = cv.threshold(gary, 120, 255, cv.THRESH_TRUNC)
cv.imshow('trunc', trunc)
cv.waitKey(0)
cv.destroyAllWindows()
3.低阈值零处理和超阈值零处理
- 低阈值零处理
低阈值零处理,字面意思,就是像素值小于等于阈值的部分被置为0(也就是黑色),大于阈值的部分不变。


示例:
import cv2 as cv
# 读取图片
flower2 = cv.imread('../images/flower.png')
# 灰度图
gary = cv.cvtColor(flower2, cv.COLOR_BGR2GRAY)
gary = cv.resize(gary, (gary.shape[1]//2, gary.shape[0]//2))
# 二值化_低阈值零处理 小于阈值的直接最小值,大于阈值的不变 cv.THRESH_TOZERO
_, tozero = cv.threshold(gary, 120, 255, cv.THRESH_TOZERO)
cv.imshow('tozero', tozero)
cv.waitKey(0)
cv.destroyAllWindows()
- 超阈值零处理
超阈值零处理就是将灰度图中的每个像素与阈值进行比较,像素值大于阈值的部分置为0(也就是黑色),像素值小于等于阈值的部分不变。


示例:
import cv2 as cv
# 读取图片
flower2 = cv.imread('../images/flower.png')
# 灰度图
gary = cv.cvtColor(flower2, cv.COLOR_BGR2GRAY)
gary = cv.resize(gary, (gary.shape[1]//2, gary.shape[0]//2))
# 二值化_超阈值零处理 大于阈值的直接最小值,小于阈值的不变 THRESH_TOZERO_INV
_, tozero_INV = cv.threshold(gary, 120, 255, cv.THRESH_TOZERO_INV)
cv.imshow('tozero_INV', tozero_INV)
cv.waitKey(0)
cv.destroyAllWindows()
4.OTSU阈值法
cv2.THRESH_OTS 并不是一个有效的阈值类型或标。THRESH_OTSU 本身并不是一个独立的阈值化方法,而是与 OpenCV 中的二值化方法结合使用的一个标志。具体来说,THRESH_OTSU 通常与 THRESH_BINARY 或 THRESH_BINARY_INV 结合使用。在实际应用中,如果你使用 THRESH_OTSU 标志但没有指定其他二值化类型,默认情况下它会与 THRESH_BINARY 结合使用。也就是说,当你仅指定了 cv2.THRESH_OTSU,实际上等同于同时指定了 cv2.THRESH_BINARY + cv2.THRESH_OTSU。
在介绍OTSU阈值法之前,我们首先要了解一下双峰图片的概念。
双峰图片就是指灰度图的直方图上有两个峰值,直方图就是对灰度图中每个像素值的点的个数的统计图,如下图所示。

-
灰度图直方图的基础概念
-
灰度级:
-
在灰度图像中,每个像素的值代表其亮度,通常范围是 0 到 255(对于 8 位灰度图像)。
-
0 表示黑色,255 表示白色,中间的值表示不同程度的灰色。
-
-
直方图定义:
-
直方图是一个柱状图,其中 x 轴表示灰度级(从 0 到 255),y 轴表示对应灰度级在图像中出现的次数(频率)。
-
每个柱子的高度代表该灰度级在图像中出现的像素数量。
-
OTSU算法是通过一个值将这张图分前景色和背景色(也就是灰度图中小于这个值的是一类,大于这个值的是一类。例如,如果你设置阈值为128,则所有大于128的像素点可以被视作前景,而小于等于128的像素点则被视为背景。),通过统计学方法(最大类间方差)来验证该值的合理性,当根据该值进行分割时,使用最大类间方差计算得到的值最大时,该值就是二值化算法中所需要的阈值。通常该值是从灰度图中的最小值加1开始进行迭代计算,直到灰度图中的最大像素值减1,然后把得到的最大类间方差值进行比较,来得到二值化的阈值。以下是一些符号规定:
T:阈值
N0:前景像素点数
N1:背景像素点数
ω0:前景的像素点数占整幅图像的比例
ω1:背景的像素点数占整幅图像的比例
υ0:前景的平均像素值
υ1:背景的平均像素值
υ:整幅图的平均像素值
rows×cols:图像的行数和列数
下面举个例子,有一张大小为4×4的图片,假设阈值T为1,那么:

也就是这张图片根据阈值1分为了前景(像素为2的部分)和背景(像素为0)的部分,并且计算出了OTSU算法所需要的各个数据,根据上面的数据,我们给出计算类间方差的公式:
![]()
g就是前景与背景两类之间的方差,这个值越大,说明前景和背景的差别就越大,效果就越好。OTSU算法就是在灰度图的像素值范围内遍历阈值T,使得g最大,基本上双峰图片的阈值T在两峰之间的谷底。
通过OTSU算法得到阈值之后,就可以结合上面的方法根据该阈值进行二值化,在本实验中有THRESH_OTSU和THRESH_INV_OTSU两种方法,就是在计算出阈值后结合了阈值法和反阈值法。
注意:使用OTSU算法计算阈值时,组件中的thresh参数将不再有任何作用。

示例:
import cv2 as cv
flower2 = cv.imread('../images/flower.png')
# 灰度图
gary = cv.cvtColor(flower2, cv.COLOR_BGR2GRAY)
gary = cv.resize(gary, (gary.shape[1]//2, gary.shape[0]//2))
# OTSU阈值法 默认结合了cv.THRESH_BINARY cv.THRESH_OTSU = cv.THRESH_OTSU + cv.THRESH_BINARY
thresh1, otsu = cv.threshold(gary, 172, 255, cv.THRESH_OTSU)
cv.imshow('otsu', otsu)
thresh2, otsu_INV = cv.threshold(gary, 172, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)
cv.imshow('otsu_inv', otsu_INV)
print(thresh1)
print(thresh2)
cv.waitKey(0)
cv.destroyAllWindows()
5.自适应二值化
与二值化算法相比,自适应二值化更加适合用在明暗分布不均的图片,因为图片的明暗不均,导致图片上的每一小部分都要使用不同的阈值进行二值化处理,这时候传统的二值化算法就无法满足我们的需求了,于是就出现了自适应二值化。
自适应二值化方法会对图像中的所有像素点计算其各自的阈值,这样能够更好的保留图片里的一些信息。自适应二值化组件内容如下图所示:

语法:
cv2.adaptiveThreshold(image_np_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 7, 10)
参数:
maxval:最大阈值,一般为255
adaptiveMethod:小区域阈值的计算方式:
ADAPTIVE_THRESH_MEAN_C:小区域内取均值
ADAPTIVE_THRESH_GAUSSIAN_C:小区域内加权求和,权重是个高斯核
thresholdType:二值化方法,只能使用THRESH_BINARY、THRESH_BINARY_INV,也就是阈值法和反阈值法
blockSize:选取的小区域的面积,如7就是7*7的小块。
c:最终阈值等于小区域计算出的阈值再减去此值
5.1 取均值
比如一张图片的左上角像素值如下图所示:

假如我们使用的小区域是3*3的,那么就会从图片的左上角开始(也就是像素值为162的地方)计算其邻域内的平均值,如果处于边缘地区就会对边界进行填充,填充值就是边界的像素点,如下图所示:

那么对于左上角像素值为162的这个点,161(也就是上图中括号内的计算结果,结果会进行取整)就是根据平均值计算出来的阈值,接着减去一个固定值C,得到的结果就是左上角这个点的二值化阈值了,接着根据选取的是阈值法还是反阈值法进行二值化操作。紧接着,向右滑动计算每个点的邻域内的平均值,直到计算出右下角的点的阈值为止。我们所用到的不断滑动的小区域被称之为核,比如3*3的小区域叫做3*3的核,并且核的大小都是奇数个,也就是3*3、5*5、7*7等。
自适应二值化(Adaptive Thresholding)的核心思想就是为图像中的每个像素点计算一个局部阈值。这种方法与全局阈值化不同,后者对整个图像使用同一个固定的阈值。而在自适应二值化中,每个像素的阈值是基于其周围邻域内的像素值动态确定的。
示例:
import cv2 as cv
flower2 = cv.imread('../images/flower.png')
# 灰度图
gary = cv.cvtColor(flower2, cv.COLOR_BGR2GRAY)
gary = cv.resize(gary, (gary.shape[1]//2, gary.shape[0]//2))
# 每一个像素点都有一个阈值,每一个阈值都是小区域计算的
# 自适应二值化 小区域计算 必须结合阈值法或者反阈值法
# 取均值
auto_mean = cv.adaptiveThreshold(gary, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 7, 2)
cv.imshow('auto_mean', auto_mean)
cv.waitKey(0)
cv.destroyAllWindows()
5.2 取加权均值
对小区域内的像素进行加权求和得到新的阈值,其权重值来自于高斯分布。
高斯分布,通过概率密度函数来定义高斯分布,一维高斯概率分布函数为:


此时我们拓展到二维图像,一般情况下我们使x轴和y轴的相等并且,此时我们可以得到二维高斯函数的表达式为:

高斯概率函数是相对于二维坐标产生的,其中(x,y)为点坐标,要得到一个高斯滤波器模板,应先对高斯函数进行离散化,将得到的值作为模板的系数。例如:要产生一个3*3的高斯权重核,以核的中心位置为坐标原点进行取样,其周围的坐标如下图所示(x轴水平向右,y轴竖直向上)

将坐标带入上面的公式中,即可得到一个高斯权重核。
而在opencv里,当kernel(小区域)的尺寸为1、3、5、7并且用户没有设置sigma的时候(sigma <= 0),核值就会取固定的系数,这是一种默认的值是高斯函数的近似。
| kernel尺寸 | 核值 |
|---|---|
| 1 | [1] |
| 3 | [0.25, 0.5, 0.25] |
| 5 | [0.0625, 0.25, 0.375, 0.25, 0.0625] |
| 7 | [0.03125, 0.109375, 0.21875, 0.28125, 0.21875, 0.109375, 0.03 |
比如kernel的尺寸为3*3时,使用:

进行矩阵的乘法,就会得到如下的权重值,其他的类似。

而当kernels尺寸超过7的时候,如果sigma设置合法(用户设置了sigma),则按照高斯公式计算.当sigma不合法(用户没有设置sigma),则按照如下公式计算sigma的值:

某像素点的阈值计算过程如下图所示:

首先还是对边界进行填充,然后计算原图中的左上角(也就是162像素值的位置)的二值化阈值,其计算过程如上图所示,再然后根据选择的二值化方法对左上角的像素点进行二值化,之后核向右继续计算第二个像素点的阈值,第三个像素点的阈值…直到右下角(也就是155像素值的位置)为止。
当核的大小不同时,仅仅是核的参数会发生变化,计算过程与此是一样的。
示例:
import cv2 as cv
flower2 = cv.imread('../images/flower.png')
# 灰度图
gary = cv.cvtColor(flower2, cv.COLOR_BGR2GRAY)
gary = cv.resize(gary, (gary.shape[1]//2, gary.shape[0]//2))
# 每一个像素点都有一个阈值,每一个阈值都是小区域计算的
# 自适应二值化 小区域计算 必须结合阈值法或者反阈值法
# 取加权均值法 高斯核
auto_gauss = cv.adaptiveThreshold(gary, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 7, 2)
cv.imshow('auto_gauss', auto_gauss)
cv.waitKey(0)
cv.destroyAllWindows()
 -- 翻转、仿射变换与二值化核心技巧&spm=1001.2101.3001.5002&articleId=149578554&d=1&t=3&u=a721d4d4baf54d4cb84abc4641242405)
5499

被折叠的 条评论
为什么被折叠?



