多边形的凸凹角点

2024-09-30 16:37:21 发布

您现在位置:Python中文网/ 问答频道 /正文

问题

我正在做一个项目,我需要得到哑铃形状的边界框。但是,我需要尽可能少的点,并且盒子需要适合所有角落的形状。下面是我做的一个图像测试:Blurry, cracked, dumbell shape

我不在乎形状的间隙,我只想把它清理干净,把边弄直,这样我就可以得到这样一个形状的轮廓:Cleaned up

我一直在尝试threshold()它,用findContours()得到它的轮廓,然后用approxPolyDP()来简化轮廓最终的疯狂数量。所以,在摆弄了三天之后,我怎么能简单地得到:

  • 两个方框,指定哑铃的末端和中间的矩形,或
  • 一个轮廓,所有角有十二个点

第二个选择是首选的,因为这确实是我的最终目标:得到那些角落的分数。在

有几点需要注意:

  • 我正在使用OpenCV for Python
  • 在输入图像中通常会有许多不同大小的形状
  • 他们将只有水平或垂直定位。没有奇怪的27度角。。。在

我需要的是:

我真的不需要别人为我写代码,我只需要一些方法或算法来完成这项工作,最好是一些简单的例子。在

我的代码

下面是我的代码,其中有一些我甚至不使用的函数,但我最终会使用它们:

import cv2
import numpy as np

class traceImage():

    def __init__(self, imageLocation):
        self.threshNum = 127
        self.im = cv2.imread(imageLocation)
        self.imOrig = self.im
        self.imGray = cv2.cvtColor(self.im, cv2.COLOR_BGR2GRAY)
        self.ret, self.imThresh = cv2.threshold(self.imGray, self.threshNum, 255, 0)
        self.contours, self.hierarchy = cv2.findContours(self.imThresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    def createGray(self):
        self.imGray = cv2.cvtColor(self.im, cv2.COLOR_BGR2GRAY)

    def adjustThresh(self, threshNum):
        self.ret, self.imThresh = cv2.threshold(self.imGray, threshNum, 255, 0)

    def getContours(self):
        self.contours, self.hierarchy = cv2.findContours(self.imThresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    def approximatePoly(self, percent):
        i=0
        for shape in self.contours:
            shape = cv2.approxPolyDP(shape, percent*cv2.arcLength(shape, True), True)
            self.contours[i] = shape
            i+=1

    def drawContours(self, blobWidth, color=(255,255,255)):
        cv2.drawContours(self.im, self.contours, -1, color, blobWidth)

    def newWindow(self, name):
        cv2.namedWindow(name)

    def showImage(self, window):
        cv2.imshow(window, self.im)

    def display(self):
        while True:
            cv2.waitKey()

    def displayUntil(self, key):
        while True:
            pressed = cv2.waitKey()
            if pressed == key:
                break

if __name__ == "__main__":
    blobWidth = 30
    ti = traceImage("dumbell.png")
    ti.approximatePoly(0.01)
    for thresh in range(127,256):
        ti.adjustThresh(thresh)
        ti.getContours()
        ti.drawContours(blobWidth)
    ti.showImage("Image")
    ti.displayUntil(10)
    ti.createGray()
    ti.adjustThresh(127)
    ti.getContours()
    ti.approximatePoly(0.0099)
    ti.drawContours(2, (0,255,0))
    ti.showImage("Image")
    ti.display()

代码说明

我知道我可能不会在这里做一些事情,但是嘿,我很自豪:)

所以,我们的想法是这些哑铃上经常会有洞和缝隙,所以我想如果我迭代127到255之间的所有阈值,把轮廓画到足够厚的图像上,绘制轮廓的厚度会填充任何足够小的洞,我可以使用新的,滴状图像获取边缘,然后将边缩小到大小。那是我的想法。一定有另一种更好的方式。。。在

摘要

我想得到12个点,每个角对应一个点。在

编辑:

在尝试了一些腐蚀和膨胀之后,似乎最好的选择是在某些点切割轮廓,然后在切片形状周围使用边界框来获得正确的方形角,然后进行一些计算,将这些长方体重新连接成一个形状。一个相当有趣的挑战。。。在

编辑2:

我发现了一些有用的东西!我做了我自己的直线检测系统,只检测水平线或垂直线,然后在检测到的直线/轮廓边缘上,程序绘制出一条延伸到整个图像的黑线,从而有效地在等高线的直线上对图像进行切片。一旦这样做了,它会得到切片盒的新轮廓,在碎片周围绘制边界框,然后使用膨胀来缩小间隙。到目前为止,它在大的形状上效果很好,但是当形状很小时,它往往会失去一点形状。在


Tags: 代码图像selftruedefticv2轮廓
2条回答

所以,在处理了腐蚀、膨胀、闭合、打开和观察直线轮廓之后,我找到了一个可行的解决方案。谢谢@Ante和@a.alsram!你的两个想法结合起来帮助我找到了解决办法。下面是它的工作原理。在

方法

程序迭代每个轮廓,以及轮廓中的每对点,寻找位于同一轴上的点对并计算它们之间的距离。如果距离大于可调阈值,程序将决定将这些点视为形状上的边。然后程序使用该边,并沿整个轮廓绘制一条黑线,从而在该边缘切割轮廓。然后程序重新确定轮廓,因为形状被切割。这些被切断的部分知道它们自己的轮廓,然后由边界框包围。最后,所有的形状都被扩张和腐蚀(关闭)以重新连接被切断的盒子。在

这种方法可以做几次,但每次都会有一点精度损失。但它满足了我的需要,当然是一个有趣的挑战!谢谢你们的帮助!在

纳泰博13

或许简单的解决方案会有所帮助。如果有一个阈值长度来缩小间隙, 可以在单元格长度=阈值的网格中分割图像,然后使用 里面有东西的细胞。只有水平和 垂直线,并注意网格遵循原来的水平线 以及垂直线,它将覆盖主要线路特征。

更新

看看mathematical morphology。你可以用1*2+k来构造元素。在

算法应取阈值参数k,并进行膨胀和比腐蚀。这意味着改变图像,以便对于每个白色像素,将距离k((2*k+1)x(2*k+1)框)上的所有邻居设置为白色,然后更改图像,以便对于每个黑色像素,将距离k上的邻居设置为黑色。在

对边界像素进行操作就足够了。在

相关问题 更多 >