簡體   English   中英

如何使用 python opencv 將重疊的卡彼此分開?

[英]How do i separate overlapping cards from each other using python opencv?

我正在嘗試檢測撲克牌並將它們轉換為使用 python opencv 鳥瞰卡片。 我的代碼適用於簡單的案例,但我並沒有停留在簡單的案例上,而是想嘗試更復雜的案例。 我在為卡片找到正確的輪廓時遇到問題。這是我試圖檢測卡片並繪制輪廓的附加圖像:

在此處輸入圖像描述

我的代碼:

path1 = "F:\\ComputerVisionPrograms\\images\\cards4.jpeg"
g = cv2.imread(path1,0)
img = cv2.imread(path1)

edge = cv2.Canny(g,50,200)

p,c,h = cv2.findContours(edge, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
rect = []
for i in c:
    p = cv2.arcLength(i, True)
    ap = cv2.approxPolyDP(i, 0.02 * p, True)
    if len(ap)==4:
        rect.append(i)
cv2.drawContours(img,rect, -1, (0, 255, 0), 3)

plt.imshow(img)
plt.show()

結果:

在此處輸入圖像描述

這不是我想要的,我只想選擇矩形卡,但由於它們相互遮擋,我沒有得到我期望的結果。 我相信我需要應用形態學技巧或其他操作來將它們分開或使邊緣更加突出或可能是其他東西。 如果您能分享您解決此問題的方法,將不勝感激。

其他研究員要求的更多示例:

在此處輸入圖像描述

在此處輸入圖像描述

有很多方法可以在圖像中找到重疊的對象。 您確定的信息是您的卡片都是矩形,大部分是白色並且大小相同。 你的變量是亮度,角度,可能是一些透視失真。 如果您想要一個強大的解決方案,您需要解決所有這些問題。

我建議使用霍夫變換來查找卡片邊緣。 首先,運行常規邊緣檢測。 比你需要清理的結果,因為許多短邊將屬於“面”卡。 我建議使用 dilate(11)->erode(15)->dilate(5) 的組合。 這種組合將填補“人臉”卡片中的所有空白,然后它“縮小”斑點,在去除原始邊緣的過程中,最后長回來並與原始人臉圖片重疊一點。 然后將其從原始圖像中刪除。

現在你有一個幾乎所有相關邊緣的圖像。 使用霍夫變換找到它們。 它會給你一組線。 在對它們進行一點過濾后,您可以將這些邊緣適合卡片的矩形形狀。

dst = cv2.Canny(img, 250, 50, None, 3)

cn = cv2.dilate(dst, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11)))
cn = cv2.erode(cn, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15)))
cn = cv2.dilate(cn, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)))
dst -= cn
dst[dst < 127] = 0

cv2.imshow("erode-dilated", dst)

# Copy edges to the images that will display the results in BGR
cdstP = cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)

linesP = cv2.HoughLinesP(dst, 0.7, np.pi / 720, 30, None, 20, 15)

if linesP is not None:
    for i in range(0, len(linesP)):
        l = linesP[i][0]
        cv2.line(cdstP, (l[0], l[1]), (l[2], l[3]), (0, 255, 0), 2, cv2.LINE_AA)

cv2.imshow("Detected edges", cdstP)

這將為您提供以下信息:

在此處輸入圖像描述

另一種獲得更好結果的方法是放棄邊緣檢測/線檢測部分(我個人更喜歡),在圖像預處理后找到輪廓。

以下是我的代碼和結果:

img = cv2.imread(<image_name_here>)
imgC = img.copy()

# Converting to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Applying Otsu's thresholding
Retval, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# Finding contours with RETR_EXTERNAL flag to get only the outer contours
# (Stuff inside the cards will not be detected now.)
cont, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Creating a new binary image of the same size and drawing contours found with thickness -1.
# This will colour the contours with white thus getting the outer portion of the cards.
newthresh = np.zeros(thresh.shape, dtype=np.uint8)
newthresh = cv2.drawContours(newthresh, cont, -1, 255, -1)

# Performing erosion->dilation to remove noise(specifically white portions detected of the poker coins).
kernel = np.ones((3, 3), dtype=np.uint8)
newthresh = cv2.erode(newthresh, kernel, iterations=6)
newthresh = cv2.dilate(newthresh, kernel, iterations=6)

# Again finding the final contours and drawing them on the image.
cont, hier = cv2.findContours(newthresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(imgC, cont, -1, (255, 0, 0), 2)

# Showing image
cv2.imshow("contours", imgC)
cv2.waitKey(0)

結果 -

卡1輸出 卡2輸出

這樣,我們就得到了圖像中卡片的邊界。 要檢測和分離每張卡片,需要更復雜的算法,或者可以使用深度學習 model 來完成。

我正在檢測您的形狀內的白色矩形。 最終結果是檢測到的圖像和邊界框坐標。 劇本還沒有完成。 我會在接下來的幾天里繼續嘗試。

import os
import cv2
import numpy as np


def rectangle_detection(img):    
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    _, binarized = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

    cn = cv2.dilate(binarized, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11)), iterations=3)
    cn = cv2.erode(cn, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15)), iterations=3)
    cn = cv2.dilate(cn, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)), iterations=3)

    _, contours, _ = cv2.findContours(binarized, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    # contours = sorted(contours, key=lambda x: cv2.contourArea(x))

    # detect all rectangles
    rois = []
    for contour in contours:
        cont_area = cv2.contourArea(contour)
        approx = cv2.approxPolyDP(contour, 0.02*cv2.arcLength(contour, True), True)
        if 1000 < cont_area < 15000:
            x, y, w, h = cv2.boundingRect(contour)
            rect_area = w * h
            if cont_area / rect_area < 0.6: # check the 'rectangularity'
                continue     
            cv2.drawContours(img, [approx], 0, (0, 255, 0), 2)
            if len(approx) == 4:
                cv2.putText(img, "Rect", (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255))
            rois.append((x, y, w, h))
    return img, rois


def main():
    # load and prepare images
    INPUT = 'path'
    img = cv2.imread(INPUT)
    display, rects = rectangle_detection(img)
    cv2.imshow('img', display)
    cv2.waitKey()


if __name__ == "__main__":
    main()

在此處輸入圖像描述

在此處輸入圖像描述

在此處輸入圖像描述

暫無
暫無

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

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