正如在评论中提到的,这里似乎最容易做的事情是用一个盒子过滤器(或类似的,但椭圆形状)来卷积你的图像,这将给你整个图像的窗口平均值。你可以简单地在你的角点索引这个卷积结果。如果这些点的卷积结果大于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
recipes
用于成对迭代(例如。
s -> (s0, s1), (s1, s2), ...
). 这对问题一点都不重要,但对于我来说,消除从中获取的重复点非常有用
findContours()
. 在那之后,其余的按照前面所描述的进行。你可以画你自己的内核或任何你喜欢的,但我只是从
getStructuringElement()
由于您可以使用任意大小的椭圆(尽管注意这会返回一个形状奇怪的内核,但您可以自己更好地定义一个圆)。请注意,内核的大小在这里是以总宽度指定的,而不仅仅是半径,并且它由其中的1个数进行规范化,因此结果总是在0和1之间。