OpenCV:任意大型轮廓组之间的最小距离(Python) [英] OpenCV: Minimum distance between arbitrarily large sets of contours (Python)

查看:672
本文介绍了OpenCV:任意大型轮廓组之间的最小距离(Python)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm interested in calculating the average minimum distance between elements of two sets of contours.

这是一个示例图像:

Here is a sample image:

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

Here's my code so far:

    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)

从这些图片可以看出,屏蔽和控制工作(显示第一组轮廓):

As you can see from these images, the masking and thesholding works (shown for the first set of contours):

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

The cntDistanceCompare() function loops through each contour of set A and B, outputting average minimum distance between contours. Within this function, minDistance() calculates from the (x,y) points on each set of contours A and B a minimum pythagorean distance (using the distance formula).

抛出以下错误:
Traceback(最近一次调用最后一次):
文件mindistance.py,第46行,
cntDistanceCompare(contoursA,contoursB)
文件mindistance .py,第26行,cntDistanceCompare
minDist = minDistance(contourA,contourB)
文件mindistance.py :,第15行,minDistance
表示xB,yB表示contourOther [0] :
TypeError:'numpy.uint8'对象不可迭代

The following error is thrown: Traceback (most recent call last): File "mindistance.py", line 46, in cntDistanceCompare(contoursA, contoursB) File "mindistance.py", line 26, in cntDistanceCompare minDist = minDistance(contourA,contourB) File "mindistance.py:, line 15, in minDistance for xB, yB in contourOther[0]: TypeError: 'numpy.uint8' object is not iterable

我怀疑这个问题是由于我对如何引用x,y坐标缺乏了解而引起的由cv2.findContours()给出的数据结构中每个轮廓顶点的数据。

I suspect this problem arises from my lack of knowledge of how to reference the x,y coordinates of each contour vertex within the data structre given by cv2.findContours().

推荐答案

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

I am using an older version of openCV where findContours only returns two values, but hopefully the important part of this code makes sense. I didn't test your functions, but I did show how to get the contour centers. You have to do some stuff with "moments."

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)

编辑:我现在正在玩你的功能,我担心我误解了这个问题。让我知道,我会删除我的答案。

I'm playing with your functions now and I fear I misread the question. Let me know and I'll delete my answer.

这篇关于OpenCV:任意大型轮廓组之间的最小距离(Python)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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