【问题标题】:OpenCV: Minimum distance between arbitrarily large sets of contours (Python)OpenCV:任意大轮廓集之间的最小距离(Python)
【发布时间】:2015-12-22 18:32:15
【问题描述】:

我有兴趣计算两组轮廓元素之间的平均最小距离。

这是一个示例图像:

到目前为止,这是我的代码:

    import cv2
    import numpy as np

def contours(layer):
    gray = cv2.cvtColor(layer, cv2.COLOR_BGR2GRAY)
    ret,binary = cv2.threshold(gray, 1,255,cv2.THRESH_BINARY) 
    image, contours, hierarchy =         cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
    drawn = cv2.drawContours(image,contours,-1,(150,150,150),3)
    return contours, drawn

def minDistance(contour, contourOther):
    distanceMin = 99999999
    for xA, yA in contour[0]:
        for xB, yB in contourOther[0]:
            distance = ((xB-xA)**2+(yB-yA)**2)**(1/2) # distance formula
            if (distance < distanceMin):
                distanceMin = distance
    return distanceMin

def cntDistanceCompare(contoursA, contoursB):
    cumMinDistList = []
    for contourA in contoursA:
        indMinDistList = []
        for contourB in contoursB:
            minDist = minDistance(contourA,contourB)
            indMinDistList.append(minDist)
        cumMinDistList.append(indMinDistList)
    l = cumMinDistList  
    return sum(l)/len(l) #returns mean distance

def maskBuilder(bgr,hl,hh,sl,sh,vl,vh):
    hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV)
    lower_bound = np.array([hl,sl,vl],dtype=np.uint8)
    upper_bound = np.array([hh,sh,vh],dtype=np.uint8)
    return cv2.inRange(hsv, lower_bound,upper_bound)

img = cv2.imread("sample.jpg")
maskA=maskBuilder(img, 150,185, 40,220, 65,240) 
maskB=maskBuilder(img, 3,20, 50,180, 20,250)
layerA = cv2.bitwise_and(img, img, mask = maskA)
layerB = cv2.bitwise_and(img, img, mask = maskB)
contoursA = contours(layerA)[0]
contoursB = contours(layerA)[1]

print cntDistanceCompare(contoursA, contoursB)

正如您从这些图像中看到的那样,掩蔽和遮蔽有效(显示为第一组轮廓):

cntDistanceCompare() 函数循环遍历集合 A 和 B 的每个轮廓,输出轮廓之间的平均最小距离。在此函数中,minDistance() 根据每组轮廓 A 和 B 上的 (x,y) 点计算最小毕达哥拉斯距离(使用距离公式)。

抛出以下错误: 回溯(最近一次通话最后): 文件“mindistance.py”,第 46 行,在 cntDistanceCompare(轮廓A,轮廓B) 文件“mindistance.py”,第 26 行,在 cntDistanceCompare 中 minDist = minDistance(contourA,contourB) 文件“mindistance.py:,第 15 行,在 minDistance 中 对于轮廓其他 [0] 中的 xB、yB: TypeError: 'numpy.uint8' 对象不可迭代

我怀疑这个问题是因为我不知道如何引用 cv2.findContours() 给出的数据结构中每个轮廓顶点的 x,y 坐标。

【问题讨论】:

  • 那里有一些重复的代码。
  • 感谢您指出这一点。已更正。
  • @DavidShaked maskBuilder函数有什么用?
  • maskBuilder 函数实质上将所有不属于指定颜色范围的图像内容涂黑,在这种情况下,该范围是根据 HSV(色调饱和度,值)颜色空间定义的。请参阅我之前的帖子:stackoverflow.com/questions/32238887/…。我在这里使用它来根据颜色选择图像中的对象组。
  • 顺便说一下,@Jason 的答案中的 getContourCenters(contourData) 函数解决了您对我建议的函数的需求(这里,对于旁观者:stackoverflow.com/questions/32646551/…),它可以为您的距离找到几何中心计算。

标签: python opencv image-processing


【解决方案1】:

我使用的是旧版本的 openCV,其中findContours 只返回两个值,但希望这段代码的重要部分有意义。我没有测试你的功能,但我确实展示了如何获得轮廓中心。你必须用“时刻”做一些事情。

import cv2
import numpy as np

def contours(layer):
    gray = cv2.cvtColor(layer, cv2.COLOR_BGR2GRAY)
    ret,binary = cv2.threshold(gray, 1,255,cv2.THRESH_BINARY) 
    contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
    #drawn = cv2.drawContours(image,contours,-1,(150,150,150),3)
    return contours #, drawn

def minDistance(contour, contourOther):
    distanceMin = 99999999
    for xA, yA in contour[0]:
        for xB, yB in contourOther[0]:
            distance = ((xB-xA)**2+(yB-yA)**2)**(1/2) # distance formula
            if (distance < distanceMin):
                distanceMin = distance
    return distanceMin

def cntDistanceCompare(contoursA, contoursB):
    cumMinDistList = []
    for contourA in contoursA:
        indMinDistList = []
        for contourB in contoursB:
            minDist = minDistance(contourA,contourB)
            indMinDistList.append(minDist)
        cumMinDistList.append(indMinDistList)
    l = cumMinDistList  
    return sum(l)/len(l) #returns mean distance

def maskBuilder(bgr,hl,hh,sl,sh,vl,vh):
    hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV)
    lower_bound = np.array([hl,sl,vl],dtype=np.uint8)
    upper_bound = np.array([hh,sh,vh],dtype=np.uint8)
    return cv2.inRange(hsv, lower_bound,upper_bound)

def getContourCenters(contourData):
    contourCoordinates = []
    for contour in contourData:
        moments = cv2.moments(contour)
        contourX = int(moments['m10'] / float(moments['m00']))
        contourY = int(moments['m01'] / float(moments['m00']))
        contourCoordinates += [[contourX, contourY]]
    return contourCoordinates

img = cv2.imread("sample.jpg")
maskA=maskBuilder(img, 150,185, 40,220, 65,240) 
maskB=maskBuilder(img, 3,20, 50,180, 20,250)
layerA = cv2.bitwise_and(img, img, mask = maskA)
layerB = cv2.bitwise_and(img, img, mask = maskB)
contoursA = contours(layerA)
contoursB = contours(layerB)

print getContourCenters(contoursA)
print getContourCenters(contoursB)

#print cntDistanceCompare(contoursA, contoursB)

编辑:我现在正在使用您的功能,我担心我误读了这个问题。告诉我,我会删除我的答案。

【讨论】:

  • 很好的暂定解决方案。我想这应该使程序运行得比非常多的点的比较快得多。这里的限制是奇怪形状的斑点不会被考虑,因为我希望它们出现在我的实际应用程序中(医学图像分析)。感谢您的帮助!
  • 你能告诉我如何访问给定轮廓的坐标吗? xi 的轮廓[i][0] 和 yi 的轮廓 [i][1] 之类的东西?
  • 确认上面确实是这样,
  • 你还在为这个错误而烦恼吗?
猜你喜欢
  • 1970-01-01
  • 2017-06-09
  • 1970-01-01
  • 1970-01-01
  • 2020-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
相关资源
最近更新 更多