python-opencv 形態學

五、形態學運算 檢測邊和 角點

 形態學算子檢測圖像中的邊緣和拐角(實際用:Canny或Harris等算法)

5.1 檢測邊緣

 形態學檢測邊緣的原理:在膨脹時,圖像中的物體會想周圍“擴張”腐蝕時,圖像中的物體會“收縮”。由於這兩幅圖像其變化的區域只發生在邊緣。所以這時將兩幅圖像相減,得到的就是圖像中物體的邊緣。

import cv2
original_img = cv2.imread('image/1.jpg',0)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
dilate_img = cv2.dilate(original_img, kernel)
erode_img = cv2.erode(original_img, kernel)
"""
我選了一張較好的圖片,有的圖片要去噪(高斯模糊)
將兩幅圖像相減獲得邊;cv2.absdiff參數:(膨脹後的圖像,腐蝕後的圖像)
上面得到的結果是灰度圖,將其二值化以便觀察結果
反色,對二值圖每個像素取反
"""
absdiff_img = cv2.absdiff(dilate_img,erode_img);
retval, threshold_img = cv2.threshold(absdiff_img, 40, 255, cv2.THRESH_BINARY);
result = cv2.bitwise_not(threshold_img);
cv2.imshow("rlufei",original_img)
cv2.imshow("dilate_img",dilate_img)
cv2.imshow("erode_img",erode_img)
cv2.imshow("absdiff_img",absdiff_img)
cv2.imshow("threshold_img",threshold_img)
cv2.imshow("result",result)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

5.2檢測拐角

拐角的檢測的原理:先用十字形的結構元素膨脹像素,這種情況下只會在邊緣處“擴張”,角點不發生變化。接着用菱形的結構元素腐蝕原圖像,導致只有在拐角處纔會“收縮”,而直線邊緣都未發生變化。第二步是用X形膨脹原圖像,角點膨脹的比邊要多。這樣第二次用方塊腐蝕時,角點恢復原狀,而邊要腐蝕的更多。所以當兩幅圖像相減時,只保留了拐角處。
 

import cv2
image = cv2.imread('image/1.jpg',0)
original_image = image.copy()
#構造5×5的結構元素,分別爲十字形、菱形、方形和X型
cross = cv2.getStructuringElement(cv2.MORPH_CROSS,(5, 5))
diamond = cv2.getStructuringElement(cv2.MORPH_RECT,(5, 5))
diamond[0, 0] = 0
diamond[0, 1] = 0
diamond[1, 0] = 0
diamond[4, 4] = 0
diamond[4, 3] = 0
diamond[3, 4] = 0
diamond[4, 0] = 0
diamond[4, 1] = 0
diamond[3, 0] = 0
diamond[0, 3] = 0
diamond[0, 4] = 0
diamond[1, 4] = 0
square = cv2.getStructuringElement(cv2.MORPH_RECT,(5, 5))  #構造方形結構元素
x = cv2.getStructuringElement(cv2.MORPH_CROSS,(5, 5))
dilate_cross_img = cv2.dilate(image,cross)                #使用cross膨脹圖像
erode_diamond_img = cv2.erode(dilate_cross_img, diamond)  #使用菱形腐蝕圖像
dilate_x_img = cv2.dilate(image, x)                       #使用X膨脹原圖像
erode_square_img = cv2.erode(dilate_x_img,square)         #使用方形腐蝕圖像
result = cv2.absdiff(erode_square_img, erode_diamond_img)          #將兩幅閉運算的圖像相減獲得角
retval, result = cv2.threshold(result, 40, 255, cv2.THRESH_BINARY) #使用閾值獲得二值圖

#在原圖上用半徑爲5的圓圈將點標出。
for j in range(result.size):
    y = int(j / result.shape[0])
    x = int(j % result.shape[0])
    if result[x, y] == 255:                                        #result[] 只能傳入整型
        cv2.circle(image,(y,x),5,(255,0,0))
cv2.imshow("original_image", original_image)
cv2.imshow("Result", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

四、禮帽/頂帽,黑帽 算法

該算法可以圖像識別的預處理,用於圖像二值化後去除孤立點,如下圖所示 

import cv2
original_img = cv2.imread('image/1.jpg',0)
gray_img = cv2.resize(original_img,None,fx=0.8, fy=0.8, interpolation = cv2.INTER_CUBIC) #圖形太大了縮小一點
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))              #定義矩形結構元素(核大小爲3效果好)
TOPHAT_img = cv2.morphologyEx(gray_img, cv2.MORPH_TOPHAT, kernel)     #頂帽運算
BLACKHAT_img = cv2.morphologyEx(gray_img, cv2.MORPH_BLACKHAT, kernel) #黒帽運算
bitwiseXor_gray = cv2.bitwise_xor(gray_img,TOPHAT_img)
#顯示如下腐蝕後的圖像
cv2.imshow("gray_img", gray_img)
cv2.imshow("TOPHAT_img", TOPHAT_img)
cv2.imshow("BLACKHAT_img", BLACKHAT_img)
cv2.imshow("bitwiseXor_gray",bitwiseXor_gray)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

三、開運算和閉運算

