Python OpenCV图像分割:阈值与轮廓算法详解
本文详解Python OpenCV中的图像分割技术,涵盖固定阈值、自适应阈值及Otsu大津法。重点解析基于轮廓的字符分离流程,包括二值化、轮廓提取与包围框计算,并提供完整代码示例,帮助开发者实现高精度的图像分割应用。
前言
图像分割的核心任务,是依据灰度、色彩、空间纹理或几何形状等特征,将图像划分为若干个互不重叠的区域。
最基础的图像分割场景,即是将目标物体从背景中分离出来。
1.图像二值化
在opencv-python库中,cv2.threshold函数常用于实现基础的图像二值化分割功能。
其函数调用格式为:retval, dst = cv2.threshold(src, thresh, maxval, thresholdType[, dst])
参数src代表原图像,且必须为灰度图像。
参数dst用于存储处理后的结果图像。
参数thresh指定用于判断的阈值。
参数maxVal定义结果图像中像素的最大值。
参数thresholdType指定二值化的具体类型。

然而,使用固定阈值方法存在两个主要局限:
问题一:
该方法依据全图统一的阈值对像素进行判断,并非在所有场景下都能取得理想效果。
例如,当图像不同区域的光照条件存在显著差异时,统一阈值往往导致分割失败。

问题二:
阈值需要人工手动设定,不同图片适宜的阈值各不相同,更换图片后可能需要重新调整代码中的阈值参数。

为解决全图统一阈值带来的问题,可采用自适应阈值分割法。
自适应阈值分割算法依据像素周围的局部区域来确定该像素的阈值。
这意味着同一图像的不同区域可以拥有不同的阈值。
这种方法能为光照变化较大的图像提供更好的分割效果。
2.自适应阈值分割算法
其函数调用格式为:dst= cv2.adaptiveThreshold(src, maxValue, adaptiveMethod,thresholdType, blockSize, C, dst=None)
各参数具体解释如下:
参数src代表原图像,必须为灰度图像。
参数maxValue定义结果图像中像素的最大值,通常设置为255。
参数adaptiveMethod指定阈值的计算方法,包含以下两种计算方式:

参数thresholdType指定二值化方式,例如cv2.THRESH_BINARY、cv2.THRESH_TRUNC、
cv2.THRESH_TOZERO等。

参数blockSize定义局部区域的大小。
参数C为阈值计算中减去的常数。
该方法的缺点在于blockSize需要手动指定,但实际物体的大小存在差异,难以一概而论。
3.Otsu阈值分割算法
该算法能够根据图像内容自动计算最佳阈值:
- Otsu阈值分割算法
- 大津法
- 直方图技术
其函数调用格式为:retval, dst = cv2.threshold(src, thresh, maxval, thresholdType[, dst])
各参数具体解释如下:
- 参数src代表原图像,要求必须是灰度图像。
- 参数dst用于存储结果图像。
- 参数thresh在此模式下无实际作用。
- 参数maxVal定义像素灰度的最大值。
- 参数thresholdType指定阈值类型,需在原有参数值基础上额外传递一个参数值,即cv2.THRESH_OTSU。
- 例如组合使用:cv2.THRESH_BINARY+cv2.THRESH_OTSU
利用固定阈值算法进行分割,适用的图片范围较为局限。
同一个固定阈值,在某些图像上表现良好,但在其他图片上效果可能不佳。
如:

利用Otsu阈值算法进行分割,适用的图片范围相对较广。
对于每张图片,Otsu阈值算法能自动找到针对性的最佳阈值。
如:

4.基于轮廓的字符分离
具体分割步骤如下:
1. 检测出图像中字符的轮廓。
2. 获取每一条轮廓的包围框,并根据包围框坐标提取感兴趣区域(ROI)。
4.1轮廓检测
函数调用格式为:contours, hierarchy = cv2.findContours(image, mode, method)
各参数具体解释如下:
参数contours返回轮廓列表,每条轮廓包含构成该轮廓的一系列点的坐标。
参数hierarchy表示轮廓之间的层级关系。
参数image代表原始图像,需为二值图。
参数mode指定轮廓的检索模式。

