我不确定这是否真的是你所期望的,但如果这样的话,有很多方法可以帮助 findContours 完成它的工作。这是我经常使用的一种方式。
将图像转换为灰色
Ig = cv2.cvtColor(I,cv2.COLOR_BGR2GRAY)

- 阈值化
背景和前景值在颜色方面看起来非常均匀,但在局部它们不是,所以我应用了基于 Otsu 方法的阈值以对强度进行二值化。
_,It = cv2.threshold(Ig,0,255,cv2.THRESH_OTSU)
- 索贝尔震级
为了只提取轮廓,我处理了 Sobel 边缘检测器的幅度。
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)

- 细化(可选)
我使用在ximgproc
.
细化的目的是将轮廓厚度减少到尽可能少的像素。
m = cv2.ximgproc.thinning(m,None,cv2.ximgproc.THINNING_GUOHALL)

最后一步 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 的方法可能更稳健。你可以在这里找到一个例子。
这个也可能很有趣。
-编辑-
我找到了一种更简单的方法来实现您的目标。
像以前一样,在加载图像后应用阈值确保图像是二进制的。通过使用按位非运算反转图像,轮廓在黑色背景上变为白色。应用cv2.connectedComponentsWithStats
返回(除其他外)一个标签矩阵,其中源中的每个连接的白色区域都被分配了一个唯一的标签。然后findContours
根据标签应用,可以为每个区域提供外部轮廓。
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)

PS 在函数返回的输出中findContours
有一个层次矩阵。通过分析该矩阵可以达到相同的结果,但是它有点复杂,如这里解释的那样。