開運算和閉運算就是將腐蝕和膨脹按照一定的次序進行處理。  運算不可逆,即先開後閉並不能得到原先的圖像。
爲了獲取圖像中的主要對象:對一副二值圖連續使用閉運算和開運算,或者消除圖像中的噪聲,也可以對圖像先用開運算後用閉運算,不過這樣也會消除一些破碎的對象。

開運算:先腐蝕後膨脹,用於移除由圖像噪音形成的斑點

閉運算:先膨脹後腐蝕,用來連接被誤分爲許多小塊的對象

"""
cv2.morphologyEx(src,      # 輸入圖片
                 op,       # 需要處理類型的函數:(cv2.MORPH_OPEN,cv2.MORPH_CLOSE,cv2.MORPH_GRADIENT)
                 kernel,   # 卷積核大小
                 dst=None, 
                 anchor=None, 
                 iterations=None,     #迭代次數,默認1次
                 borderType=None, 
                 borderValue=None)
"""
import cv2
import numpy as np
original_img = cv2.imread('original_img.png',0)
gray_res = cv2.resize(original_img,None,fx=0.8,fy=0.8,
                 interpolation = cv2.INTER_CUBIC)                #圖形太大了縮小一點
# B, G, img = cv2.split(res)
# _,RedThresh = cv2.threshold(img,160,255,cv2.THRESH_BINARY)     #設定紅色通道閾值160(閾值影響開閉運算效果)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))         #定義矩形結構元素

closed1 = cv2.morphologyEx(gray_res, cv2.MORPH_CLOSE, kernel,iterations=1)    #閉運算1
closed2 = cv2.morphologyEx(gray_res, cv2.MORPH_CLOSE, kernel,iterations=3)    #閉運算2
opened1 = cv2.morphologyEx(gray_res, cv2.MORPH_OPEN, kernel,iterations=1)     #開運算1
opened2 = cv2.morphologyEx(gray_res, cv2.MORPH_OPEN, kernel,iterations=3)     #開運算2
gradient = cv2.morphologyEx(gray_res, cv2.MORPH_GRADIENT, kernel)             #梯度

#顯示如下腐蝕後的圖像
cv2.imshow("gray_res", gray_res)
cv2.imshow("Close1",closed1)
cv2.imshow("Close2",closed2)
cv2.imshow("Open1", opened1)
cv2.imshow("Open2", opened2)
cv2.imshow("gradient", gradient)

cv2.waitKey(0)
cv2.destroyAllWindows()

 

二、腐蝕和膨脹

腐蝕:腐蝕會把物體的邊界腐蝕掉,卷積核沿着圖象滑動,如果卷積覈對應的原圖的所有像素值爲1,那麼中心元素就保持原來的值,其餘部分變爲零。主要應用在去除白噪聲,也可以斷開連在一起的物體

膨脹:卷積核所對應的原圖像的像素值只要有一個是1,中心像素值就是1。一般在除噪是,先腐蝕再膨脹開運算,因爲腐蝕在去除白噪聲的時候也會使圖像縮小,所以我們之後要進行膨脹。當然也可以用來將兩者物體連通。

import cv2
import numpy as np
import math
import matplotlib.pyplot as plt

targetImg = cv2.imread('image/1.jpg')
kernel_4 = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
HSV = cv2.cvtColor(targetImg, cv2.COLOR_BGR2HSV)  # 把BGR圖像轉換爲HSV格式
Lower = np.array([0, 3, 5])  # 要識別顏色-紅色的下限    ## 0 5 5 10 255 255
Upper = np.array([10, 255, 255])  # 要識別的顏色-紅色的上限
    # mask是把HSV圖片中在顏色範圍內的區域變成白色,其他區域變成黑色
mask = cv2.inRange(HSV, Lower, Upper)
erosion = cv2.erode(mask, kernel_4, iterations=1)
erosion = cv2.erode(erosion, kernel_4, iterations=1)
dilation = cv2.dilate(erosion, kernel_4, iterations=1)
dilation = cv2.dilate(dilation, kernel_4, iterations=1)

cv2.imshow("img", targetImg)
cv2.imshow("mask", mask)
cv2.imshow("target", target)
cv2.imshow("erosion", erosion)
cv2.imshow("dilation", dilation)
cv2.waitKey()
# cv2.imshow("cv_cut_img_circle", cv_cut_img_circle)
# return cropped

一、定義結構元素

形態學處理的核心就是定義結構元素,在OpenCV-Python中,可以使用其自帶的getStructuringElement函數,也可以直接使用NumPy的ndarray來定義一個結構元素。

(形象圖如下:)

如下代碼:爲上圖的十字形結構
當然還可以定義橢圓/矩形等:
橢圓:cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
矩形:cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))

element = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
print("elemrnt":element )
------------------------------------------------
import numpy as np
NpKernel = np.uint8(np.zeros((5,5)))
for i in range(5):
	NpKernel[2, i] = 1
	NpKernel[i, 2] = 1
print("NpKernel ",NpKernel )

上述結果輸出(相同):
array([[0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0]], dtype=uint8)

參考書籍:

《opencv基礎開發教程 》

參考blog:

https://blog.csdn.net/sunny2038/article/details/9137759
https://blog.csdn.net/on2way/article/details/46850813

https://blog.csdn.net/wsp_1138886114/article/details/82917661

 

 

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