python计算不规则图形面积_python opencv中的不规则形状检测和测量
正如我在評(píng)論中提到的那樣,對(duì)于這個(gè)問(wèn)題,分水嶺似乎是一個(gè)很好的方法.但是當(dāng)你回答時(shí),定義標(biāo)記的前景和背景是困難的部分!我的想法是使用形態(tài)梯度沿著冰晶獲得良好的邊緣并從那里開始工作;形態(tài)梯度似乎很有效.
import numpy as np
import cv2
img = cv2.imread('image.png')
blur = cv2.GaussianBlur(img, (7, 7), 2)
h, w = img.shape[:2]
# Morphological gradient
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
gradient = cv2.morphologyEx(blur, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('Morphological gradient', gradient)
cv2.waitKey()
從這里開始,我使用一些閾值來(lái)對(duì)梯度進(jìn)行二值化.可能有一種更清潔的方法來(lái)做到這一點(diǎn)……但這比我嘗試過(guò)的其他一些想法更好.
# Binarize gradient
lowerb = np.array([0, 0, 0])
upperb = np.array([15, 15, 15])
binary = cv2.inRange(gradient, lowerb, upperb)
cv2.imshow('Binarized gradient', binary)
cv2.waitKey()
現(xiàn)在我們有幾個(gè)問(wèn)題.它需要一些清理,因?yàn)樗軄y,而且,圖像邊緣的冰晶出現(xiàn)了 – 但我們不知道那些晶體實(shí)際上在哪里結(jié)束所以我們應(yīng)該忽略那些.為了從掩碼中刪除它們,我遍歷邊緣上的像素并使用floodFill()從二進(jìn)制圖像中刪除它們.不要在行和列的順序上混淆; if語(yǔ)句指定圖像矩陣的行和列,而floodFill()的輸入需要點(diǎn)(即x,y形式,與row,col相反).
# Flood fill from the edges to remove edge crystals
for row in range(h):
if binary[row, 0] == 255:
cv2.floodFill(binary, None, (0, row), 0)
if binary[row, w-1] == 255:
cv2.floodFill(binary, None, (w-1, row), 0)
for col in range(w):
if binary[0, col] == 255:
cv2.floodFill(binary, None, (col, 0), 0)
if binary[h-1, col] == 255:
cv2.floodFill(binary, None, (col, h-1), 0)
cv2.imshow('Filled binary gradient', binary)
cv2.waitKey()
大!現(xiàn)在只是打開和關(guān)閉一些清理它…
# Cleaning up mask
foreground = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
foreground = cv2.morphologyEx(foreground, cv2.MORPH_CLOSE, kernel)
cv2.imshow('Cleanup up crystal foreground mask', foreground)
cv2.waitKey()
所以這個(gè)圖像被標(biāo)記為“前景”,因?yàn)樗哂形覀兿胍指畹膶?duì)象的可靠前景.現(xiàn)在我們需要?jiǎng)?chuàng)建一個(gè)確定的對(duì)象背景.現(xiàn)在,我以天真的方式做到了這一點(diǎn),這只是為了使你的前景成長(zhǎng),所以你的對(duì)象可能都是在那個(gè)前景中定義的.但是,您可以使用原始蒙版或甚至漸變以不同的方式來(lái)獲得更好的定義.盡管如此,這仍然可以,但不是很強(qiáng)大.
# Creating background and unknown mask for labeling
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (17, 17))
background = cv2.dilate(foreground, kernel, iterations=3)
unknown = cv2.subtract(background, foreground)
cv2.imshow('Background', background)
cv2.waitKey()
因此所有的黑色都是流域的“確定背景”.我還創(chuàng)建了未知矩陣,它是前景和背景之間的區(qū)域,這樣我們就可以預(yù)先標(biāo)記傳遞到分水嶺的標(biāo)記,“嘿,這些像素肯定在前景中,這些像素肯定是背景,我我不確定這些之間.“現(xiàn)在剩下要做的就是分水嶺!首先,使用連接的組件標(biāo)記前景圖像,識(shí)別未知和背景部分,并將它們傳遞到:
# Watershed
markers = cv2.connectedComponents(foreground)[1]
markers += 1 # Add one to all labels so that background is 1, not 0
markers[unknown==255] = 0 # mark the region of unknown with zero
markers = cv2.watershed(img, markers)
你會(huì)注意到我在img上運(yùn)行了分水嶺().您可以嘗試在圖像的模糊版本上運(yùn)行它(可能是中間模糊 – 我嘗試了這個(gè)并且為晶體獲得了更平滑的邊界)或其他預(yù)處理版本的圖像,這些版本定義了更好的邊界或某些東西.
將標(biāo)記可視化需要一些工作,因?yàn)樗鼈冊(cè)趗int8圖像中都是小數(shù)字.所以我做的是在0到179中為它們分配一些色調(diào)并在HSV圖像中設(shè)置,然后轉(zhuǎn)換為BGR以顯示標(biāo)記:
# Assign the markers a hue between 0 and 179
hue_markers = np.uint8(179*np.float32(markers)/np.max(markers))
blank_channel = 255*np.ones((h, w), dtype=np.uint8)
marker_img = cv2.merge([hue_markers, blank_channel, blank_channel])
marker_img = cv2.cvtColor(marker_img, cv2.COLOR_HSV2BGR)
cv2.imshow('Colored markers', marker_img)
cv2.waitKey()
最后,將標(biāo)記覆蓋到原始圖像上以檢查它們的外觀.
# Label the original image with the watershed markers
labeled_img = img.copy()
labeled_img[markers>1] = marker_img[markers>1] # 1 is background color
labeled_img = cv2.addWeighted(img, 0.5, labeled_img, 0.5, 0)
cv2.imshow('watershed_result.png', labeled_img)
cv2.waitKey()
嗯,那就是整個(gè)管道.您應(yīng)該能夠連續(xù)復(fù)制/粘貼每個(gè)部分,并且您應(yīng)該能夠獲得相同的結(jié)果.該管道中最薄弱的部分是對(duì)梯度進(jìn)行二值化并定義流域的確定背景.距離變換可能有助于以某種方式對(duì)梯度進(jìn)行二值化,但我還沒(méi)有到達(dá)那里.無(wú)論哪種方式……這是一個(gè)很酷的問(wèn)題,我很想看到你對(duì)這個(gè)管道所做的任何改變,或者它對(duì)其他冰晶圖像的影響.
總結(jié)
以上是生活随笔為你收集整理的python计算不规则图形面积_python opencv中的不规则形状检测和测量的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 信用卡主人死亡怎么办 这两种情况了解一下
- 下一篇: 盲盒是什么东西 在青少年中非常的火