python计算不规则图形面积_python opencv中的不规则形状检测和测量
正如我在評論中提到的那樣,對于這個問題,分水嶺似乎是一個很好的方法.但是當你回答時,定義標記的前景和背景是困難的部分!我的想法是使用形態梯度沿著冰晶獲得良好的邊緣并從那里開始工作;形態梯度似乎很有效.
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()
從這里開始,我使用一些閾值來對梯度進行二值化.可能有一種更清潔的方法來做到這一點……但這比我嘗試過的其他一些想法更好.
# 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()
現在我們有幾個問題.它需要一些清理,因為它很亂,而且,圖像邊緣的冰晶出現了 – 但我們不知道那些晶體實際上在哪里結束所以我們應該忽略那些.為了從掩碼中刪除它們,我遍歷邊緣上的像素并使用floodFill()從二進制圖像中刪除它們.不要在行和列的順序上混淆; if語句指定圖像矩陣的行和列,而floodFill()的輸入需要點(即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()
大!現在只是打開和關閉一些清理它…
# 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()
所以這個圖像被標記為“前景”,因為它具有我們想要分割的對象的可靠前景.現在我們需要創建一個確定的對象背景.現在,我以天真的方式做到了這一點,這只是為了使你的前景成長,所以你的對象可能都是在那個前景中定義的.但是,您可以使用原始蒙版或甚至漸變以不同的方式來獲得更好的定義.盡管如此,這仍然可以,但不是很強大.
# 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()
因此所有的黑色都是流域的“確定背景”.我還創建了未知矩陣,它是前景和背景之間的區域,這樣我們就可以預先標記傳遞到分水嶺的標記,“嘿,這些像素肯定在前景中,這些像素肯定是背景,我我不確定這些之間.“現在剩下要做的就是分水嶺!首先,使用連接的組件標記前景圖像,識別未知和背景部分,并將它們傳遞到:
# 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)
你會注意到我在img上運行了分水嶺().您可以嘗試在圖像的模糊版本上運行它(可能是中間模糊 – 我嘗試了這個并且為晶體獲得了更平滑的邊界)或其他預處理版本的圖像,這些版本定義了更好的邊界或某些東西.
將標記可視化需要一些工作,因為它們在uint8圖像中都是小數字.所以我做的是在0到179中為它們分配一些色調并在HSV圖像中設置,然后轉換為BGR以顯示標記:
# 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()
最后,將標記覆蓋到原始圖像上以檢查它們的外觀.
# 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()
嗯,那就是整個管道.您應該能夠連續復制/粘貼每個部分,并且您應該能夠獲得相同的結果.該管道中最薄弱的部分是對梯度進行二值化并定義流域的確定背景.距離變換可能有助于以某種方式對梯度進行二值化,但我還沒有到達那里.無論哪種方式……這是一個很酷的問題,我很想看到你對這個管道所做的任何改變,或者它對其他冰晶圖像的影響.
總結
以上是生活随笔為你收集整理的python计算不规则图形面积_python opencv中的不规则形状检测和测量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信用卡主人死亡怎么办 这两种情况了解一下
- 下一篇: 盲盒是什么东西 在青少年中非常的火