python+opencv邊緣檢測方法整理

南山葉發表於2020-11-03

python+opencv邊緣方法整理

#邊緣檢測
####基於搜尋(一階導數)
#Roberts運算元
#交叉微分演算法,它是基於交叉差分的梯度演算法,通過區域性差分計算檢測邊緣線條。
#常用來處理具有陡峭的低噪聲影像,當影像邊緣接近於正45度或負45度時,該演算法處理效果更理想。
#其缺點是對邊緣的定位不太準確,提取的邊緣線條較粗。
def Roberts(gray):
    kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
    kernely = np.array([[0, -1], [1, 0]], dtype=int)
    x = cv2.filter2D(gray, cv2.CV_16S, kernelx)
    y = cv2.filter2D(gray, cv2.CV_16S, kernely)
    # 轉uint8
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    return Roberts

#Prewitt運算元
#採用33模板對區域內的畫素值進行計算,而Robert運算元的模板為22,
# 故Prewitt運算元的邊緣檢測結果在水平方向和垂直方向均比Robert運算元更加明顯。Prewitt運算元適合用來識別噪聲較多、灰度漸變的影像
def Prewitt(gray):
    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(gray, cv2.CV_16S, kernelx)
    y = cv2.filter2D(gray, cv2.CV_16S, kernely)
    # 轉uint8
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    Prewitt = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    return Prewitt

#Sobel運算元
#結合了高斯平滑和微分求導。該運算元用於計算影像明暗程度近似值,
# 根據影像邊緣旁邊明暗程度把該區域內超過某個數的特定點記為邊緣。
# Sobel運算元在Prewitt運算元的基礎上增加了權重的概念,認為相鄰點的距離遠近對當前畫素點的影響是不同的,距離越近的畫素點對應當前畫素的影響越大,從而實現影像銳化並突出邊緣輪廓。
#Sobel運算元的邊緣定位更準確,常用於噪聲較多、灰度漸變的影像。
def Sobel(gray):
    x = cv2.Sobel(gray, cv2.CV_16S, 1, 0)  # 對x求一階導
    y = cv2.Sobel(gray, cv2.CV_16S, 0, 1)  # 對y求一階導
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    return Sobel

#Scharr運算元
# Scharr 運算元是對 Sobel 運算元差異性的增強,兩者之間的在檢測影像邊緣的原理和使用方式上相同。
# Scharr 運算元的主要思路是通過將模版中的權重係數放大來增大畫素值間的差異。
# Scharr 運算元又稱為 Scharr 濾波器,也是計算 x 或 y 方向上的影像差分,在 OpenCV 中主要是配合 Sobel 運算元的運算而存在的
def scharr(gray):
    x = cv2.Scharr(gray, cv2.CV_16S, 1, 0)  # X 方向
    y = cv2.Scharr(gray, cv2.CV_16S, 0, 1)  # Y 方向
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    scharr = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    return scharr


#Kirsch,Robinson運算元,
# Kirsch邊緣運算元由八個方向的卷積核構成,這8個模板代表8個方向,對影像上的8個特定邊緣方向作出最大響應,運算中取最大值作為影像的邊緣輸出
def Kirsch(gray):
    # 定義Kirsch 卷積模板
    m1 = np.array([[5, 5, 5], [-3, 0, -3], [-3, -3, -3]])
    m2 = np.array([[-3, 5, 5], [-3, 0, 5], [-3, -3, -3]])
    m3 = np.array([[-3, -3, 5], [-3, 0, 5], [-3, -3, 5]])
    m4 = np.array([[-3, -3, -3], [-3, 0, 5], [-3, 5, 5]])
    m5 = np.array([[-3, -3, -3], [-3, 0, -3], [5, 5, 5]])
    m6 = np.array([[-3, -3, -3], [5, 0, -3], [5, 5, -3]])
    m7 = np.array([[5, -3, -3], [5, 0, -3], [5, -3, -3]])
    m8 = np.array([[5, 5, -3], [5, 0, -3], [-3, -3, -3]])
    # 周圍填充一圈
    # 卷積時,必須在原圖周圍填充一個畫素
    graym = cv2.copyMakeBorder(gray, 1, 1, 1, 1, borderType=cv2.BORDER_REPLICATE)
    temp = list(range(8))
    gray1 = np.zeros(graym.shape)  # 複製空間  此處必須的重新複製一塊和原影像矩陣一樣大小的矩陣,以儲存計算後的結果
    for i in range(1, gray.shape[0] - 1):
        for j in range(1, gray.shape[1] - 1):
            temp[0] = np.abs((np.dot(np.array([1, 1, 1]), (m1 * gray[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]])))
            # 利用矩陣的二次型表達,可以計算出矩陣的各個元素之和
            temp[1] = np.abs((np.dot(np.array([1, 1, 1]), (m2 * gray[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]])))
            temp[2] = np.abs((np.dot(np.array([1, 1, 1]), (m1 * gray[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]])))
            temp[3] = np.abs((np.dot(np.array([1, 1, 1]), (m3 * gray[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]])))
            temp[4] = np.abs((np.dot(np.array([1, 1, 1]), (m4 * gray[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]])))
            temp[5] = np.abs((np.dot(np.array([1, 1, 1]), (m5 * gray[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]])))
            temp[6] = np.abs((np.dot(np.array([1, 1, 1]), (m6 * gray[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]])))
            temp[7] = np.abs((np.dot(np.array([1, 1, 1]), (m7 * gray[i - 1:i + 2, j - 1:j + 2]))).dot(np.array([[1], [1], [1]])))
            gray1[i, j] = np.max(temp)
            if gray1[i, j] > 255:# 此處的閾值一般寫255,根據實際情況選擇0~255之間的值
                gray1[i, j] = 255
            else:
                gray1[i, j] = 0
    #print('Kirsch運算元後圖片尺寸',gray1.shape)
    gray2= cv2.resize(gray1, (gray.shape[0], gray.shape[1]))
    Kirsch=gray2
    #print('gray2運算元後圖片尺寸', gray2.shape)
    return Kirsch


