确定凹点

3
如果我使用goodFeaturesToTrack,我可以获得所有角点(红色,蓝色)。然而,我只想保留凹角点(蓝色)。我不知道如何实现。我该怎么做?

enter image description here enter image description here

以下是实际运行样例的图片: 在此输入图像描述

取凸包。在凸包中的点是红色的点;不在凸包中的点是蓝色的点。请参见此处。请注意,如果您使用最后一个可选参数returnPoints并将其设置为False,它将只返回原始点中在凸包内的索引(因此您还将知道不在凸包中的点的索引)。 - alkasm
抱歉,我的解释不够详细。实际上,上面的图像模拟了一些真实情况。也就是说,白色区域不是平滑的。因此,凸包可能会跳过某些点或添加噪点。 - SinLok
@AlexanderReynolds 并不是所有的凸角都在凸包上。实际上,你可以在示例图像中看到这一点。 - m69 ''snarky and unwelcoming''
@m69 啊...嗯,我明白了。而将逆像的凸包作为凹点也会有同样的问题。 - alkasm
1
我猜一般来说,如果你有一个掩模,那么在每个蓝点(凹面)处,周围的像素中白色的比黑色的多,对吧,因为角度需要小于180度。你可以实现只查看直接邻域(周围的8个像素),或者使用更大的半径并计算白色像素与黑色像素的数量。 - alkasm
@AlexanderReynolds 我上传了一个实际使用案例的简单示例。 - SinLok
2个回答

3

如评论中所述,这里的简单方法似乎是将图像与盒式滤波器(或类似的椭圆形状)卷积,这将在整个图像上给出窗口平均值。您可以在角点处简单地索引此卷积结果。如果这些点处的卷积结果超过50%,则该点周围有更多白色,因此它是凹点。否则,它是凸点。以下是代码示例。

import cv2
import numpy as np
from itertools import tee

def pairwise(iterable):
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

# read image as grayscale
img = cv2.imread('example.png', 0)

# get corner points, remove duplicate/nearby points
contours = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
contour = contours[0]
pts = np.array([contour[0]] + [pt1 for pt0, pt1 in pairwise(contour) if not (abs(pt0 - pt1) <= 1).all()])
x, y = pts[:, -1, 0], pts[:, -1, 1]

# get the kernel that you will sum around your corner points
kernel = np.float64(cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13, 13)))
kernel /= np.sum(kernel)

# convolve the image with the kernel, and pull out the sums at the corner points
conv = cv2.filter2D(img/255, cv2.CV_64F, kernel)
neighborhood_sums = conv[y, x]

# concave indices have more white than black around them, so convolution will be >= 1/2
concave_indices = neighborhood_sums >= 0.5

# draw markers
marked = cv2.merge([img, img, img])
for pt, concave in zip(pts, concave_indices):
    color = (255, 0, 255) if concave else (0, 255, 0)
    marker = cv2.MARKER_TRIANGLE_UP if concave else cv2.MARKER_TRIANGLE_DOWN
    cv2.drawMarker(marked, tuple(pt[0]), color, markerType=marker, markerSize=10, thickness=3)

在导入之后,我定义了 itertools中的一种方法 来成对迭代(例如,s -> (s0, s1), (s1, s2), ...)。这对于消除从 findContours() 获取的重复点非常有用,但与问题无关。在此之后,其余部分如先前所述进行。您可以自己绘制内核或者使用 getStructuringElement() 中提供的一个内核,因为它可以创建任意大小的椭圆(请注意,这返回一个形状奇怪的内核,您可能最好自己定义一个圆)。请注意,内核的大小在此处以总宽度指定,而不仅仅是半径,并且它被其中1的数量标准化,以便结果始终在0和1之间。
以下是上述操作在第一张图片上的结果:

Marked concave vs convex points


1

其中一种解决方案是在不同的内核中使用HIT_MISS_MORPH

如果您选择此内核:

[[-1 -1  1]
 [-1 -1  1]
 [ 1  1  1]]

然后在阈值化图像上执行hitmiss操作,可以得到两个锚点:

mask = cv2.morphologyEx(threshed, cv2.MORPH_HITMISS, kernel, anchor=(-1,-1))

enter image description here

在原始图像上绘制:

enter image description here


在不同的内核中发现了锚点(旋转基本内核和/或反转它):

enter image description here

在原始图像上以彩色显示:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接