图像分割的依据是基于图像中各区域具有不同的特性(比如,灰度、颜色、纹理)。图像分割的目的是将图像划分成若干具有相近或相同特性的子区域,以便继续在分割成的相关区域中提取目标,并进而根据目标的特征或结构信息对其进行分类和识别,最后再给出对整幅图像分析结果的描述信息。所以,图像分割就显得尤为重要。
在数字图像中,对图像分割一个比较严格的定义:
1、分割成的所有子区域的并应能够构成原来的区域R。
2、分割成的各个子区域互不重叠。
3、分割得到的属于同一区域的像素应具有某些相同的特性。
4、分割得到的属于不同区域的像素应具有不同的性质。
5、同一子区域内的像素应当是连通的。
首先介绍一下图像边缘的概念,由于自然景物中物体、背景、区域的物理形状、几何特性、材质特性及其反射系数的不同,导致了图像中灰度的突变,并在图像中形成了一个不同的区域。图像边缘意味着图像中一个区域的终结和另一个区域的开始。,也就是两个相邻区域之间的像素几何构成了图像的边缘。图像边缘的特点是两个的灰度在通过边缘时将发生某种显著的变化
理想的阶跃变化如左图,实际上大多数是右图
基于边缘的图像分割方法,第一步就应该是先确定图像中的边缘信息,然后将他们连在一块作为边界。
Hough变换的边缘检测算法
在实际中,我们多用极坐标的方式来表示一个直线,如下图所示:
通过极坐标的方式来表示X-Y坐标中的一条直线,其实也就相当于把X-Y空间中的一条直线与极坐标中的一组曲线的交点对应起来, 下面这个图很好地表示出了这种关系:
对于怎么具体提取图像中的直线,就不细讲了,可以查阅相关图像处理书籍,简略讲一下实现过程,以及用到的两个重要函数:
实现过程:
首先通过Canny算子获取直线的边缘,然后通过Hough变换获取直线边缘在图像中的坐标,最后按照坐标绘画出来。
Canny函数:
cv.Canny( | image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]] | ) -> | edges |
这里是cv中的canny函数的一种用法,他需要输入6个参数:
image:这是需要输入的图像数据。
threshold1:这是下阈值
threshold2:这是上阈值
可以对照上文中实际的边缘特点的曲线图来理解,灰度值在这两个阈值中间会被认定为边界
apertureSize:Sobel算子的孔径大小。一般用3×3大小的卷积核
Canny算子最终返回的是一个与原图像大小相同的存储边缘数据的矩阵,它是一个二值图像。
HoughLinesP()函数:
cv.HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]]) ->lines
这是cv中HoughLinesP()函数,它需要输入6个参数。
image:这是存储了边缘数据的图像,也就是经过Canny算子提取出来的边缘。
rho:以像素为单位的累加器的距离分辨率。
theta:以弧度表示的累加器的角度分辨率。
threshold:这是与累加器中的结果进行对比,只有大于这个阈值的点,才会被认定是一条直线
minLineLength:最小的线长度,如果线长度低于这个设定的最小长度,将不会被认定为一条直线
maxLineGap:同一直线上的点之间连接的最大允许间距。
HoughLinesP函数最终返回的是一个存储每一段线段起点和终点的矩阵[x1,y1,x2,y2]
实现程序如下所示,所用的图片是用绘图软件随意绘制的图像:
import cv2
import numpy as np
img = cv2.imread('C:\\Users\\yu\\Desktop\\picture_csdn\\lines_test.png', cv2.IMREAD_COLOR)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('img_gray', img_gray)
# Canny边缘检测
img_Canny = cv2.Canny(img_gray, 0, 250, (3, 3))
cv2.imshow('img_canny', img_Canny)
result_HoughLinesP = cv2.HoughLinesP(img_Canny, 1, 1 * np.pi / 180, 10, minLineLength=1, maxLineGap=5)
# 画出检测的线段
for result in result_HoughLinesP:
for x1, y1, x2, y2 in result:
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 255), 2)
cv2.imshow('result', img)
cv2.waitKey(0)
实验图像:
经过Canny算子提取的边缘图像:
最终画出直线的图像: