Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在python opencv中完成/关闭轮廓?_Python_Opencv - Fatal编程技术网

如何在python opencv中完成/关闭轮廓?

如何在python opencv中完成/关闭轮廓?,python,opencv,Python,Opencv,我有一个圆周率摄像机指向一张白色背景的卡片。然而,局部阴影似乎阻止了我用于卡片检测的轮廓的闭合,这意味着整体检测失败。下面是我的意思的截图: 你可以看到它的底角特别粗糙。这是我用来达到这一目的的代码: gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray = cv2.blur(gray, (5,5)) gray = cv2.bilateralFilter(gray, 11, 17, 17) #blur. very CPU intensive.

我有一个圆周率摄像机指向一张白色背景的卡片。然而,局部阴影似乎阻止了我用于卡片检测的轮廓的闭合,这意味着整体检测失败。下面是我的意思的截图:

你可以看到它的底角特别粗糙。这是我用来达到这一目的的代码:

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.blur(gray, (5,5))
gray = cv2.bilateralFilter(gray, 11, 17, 17) #blur. very CPU intensive.
cv2.imshow("Gray map", gray)

edges = cv2.Canny(gray, 30, 120)

cv2.imshow("Edge map", edges)

#find contours in the edged image, keep only the largest
# ones, and initialize our screen contour
# use RETR_EXTERNAL since we know the largest (external) contour will be the card edge.
_, cnts, _ = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:1]
screenCnt = None

# loop over our contours
for c in cnts:
    # approximate the contour
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.3 * peri, True)

    cv2.drawContours(image, [cnts[0]], -1, (0, 255, 0), 2)

    # if our approximated contour has four points, then
    # we can assume that we have found our card
    if len(approx) == 4:
        screenCnt = approx;
    break
有没有办法强迫它关闭特定的轮廓?如果我更模糊图像以平滑阴影,这也不起作用,因为它只是忽略那些没有边缘的角。令人恼火的是,它离闭合轮廓只有几个像素远,但它从来没有

编辑:我现在有了一个更真实的设置,背景是米色,有更多的阴影干扰。米色是必要的,因为有些卡片有白色边框,所以白色不起作用。边缘检测主要在阴影所在的左侧失败


正如我在对您的回答的评论中提到的,在边界中“连接”线条的最简单方法之一是使用形态运算符。在下面的代码中,图像的边缘使用椭球形状展开。这种技术允许我们合并靠近的行,并填充一些空白。有关此主题的更多信息,请参阅

在这里,您可以看到原始边缘图像、放大图像和使用放大边缘获得的轮廓(使用原始屏幕截图的裁剪区域获得的图像):

但是,正如你所看到和想象的,在更一般的情况下解决这个问题更为复杂,需要使用其他方法,并且可能比SO问题更为广泛(或者至少从现在的表述方式来看)

通过查看更困难的情况,我建议您使用其他图像表示来替换灰度输入图像(例如HSV颜色空间中的H通道),以减少或减弱阴影的效果。您还可以探索问题中的一些约束:卡片始终以直线作为边界,并使用能够处理参数化形式的方法,例如Hough线检测器。看看这个问题,它可能会给你一些关于如何提高成绩的见解:


备注:双向过滤在计算上非常昂贵,尤其是在使用RPi运行应用程序时。我建议您投资一些其他选择,如高斯滤波,以减少图片中的噪声量(假设您确实需要这样做)。

有几种方法可以解决您的问题。1) 可以使用形态学操作符关闭图像边界(放大等)。2) 您可以使用大津方法设置图像阈值,然后查找边界。3) 你可能想看看这个问题:@EliezerBernart我将在什么上应用形态学操作符;边缘层还是原始层?我尝试了Otsu阈值,但它不能自动找出正确的阈值来移除阴影。此外,有些卡片有白色边框(我后来改为框棕色背景),这至少会使简单的阈值无效。如果你的背景颜色变化很大,而大津帮不了忙,你可能想扩大你的边缘,或者与其他操作符和你应用它们的顺序玩一玩。您可以尝试的另一种方法是使用Hough线检测卡的边框:)您可以共享您的卡图片,以便我运行您的代码并验证错误吗?@EliezerBernart将我当前设置的屏幕截图附加到OP。好的,谢谢!我来看看;)谢谢你的回答;它确实考虑到了我提出的第一个场景。你是对的,它没有涵盖第二个更困难的情况,但我会按照你的建议检查Hough线。关于双边过滤,你也是对的;我的Pi运行速度大约为2fps,这对于我来说已经足够了。我将用高斯函数做实验,虽然它会模糊边缘,但我怀疑它会使边缘检测变得更加棘手(边缘保留是我选择双边的原因)。这是正确的!如果你打算基于边缘进行卡片检测,一般来说模糊会让事情变得有点棘手;看起来,在部分阴影中,白色边框显示的穿透力足以检测到正确的边缘。有没有一种方法可以增加边缘或类似区域的对比度?我不知道我是否明白你的意思,但也许你想要的是一种图像锐化技术:嗯,我试过了,但它仍然无法在卡的阴影边缘上拾取。我也试过Hough线,但它只在卡片的右边画了一条线,没有其他的线。我怀疑这是因为它依赖于我已经有缺陷的边缘图像。
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(9,9))
dilated = cv2.dilate(image, kernel)
_, cnts, _ = cv2.findContours(dilated.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)