2 回答
TA贡献1820条经验 获得超2个赞
您可以在您的案例中使用模块 scikit-image 中的函数regionprops 。这是我得到的。
这是我使用的代码。
import cv2
import matplotlib.pyplot as plt
from skimage import measure
import numpy as np
cells = cv2.imread('cells.png',0)
ret,thresh = cv2.threshold(cells,20,255,cv2.THRESH_BINARY_INV)
labels= measure.label(thresh, background=0)
bg_label = labels[0,0]
labels[labels==bg_label] = 0 # Assign background label to 0
props = measure.regionprops(labels)
fig,ax = plt.subplots(1,1)
plt.axis('off')
ax.imshow(cells,cmap='gray')
centroids = np.zeros(shape=(len(np.unique(labels)),2)) # Access the coordinates of centroids
for i,prop in enumerate(props):
my_centroid = prop.centroid
centroids[i,:]= my_centroid
ax.plot(my_centroid[1],my_centroid[0],'r.')
# print(centroids)
# fig.savefig('out.png', bbox_inches='tight', pad_inches=0)
plt.show()
祝你研究顺利!
TA贡献1765条经验 获得超5个赞
问题
cv2.findContours
使用具有几种不同“检索模式”的算法。这些会影响返回哪些轮廓以及返回方式。这记录在这里。这些作为 的第二个参数给出findContours
。您的代码使用cv2.RETR_EXTERNAL
which 意味着findContours
只会返回单独对象的最外层边框。
解决方案
将此参数更改为cv2.RETR_LIST
将为您提供图像中的所有轮廓(包括最外层的边框)。这是最简单的解决方案。
例如
import cv2
import imutils
img = cv2.imread('/Users/kate/Desktop/SegmenterTest/SegmentedCells/Seg1.png')
image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(image, 60, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# loop over the contours
for c in cnts:
# compute the center of the contour
M = cv2.moments(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
# draw the contour and center of the shape on the image
cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
cv2.circle(image, (cX, cY), 7, (255, 255, 255), -1)
cv2.putText(image, "center", (cX - 20, cY - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
# show the image
cv2.imshow("Image", image)
cv2.waitKey(0)
只选择最里面的对象
要可靠地忽略外部轮廓,您可以利用findContours
返回它检测到的轮廓的层次结构的能力。为此,您可以再次将检索模式参数更改为RETR_TREE
,这将生成完整的层次结构。
层次结构是一个数组,其中包含图像中每个轮廓的 4 个值的数组。每个值都是轮廓数组中轮廓的索引。从文档:
对于每个第 i 个轮廓
contours[i]
,元素hierarchy[i][0]
、hierarchy[i][1]
、hierarchy[i][2]
和hierarchy[i][3]
分别设置为同一层级下一个和上一个轮廓、第一个子轮廓和父轮廓的轮廓中从 0 开始的索引。如果轮廓 i 没有下一个、上一个、父级或嵌套轮廓,则相应的元素hierarchy[i]
将为负数。
当我们说“最里面”时,我们的意思是没有孩子的轮廓(它们内部的轮廓)。所以我们想要那些在层次结构中的条目具有负的第三值的轮廓。也就是说, contours[i]
,使得hierarchy[i][2] < 0
一个小问题是,虽然findContours
返回一个包含层次结构的元组,但imutils.grabContours
会丢弃层次结构并仅返回轮廓数组。grabContours
所有这一切意味着,如果我们打算使用不同版本的 OpenCV,我们必须自己完成工作。这只是一个简单的if else
声明。
res = cv2.findContours(thresh.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# switch for different versions of OpenCV
if len(cnts) == 3:
_, cnts, hierarchy = res
else:
cnts, hierarchy = res
一旦你有了hierarchy,检查一个轮廓是否cnts[i]是“最里面的”可以用 完成hierarchy[0][i][2] < 0,这应该是False针对包含其他轮廓的轮廓。
基于您问题代码的完整示例:
import cv2
import imutils
img = cv2.imread('/Users/kate/Desktop/SegmenterTest/SegmentedCells/Seg1.png')
image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(image, 60, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# switch for different versions of OpenCV
if len(cnts) == 3:
_, cnts, hierarchy = cnts
else:
cnts, hierarchy = cnts
# loop over the contours
for i, c in enumerate(cnts):
# check that it is 'innermost'
if hierarchy[0][i][2] < 0:
# compute the center of the contour
M = cv2.moments(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
# draw the contour and center of the shape on the image
cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
cv2.circle(image, (cX, cY), 7, (255, 255, 255), -1)
cv2.putText(image, "center", (cX - 20, cY - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
# show the image
cv2.imshow("Image", image)
cv2.waitKey(0)
添加回答
举报