opencv 圖像形態變換·講解

                         QQ:3020889729                                                                                 小蔡

形態變換的實現過程

形態變換是一些基於圖像形狀的簡單操作。通常在二進制圖像上執行,當然也可以在多通道圖像上執行。
它有兩個輸入,一個是我們的原始圖像,而另外的一個是決定操作性質的結構元素或者說內核。
正是基於這樣的內核,才使得我們通過指定的方法實現關於內核下的形態變化。
其中,兩種基本的形態學算子是侵蝕和膨脹——除此之外,這裏還會講解部分其它形態變換,以及常用內核的創建方法。

形態變換實例(以灰度圖像爲例)

多通道圖像也可以發生形態變換,這一篇博客未涉及,後邊會作爲補充講解補上。
(其實現本質與灰度圖像無二,只是內核的設置上要改動一下元素值)

1.侵蝕(Erosion)——內核區域存在的像素值全爲1,整個區域才置1,否則置爲0

涉及的方法——erode()

其作用是,傳入內核,實現對原輸入圖像的侵蝕——本質是侵蝕前景物體的邊界。
其侵蝕的形式是——內核在圖像中滑動(如2D卷積),僅在當內核下的所有像素均爲1時,原始圖像中的像素(1或0)才被視爲1,否則它將被侵蝕(設爲零)。
方法參數如下:

  1. 輸入圖像(src )
  2. 輸入內核(kernel )
  3. 錨點(anchor )——默認爲元素中心,一般不修改
  4. 迭代數(iterations)——也就是侵蝕次數
  5. 邊界像素處理類型(borderType )——一般不設置
  6. 邊界不變時的邊界值(borderValue )——默認值

代碼實例

通過numpy創建一個內核,實現侵蝕

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/images1.jfif', 0)
    kernel = np.ones((5, 5), np.uint8)  # 創建一個uint8的5*5全一矩陣
    img_ex = cv.erode(img, kernel, iterations=1)  # 侵蝕1次
    cv.imshow('imag1', img)
    cv.imshow('imag2', img_ex)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:
在這裏插入圖片描述

2.擴張(Dilation)——內核區域存在像素值爲1,整個區域就置1

涉及的方法——dilate()

其作用是,傳入內核,實現對原輸入圖像的擴張。
它與侵蝕正好相反。如果內核下的至少一個像素爲“ 1”,則像素元素爲“ 1”。
通常,在消除噪音的情況下,腐蝕後會膨脹。因爲腐蝕會消除白噪聲,但也會縮小物體。因此,我們需要對其進行擴展。由於噪音消失了,它們是不會回來的,使得我們的目標區域增加。擴張,在連接對象的損壞部分時也很有用。
方法參數如下:

  1. 輸入圖像(src )
  2. 輸入內核(kernel )
  3. 錨點(anchor )——默認爲元素中心,一般不修改
  4. 迭代數(iterations)——也就是擴張次數
  5. 邊界像素處理類型(borderType )——一般不設置
  6. 邊界不變時的邊界值(borderValue )——默認值

代碼實例

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/images1.jfif', 0)
    kernel = np.ones((5, 5), np.uint8)  # 創建一個uint8的5*5全一矩陣
    img_ex = cv.dilate(img, kernel, iterations=1)  # 擴張1次
    cv.imshow('imag1', img)
    cv.imshow('imag2', img_ex)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:(可以看出,在內核掃過圖形區域時,只要有1就擴張(範圍內全部置1),否則保留爲0)
在這裏插入圖片描述

3.開場(Opening)

涉及的方法——morphologyEx()

該方法使用侵蝕和膨脹作爲基本操作來執行高級形態轉換——開場。它同樣對於消除噪聲很有用。
方法參數如下:

  1. 輸入圖像(src )
  2. 形態學運算類型(MorphTypes)
  3. 輸入內核(kernel )
  4. 錨點(anchor )——默認爲元素中心,一般不修改
  5. 迭代數(iterations)——也就是擴張次數
  6. 邊界像素處理類型(borderType )——一般不設置
  7. 邊界不變時的邊界值(borderValue )——默認值

形態學運算類型(MorphTypes)選項:也對應着執行效果

  • cv.MORPH_ERODE——侵蝕運算
  • cv.MORPH_DILATE——擴張運算
  • cv.MORPH_OPEN——開張運算
  • cv.MORPH_CLOSE——閉幕運算
  • cv.MORPH_GRADIENT——形態梯度運算
  • cv.MORPH_TOPHAT——高頂禮帽運算
  • cv.MORPH_BLACKHAT——黑帽運算
  • cv.MORPH_HITMISS——命中或未命中——本次不涉及,它僅僅操作對CV_8UC1二進制映像運算。

