OpenCV:将“模糊最大值”减少为单点

2024-05-29 04:46:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用了:

result = cv2.matchTemplate(frame, template, cv2.TM_CCORR_NORMED)

要生成此输出,请执行以下操作: enter image description here 我需要一个(x,y)元组列表,位于结果中每个局部极大值(亮点)处。简单地找到阈值以上的所有点是行不通的,因为在每个最大值周围都有许多这样的点

我可以保证任意两个最大值之间的最小距离,这应该有助于加快速度

有没有一种有效的方法可以做到这一点

(附注:这是从https://forum.opencv.org/t/locating-local-maximums/1534交叉发布的)

更新

基于excellent suggestion乘以Michael Lee,我将骨架化添加到阈值图像中。很接近,但骨骼化仍然有许多“蠕虫”,而不是单个点。我的处理流程如下:

# read the image
im = cv.imread("image.png", cv.IMREAD_GRAYSCALE)
# apply thresholding
ret, im2 = cv.threshold(im, args.threshold, 255, cv.THRESH_BINARY)
# dilate the thresholded image to eliminate "pinholes"
im3 = cv.dilate(im2, None, iterations=2)
# skeletonize the result
im4 = cv.ximgproc.thinning(im3, None, cv.ximgproc.THINNING_ZHANGSUEN)
# print the number of points found
x, y = np.nonzero(im5)
print(x.shape)
# => 1208

这是朝着正确的方向迈出的一步,但应该有220点,而不是1208点

以下是中间结果。正如您在上一张图片(骷髅化)中看到的,仍然有很多小“蠕虫”,而不是单点。有更好的方法吗

阈值: enter image description here

扩大: enter image description here

骨骼化: enter image description here


Tags: the方法imagenonethreshold阈值resultcv2
2条回答

更新2/14:似乎骨骼化只让你走了一段路。这里有一个更好的解决方案,我相信它会帮你解决剩下的问题。下面是如何在scikit图像中执行此操作-也许您可以在OpenCV中找到类似的操作-看起来cv2.findContours将是一个良好的开始

# mask is the thresholded image (before or after dilation should work, no skeletonization.

from skimage.measure import label, regionprops
labeled_image = label(mask)
output_points = [region.centroid for region in regionprops(labeled_image)]

说明:Label会将二进制图像转换为带标签的图像,其中每个遮罩具有不同的整数值。然后,regionprops使用这些标签来分离每个遮罩,从中我们可以使用质心属性来计算每个遮罩的中点-这保证是单个点


Simply finding all points above a threshold doesn't work, since there are many such points around each maximum.

事实上,这是可行的——只要您再应用一个处理步骤。在阈值化之后,我们想要骨骼化。Scikit image有一个很好的函数来实现here,它应该为您提供一个带有单点的二进制掩码

之后,您可能会想运行以下内容:

indices = zip(*np.where(skeleton))

为了得到你的最后分数

基于Michael Lee's answer,以下是对我有效的解决方案(使用所有openCV而不是skimage):

# read in color image and create a grayscale copy
im = cv.imread("image.png")
img = cv.cvtColor(im, cv.COLOR_BGR2GRAY)

# apply thresholding
ret, im2 = cv.threshold(img, args.threshold, 255, cv.THRESH_BINARY)
# dilate the thresholded peaks to eliminate "pinholes"
im3 = cv.dilate(im2, None, iterations=2)

contours, hier = cv.findContours(im3, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
print('found', len(contours), 'contours')
# draw a bounding box around each contour
for contour in contours:
    x,y,w,h = cv.boundingRect(contour)
    cv.rectangle(im, (x,y), (x+w,y+h), (255,0,0), 2)

cv.imshow('Contours', im)
cv.waitKey()

这正是我们想要的结果:

enter image description here

相关问题 更多 >

    热门问题