请写出Canny算子检测边缘的详细步骤。
Canny边缘检测算法可以分为一下五个步骤:
1. 使用高斯滤波器,以平滑图像,滤除噪声。
高斯滤波使用的高斯核是具有x和y两个维度的高斯函数,且两个维度上标准差一般取相同,形式为:
G ( X , Y ) = ∑ x − m x + m ∑ y − m y + m e x p ∣ − x 2 + y 2 2 σ 2 ∣ G(X,Y)=\sum\limits^{x+m}\limits_{x-m}\sum\limits^{y+m}\limits_{y-m}exp\vert-\frac{x^2+y^2}{2\sigma^2}\vert G(X,Y)=x−m∑x+my−m∑y+mexp∣−2σ2x2+y2∣ , m = n − 1 2 m=\frac{n-1}{2} m=2n−1, n n n表示高斯滤波器窗口大小
高斯滤波其实就是将所指像素用周围的像素的某种均值代替(即卷积核),卷积核尺寸越大,去噪能力越强,因此噪声越少,但图片越模糊,canny检测算法抗噪声能力越强,但模糊的副作用也会导致定位精度不高。
2. 计算图像中每个像素点的梯度强度和方向。
图像中的边缘可以指向各个方向,因此Canny算法使用四个算子来检测图像中的水平、垂直和对角边缘。边缘检测的算子(如Roberts,Prewitt,Sobel等)返回水平 G x G_x Gx和垂直 G y G_y Gy方向的一阶导数值,由此便可以确定像素点的梯度 G G G和方向 θ \theta θ。下面以Sobel算子为例讲述如何计算梯度强度和方向。
Sobel算子是两个 3×3 的矩阵,分别为 S x S_x Sx和 S y S_y Sy和前者用于计算图像 X X X方向像素梯度矩阵 G x G_x Gx,后者用于计算图像 Y Y Y方向像素梯度矩阵 G y G_y Gy。具体形式为:
G x = S x ∗ I = [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] ∗ I G_x=S_x*I=\begin{bmatrix}-1&0&+1 \\-2&0&+2\\-1&0&+1\end{bmatrix}*I Gx=Sx∗I=⎣ ⎡−1−2−1000+1+2+1⎦ ⎤∗I, G y = S y ∗ I = [ − 1 − 2 − 1 0 0 0 + 1 + 2 + 1 ] ∗ I G_y=S_y*I=\begin{bmatrix}-1&-2&-1\\0&0&0\\+1&+2&+1 \end{bmatrix}*I Gy=Sy∗I=⎣ ⎡−10+1−20+2−10+1⎦ ⎤∗I, I I I为灰度图像矩阵,由此可得梯度强度矩阵和方向
G = G x 2 + G y 2 G=\sqrt{G_x^2+G^2_y} G=Gx2+Gy2 θ = arctan ( G y G x ) \theta=\arctan(\frac{G_y}{G_x}) θ=arctan(GxGy)
其中 G G G为梯度强度, θ \theta θ表示梯度方向, arctan \arctan arctan为反正切函数。
3. 根据梯度方向,对梯度幅值应用非极大值抑制(non-maximum suppression)。
非极大值抑制的做法为:其基本方法是将当前像素梯度强度与沿正负梯度方向上的相邻像素的梯度强度进行比较,若其最大(即为极值),则保留该像素为边缘点,若不是最大,则对其进行抑制,不将其作为边缘点。如图所示,可将像素的邻接情况划分为4个区域,其中每个区域包含上下两部分。沿梯度方向检测模值的极大值点,即边缘点,遍历8个方向图像像素,把每个像素偏导值与相邻像素的模值比较,取其MAX值为边缘点,置像素灰度值为0.
算法过程如下:
tan ( θ ) = G y G x \tan(\theta)=\frac{G_y}{G_x} tan(θ)=GxGy
G p 1 = ( 1 − tan ( θ ) ) × G E + tan ( θ ) × G N E G_{p_1}=(1-\tan(\theta))\times G_E+\tan(\theta)\times G_{NE} Gp1=(1−tan(θ))×GE+tan(θ)×GNE
G p 2 = ( 1 − tan ( θ ) ) × G W + tan ( θ ) × G S W G_{p_2}=(1-\tan(\theta))\times G_W+\tan(\theta)\times G_{SW} Gp2=(1−tan(θ))×GW+tan(θ)×GSW
如果 G p ≥ G p 1 G_p\ge G_{p_1} Gp≥Gp1 且 G p ≥ G p 2 G_p \ge G_{p_2} Gp≥Gp2, G p G_p Gp 应该成为边缘点否则应该对 G P G_P GP进行抑制。剩余的三个区域计算方法类似。
4. 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
施加非极大值抑制后,剩余像素可以更准确地表示图像中的实际边缘。但仍然存在由于噪声和颜色变化引起的一些边缘像素。为了解决这些杂散响应,必须用弱梯度值过滤边缘像素,并保留具有高梯度值的边缘像素,可以通过选择高低阈值来实现。如果边缘像素的梯度值高于高阈值,则将其标记为强边缘像素;如果边缘像素的梯度值小于高阈值并且大于低阈值,则将其标记为弱边缘像素;如果边缘像素的梯度值小于低阈值,则会被抑制。
算法描述:
if G p ≥ H i g h T h r e s h o l d G_p\ge HighThreshold Gp≥HighThreshold
G p G_p Gp is an strong edge
else if G p ≥ L o w T h r e s h o l d G_p \ge LowThreshold Gp≥LowThreshold
G p G_p Gp is an weak edge
else
G p G_p Gp should be suppressed
5. 通过抑制孤立的弱边缘最终完成边缘检测
到目前为止,被划分为强边缘的像素点已经被确定为边缘,因为它们是从图像中的真实边缘中提取出来的。然而,对于弱边缘像素,将会有一些争论,因为这些像素可以从真实边缘提取也可以是因噪声或颜色变化引起的。为了获得准确的结果,应该抑制由后者引起的弱边缘。通常,由真实边缘引起的弱边缘像素将连接到强边缘像素,而噪声响应未连接。为了跟踪边缘连接,通过查看弱边缘像素及其8个邻域像素,只要其中一个为强边缘像素,则该弱边缘点就可以保留为真实的边缘。
算法描述:
if G p = = L o w T h r e s h o l d G_p == LowThreshold Gp==LowThreshold and G p G_p Gp connected to a strong edge pixel
G p G_p Gp is an strong edge
else
G p G_p Gp should be suppressd
请写出LoG(Laplacian Of Gaussian)算子的计算方法。
高斯拉普拉斯算子( L o G LoG LoG):
对于图像 I ( x , y ) I(x,y) I(x,y), 首先通过尺度为 σ \sigma σ 的高斯平滑:
G σ ( x , y ) = 1 2 π σ 2 exp ( − x 2 + y 2 2 σ 2 ) G_\sigma (x,y)=\frac{1}{\sqrt{2\pi \sigma ^2}}\exp(-\frac{x^2+y^2}{2\sigma ^2}) Gσ(x,y)=2πσ21exp(−2σ2x2+y2)
接着使用拉普拉斯算子检测边缘:
∇ 2 ∣ G σ ( x , y ) ∗ I ( x , y ) ∣ = [ ∇ 2 G σ ( x , y ) ] ∗ I ( x , y ) \nabla ^2 |G_\sigma (x,y) * I(x,y)|=[\nabla ^2G_\sigma (x,y)] * I(x,y) ∇2∣Gσ(x,y)∗I(x,y)∣=[∇2Gσ(x,y)]∗I(x,y)
该式证明如下:
d d t 2 [ h ( t ) ∗ f ( t ) ] = d d t ∫ f ( τ ) h ( t − τ ) d τ = ∫ f ( τ ) d d t 2 h ( t − τ ) d τ = f ( t ) ∗ d d t 2 h ( t ) \begin{aligned} \frac{d}{dt^2}[h(t)*f(t)] &=\frac{d}{dt}\int f(\tau )h(t-\tau )d\tau \\ &=\int f(\tau )\frac{d}{dt^2}h(t-\tau )d\tau \\ &= f(t) * \frac{d}{dt^2}h(t) \end{aligned} dt2d[h(t)∗f(t)]=dtd∫f(τ)h(t−τ)dτ=∫f(τ)dt2dh(t−τ)dτ=f(t)∗dt2dh(t)
所以高斯拉普拉斯算子等价于先对高斯函数求二阶导,再与原图进行卷积,将LoG算子展开即为:
L o G = ∇ 2 G σ ( x , y ) = ∂ 2 G σ ( x , y ) ∂ x 2 + ∂ 2 G σ ( x , y ) ∂ y 2 = x 2 + y 2 − 2 σ 2 2 π σ 6 exp ( − x 2 + y 2 2 σ 2 ) LoG=\nabla^2 G_\sigma(x,y)=\frac{\partial^2 G_\sigma(x,y)}{\partial x^2}+\frac{\partial^2 G_\sigma(x,y)}{\partial y^2}=\frac{x^2+y^2-2\sigma^2}{2\pi\sigma^6}\exp(-\frac{x^2+y^2}{2\sigma ^2}) LoG=∇2Gσ(x,y)=∂x2∂2Gσ(x,y)+∂y2∂2Gσ(x,y)=2πσ6x2+y2−2σ2exp(−2σ2x2+y2)
写出DoG (Difference Of Gaussian)算子的计算方法。
高斯函数差分算子( D o G DoG DoG):
D o G DoG DoG即对不同尺度下的高斯函数的差分。DoG算子的表达式如下:
D o G = G σ 1 − G σ 2 = 1 2 π [ 1 σ 1 e − ( x 2 + y 2 ) / ( 2 σ 1 2 ) − 1 σ 2 e − ( x 2 + y 2 ) / ( 2 σ 2 2 ) ] DoG=G_{\sigma _1}-G_{\sigma _2}=\frac{1}{\sqrt{2\pi }}[\frac{1}{\sigma _1}e^{-(x^2+y^2)/(2\sigma _1^2)}-\frac{1}{\sigma _2}e^{-(x^2+y^2)/({2\sigma _2^2})}] DoG=Gσ1−Gσ2=2π1[σ11e−(x2+y2)/(2σ12)−σ21e−(x2+y2)/(2σ22)]
DoG与LoG之间有何关系?
DoG算子可以用来近似LoG算子。DoG算子和LoG算子具有类似的波形,仅仅是幅度不同,不影响极值点的检测,而DoG算子的计算复杂度显然低于LoG,因此一般使用DoG代替LoG算子。
DoG算子是高斯函数的差分,具体到图像中,就是将图像在不同参数下的高斯滤波结果相减,得到差分图。LoG先对高斯核函数求取二阶导数,再与原图像进行卷积操作。LoG算子和DoG算子既可以用于检测图像边缘,也可用于检测局部极值点或极值区域。
相似性证明如下
因为,
∂ G ∂ σ = x 2 + y 2 − 2 σ 2 2 π σ 5 e x 2 + y 2 2 σ 2 \frac{\partial G}{\partial \sigma }=\frac{x^2+y^2-2\sigma ^2}{2\pi \sigma ^5}e^{\frac{x^2+y^2}{2\sigma ^2}} ∂σ∂G=2πσ5x2+y2−2σ2e2σ2x2+y2
由上述的定义得
∂ G ∂ σ = σ ∇ 2 G \frac{\partial G}{\partial \sigma }=\sigma \nabla ^2G ∂σ∂G=σ∇2G
由导数的定义得:
∂ G ∂ σ = lim Δ σ → 0 G ( x , y , σ + Δ σ ) − G ( x , y , σ ) Δ σ ≈ G ( x , y , σ + k σ ) − G ( x , y , σ ) k σ − σ \frac{\partial G}{\partial \sigma }=\lim_{\Delta \sigma \to 0}\frac{G(x,y,\sigma +\Delta \sigma )-G(x,y,\sigma )}{\Delta \sigma }\approx \frac{G(x,y,\sigma +k\sigma )-G(x,y,\sigma )}{k\sigma -\sigma } ∂σ∂G=Δσ→0limΔσG(x,y,σ+Δσ)−G(x,y,σ)≈kσ−σG(x,y,σ+kσ)−G(x,y,σ)
则
σ ∇ 2 G ≈ G ( x , y , σ + k σ ) − G ( x , y , σ ) k σ − σ \sigma \nabla ^2G \approx \frac{G(x,y,\sigma +k\sigma )-G(x,y,\sigma )}{k\sigma -\sigma } σ∇2G≈kσ−σG(x,y,σ+kσ)−G(x,y,σ)
变形得
G ( x , y , σ + k σ ) − G ( x , y , σ ) ≈ ( k − 1 ) σ 2 ∇ 2 G G(x,y,\sigma +k\sigma )-G(x,y,\sigma ) \approx (k-1)\sigma ^2\nabla ^2G G(x,y,σ+kσ)−G(x,y,σ)≈(k−1)σ2∇2G
利用LoG算子对图像进行处理,可以得到何种信息?
LoG算子就是先对图像进行高斯模糊,然后再求二阶导数,二阶导数等于0处对应的像素就是图像的边缘,即得到图像的边缘信息。
设一幅二值图像中,只有一个白色区域,试给出求该区域外围轮廓线的方法(要求按顺时针的顺序给出各点的坐标,即行/列号)。
3 | 2 | 1 |
---|---|---|
4 | x | 0 |
5 | 6 | 7 |
对图像进行逐行查找(从上到下,从左到右),找到第一个值为1的点,用 P 0 P_0 P0表示。
P 0 P_0 P0:边界跟踪的起始点。
定义变量 dir:搜索方向(1,…,7)dir=7;
按逆时针方向顺序依次判断当前点(一开始为 P 0 P_0 P0 点)8个 3×3 邻居是否为 1,开始的邻居号为:
如果当前的边界点 P n P_n Pn 的坐标等于找到的第二个边界点 P 1 P_1 P1 的坐标,而且它前一个边界点 P n − 1 P_{n-1} Pn−1 的坐标又与起始点 P 0 P_0 P0 坐标相同,则算法结束。否则,重复步骤 2
设在一幅图像中分割出一个区域,如何将目标分割问题转换为一个求最小代价路径的问题?
从而,目标函数可以为:
J ( k 1 ∗ , … k n ∗ ) = ∑ i = 1 b h i + γ ∑ i = 1 n f i \mathcal{J}(k_1^*,\dots k_n^*)=\sum\limits_{i=1}\limits^bh_i+\gamma\sum\limits^n\limits_{i=1}f_i J(k1∗,…kn∗)=i=1∑bhi+γi=1∑nfi
h i = h i ( P i , k i ) h_i=h_i(P_i,k_i) hi=hi(Pi,ki)
f i = f i ( P i + 1 , k i + 1 − P i , k i ) f_i=f_i(P_{i+1,k_i+1}-P_{i,k_i}) fi=fi(Pi+1,ki+1−Pi,ki)
或者
f i = f i ( P i + 1 , k i + 1 − P i , k i , P i , k i − P i − 1 , k i − 1 ) f_i=f_i(P_{i+1,k_i+1}-P_{i,k_i},P_{i,k_i}-P_{i-1,k_i-1}) fi=fi(Pi+1,ki+1−Pi,ki,Pi,ki−Pi−1,ki−1)
基于图论的分割方法就是把要进行分割的图像看成是一个带权无向图。原图像中的各像素点就是带权无向图中的结点。边是在各结点之间形成的。边的权值 W ( i , j ) W(i,j) W(i,j)可以反正出顶点i与顶点j之间的相似程度,其可以由空间关系(如顶点i到顶点j的距离)与灰度测试(如纹理、颜色、灰度值)形成。我们可以将原带权无向图按照每各个像素之间的相似程度切割成若干个子集区域。每个子集区域内的像素相似度比较高,不同的子集区域的像素相似性较低。切割的过程实际上就是去除相似度低的结点之间的边。
代价可以包括哪些因素?
设有一幅二值图像,采用 3×3的结构元(每个元素均为1)对其进行腐蚀操作,试写出得到结果图像的方法。
腐蚀处理的结果是使原来的二值图像减小一圈, 原图A被结构B腐蚀的定义如下,z代表B的中心位置:
A ⊙ B = { z ∣ ( B ) z ⊆ A } A\odot B=\{z|(B)_z \subseteq A \} A⊙B={z∣(B)z⊆A}
可以理解为,移动结构B,如果结构B完全属于原图A的区域内,则保存该位置点,所有满足条件的点构成结构A被结构B腐蚀的结果。
用结构体B对原图A进行腐蚀的整个过程如下:
试写出孔洞填充的算法。对二值图像中所有被白色区域包围(封闭)的黑色像素即为孔洞。
孔洞填充的公式为:
X k = ( X k − 1 ⊕ B ) ∩ A c k = 1 , 2 , 3 , . . . X_k=(X_{k-1} \oplus B) \cap A^c \qquad k=1,2,3,... Xk=(Xk−1⊕B)∩Ack=1,2,3,...
设原包含孔洞的图像为A,原图补集为 A c A^c Ac,用于填充膨胀的结构体为B,则孔洞填充算法流程:
上述算法步骤中使用了膨胀操作,下面简述膨胀操作过程:
膨胀处理的结果是使原来的二值图像扩大一圈, 原图A被结构B膨胀的定义如下,z代表B的中心位置:
A ⊕ B = { z ∣ ( B ^ ) z ⋂ A ≠ ∅ } A\oplus B=\{z|(\hat{B})_z \bigcap A \neq \varnothing\} A⊕B={z∣(B^)z⋂A=∅}
上式中 ( B ^ ) z (\hat{B})_z (B^)z是结构体关于中心圆点反转的结构,膨胀可以理解为,移动结构B的反转结构 ( B ^ ) z (\hat{B})_z (B^)z,如果与原图A存在重叠区域,也即交集不为空,则此时结构体中心位置对应在目标图结果中处像素为1,反之没有交集则为0。
设有两个白色区域,被一条细小的白线所连接,试设计一种算法,消除两个区域之间的细线,使两个区域分开。
使用开运算即可,开运算等于对原图先腐蚀后膨胀,可以用来消除小物体、在纤细点处分离物体、消除物体周围的毛刺等。设原图为A,结构体为B开运算的公式为:
A ∘ B = ( A ⊙ B ) ⊕ B A \circ B=(A\odot B) \oplus B A∘B=(A⊙B)⊕B
分割两个细小白线连接的白色区域的步骤如下:
计算包围给定点集的最小凸多变形。
采用安德鲁算法计算最小凸包,流程简述如下:
检查是否为凸包的方法如下:
设将要加入点 P 2 P_2 P2,凸包集中上一轮加入的节点为 P 1 P_1 P1, 上上一轮加入的节点为 P 0 P_0 P0 , 则形成两个向量: a ⃗ = P 0 → P 1 \vec{a}=P_0 \rightarrow P_1 a=P0→P1和 b ⃗ = P 0 → P 2 \vec{b}=P_0 \rightarrow P_2 b=P0→P2。如果 a ⃗ × b ⃗ < 0 \vec{a} \times \vec{b} < 0 a×b<0, 则说明第二个向量 b ⃗ \vec{b} b位于第一个向量 a ⃗ \vec{a} a的逆时针处, 此时新加入节点 P 2 P_2 P2会使结果不再是凸边形,需要逆序删除已经插入的点,直到加入 P 2 P_2 P2后,保持凸包。
上述判断方法示意图如下, 此时加入P2会使第二个向量 b ⃗ \vec{b} b位于第一个向量 a ⃗ \vec{a} a的逆时针处,凸包被破坏,需要逆序删除P1点。