参数method指定轮廓的近似办法。

4.2轮廓绘制
函数调用格式为:cv2.drawContours(image, contours, contourIdx, color, thickness)
- 参数image指定要在哪张图片上绘制轮廓。
- 参数contours为轮廓列表。
- 参数contourIdx指定绘制轮廓list中的哪条轮廓,若设为-1,则绘制其中的所有轮廓。
- 参数color指定轮廓的颜色。
- 参数thickness(可选)指定轮廓的宽度。
import cv2
img=cv2.imread("D:\\desk\\images\\car_license\\test1.png")
#去噪
image=cv2.GaussianBlur(img,(3,3),0)
#转为灰度图
gray1 = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#Ostu阈值分割
ret, th1 = cv2.threshold(gray1, 127,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
'''轮廓检测与绘制'''
#检测轮廓(外轮廓)
th1=cv2.dilate(th1,None) #膨胀,保证同一个字符只有一个外轮廓
contours,hierarchy=cv2.findContours(th1,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#轮廓可视化
th1_bgr=cv2.cvtColor(th1,cv2.COLOR_GRAY2BGR) #转为三通道图
cv2.drawContours(th1_bgr,contours,-1,(0,0,255),2) #轮廓可视化
cv2.imshow("th1_bgr",th1_bgr)
cv2.waitKey()4.3包围框获取
函数调用格式为:rect= cv2.boundingRect(points)
- 参数points为一组点的坐标。
- 参数rect返回能够包围这些点的最小外接矩形信息,格式为(x,y,width,height)。

4.4矩形绘制
函数调用格式为:cv2.rectangle(img, pt1, pt2, color[, thickness)
- 参数img指定要绘制的图片。
- 参数pt1为矩形的某个顶点的坐标。
- 参数pt2为和pt1相对的顶点坐标。
- 参数color指定矩形的颜色。
- 参数thickness(可选)指定矩形轮廓的宽度。
基于轮廓的字符分离完整代码如下:
import cv2
img=cv2.imread("D:\\desk\\images\\car_license\\test1.png")
#去噪
image=cv2.GaussianBlur(img,(3,3),0)
#转为灰度图
gray1 = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#Ostu阈值分割
ret, th1 = cv2.threshold(gray1, 127,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
'''轮廓检测与绘制'''
#检测轮廓(外轮廓)
th1=cv2.dilate(th1,None) #膨胀,保证同一个字符只有一个外轮廓
contours,hierarchy=cv2.findContours(th1,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#轮廓可视化
th1_bgr=cv2.cvtColor(th1,cv2.COLOR_GRAY2BGR) #转为三通道图
# cv2.drawContours(th1_bgr,contours,-1,(0,0,255),2) #轮廓可视化
'''包围框获取'''
words=[] #保存包围框信息
height,width=th1.shape
for contour in contours: #对于每一条轮廓
rest=cv2.boundingRect(contour) #得到这条轮廓的外接矩阵
#只有高宽比在1.5到3.5之间,且高 度比图片高度大于0.3的矩阵才保留
if rest[3]/rest[2]>1.5 and rest[3]/rest[2]<3.5 and rest[3]/height>0.3:
words.append(rest) #将当前矩形加入矩形列表
cv2.rectangle(th1_bgr,(rest[0],rest[1]),(rest[0]+rest[2],rest[1]+rest[3]),(0,0,255),3) #绘制矩形
#显示
# cv2.imshow("img",img)
cv2.imshow("th1",th1)
cv2.imshow("th1_bgr",th1_bgr)
cv2.waitKey()以上就是详解Python OpenCV图像分割算法的实现的详细内容,更多关于OpenCV图像分割算法的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









