OpenCV找不到所有轮廓 [英] Opencv not finding all contours

查看:720
本文介绍了OpenCV找不到所有轮廓的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试查找此图像的轮廓,但是方法 findContours 仅返回 1 轮廓,轮廓在图像2中突出显示.我正在尝试找到所有外部轮廓,例如这些数字在其中的圆圈.我究竟做错了什么?我该怎么做?

I'm trying to find the contours of this image, but the method findContours only returns 1 contour, the contour is highlighted in image 2. I'm trying to find all external contours like these circles where the numbers are inside. What am i doing wrong? What can i do to accomplish it?

图片1

图片2

下面是我代码的相关部分.

Below is the relevant portion of my code.

thresh = cv2.threshold(image, 0, 255,
                           cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                            cv2.CHAIN_APPROX_SIMPLE)

当我将cv2.RETR_EXTERNAL更改为cv2.RETR_LIST时,似乎两次检测到相同的轮廓或类似的东西.图像3显示了何时首先检测到圆的边界,然后如图4所示再次检测到它.我试图仅查找这些圆的外边界.我该怎么办?

When i change cv2.RETR_EXTERNAL to cv2.RETR_LIST it seems to detect the same contour twice or something like this. Image 3 shows when the border of circle is first detected and then it is detected again as shows image 4. I'm trying to find only outer borders of these circles. How can i accomplish that?

图片3

图片4

推荐答案

尽管如此,我不确定这是否真的是您期望的,有很多方法可以帮助findContours完成工作. 这是我经常使用的方法.

I am not sure this is really what you expect nevertheless in case like this there is many way to help findContours to do its job. Here is a way I use frequently.

  1. 将图像转换为灰色

  1. Convert your image to gray

Ig = cv2.cvtColor(I,cv2.COLOR_BGR2GRAY)

  1. 阈值

背景和前景值在颜色方面看起来非常均匀,但局部上却不一样,因此我基于Otsu方法对阈值进行了二值化处理.

The background and foreground values looklike quite uniform in term of colours but locally they are not so I apply an thresholding based on Otsu's method in order to binarise the intensities.

 _,It = cv2.threshold(Ig,0,255,cv2.THRESH_OTSU)

  1. 苏贝尔量级

为了只提取轮廓,我处理了Sobel边缘检测器的大小.

In order to extract only the contours I process the magnitude of the Sobel edges detector.

sx = cv2.Sobel(It,cv2.CV_32F,1,0)

sy = cv2.Sobel(It,cv2.CV_32F,0,1)

m = cv2.magnitude(sx,sy)

m = cv2.normalize(m,None,0.,255.,cv2.NORM_MINMAX,cv2.CV_8U)

  1. 稀疏(可选)

我使用在ximgproc中实现的细化功能.

I use the thinning function which is implemented in ximgproc.

细化的目的是将轮廓的厚度减小到尽可能少的像素.

The interest of the thining is to reduce the contours thickness to as less pixels as possible.

 m = cv2.ximgproc.thinning(m,None,cv2.ximgproc.THINNING_GUOHALL)

  1. 最终步骤findContours

  1. Final Step findContours

_,contours,hierarchy = cv2.findContours(m,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
disp = cv2.merge((m,m,m)
disp = cv2.drawContours(disp,contours,-1,hierarchy=hierarchy,color=(255,0,0))    

希望有帮助.

我认为基于SVM或CNN的方法可能更健壮. 您可以在此处找到示例. 这个也可能很有趣.

I think an approach based on SVM or a CNN might be more robust. You can find an example here. This one may also be interesting.

-EDIT-

我找到了一种可以说更容易实现目标的方法.

I found a let say easier way to reach your goal.

像之前在加载图像后应用阈值一样,请确保图像是二进制的. 通过使用按位非操作反转图像,轮廓在黑色背景上变为白色. 应用cv2.connectedComponentsWithStats返回(以及其他)标签矩阵,在标签矩阵中,源中每个连接的白色区域均被分配了唯一的标签. 然后根据标签应用findContours,可以给出每个区域的外部轮廓.

Like previously after loading the image applying a threshold ensure that the image is binary. By reversing the image using a bitwise not operation the contours become white over a black background. Applying cv2.connectedComponentsWithStats return (among others) a label matrix in which each connected white region in the source has been assign a unique label. Then applying findContours based on the labels it is possible give the external contours for every areas.

import numpy as np
import cv2
from matplotlib import pyplot as plt




I = cv2.imread('/home/smile/Downloads/ext_contours.png',cv2.IMREAD_GRAYSCALE)

_,I = cv2.threshold(I,0.,255.,cv2.THRESH_OTSU)
I = cv2.bitwise_not(I)

_,labels,stats,centroid = cv2.connectedComponentsWithStats(I)

result = np.zeros((I.shape[0],I.shape[1],3),np.uint8)

for i in range(0,labels.max()+1):
    mask = cv2.compare(labels,i,cv2.CMP_EQ)

    _,ctrs,_ = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

    result = cv2.drawContours(result,ctrs,-1,(0xFF,0,0))

plt.figure()
plt.imshow(result)  

P.S.在函数findContours返回的输出中,有一个层次矩阵. 通过分析该矩阵可以达到相同的结果,但是它要稍微复杂一些,如此处.

P.S. Among the outputs return by the function findContours there is a hierachy matrix. It is possible to reach the same result by analyzing that matrix however it is a little bit more complex as explain here.

这篇关于OpenCV找不到所有轮廓的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