分水岭分割后提取对象
Extracting objects after watershed segmentation
我需要分割下图中的种子并裁剪它们。
https://i.stack.imgur.com/ndOkX.jpg
它们可能彼此非常接近,有时会重叠,所以我选择使用分水岭算法来完成这项任务。
我的结果如下图所示,在绘制返回的标记的轮廓之后,如您所见,我在定义用于应用它的良好标记时遇到了问题。个别种子都勾勒出来了,但是里面有很多我不想要的线。
https://i.stack.imgur.com/BtOfj.jpg
我该如何去除它们或定义更好的标记?
我的代码是运行:
from skimage.feature import peak_local_max
from skimage.segmentation import watershed
import matplotlib.pyplot as plt
from scipy import ndimage
import cv2 as cv
import imutils
import numpy as np
img = cv.imread("image.jpg");
blur = cv.GaussianBlur(img,(7,7),0)
#color space change
mSource_Hsv = cv.cvtColor(blur,cv.COLOR_BGR2HSV);
mMask = cv.inRange(mSource_Hsv,np.array([0,0,0]),np.array([80,255,255]));
output = cv.bitwise_and(img, img, mask=mMask)
#grayscale
img_grey = cv.cvtColor(output, cv.COLOR_BGR2GRAY)
#thresholding
ret,th1 = cv.threshold(img_grey,0,255,cv.THRESH_BINARY + cv.THRESH_OTSU)
#dist transform
D = ndimage.distance_transform_edt(th1)
#markers
localMax = peak_local_max(D, indices=False, min_distance=20, labels=th1)
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
#apply watershed
labels = watershed(-D, markers, mask=th1)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))
# loop over the unique labels
for label in np.unique(labels):
if label == 0:
continue
# draw label on the mask
mask = np.zeros(img_grey.shape, dtype="uint8")
mask[labels == label] = 255
# detect contours in the mask and grab the largest one
cnts = cv.findContours(mask.copy(), cv.RETR_EXTERNAL,
cv.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv.contourArea)
cv.drawContours(img, cnts, -1, (0, 255, 0), 2)
cv.imshow("segmented",img)
cv.waitKey(0)
您可以合并满足以下条件的每两个轮廓:
- 合并等高线的凸包的面积接近于两个等高线的面积之和。
以下解决方案使用了一种 "brute force" 方法,尝试将每个轮廓与所有其他轮廓合并(效率不高)。
这是一个工作代码示例(请阅读评论):
from skimage.feature import peak_local_max
from skimage.segmentation import watershed
import matplotlib.pyplot as plt
from scipy import ndimage
import cv2 as cv
import imutils
import numpy as np
img = cv.imread("image.jpg");
blur = cv.GaussianBlur(img,(7,7),0)
#color space change
mSource_Hsv = cv.cvtColor(blur,cv.COLOR_BGR2HSV);
mMask = cv.inRange(mSource_Hsv,np.array([0,0,0]),np.array([80,255,255]));
output = cv.bitwise_and(img, img, mask=mMask)
#grayscale
img_grey = cv.cvtColor(output, cv.COLOR_BGR2GRAY)
#thresholding
ret,th1 = cv.threshold(img_grey,0,255,cv.THRESH_BINARY + cv.THRESH_OTSU)
#dist transform
D = ndimage.distance_transform_edt(th1)
#markers
localMax = peak_local_max(D, indices=False, min_distance=20, labels=th1)
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
#apply watershed
labels = watershed(-D, markers, mask=th1)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))
contours = []
# loop over the unique labels, and append contours to all_cnts
for label in np.unique(labels):
if label == 0:
continue
# draw label on the mask
mask = np.zeros(img_grey.shape, dtype="uint8")
mask[labels == label] = 255
# detect contours in the mask and grab the largest one
cnts = cv.findContours(mask.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv.contourArea)
## Ignore small contours
#if c.shape[0] < 20:
# continue
# Get convex hull of contour - it' going to help when merging contours
hull = cv.convexHull(c)
#cv.drawContours(img, c, -1, (0, 255, 0), 2)
cv.drawContours(img, [hull], -1, (0, 255, 0), 2, 1)
# Append hull to contours list
contours.append(hull)
# Merge the contours that does not increase the convex hull by much.
# Note: The solution is kind of "brute force" solution, and can be better.
################################################################################
for i in range(len(contours)):
c = contours[i]
area = cv.contourArea(c)
# Iterate all contours from i+1 to end of list
for j in range(i+1, len(contours)):
c2 = contours[j]
area2 = cv.contourArea(c2)
area_sum = area + area2
# Merge contours together
tmp = np.vstack((c, c2))
merged_c = cv.convexHull(tmp)
merged_area = cv.contourArea(merged_c)
# Replace contours c and c2 by the convex hull of merged c and c2, if total area is increased by no more then 10%
if merged_area < area_sum*1.1:
# Replace contour with merged one.
contours[i] = merged_c
contours[j] = merged_c
c = merged_c
area = merged_area
################################################################################
# Draw new contours in red color
for c in contours:
#Ignore small contours
if cv.contourArea(c) > 100:
cv.drawContours(img, [c], -1, (0, 0, 255), 2, 1)
cv.imshow("segmented",img)
cv.waitKey(0)
cv.destroyAllWindows()
结果:
我需要分割下图中的种子并裁剪它们。
https://i.stack.imgur.com/ndOkX.jpg
它们可能彼此非常接近,有时会重叠,所以我选择使用分水岭算法来完成这项任务。
我的结果如下图所示,在绘制返回的标记的轮廓之后,如您所见,我在定义用于应用它的良好标记时遇到了问题。个别种子都勾勒出来了,但是里面有很多我不想要的线。
https://i.stack.imgur.com/BtOfj.jpg
我该如何去除它们或定义更好的标记?
我的代码是运行:
from skimage.feature import peak_local_max
from skimage.segmentation import watershed
import matplotlib.pyplot as plt
from scipy import ndimage
import cv2 as cv
import imutils
import numpy as np
img = cv.imread("image.jpg");
blur = cv.GaussianBlur(img,(7,7),0)
#color space change
mSource_Hsv = cv.cvtColor(blur,cv.COLOR_BGR2HSV);
mMask = cv.inRange(mSource_Hsv,np.array([0,0,0]),np.array([80,255,255]));
output = cv.bitwise_and(img, img, mask=mMask)
#grayscale
img_grey = cv.cvtColor(output, cv.COLOR_BGR2GRAY)
#thresholding
ret,th1 = cv.threshold(img_grey,0,255,cv.THRESH_BINARY + cv.THRESH_OTSU)
#dist transform
D = ndimage.distance_transform_edt(th1)
#markers
localMax = peak_local_max(D, indices=False, min_distance=20, labels=th1)
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
#apply watershed
labels = watershed(-D, markers, mask=th1)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))
# loop over the unique labels
for label in np.unique(labels):
if label == 0:
continue
# draw label on the mask
mask = np.zeros(img_grey.shape, dtype="uint8")
mask[labels == label] = 255
# detect contours in the mask and grab the largest one
cnts = cv.findContours(mask.copy(), cv.RETR_EXTERNAL,
cv.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv.contourArea)
cv.drawContours(img, cnts, -1, (0, 255, 0), 2)
cv.imshow("segmented",img)
cv.waitKey(0)
您可以合并满足以下条件的每两个轮廓:
- 合并等高线的凸包的面积接近于两个等高线的面积之和。
以下解决方案使用了一种 "brute force" 方法,尝试将每个轮廓与所有其他轮廓合并(效率不高)。
这是一个工作代码示例(请阅读评论):
from skimage.feature import peak_local_max
from skimage.segmentation import watershed
import matplotlib.pyplot as plt
from scipy import ndimage
import cv2 as cv
import imutils
import numpy as np
img = cv.imread("image.jpg");
blur = cv.GaussianBlur(img,(7,7),0)
#color space change
mSource_Hsv = cv.cvtColor(blur,cv.COLOR_BGR2HSV);
mMask = cv.inRange(mSource_Hsv,np.array([0,0,0]),np.array([80,255,255]));
output = cv.bitwise_and(img, img, mask=mMask)
#grayscale
img_grey = cv.cvtColor(output, cv.COLOR_BGR2GRAY)
#thresholding
ret,th1 = cv.threshold(img_grey,0,255,cv.THRESH_BINARY + cv.THRESH_OTSU)
#dist transform
D = ndimage.distance_transform_edt(th1)
#markers
localMax = peak_local_max(D, indices=False, min_distance=20, labels=th1)
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
#apply watershed
labels = watershed(-D, markers, mask=th1)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))
contours = []
# loop over the unique labels, and append contours to all_cnts
for label in np.unique(labels):
if label == 0:
continue
# draw label on the mask
mask = np.zeros(img_grey.shape, dtype="uint8")
mask[labels == label] = 255
# detect contours in the mask and grab the largest one
cnts = cv.findContours(mask.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv.contourArea)
## Ignore small contours
#if c.shape[0] < 20:
# continue
# Get convex hull of contour - it' going to help when merging contours
hull = cv.convexHull(c)
#cv.drawContours(img, c, -1, (0, 255, 0), 2)
cv.drawContours(img, [hull], -1, (0, 255, 0), 2, 1)
# Append hull to contours list
contours.append(hull)
# Merge the contours that does not increase the convex hull by much.
# Note: The solution is kind of "brute force" solution, and can be better.
################################################################################
for i in range(len(contours)):
c = contours[i]
area = cv.contourArea(c)
# Iterate all contours from i+1 to end of list
for j in range(i+1, len(contours)):
c2 = contours[j]
area2 = cv.contourArea(c2)
area_sum = area + area2
# Merge contours together
tmp = np.vstack((c, c2))
merged_c = cv.convexHull(tmp)
merged_area = cv.contourArea(merged_c)
# Replace contours c and c2 by the convex hull of merged c and c2, if total area is increased by no more then 10%
if merged_area < area_sum*1.1:
# Replace contour with merged one.
contours[i] = merged_c
contours[j] = merged_c
c = merged_c
area = merged_area
################################################################################
# Draw new contours in red color
for c in contours:
#Ignore small contours
if cv.contourArea(c) > 100:
cv.drawContours(img, [c], -1, (0, 0, 255), 2, 1)
cv.imshow("segmented",img)
cv.waitKey(0)
cv.destroyAllWindows()
结果: