数字图像处理:(5)非微分算子在数字图像处理中的应用
本節是非微分邊緣檢測算子——Canny算子
邊緣是圖像中灰度有階躍變化,或屋頂變化的像素的結合。
?
?1、? Canny算子邊緣檢測基本原理
? ? ? ? 該算子功能比前面幾種都要好,但是它實現起來較為麻煩,Canny算子是一個具有濾波,增強,檢測的多階段的優化算子,在進行處理前,Canny算子先利用高斯平滑濾波器來平滑圖像以除去噪聲,Canny分割算法采用一階偏導的有限差分來計算梯度幅值和方向,在處理過程中,Canny算子還將經過一個非極大值抑制的過程,最后Canny算子還采用兩個閾值來連接邊緣。
2、? Canny算子算法步驟
第一步:用高斯濾波器平滑圖像。
見鏈接:https://blog.csdn.net/m0_37957160/article/details/119377528
第二步:計算整個圖像的每一個像素的梯度幅值和梯度方向。
?數字圖像處理中提供了好多種算子,計算圖像的梯度和梯度方向。比如Sobel算子。
比如下邊是使用Sobel算子計算的整個圖像中每一個像素的梯度和方向:
現在邊太粗了需要變細。
第三步:對梯度幅值進行非極大值抑制。
Canny算法論文里邊是這樣介紹的:在上述梯度矩陣(包含大小和方向 ),這個梯度方向有可能不是離散的,是連續的。那么論文里邊假設我就關注如下的4個軸即4個方向 ,
假設只關注4個方向,
?比如說某一個梯度的方向是30度,那么在0到45度之間他是離45度方向比較近,那么就規定他為45度。就是查看他在上述方向劃分的模式下,離哪一個比較近就把他的方向歸并到哪一個方向上。
因為圖像的像素分布是離散的,如果把其中一個像素的8鄰域按照上述模式蓋上去,
?
上述的NMS是Canny論文里邊的思路,有后人改進的思想:用亞像素去線性差值的方法去進行非極大值抑制。
第四步:用雙閾值算法檢測和連接邊緣。(閾值A和閾值B)
(PS:如果只是單一閾值的話,你這個閾值調的比較高,那整個圖像里邊一些細微的邊緣(即非極大值抑制之后他那些梯度比較小的邊)很可能就直接被扔掉了,但是呢,如果把閾值設置的比較低,好多雜亂無章的邊也會包含進來,所以引進了雙閾值)
如果做完NMS的梯度值小于閾值A的話,那么該點直接扔掉,比如說賦值為0;如果這個值比我設置的B值還要大的話,那么就認為該點是邊緣點;如果在A和B之間的點叫做中庸點,對待中庸點會分兩種情況:第一種情況就是該中庸點與已經確定的邊緣點所組成的邊有關系(就是相連,該中庸點與確定的邊界相連),那么就認為該中庸點也是一個邊緣點(置為255),如果該中庸點在一條邊上那么該邊也被認為是一條邊界邊。反之那么認為該中庸點是非邊緣點。
3 、 Canny算子python實現
import cv2
import numpy as np
import mathdef Canny(img, threshold1, threshold2):# 高斯濾波gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)new_gray = cv2.GaussianBlur(gray, (5, 5), 1)gaussian_result = np.uint8(np.copy(new_gray))cv2.imshow('gaussian',gaussian_result)# 算梯度幅值W1, H1 = new_gray.shape[:2]dx = np.zeros([W1 - 1, H1 - 1])dy = np.zeros([W1 - 1, H1 - 1])d = np.zeros([W1 - 1, H1 - 1])ddgree = np.zeros([W1 - 1, H1 - 1])for i in range(1, W1 - 1):for j in range(1, H1 - 1):dx[i, j] = new_gray[i - 1, j - 1] + 2 * new_gray[i, j - 1] + new_gray[i + 1, j - 1] - \new_gray[i - 1, j + 1] - 2 * new_gray[i, j + 1] - new_gray[i + 1, j + 1]dy[i, j] = new_gray[i - 1, j - 1] + 2 * new_gray[i - 1, j] + new_gray[i - 1, j + 1] - \new_gray[i + 1, j - 1] - 2 * new_gray[i + 1, j] - new_gray[i + 1, j + 1]d[i, j] = np.sqrt(np.square(dx[i, j]) + np.square(dy[i, j])) # 圖像梯度幅值作為圖像強度值ddgree[i, j] = math.degrees(math.atan2(dy[i, j], dx[i, j]))if ddgree[i, j] < 0:ddgree += 360d_r = np.uint8(np.copy(d))cv2.imshow('tidu', d_r)# 非極大值抑制W2, H2 = d.shapeNMS = np.copy(d)NMS[0, :] = NMS[W2 - 1, :] = NMS[:, 0] = NMS[:, H2 - 1] = 0for i in range(1, W2 - 1):for j in range(1, H2 - 1):if d[i, j] == 0:NMS[i, j] = 0else:g1 = Noneg2 = Noneif (ddgree[i, j] <= 22.5 and ddgree[i, j] >= 0) or (ddgree[i, j] >= 337.5):g1 = NMS[i, j - 1]g2 = NMS[i, j + 1]elif (ddgree[i, j] <= 67.5 and ddgree[i, j] > 22.5) or (ddgree[i, j] <= 337.5 and ddgree[i, j] > 292.5):g1 = NMS[i - 1, j + 1]g2 = NMS[i + 1, j - 1]elif ddgree[i, j] <= 112.5 and ddgree[i, j] > 67.5 or (ddgree[i, j] <= 292.5 and ddgree[i, j] > 247.5):g1 = NMS[i - 1, j]g2 = NMS[i + 1, j]elif (ddgree[i, j] <= 157.5 and ddgree[i, j] > 112.5) or (ddgree[i, j] <= 247.5 and ddgree[i, j] > 202.5):g1 = NMS[i - 1, j - 1]g2 = NMS[i + 1, j + 1]else:g1 = NMS[i, j - 1]g2 = NMS[i, j + 1]if NMS[i, j] < g1 or NMS[i, j] < g2:NMS[i, j] = 0nms_r = np.uint8(np.copy(NMS))cv2.imshow('nms', nms_r)# 雙閾值算法檢測、連接邊緣W3, H3 = NMS.shapeDT = np.zeros([W3, H3], dtype=np.uint8)# 定義高低閾值TL = min(threshold1, threshold2)TH = max(threshold1, threshold2)for i in range(1, W3 - 1):for j in range(1, H3 - 1):if (NMS[i, j] < TL):DT[i, j] = 0elif (NMS[i, j] > TH):DT[i, j] = 255else:if NMS[i - 1, j] > TH or NMS[i - 1, j - 1] > TH or NMS[i - 1, j + 1] > TH or NMS[i, j - 1] > TH \or NMS[i, j + 1] > TH or NMS[i + 1, j] > TH or NMS[i + 1, j - 1] > TH or NMS[i + 1, j + 1] > TH: \DT[i, j] = 255return DTimg = cv2.imread('test.jpg')
cv2.imshow('src', img)
result = Canny(img, 60, 120)
cv2.imshow('dst', result)
cv2.waitKey(0)
結果如下:
?4、擴展部分
(1)邊緣檢測算子比較:
?(2)邊緣提取和邊緣跟蹤:
?
Canny算子B站講解:https://space.bilibili.com/580742386?spm_id_from=333.788.b_765f7570696e666f.1
參考鏈接:https://www.cnblogs.com/wj-1314/p/9800272.html
https://www.bilibili.com/video/BV1U4411277i?from=search&seid=16066791906732345516
總結
以上是生活随笔為你收集整理的数字图像处理:(5)非微分算子在数字图像处理中的应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: halcon与QT联合:(5.4)瓶盖检
- 下一篇: 数字图像处理:滤波