深入解析opencv骨架提取的算法步驟
前言
個人感覺骨架提取提取的就是開運算過程的不可逆。
一.算法步驟
1.算法步驟
首先上一下比較官方的算法步驟:
1.獲得原圖像的首地址及圖像的寬和高,并設置循環(huán)標志1
2.用結構元素腐蝕原圖像,并保存腐蝕結果
3.設置循環(huán)標志為0,如果腐蝕結果中有一個點為255,即原圖像尚未被完全腐蝕成空集,則將循環(huán)標志設為1.
4.用結構元素對腐蝕后的圖像進行開運算(消除小的白色區(qū)域),并求取腐蝕運算與開運算的差(得到消除的白色區(qū)域)
5.用[4]中求得的結果與之前求得的骨架進行并集運算,以獲得本次循環(huán)求得的骨架
6.把本次循環(huán)中保存的腐蝕結果賦值給原圖像
7.重復步驟[2]-[6],直到將原圖像腐蝕成空集為止。
最終求得的骨架就是結果。
2.分析
作者的理解是這樣的:
輸入:img(二值圖)
輸出:out(和img一樣shape的圖像,初始化是全0)
while img中有像素值為255(在這個循環(huán)里面,一直腐蝕我們的二值圖,直到全部為黑色):
腐蝕img圖像
對img開運算
img2=開運算前的圖像減去開運算后的圖像
out+=img2
輸出out
首先說一下開運算,就是對圖像先做腐蝕再做膨脹。上面一個核心點就是這一步(img2=開運算前的圖像減去開運算后的圖像),在這里為什么說個人感覺骨架提取提取的就是開運算過程的不可逆呢?我們對這個開運算過程分析一下:
1.假如開運算后的圖像和開運算前的圖像不一樣,比如下面這張圖片:

可以看到這張圖片中白色的大部分都比較細小,我們對這張圖片做開運算的時候,我們先腐蝕,很容易就讓一部分的白色的部分消失掉,那么這個白色的部分消失掉之后對腐蝕后的圖片做膨脹消失的白色部分是膨脹不回來的。這些消失的部分就是開運算過程中的不可逆的部分了。
然后我們在后面(img2=開運算前的圖像減去開運算后的圖像),這一步當中就是得到了開運算中消失的那些白色部分了,這一部分就是開運算過程中的不可逆的部分,然后將它疊加到out上。
然后我們通過對圖像不斷的腐蝕,開運算,得到了所有這些圖像中在開運算中不可逆的部分,就得到了我們的骨架了。
2.假如開運算后的圖像和開運算前的圖像不一樣,那這樣的話我們在這一步(img2=開運算前的圖像減去開運算后的圖像)得到img2中的每一個元素就為0了,那在后面out+=img2這一步的時候就out相當于不變,進入下一步循環(huán)在繼續(xù)把白色部分腐蝕地更小,直到得到開運算中出現了不可逆地部分再疊加到out上。
所以粗暴地來說,骨架提取就是對我們地前景區(qū)域,不斷地腐蝕,細化前景,直到將前景壓縮到細地不能再細了。我們的骨架提取提取的就是這一部分。
二.代碼實現
1.預處理
這里我們的圖片是以灰度圖片方式讀取進來的,然后需要閾值處理轉換到二值圖。
然后我們的圖片可能會有一些其他的較大的噪聲的影響,我們首先對圖像先進行腐蝕操作,手動過濾掉一些濾波可能無法過濾的較大噪聲。
'''
用于挑選一個好的二值圖
'''
import cv2
import numpy as np
import os
def refine(img_path):
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
# thresh, img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
thresh, img = cv2.threshold(img, 50, 255, cv2.THRESH_BINARY)
h, w = img.shape[0:2]
#前景背景反轉
for i in range(h):
for j in range(w):
if img[i, j] == 255:
img[i, j] = 0
else:
img[i, j] = 255
cv2.namedWindow("binary", 0)
cv2.resizeWindow("binary", 640, 480)
cv2.imshow('binary', img)
dst = img.copy()
num_erode = 0
while (True):
if np.sum(dst) == 0:
break
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
dst = cv2.erode(dst, kernel)
cv2.namedWindow("z", 0)
cv2.resizeWindow("z", 640, 480)
cv2.imshow('z', dst)
c = cv2.waitKey(0)
if c == ord("q"):
print("保存")
cv2.imwrite("./refine.png", dst)
break
num_erode = num_erode + 1
if __name__ == '__main__':
refine("input.png")
在這里需要注意的是我們對圖像進行二值化可能會將我們的背景和前景反轉,在這里我們需要反轉回來。否則的話把反轉的代碼注釋掉即可。
我的原圖如下:

然后經過腐蝕的圖片如下:

2. 骨架提取實現
然后下面就是骨架提取的代碼了:
'''
骨架提取
'''
import cv2
import numpy as np
#由于我們經過之前的代碼轉換到了二值圖,所以這里不需要轉換
img = cv2.imread('refine.png', cv2.IMREAD_GRAYSCALE)
dst = img.copy()
skeleton = np.zeros(dst.shape, np.uint8)
while (True):
if np.sum(dst) == 0:
break
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (7, 7))
dst = cv2.erode(dst, kernel, None, None, 1)
open_dst = cv2.morphologyEx(dst, cv2.MORPH_OPEN, kernel)
result = dst - open_dst
skeleton = skeleton + result
cv2.waitKey(1)
cv2.namedWindow("result",0)
cv2.resizeWindow("result",640,480)
cv2.imshow('result', skeleton)
cv2.imwrite("output.png",skeleton)
cv2.waitKey(0)
cv2.destroyAllWindows()
在這里我們可以通過開運算的結果元大小來稍微調整一下提取的骨架粗細。
77開運算結構元提取的骨架如下:

55開運算結構元提取的骨架如下:

到此這篇關于深入解析opencv骨架提取的算法步驟的文章就介紹到這了,更多相關opencv骨架提取內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python安裝Imaging報錯:The _imaging C module is not installed問題解決
這篇文章主要介紹了Python安裝Imaging報錯:The _imaging C module is not installed問題解決方法,原來是PIL庫的庫文件沒有加到系統(tǒng)中導致老是提示這個錯誤,需要的朋友可以參考下2014-08-08
python中文分詞,使用結巴分詞對python進行分詞(實例講解)
下面小編就為大家?guī)硪黄猵ython中文分詞,使用結巴分詞對python進行分詞的實例講解。有比較好的參考價值,希望能給大家做個參考。一起跟隨小編過來看看吧2017-11-11

