簡體   English   中英

OpenCV凹凸角點的多邊形

[英]OpenCV concave and convex corner points of polygons

問題

我正在開發一個項目,我需要獲得像形狀一樣的dumbell邊界框。 但是,我需要盡可能少的點,並且盒子需要適合所有角落的形狀。 這是我測試的圖像: 模糊,破裂,啞鈴形狀

我不關心形狀的間隙,我只想清理它,並將邊緣拉直,這樣我就可以得到這樣的形狀輪廓: 清理

我一直在嘗試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並將輪廓繪制到具有足夠厚度的圖像上,則繪制的厚度為輪廓將填充任何足夠小的孔,我可以使用新的,blobby圖像來獲得邊緣,然后將邊縮回到尺寸。 這是我的想法。 盡管如此,還有另一種更好的方式......

摘要

我想得到12分; 一個形狀的每個角落。

編輯:

在嘗試了一些侵蝕和擴張之后,似乎最好的選擇是在某些點處切割輪廓,然后在切片形狀周圍使用邊界框來獲得正確的四四方角,然后進行一些計算以將盒子重新加入一個形狀。 一個相當有趣的挑戰......

編輯2:

我發現了一些效果很好的東西! 我制作了自己的線檢測系統,只檢測水平或垂直線,然后在檢測到的線/輪廓邊緣,程序繪制一條延伸到整個圖像的黑線,從而有效地切割圖像的直線。輪廓。 一旦它這樣做,它會獲得切片盒的新輪廓,在片段周圍繪制邊界框,然后使用擴張來封閉間隙。 到目前為止,它適用於大型形狀,但是當形狀很小時,它往往會失去一些形狀。

所以,在擺弄了侵蝕,擴張,關閉,打開和看直線輪廓之后,我找到了一個有效的解決方案。 謝謝@Ante和@ a.alsram! 你的兩個想法結合起來幫助我找到了解決方案。 所以這是它的工作原理。

方法

程序迭代每個輪廓,並遍歷輪廓中的每對點,尋找位於同一軸上的點對並計算它們之間的距離。 如果距離大於可調閾值,則程序確定這些點被視為形狀上的邊緣。 然后程序使用該邊緣,沿整個輪廓繪制一條黑線,從而切割該邊緣的輪廓。 然后程序重新確定輪廓,因為形狀被切斷。 被切斷的這些碎片知道它們自己的輪廓,然后由邊界框界定。 最后,所有形狀都被擴張和侵蝕(接近)以重新加入被切斷的盒子。

這種方法可以多次完成,但每次都有一點精度損失。 但它適用於我需要的東西,當然是一個有趣的挑戰! 謝謝你的幫助!

natebot13

也許簡單的解決方案可以提 如果有一個閾值長度來關閉間隙,則可以在單元長度> =閾值的網格中分割圖像,並使用內部具有某些內容的單元格。 由此將只有水平和垂直線,並通過關注網格遵循原始水平和垂直線,它將覆蓋主線特征。

更新

看看數學形態學 我認為使用結構元素(2 * k + 1)x(2 * k + 1)像素的結束操作可以做你想要的。

算法應采用閾值參數k,並執行擴張和侵蝕。 這意味着更改圖像,以便為每個白色像素設置距離k((2 * k + 1)x(2 * k + 1)框)上的所有鄰居到白色,然后改變圖像,以便為每個黑色像素設置鄰居距離k到黑色。

在邊界像素上進行操作就足夠了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM