引子
大家好,今天给大家分享两个来自OpenCV研习社提问的帖子,都是很经典的图像处理与分析问题,希望通过这两个例子,大家能够得到更多的启发,从而想到更好的解决类似问题的思路。
01
问题一:寻找靶心

图一
02
问题二:寻找其中的缺失点

图二
解决方法
01
寻找靶心
仔细观察图一,可以看到两个最直接的是靶心有十字交叉线,而在OpenCV形态学处理中,支持十字交叉结构元素,所以我们可以先检测两条线,然后获取十字交叉结构,最后对结构进行轮廓分析,获取中心点,即可获得最终的靶心位置,最终寻找到的靶心位置图示如下:

获取水平与垂直线如下:

获取十字交叉线如下:

代码实现如下:
代码语言:javascript复制image = cv.imread("D:/images/zsxq/cross.jpg")
cv.imshow("input", image)
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_OTSU | cv.THRESH_BINARY_INV)
se1 = cv.getStructuringElement(cv.MORPH_CROSS, (50, 1))
se2 = cv.getStructuringElement(cv.MORPH_CROSS, (1, 50))
hline = cv.morphologyEx(binary, cv.MORPH_OPEN, se1)
vline = cv.morphologyEx(binary, cv.MORPH_OPEN, se2)
contours, hireachy = cv.findContours(hline, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
mask = np.zeros_like(hline)
max = -1
index = 0
for cnt in range(len(contours)):
x, y, w, h = cv.boundingRect(contours[cnt])
if max < w:
max = w
index = cnt
cv.drawContours(mask, contours, index, (255), -1, 8)
cv.imshow("vline", vline)
contours, hireachy = cv.findContours(vline, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
max = -1
index = 0
for cnt in range(len(contours)):
x, y, w, h = cv.boundingRect(contours[cnt])
if max < h and x < int(gray.shape[1]*0.75):
max = h
index = cnt
cv.drawContours(mask, contours, index, (255), -1, 8)
cv.imshow("mask", mask)
se3 = cv.getStructuringElement(cv.MORPH_CROSS, (13, 13))
mask = cv.morphologyEx(mask, cv.MORPH_OPEN, se3)
cv.imshow("corss", mask)
contours, hireachy = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for cnt in range(len(contours)):
x, y, w, h = cv.boundingRect(contours[cnt])
print(x, y, w, h)
cx = (x w//2)
cy = (y h//2)
cv.circle(image, (cx, cy), 4, (0, 0, 255), 4, 8, 0)
cv.imshow("result", image)
cv.imwrite("D:/find_cross.png", image)
cv.waitKey(0)
cv.destroyAllWindows()02
寻找缺失
仔细观察图二,缺失是偶发情况,针对这种情况下,要完成计数与缺失位置标定!我感觉我的密集恐惧症已经开始犯了!首先需要获取这些位置,通过二值话与轮廓发现搞定,然后根据这些轮廓位置,重新绘制统一的圆形标记,轮廓发现对每个圆形标记进行上下左右位置最近领搜索,返回间隔距离,-1表示边界,根据间隔距离设置阈值查找缺失,最终运行结果如下:

从原图得到的标记图如下:

代码实现如下:
代码语言:javascript复制image = cv.imread("D:/images/zsxq/zsxq_40.png")
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_OTSU | cv.THRESH_BINARY_INV)
cv.imshow("binary", binary)
contours, hireachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
mask = np.zeros_like(binary)
for cnt in range(len(contours)):
area = cv.contourArea(contours[cnt])
if area < 50:
continue
x, y, w, h = cv.boundingRect(contours[cnt])
if (y h) > (binary.shape[0] - 10):
continue
cx = (x w//2)
cy = (y h//2)
cv.circle(mask, (cx, cy), 4, (255), 4, 8, 0)
cv.imshow("mask", mask)
contours, hireachy = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for cnt in range(len(contours)):
x, y, w, h = cv.boundingRect(contours[cnt])
cx = (x w//2)
cy = (y h//2)
left = find_neighborhood(mask, cx, cy, 1)
right = find_neighborhood(mask, cx, cy, 2)
# top = find_neighborhood(mask, cx, cy, 3)
# bottom = find_neighborhood(mask, cx, cy, 4)
if left == -1 or right == -1: # or top == -1 or bottom == -1:
continue
dx = right - left
# dy = top - bottom
# print(dx, dy)
if dx > 15:
cv.circle(image, (cx left 10, cy), 4, (0, 0, 255), 4, 8, 0)
cv.imshow("test", image)
cv.imwrite("D:/find_miss.png", image)
cv.waitKey(0)
cv.destroyAllWindows()


