簡體   English   中英

如何使用 cv2.minAreaRect(cnt) 在多輪廓圖像上獲得唯一的最小區域矩形?

[英]How to get the only min area rectangle on a multiple contours image with cv2.minAreaRect(cnt)?

我只想使用一個矩形來覆蓋此圖像中的圓圈:

我的形象

並使用cv2.minAreaRect(cnt)得到這個結果:

加工后

此圖像似乎分為多個部分。 也許是因為這張圖片的邊緣有一些斷點。 你能告訴我如何只使用一個矩形來覆蓋我圖像的這一圈嗎? 非常感謝你!

這是我的代碼:

def draw_min_rect_circle(img, cnts):  # conts = contours
    img = np.copy(img)

    for cnt in cnts:
        x, y, w, h = cv2.boundingRect(cnt)
        cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)  # blue

        min_rect = cv2.minAreaRect(cnt)  # min_area_rectangle
        min_rect = np.int0(cv2.boxPoints(min_rect))
        cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2)  # green

        (x, y), radius = cv2.minEnclosingCircle(cnt)
        center, radius = (int(x), int(y)), int(radius)  # center and radius of minimum enclosing circle
        img = cv2.circle(img, center, radius, (0, 0, 255), 2)  # red
return img

您可能使用cv2.findContours()搜索輪廓並遍歷它們以在圖像上繪制矩形。 問題是你的圖像沒有由一條連接線組成的圓圈,而是許多虛線。

輪廓是連接所有連續點(沿着邊界)的曲線,具有相同的顏色或強度(OpenCV 文檔)。

因此,為了獲得更好的結果,您應該在搜索輪廓之前先准備圖像。 您可以使用各種工具對圖像進行預處理(您可以搜索 OpenCV 文檔)。 在這種情況下,我會嘗試用一個小內核執行稱為“關閉”的過程。 關閉是先膨脹后像素腐蝕。 它可以幫助將您的小輪廓連接到一個大輪廓(圓)。 然后你可以選擇最大的一個並繪制一個邊界矩形。

例子:

輸入圖像:

在此處輸入圖像描述

import cv2
import numpy as np

img = cv2.imread('test.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((3,3), dtype=np.uint8)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
_, contours, hierarchy = cv2.findContours(closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x,y), (x+w, y+h), (255,255,0), 1)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

結果:

在此處輸入圖像描述

執行關閉操作后的圖像:

在此處輸入圖像描述

希望能幫助到你。 干杯!

可以將所有輪廓連接成一個輪廓,因為它們只是描述輪廓的點坐標的 numpy 數組。 您可以使用np.concatenate(contours)並且cv2.minAreaRect函數似乎並不關心新數組中的點是否連續。 在我的例子中,這比使用關閉函數效果更好,因為我有更復雜的對象。 如果您願意,可以嘗試一下,這很簡單。 這是您的函數的樣子:

def draw_min_rect_circle(img, cnts):  # conts = contours
    img = np.copy(img)

    join_cnts = np.concatenate(cnts)

    x, y, w, h = cv2.boundingRect(join_cnts)
    cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)  # blue

    min_rect = cv2.minAreaRect(join_cnts)  # min_area_rectangle
    min_rect = np.int0(cv2.boxPoints(min_rect))
    cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2)  # green

    (x, y), radius = cv2.minEnclosingCircle(join_cnts)
    center, radius = (int(x), int(y)), int(radius)  # center and radius of minimum enclosing circle
    img = cv2.circle(img, center, radius, (0, 0, 255), 2)  # red
    
return img

你需要做的是,你需要通過合並輪廓以某種方式從圖像中只獲得 1 個輪廓,這有點困難,所以如果你只想要一個圍繞所有輪廓的封閉矩形,你可以這樣做

def draw_min_rect_circle(img, cnts):  # conts = contours
    img = np.copy(img)
    x1,y1 = np.inf
    x2,y2 = 0
    for cnt in cnts:
        x, y, w, h = cv2.boundingRect(cnt)
        if x > x1:
           x1=x
        if y > y1:
           y1=y
        if x2 < x+w
           x2 = x+w
        if y2 < y+h
           y2 = y+h
     w = x2 - x1
     h = y2 - y1
     r = math.sqrt((w*w) + (h*h)) / 2

     cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
     cv2.circle(img, (x1+w/2,y1+h/2), r, (0, 0, 255), 2)

暫無
暫無

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

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