代碼實例(包含前邊兩種變換的實現)

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/images1.jfif', 0)
    kernel = np.ones((5, 5), np.uint8)  # 創建一個uint8的5*5全一矩陣
    img_erode = cv.morphologyEx(img, cv.MORPH_ERODE, kernel)  # 形態學侵蝕運算
    img_dilate = cv.morphologyEx(img, cv.MORPH_DILATE, kernel)  # 擴張運算
    img_open = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)  # 開場運算
    cv.imshow('imag1', img)
    cv.imshow('erode', img_erode)
    cv.imshow('dilate', img_dilate)
    cv.imshow('open', img_open)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:開場的形態學運算類型爲——cv.MORPH_OPEN實現過程:——先執行侵蝕然後擴張
在這裏插入圖片描述
其它實例的效果:
在這裏插入圖片描述

4.閉幕(Closing)

涉及的方法——morphologyEx()

實現閉幕,採用形態學運算類型爲——cv.MORPH_CLOSE

代碼實例

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/images1.jfif', 0)
    kernel = np.ones((5, 5), np.uint8)  # 創建一個uint8的5*5全一矩陣
    img_close = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)  # 形態學侵蝕運算
    cv.imshow('imag1', img)
    cv.imshow('close', img_close)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:——先執行擴張然後侵蝕
在這裏插入圖片描述
其它實例的效果:
在這裏插入圖片描述

5.形態梯度(Morphological Gradient)

涉及的方法——morphologyEx()

實現閉幕,採用形態學運算類型爲——cv.MORPH_GRADIENT

代碼實例

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/images1.jfif', 0)
    kernel = np.ones((5, 5), np.uint8)  # 創建一個uint8的5*5全一矩陣
    img_gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)  # 形態學侵蝕運算

    cv.imshow('imag1', img)
    cv.imshow('gradient', img_gradient)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:左方爲變化效果
在這裏插入圖片描述
其它實例的效果:
在這裏插入圖片描述

6.高頂禮帽(Top Hat)

涉及的方法——morphologyEx()

實現閉幕,採用形態學運算類型爲——cv.MORPH_TOPHAT

代碼實例

使用高頂禮帽——內核大小需要配置一下,不同的內核,對於圖形變換的效果影響不同。

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/images1.jfif', 0)
    kernel = np.ones((9, 9), np.uint8)  # 創建一個uint8的5*5全一矩陣
    img_tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)  # 高頂禮帽運算

    cv.imshow('imag1', img)
    cv.imshow('tophat', img_tophat)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:這是圖像的擴張和腐蝕之間的區別——這張實例圖不是很清楚,可以看一下後邊的那個實例圖像。
在這裏插入圖片描述
其它實例的效果:
在這裏插入圖片描述

7.黑帽(Black Hat)

涉及的方法——morphologyEx()

實現閉幕,採用形態學運算類型爲——cv.MORPH_BLACKHAT

代碼實例

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/images1.jfif', 0)
    kernel = np.ones((5, 5), np.uint8)  # 創建一個uint8的5*5全一矩陣
    img_blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)  # 黑帽運算

    cv.imshow('imag1', img)
    cv.imshow('blackhat', img_blackhat)
    cv.waitKey(0)
    cv.destroyAllWindows()

效果:
在這裏插入圖片描述
其它實例的效果:
在這裏插入圖片描述

常見結構元素(內核)的創建

我們常用的內核有矩形,橢圓形,十字形等。而通過numpy創建的ones矩陣僅爲矩形內核,當然也可以手動設置矩陣元素使得其爲一些其他形狀。正因如此,多餘內核的多樣創建,opencv提供了一個getStructuringElement()方法——實現不同形狀內核的創建。
該getStructuringElement()函數構造並返回可進一步傳遞給erode,dilate或morphologyEx的結構元素。但是您也可以自己構造一個任意的二進制掩碼,並將其用作結構元素。

getStructuringElement方法的講解

參數如下:

  1. 內核形狀
  2. 內核大小
  3. 錨點——默認元素中心

內核形狀類型:

  • cv.MORPH_RECT——矩形
  • cv.MORPH_CROSS——十字形
  • cv.MORPH_ELLIPSE——橢圓形

代碼實例——三種常用內核類型的效果輪播

import cv2 as cv
import numpy as np


if __name__ == "__main__":
    img = cv.imread('../imag_in_save/images1.jfif', 0)
    cv.namedWindow('Showing', cv.WINDOW_NORMAL)
    choice = [cv.MORPH_RECT, cv.MORPH_CROSS, cv.MORPH_ELLIPSE]
    title = ['RECT', 'CROSS', 'ELLIPSE']
    # 依次對應內核類型的矩形,十字形, 橢圓形

    counts = 0  # 遍歷內核類型
    while True:

        kernel = cv.getStructuringElement(choice[counts], (5, 5))  # 創建一個矩形內核
        img_blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)  # 黑帽運算
        img_blackhat = cv.putText(img_blackhat, title[counts], (20, 40), cv.FONT_ITALIC, 1, 160, 2, cv.LINE_AA)
        cv.imshow('Showing', img_blackhat)
        k = cv.waitKey(1600) & 0xFF
        if k == 27:
            break
        counts += 1
        if counts == 3:
            counts = 0
    cv.destroyAllWindows()

效果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章