cv2.HoughCircles的结果不可靠 [英] Unreliable results with cv2.HoughCircles

查看:243
本文介绍了cv2.HoughCircles的结果不可靠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含5个油滴的视频,我正在尝试使用cv2.HoughCircles来查找它们。

I have a video with 5 oil droplets, and I am trying to use cv2.HoughCircles to find them.

这是我的代码:

import cv, cv2
import numpy as np

foreground1 = cv2.imread("foreground1.jpg")
vid = cv2.VideoCapture("NB14.avi")

cv2.namedWindow("video")
cv2.namedWindow("canny")
cv2.namedWindow("blur")

while True:
    ret, frame = vid.read()
    subtract1 = cv2.subtract( foreground1, frame)
    framegrey1 = cv2.cvtColor(subtract1, cv.CV_RGB2GRAY)
    blur = cv2.GaussianBlur(framegrey1, (0,0), 2)
    circles =  cv2.HoughCircles(blur, cv2.cv.CV_HOUGH_GRADIENT, 2, 10, np.array([]), 40, 80, 5, 100)
    if circles is not None:
            for c in circles[0]:
                    cv2.circle(frame, (c[0],c[1]), c[2], (0,255,0),2)
    edges = cv2.Canny( blur, 40, 80 )
    cv2.imshow("video", frame)
    cv2.imshow("canny", edges)
    cv2.imshow("blur", blur)
    key = cv2.waitKey(30)

我想说的是canny边缘检测器看起来非常好,而hough变换的结果非常不稳定,每帧都会提供不同的结果。

I would say that the canny edge detector looks very good, while the results from the hough transform are very unstable, every frame will provide different results.

示例:

我一直在玩这些参数,说实话,我不知道如何获得更多稳定的结果。

I have been playing with the parameters and honestly I dont know how to get more stable results.

推荐答案

最初我虽然你的油滴没有重叠,但有。所以,Hough可能确实是一个很好的方法在这里使用,但我在将RANSAC与它结合时有更好的经验。我建议去探索一下,但在这里我会提供与此不同的东西。

Initially I though there would be no overlapping in your oil droplets, but there are. So, Hough might indeed by a good method to use here, but I've had better experience when combining RANSAC with it. I would suggest exploring that, but here I will provide something different from that.

首先,我无法执行你做的背景减法,因为我没有有这个foreground1.jpg图像(所以结果可以很容易地改进)。我也不关心绘制圆圈,但你可以这样做,我只是画出我认为是圆形的物体的边框。

First of all, I couldn't perform the background subtraction that you do since I did not have this "foreground1.jpg" image (so the results can be improved easily). I also didn't care about drawing circles, but you can do that, I simply draw the border of the objects that I consider as a circle.

所以,首先让我们假设没有重叠。然后找到图像中的边缘(简单),通过Otsu对边缘检测器的响应进行二值化,填充孔,最后测量圆度就足够了。现在,如果存在重叠,我们可以使用Watershed变换结合Distance变换来分离液滴。那么问题是你不会得到真正的圆形物体,我对此并不在意,但你可以调整它。

So, first let us suppose there is no overlapping. Then finding the edges in your image (easy), binarizing the response of the edge detector by Otsu, filling holes, and finally measuring the circularity is enough. Now if there are overlaps, we can use the Watershed transform combined with the Distance transform to separate the droplets. The problem then is that you won't get really circular objects, and I didn't care much about that, but you can adjust for that.

在下面的代码中我还必须使用 scipy 来标记连接的组件(对于为Watershed构建标记很重要),因为OpenCV缺乏这一点。代码不是很短,但应该很容易理解。此外,给定完整的当前代码,不需要进行圆度检查,因为在Watershed分割之后,只剩下您之后的对象。最后,根据与对象中心的粗略距离进行一些简单的跟踪。

In the following code I also had to use scipy for labeling connected components (important for building the marker for the Watershed), since OpenCV is lacking on that. The code is not exactly short but should be simple to understand. Also, given the full current code, there is no need for the circularity check because after the segmentation by Watershed, only the objects you are after remain. Lastly, there is some simplistic tracking based on the rough distance to the object's center.

import sys
import cv2
import math
import numpy
from scipy.ndimage import label

pi_4 = 4*math.pi

def segment_on_dt(img):
    border = img - cv2.erode(img, None)

    dt = cv2.distanceTransform(255 - img, 2, 3)
    dt = ((dt - dt.min()) / (dt.max() - dt.min()) * 255).astype(numpy.uint8)
    _, dt = cv2.threshold(dt, 100, 255, cv2.THRESH_BINARY)

    lbl, ncc = label(dt)
    lbl[border == 255] = ncc + 1

    lbl = lbl.astype(numpy.int32)
    cv2.watershed(cv2.cvtColor(img, cv2.COLOR_GRAY2RGB), lbl)
    lbl[lbl < 1] = 0
    lbl[lbl > ncc] = 0

    lbl = lbl.astype(numpy.uint8)
    lbl = cv2.erode(lbl, None)
    lbl[lbl != 0] = 255
    return lbl


def find_circles(frame):
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
    frame_gray = cv2.GaussianBlur(frame_gray, (5, 5), 2)

    edges = frame_gray - cv2.erode(frame_gray, None)
    _, bin_edge = cv2.threshold(edges, 0, 255, cv2.THRESH_OTSU)
    height, width = bin_edge.shape
    mask = numpy.zeros((height+2, width+2), dtype=numpy.uint8)
    cv2.floodFill(bin_edge, mask, (0, 0), 255)

    components = segment_on_dt(bin_edge)

    circles, obj_center = [], []
    contours, _ = cv2.findContours(components,
            cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

    for c in contours:
        c = c.astype(numpy.int64) # XXX OpenCV bug.
        area = cv2.contourArea(c)
        if 100 < area < 3000:
            arclen = cv2.arcLength(c, True)
            circularity = (pi_4 * area) / (arclen * arclen)
            if circularity > 0.5: # XXX Yes, pretty low threshold.
                circles.append(c)
                box = cv2.boundingRect(c)
                obj_center.append((box[0] + (box[2] / 2), box[1] + (box[3] / 2)))

    return circles, obj_center

def track_center(objcenter, newdata):
    for i in xrange(len(objcenter)):
        ostr, oc = objcenter[i]
        best = min((abs(c[0]-oc[0])**2+abs(c[1]-oc[1])**2, j)
                for j, c in enumerate(newdata))
        j = best[1]
        if i == j:
            objcenter[i] = (ostr, new_center[j])
        else:
            print "Swapping %s <-> %s" % ((i, objcenter[i]), (j, objcenter[j]))
            objcenter[i], objcenter[j] = objcenter[j], objcenter[i]


video = cv2.VideoCapture(sys.argv[1])

obj_center = None
while True:
    ret, frame = video.read()
    if not ret:
        break

    circles, new_center = find_circles(frame)
    if obj_center is None:
        obj_center = [(str(i + 1), c) for i, c in enumerate(new_center)]
    else:
        track_center(obj_center, new_center)

    for i in xrange(len(circles)):
        cv2.drawContours(frame, circles, i, (0, 255, 0))
        cstr, ccenter = obj_center[i]
        cv2.putText(frame, cstr, ccenter, cv2.FONT_HERSHEY_COMPLEX, 0.5,
                (255, 255, 255), 1, cv2.CV_AA)

    cv2.imshow("result", frame)
    cv2.waitKey(10)
    if len(circles[0]) < 5:
        print "lost something"

这适用于整个视频,这里是两个样本:

This works for your entire video, and here are two samples:

这篇关于cv2.HoughCircles的结果不可靠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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