影像輪廓處理

crossoverpptx發表於2022-12-23

1、輪廓提取

輪廓提取是提取出影像的外部輪廓特徵,輪廓可能是邊緣的一部分。

2、輪廓提取方法及Python實現

2.1 掏空內部點法

掏空內部點法的原理非常簡單:如果原圖中有一點為黑,且它的8個相鄰點皆為黑色,則將該點刪除,否則認為該點在影像的邊緣,需要保留。依次處理影像中每一個畫素,則最後留下來的就是影像的輪廓。對於非二值影像,需要先進行二值化處理。
程式碼如下:

def Get_contour(bin_img):
    contour_img = np.zeros(shape=(bin_img.shape),dtype=np.uint8)
    contour_img += 255
    h = bin_img.shape[0]
    w = bin_img.shape[1]
    for i in range(1,h-1):
        for j in range(1,w-1):
            if(bin_img[i][j]==0):
                contour_img[i][j] = 0
                sum = 0
                sum += bin_img[i - 1][j + 1]
                sum += bin_img[i][j + 1]
                sum += bin_img[i + 1][j + 1]
                sum += bin_img[i - 1][j]
                sum += bin_img[i + 1][j]
                sum += bin_img[i - 1][j - 1]
                sum += bin_img[i][j - 1]
                sum += bin_img[i + 1][j - 1]
                if sum ==  0:
                    contour_img[i][j] = 255

    return contour_img

效果如下(左側是Otsu二值化影像;右側是輪廓影像):

2.2 opencv-python中輪廓提取方法的應用

(1)opencv-python中使用cv2.findContours函式來檢測影像的邊緣,其函式原型如下:

contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

引數說明如下:
image:輸入影像;
mode:輪廓檢索模式;
method:輪廓逼近方法;
contours:返回的輪廓;
hierachy:每條輪廓對應的屬性;
offset:每個輪廓點移動的可選偏移量。
備註:image引數需要是二值圖,而不是灰度圖,返回結果是等高線和層次結構。

輪廓檢索模式:
cv2.RETR_EXTERNAL:表示只檢測外輪廓;
cv2.RETR_LIST:檢測的輪廓,不建立等級關係;
cv2.RETR_CCOMP:建立兩個等級的輪廓,上面的一層為外邊界,裡面的一層為內孔的邊界資訊。如果內孔內還有一個連通物體,這個物體的邊界也在頂層;
cv2.RETR_TREE:建立一個等級樹結構的輪廓。

輪廓逼近方法:
cv2.CHAIN_APPROX_NONE:儲存所有的輪廓點,相鄰的兩個點的畫素位置差不超過1,即 max(abs(x1-x2),abs(y2-y1))==1,一般不會用到;
cv2.CHAIN_APPROX_SIMPLE:壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點座標,例如一個矩形輪廓只需4個點來儲存輪廓資訊;
cv2.CHAIN_APPROX_TC89_L1,cv2.CV_CHAIN_APPROX_TC89_KCOS:使用teh-Chinl chain近似演算法。

(2)輪廓發現之後,還要透過cv2.drawContours函式繪製輪廓,其函式原型如下:

image = cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])

引數說明如下:
image:輸入影像;
contours:輪廓,在Python中是一個list,就是cv2.findContours函式找出來的點集,一個列表;
contourIdx:輪廓的索引,指定繪製輪廓list中的哪條輪廓,要繪製所有輪廓,傳遞-1;
color:顏色;
thickness:厚度,如果是-1,表示填充;
lineType:線型;
hierarchy:層次結構的可選資訊;
maxLevel:繪製輪廓的最大級別,0:僅繪製指定的輪廓,1:繪製輪廓和所有巢狀輪廓,2:繪製輪廓,所有巢狀輪廓,所有巢狀到巢狀的輪廓;
offset:輪廓偏移引數。

根據上面兩個函式,測試程式碼如下:

# 第一步:讀入影像
img = cv2.imread('lenna.jpg')

# 第二步:對影像做灰度處理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 第三步:對影像做二值化處理
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 第四步:獲得影像的輪廓值
contours, heriachy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

# 第五步:繪製影像輪廓
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
res = cv2.drawContours(img, contours, -1, (0, 0, 255), 1)

plt.imshow(res, cmap='gray')
plt.title('contour')
plt.axis('off')
plt.show()

效果如下:

相關文章