【图像处理】灰度图像与二值化
参考文章:
OpenCV——灰度图像与图像二值化处理
一、灰度图
1.1 灰度图是什么
灰度图(Gray Scale Image) 仅用灰度色阶表示图像亮度的非色彩图像,像素值范围通常为0(纯黑)到255(纯白)之间的256个等级。
- 灰度图与彩色图的核心区别:彩色图由R、G、B三通道组成,而灰度图仅单通道。彩色图转灰度图的本质是将三通道合并为单通道。
- 灰度图像每个像素只有一个采样颜色,显示为从黑到白的灰度渐变(256级,8位存储),不同于只有黑白两色的黑白图像。
一副灰度图像示例:
二、图像二值化
2.1 图像二值化是什么
图像二值化:通过设定阈值将灰度图像转换为仅含两个值(通常为0和255)的图像,是图像处理的基础技术
2.2 常见的二值化方法
2.2.1 最大值法
对彩色图像的每个像素,从R、G、B三通道值中选取最大值作为灰度图对应位置的像素值。
例如,某像素RGB值为(91,121,46),最大值为121,故灰度值为121。
代码示例:
import cv2 as cv
import numpy as np
#读图
cat=cv.imread("../images/cat1.png")
h,w=cat.shape[:2]
black=np.zeros((h,w),dtype=np.uint8)#遍历行
for i in range(h):#遍历列for j in range(w):black[i,j]=max(cat[i,j][0],cat[i,j][1],cat[i,j][2])
#显示
cv.imshow("black",black)
cv.waitKey(0)
cv.destroyAllWindows()
2.2.2 平均值法
对彩色图像的每个像素,计算R、G、B三通道值的平均值(求和后除以3,取整)作为灰度值。
示例:某像素RGB值为(91,121,46),平均值为(91+121+46)/3=86,故灰度值为86。
代码示例:
#读图
cat=cv.imread("../images/cat1.png")
h,w=cat.shape[:2]
black=np.zeros((h,w),dtype=np.uint8)#遍历行
for i in range(h):#遍历列for j in range(w):#防止溢出black[i,j]=np.uint8((int(cat[i,j,0])+int(cat[i,j,1])+int(cat[i,j,2]))//3)
#显示
cv.imshow("black",black)
cv.waitKey(0)
cv.destroyAllWindows()
2.2.3 加权平均值法
按固定权重计算R、G、B三通道的加权和作为灰度值,常用权重为:R×0.299、G×0.587、B×0.114(权重和为1)。
示例:某像素RGB值为(10,121,46),加权和为10×0.299+121×0.587+46×0.114=79,故灰度值为79。
代码示例:
import cv2 as cv
import numpy as np
#读图
cat=cv.imread("../images/cat1.png")
h,w=cat.shape[:2]
black=np.zeros((h,w),dtype=np.uint8)
#定义每个通道上的权重
wb,wg,wr=0.114,0.587,0.299
#遍历行
for i in range(h):#遍历列for j in range(w):black[i,j]=round(wb*cat[i,j][0]+wg*cat[i,j][1]+wr*cat[i,j][2])
#显示
cv.imshow("black",black)
cv.waitKey(0)
cv.destroyAllWindows()
最常见的加权均值代码可直接使用OpenCV内置函数实现。
2.2.4 两个极端的灰度值
灰度图像中亮度的两个极端:
- 最暗的灰度值:0(纯黑,无任何亮度)
- 最亮的灰度值:255(纯白,最大亮度)
(上:灰度值0(纯黑);下:灰度值255(纯白))
2.3 图像二值化处理
二值图像的二维矩阵仅含0(黑)和1(或255,白),数据类型通常为1个二进制位,适用于文字识别、掩膜存储等场景。
一副二值化后的图像示例:
注意:二值化处理的输入必须是灰度图,过程是将灰度图像素按规则修改为0和maxval(通常255),以简化图像、节约资源、辅助边缘检测。
2.3.1全局阈值法:
binary = cv.threshold(img,thresh,maxval,type)
-
参数说明:
img
:输入的灰度图thresh
:设定的阈值maxval
:最大值(通常为255)type
:阈值处理类型
-
返回值:
- 第一个值(常用
_
表示):计算出的阈值(自适应阈值时自动生成) - 第二个值(
binary
):二值化后的图像矩阵
- 第一个值(常用
1. 阈值法(THRESH_BINARY)
像素值≤阈值时设为0,>阈值时设为maxval(前景)。
示例:
效果对比:
(上:灰度图;下:二值化图)
代码示例:
import cv2 as cv
#读图
flower=cv.imread("../images/flower.png")
#灰度化
gray=cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
#二值化:阈值法
_,binary=cv.threshold(gray,127,255,cv.THRESH_BINARY)
print()#返回的是一个浮点数cv.imshow("gray",gray)
cv.imshow("binary",binary)
cv.waitKey(0)
cv.destroyAllWindows()
代码结果:
灰度化也可直接用cv.IMREAD_GRAYSCALE
标志:cv.imread()
以灰度格式读取图像。
2. 反阈值法(THRESH_BINARY_INV)
与阈值法相反:像素值>阈值时设为0,≤阈值时设为maxval。
示例:
效果对比:
(上:灰度图;下:二值化图)
代码示例:
import cv2 as cv
#读图
flower=cv.imread("../images/flower.png")
#灰度化
gray=cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
#二值化:反阈值法
gray=cv.resize(gray, (480,480))
_,binary_inv=cv.threshold(gray, 127, 255,cv.THRESH_BINARY_INV)cv.imshow("gray",gray)
cv.imshow("binary_inv",binary_inv)
cv.waitKey(0)
cv.destroyAllWindows()
3. 截断阈值法(THRESH_TRUNC)
像素值>阈值时设为阈值,≤阈值时不变(最大像素值为阈值,maxval
参数无效)。
示例:
效果对比(阈值255时与原图一致):
(上:灰度图;下:二值化图)
代码示例:
import cv2 as cv
#读图
flower=cv.imread("../images/flower.png")
#灰度化
gray=cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray=cv.resize(gray,(480,480))
#截断阈值法
thresh,truc=cv.threshold(gray,127,255,cv.THRESH_TRUNC)cv.imshow("gray",gray)
cv.imshow("truc",truc)
cv.waitKey(0)
cv.destroyAllWindows()
4. 低阈值零处理(THRESH_TOZERO)
像素值≤阈值时设为0,>阈值时不变(生成的图像像素值可能多于2个)。
示例:
效果对比:
(上:灰度图;下:二值化图)
代码示例:
import cv2 as cv
#读图
flower=cv.imread("../images/flower.png")
#灰度化
gray=cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray=cv.resize(gray,(480,480))
#低阈值,零处理
thresh,zeros=cv.threshold(gray,127,255,cv.THRESH_TOZERO)
cv.imshow("zero",zeros)
cv.waitKey(0)
cv.destroyAllWindows()
5. 超阈值零处理(THRESH_TOZERO_INV)
像素值>阈值时设为0,≤阈值时不变。
示例:
效果对比:
(上:灰度图; 下:二值化图)
2.3.2 非全局阈值
全局阈值法需手动设置阈值,不适用于明暗不均的图像,因此需自动计算阈值的方法。
1. OTSU阈值法
THRESH_OTSU
是与二值化方法结合使用的标志(通常与THRESH_BINARY
或THRESH_BINARY_INV
结合),通过最大类间方差自动计算阈值,适用于双峰图像(灰度直方图有两个峰值)。
灰度图直方图基础:
- 灰度级:0(黑)到255(白)的亮度值
- 直方图:x轴为灰度级,y轴为对应灰度级的像素数量
双峰图像直方图示例:
核心原理:遍历灰度值范围,找到使前景(<阈值)与背景(>阈值)类间方差最大的阈值(类间方差越大,前景与背景差异越明显)。
类间方差公式:
g = ω 0 ( μ 0 − μ ) 2 + ω 1 ( μ 1 − μ ) 2 g=\omega_0(\mu_0-\mu)^2+\omega_1(\mu_1-\mu)^2 g=ω0(μ0−μ)2+ω1(μ1−μ)2
其中:
- T T T:阈值
- N 0 / N 1 N_0/N_1 N0/N1:前景/背景像素数
- ω 0 / ω 1 \omega_0/\omega_1 ω0/ω1:前景/背景像素占比
- μ 0 / μ 1 \mu_0/\mu_1 μ0/μ1:前景/背景平均像素值
- μ \mu μ:整幅图平均像素值
效果对比:
代码示例:
import cv2 as cv
#读图
flower=cv.imread("../images/flower.png")
#灰度化
gray=cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray=cv.resize(gray,(480,480))#OTSU阈值法,默认结合阈值法 最大类间方差 cv.THRESH_OTSU=cv.THRESH_OTSU+cv.THRESH_BINARY
thresh,otsu=cv.threshold(gray,127,255,cv.THRESH_OTSU)
cv.imshow("ostu", otsu)
#print(thresh)
#OTSU+反阈值法
thresh,otsu_inv=cv.threshold(gray,127,255,cv.THRESH_OTSU+cv.THRESH_BINARY_INV)
cv.imshow("otsu_inv", otsu_inv)
cv.waitKey(0)
cv.destroyAllWindows()
2. 自适应二值化
适用于明暗分布不均的图像,为每个像素计算局部阈值(基于周围邻域像素值)。
函数:cv.adaptiveThreshold(image_np_gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 7, 10)
参数说明:
maxval
:最大阈值(通常255)adaptiveMethod
:局部阈值计算方式ADAPTIVE_THRESH_MEAN_C
:邻域均值ADAPTIVE_THRESH_GAUSSIAN_C
:邻域高斯加权和
thresholdType
:二值化类型(仅THRESH_BINARY
或THRESH_BINARY_INV
)blockSize
:邻域大小(奇数,如7×7)c
:阈值修正值(最终阈值=邻域计算值-c)
(1)取均值
以3×3邻域为例,计算每个像素邻域内的平均值(边缘填充边界像素),减去c
得到阈值,再按二值化规则处理。
计算过程示例:
(2)加权求和
基于高斯分布的权重对邻域像素加权求和,权重来自高斯核(如3×3核的默认权重)。
二维高斯函数:
g ( x , y ) = 1 2 π σ 2 e − ( x 2 + y 2 ) 2 σ 2 g(x,y)=\frac{1}{2\pi \sigma ^{2}}e^{-\frac{(x^{2}+y^{2})}{2\sigma ^{2}}} g(x,y)=2πσ21e−2σ2(x2+y2)
3×3高斯核示例:
计算过程示例:
代码示例:
import cv2 as cv
#读图
flower=cv.imread("../images/flower.png")
#灰度化
gray=cv.cvtColor(flower,cv.COLOR_BGR2GRAY)
gray=cv.resize(gray,(480,480))#自适应二值化,必须结合阈值法或者反阈值法,返回值只有一个
binary=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,7,10)
cv.imshow("binary", binary)
binary_gauss=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,11,10)
cv.imshow("adaptive_thresh", binary_gauss)
cv.waitKey(0)
cv.destroyAllWindows()
四、总结
-
灰度图像生成:
- 最大值法:突出亮部,可能丢失暗部信息。
- 平均值法:适用于均衡图像,可能降低对比度。
- 加权平均值法:符合人眼感知,保留重要视觉信息。
-
二值化处理:
- 阈值法/反阈值法:像素值与阈值比较后全量转换(0或maxval)。
- 截断阈值法:仅高于阈值的像素被截断为阈值。
- 低阈值零处理:低于阈值的像素置0,其余保留。
- 超阈值零处理:高于阈值的像素置0,其余保留。
更多资料:https://www.csdn.net/