目录
1背景知识
针对单色图像的分割算法基于处理灰度值的两类特性之一:不连续性和相似性
灰度局部剧烈变化检测为基础的分割方法
2 点,线和边缘检测
2.1 基础知识
1.一阶导数通常在图像中产生较粗的边缘
2.二阶导数对精细细节有较强的响应
3.二阶导数在灰度斜坡和灰度台阶过渡处会产生双边缘响应
4.二阶导数的符号可用于确定边缘的过渡是从亮到暗还是从暗到亮
2.2 点的检测
使用拉普拉斯算子:
▽
2
f
(
x
,
y
)
=
∂
2
f
∂
x
2
+
∂
2
f
∂
y
2
=
f
(
x
+
1
,
y
)
+
f
(
x
−
1
,
y
)
+
f
(
x
,
y
+
1
)
+
f
(
x
,
y
−
1
)
−
4
f
(
x
,
y
)
\bigtriangledown ^2f(x,y)=\frac{\partial^2f }{\partial x^2 }+\frac{\partial^2f }{\partial y^2 }=f(x+1,y)+f(x-1,y)+f(x,y+1)+f(x,y-1)-4f(x,y)
▽2f(x,y)=∂x2∂2f+∂y2∂2f=f(x+1,y)+f(x−1,y)+f(x,y+1)+f(x,y−1)−4f(x,y)
下图是点检测(拉普拉斯)模板
2.3 线检测
复杂度更高,可使用下列线检测模板
第一个模板对于水平线有最佳响应。
第二个模板对于
4
5
。
45^。
45。方向的线有最佳响应。
第三个模板对于垂直线有最佳响应。
第四个模板对于
−
4
5
。
-45^。
−45。方向的线有最佳响应。
应用上述模板可以对特定方向的线进行更好的检测。
2.4 边缘模型
该模型是基于灰度突变来分割图像的最常用的方法。
- 台阶边缘是指在1个像素的距离上发生两个灰度级间理想的过渡。
- 斜坡模型中斜坡与边缘的模糊程度成反比。
- 屋顶边缘是通过一个区域的线的模型,屋顶边缘的基底(宽度)由该线的宽度和尖锐度决定。
一阶导数的幅度可用于检测图像中的某个点处是否存在一个边缘,二阶导数的符号可用于确定一个边缘像素位于该边缘的暗的一侧还是亮的一侧。
边缘检测的三步骤:
- 1.为降噪对图像进行平滑处理
- 2.边缘点的检测
- 3.边缘定位
2.5基本边缘检测
寻找边缘,检测灰度变化可以使用一阶或二阶导数完成。
使用梯度来寻找边缘的强度和方向。
Prewitt算子公式:
g
x
=
(
z
7
+
z
8
+
z
9
)
−
(
z
1
+
z
2
+
z
3
)
g_x=(z_7+z_8+z_9)-(z_1+z_2+z_3)
gx=(z7+z8+z9)−(z1+z2+z3)
g
y
=
(
z
3
+
z
6
+
z
9
)
−
(
z
1
+
z
4
+
z
7
)
g_y=(z_3+z_6+z_9)-(z_1+z_4+z_7)
gy=(z3+z6+z9)−(z1+z4+z7)
Sobel算子公式:能较好的抑制噪声
g
x
=
(
z
7
+
2
z
8
+
z
9
)
−
(
z
1
+
2
z
2
+
z
3
)
g_x=(z_7+2z_8+z_9)-(z_1+2z_2+z_3)
gx=(z7+2z8+z9)−(z1+2z2+z3)
g
y
=
(
z
3
+
2
z
6
+
z
9
)
−
(
z
1
+
2
z
4
+
z
7
)
g_y=(z_3+2z_6+z_9)-(z_1+2z_4+z_7)
gy=(z3+2z6+z9)−(z1+2z4+z7)
Roberts算子公式:该算子是最早尝试使用具有对角优势的二维模板之一。
g
x
=
(
z
9
−
z
5
)
g_x=(z_9-z_5)
gx=(z9−z5)
g
y
=
(
z
8
−
z
6
)
g_y=(z_8-z_6)
gy=(z8−z6)
Marr-Hildreth
灰度变化与图像尺寸无关,检车要求使用不同尺寸的算子
灰度的突然变化会在一阶导数中引起波峰或波谷,或在二阶导数中等效地引起零交叉。
# Prewitt算子
kernelx = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=int)
kernely = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)
x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Prewitt = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
# Sobel算子
x = cv2.Sobel(grayImage, cv2.CV_16S, 1, 0)
y = cv2.Sobel(grayImage, cv2.CV_16S, 0, 1)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
# Roberts算子
kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
kernely = np.array([[0, -1], [1, 0]], dtype=int)
x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
2.6 更先进的边缘检测技术
Marr-Hildreth边缘检测器:
-
得出结论:
灰度变化与图像尺寸无关
灰度的突然变化会在一阶导数中引起波峰或波谷,或在二阶导数中等效地引起零交叉。 -
该检测器实现步骤如下:
1.用一个n*n的高斯低通滤波器对输入图像滤波
2.计算图像的拉普拉斯
3.找到步骤2所得图像的零交叉
Canny边缘检测:该边缘检测器十分优秀
import cv2
import numpy as np
image = cv2.imread('C:\jimei.jpg', cv2.IMREAD_GRAYSCALE)
blurred = cv2.GaussianBlur(image, (5, 5), 0)
edges = cv2.Canny(blurred, 50, 150)
cv2.namedWindow('img',cv2.WINDOW_NORMAL)
cv2.resizeWindow('img',800,600)
cv2.namedWindow('canny',cv2.WINDOW_NORMAL)
cv2.resizeWindow('canny',800,600)
cv2.imshow('img', image)
cv2.imshow('canny', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
3 阈值处理
假设灰度直方图对应于图像f(x,y),该图像由暗色背景上的较亮物体组成,以这样的组成方式,物体像素和背景像素所具有的灰度值组合成了两种支配模式。从背景中提取物体的一种明显方法是选择一个将这些模式分开的阈值T。然后,f(x,y)>T的任何点(ī,y)称为一个对象点;否则将该点称为背景点。
分割后的图像g(x,y)有下列式子给出:
g
(
x
,
y
)
=
{
1
f
(
x
,
y
)
>
T
0
f
(
x
,
y
)
≤
T
g(x,y)=\begin{cases}1& f(x,y)>T \\0& f(x,y)\le T\end{cases}
g(x,y)={10f(x,y)>Tf(x,y)≤T
阈值处理分为可变阈值处理和全局阈值处理。
3.1 全局阈值处理
- 步骤如下
1.为全局阈值T选择一个初始估计值、
2.用T分割该图像。这将产生两组像素:G1由灰度值大于T的所有像素组成,G2由所有小T的像素组成
3.对G1和G2的像素分别计算平均灰度值m1和m2.
4.计算一个新阈值: T = 1 2 ( m 1 + m 2 ) T=\frac{1}{2}(m1+m2) T=21(m1+m2)
5.重复步骤2到步骤4,直到连续迭代中的T值见的差小于一个预定义的参数为止。
3.2 Otsu方法
该方法在类间方法最大的情况下是最佳的。即众所周知的统计鉴别分析中所用的度量。基本概念是好值分类就它的像素灰度值而论应该是截然不同的,反过来说,就它的灰度值而言给出最好的类间分离的值就是最好的(最佳的)阈值。除了其最佳性之外,Otsu方法有一个重要的特性,即它完全以在一幅图像的直方图上执行计算为基础,直方图是很容易得到的一维阵列。
下面为T=125时的阈值分割代码
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("C:\jimei.jpg", flags=0)
ret2, imgOtsu = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU) # 阈值分割, thresh=T
plt.figure(figsize=(7, 7))
plt.title("OTSU binary(T={})".format(round(ret2))), plt.axis('off')
plt.imshow(imgOtsu, 'gray')
plt.tight_layout()
plt.show()
- 改进全局阈值处理
可使用图像平滑来改善
可利用边缘来改进
3.3可变阈值处理
可变阈值处理最简单的方法之一是把一幅图像分为不重叠的矩形。这种方法用于补偿光照和/或反射的不均匀性。选择的矩形要足够小,以便每个矩形的光照都近似是均匀的。
更为一般的方法是在一幅图像中的每一点f(x,y)计算阈值,该阈值是以一个或多个在f(x,y)邻域计算的特性为基础的。
还可以使用移动平均。
4 基于区域的分割
4.1区域生长
区域生长是根据预先定义的生长准则将像素或子区域组合为更大区域的过程。基本方法是从一组“种子”点开始,将与种子预先定义的性质相似的那些邻域像素添加到每个种子上来形成这些生长区域(如特定范围的灰度或颜色)。
4.2 区域分裂与聚合
可供选择的方法是首先将一幅图像细分为一组任意的不相交区域,然后聚合和/或分裂这些区域。
用形态学分水岭的分割:通过构建分水岭分割算法所需的水坝或分水线。