#Canny運算元
# Canny方法不容易受噪聲干擾,能夠檢測到真正的弱邊緣。
# 優點在於,使用兩種不同的閾值分別檢測強邊緣和弱邊緣,並且當弱邊緣和強邊緣相連時,才將弱邊緣包含在輸出影像中。
def  canny(gray):
    # 高斯濾波降噪
    gaussian = cv2.GaussianBlur(gray, (3, 3), 0)
    # Canny運算元
    canny = cv2.Canny(gaussian, 50, 180)
    return canny


####基於零交叉(二階導數)
#Laplacian運算元
#n維歐幾里德空間中的一個二階微分運算元,常用於影像增強領域和邊緣提取
# Laplacian運算元其實主要是利用Sobel運算元的運算,通過加上Sobel運算元運算出的影像x方向和y方向上的導數,得到輸入影像的影像銳化結果。
# 同時,在進行Laplacian運算元處理之後,還需要呼叫convertScaleAbs()函式計算絕對值,並將影像轉換為8點陣圖進行顯示。
def laplacian(gray):
    dst = cv2.Laplacian(gray, cv2.CV_16S, ksize = 3)
    laplacian = cv2.convertScaleAbs(dst)
    return laplacian

#LOG運算元#Marr-Hildreth運算元
# 根據影像的訊雜比來求檢測邊緣的最優濾波器。
# 該演算法首先對影像做高斯濾波,然後再求其拉普拉斯( Laplacian )二階導數,
# 根據二階導數的過零點來檢測影像的邊界,即通過檢測濾波結果的零交叉( Zero crossings )來獲得影像或物體的邊緣。
# LOG 運算元實際上是把 Gauss 濾波和 Laplacian 濾波結合了起來,先平滑掉噪聲,再進行邊緣檢測。
# LOG 運算元與視覺生理中的數學模型相似,因此在影像處理領域中得到了廣泛的應用。
# 它具有抗干擾能力強,邊界定位精度高,邊緣連續性好,能有效提取對比度弱的邊界等特點。
def log(gray):
    # 先通過高斯濾波降噪
    gaussian = cv2.GaussianBlur(gray, (3, 3), 0)
    # 再通過拉普拉斯運算元做邊緣檢測
    dst = cv2.Laplacian(gaussian, cv2.CV_16S, ksize=3)
    log = cv2.convertScaleAbs(dst)
    return log


#DoG運算元
# (1)灰度化影像
# (2)計算方差為2和3.2的兩個高斯濾波後的影像
# (3)求兩個之差——將二者之差再除以2(歸一化)
def DoG(gray):
    gimg1 = filters.gaussian(gray, sigma=2)
    gimg2 = filters.gaussian(gray, sigma=1.6 * 2)
    # 兩個高斯運算的差分
    dimg = gimg2 - gimg1
    # 將差歸一化
    dimg /= 2
    #二值化邊緣
    edge=np.copy(dimg)
    edge[edge>0]=255
    edge[edge <= 0] = 0
    edge=edge.astype(np.uint8)
    #影像邊緣抽象化
    asbstraction=-np.copy(dimg)
    asbstraction=asbstraction.astype(np.float32)
    asbstraction[asbstraction>=0]=0.1
    asbstraction[asbstraction<0]=0.1+np.tanh(asbstraction[asbstraction<0])
    DoG=asbstraction
    #return edge
    return DoG

相關文章