带有轮廓的扑克牌的 4 个角

4 corners of a playingcard with contours

我正在尝试查找扑克牌的 4 个角的坐标,以便我可以使用它来扭曲卡片的透视图,然后用于识别。我试过使用 cv.boundingRect,但由于我使用的是实时视频源,所以我只需要卡片而不是卡片的最近矩形。现在它可以使用 boundingRect,但如果我倾斜图像的角度,坐标是 boundingRect 而不是扑克牌。看图片: straight angle ... crooked angle

然后我需要扑克牌 4 个角的轮廓坐标,而不是使用 boundingRect。 这是我目前的方法:

def getContours(img, imgContour, standardimg):
global counter
contours, hierachy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

for contour in contours:
    area = cv2.contourArea(contour)
    areaMin = cv2.getTrackbarPos("area", "parameters")
    if area > areaMin:
        cv2.drawContours(imgContour, contour, -1, (255, 0, 255), 5)
        peri = cv2.arcLength(contour, True)
        approx = cv2.approxPolyDP(contour, 0.04 * peri, True)

        if len(approx) == 4:
            x, y, w, h = cv2.boundingRect(approx)

            cv2.rectangle(imgContour, (x, y), (x + w, y + h), (255, 255, 0), 3)


            cv2.putText(imgContour, "Area: " + str(int(area)), (x + w + 20, y + 45), cv2.FONT_HERSHEY_COMPLEX, 0.7,
                        (0, 255, 0), 2)

            if cv2.waitKey(1) & 0xFF == ord('c'):
                counter = counter + 1
                cv2.imwrite('warpedPicture' + str(counter) + '.jpg', imgContour)

                coordinates.insert(0, x)
                coordinates.insert(1, y)
                coordinates.insert(2, h)
                coordinates.insert(3, w)
                warpPicture(coordinates[0], coordinates[1], coordinates[2], coordinates[3], standardimg)

Python/OpenCV 中一种可能比边界框更好的可能方法如下:

  • 读取输入
  • 转换为灰色
  • 阈值
  • 获取外轮廓
  • 计算周长
  • 将轮廓近似为四边形
  • 在输入上绘制四边形
  • 保存结果


输入 A:

import cv2
import numpy as np

# load image
img = cv2.imread("5_hearts_A.png")
hh, ww = img.shape[:2]

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

# threshold the grayscale image
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

# remove white borders
thresh = thresh[2:hh-2, 2:ww-2]
thresh = cv2.copyMakeBorder(thresh, 2,2,2,2, cv2.BORDER_REPLICATE)

# find outer contour
cntrs = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
cntr = cntrs[0]

# draw contour on copy of img as result
contour = img.copy()
cv2.drawContours(contour,[cntr], 0, (0,0,255), 1)

# limit contour to quadrilateral
peri = cv2.arcLength(cntr, True)
corners = cv2.approxPolyDP(cntr, 0.04 * peri, True)

# draw quadrilateral on input image from detected corners
result = img.copy()
cv2.polylines(result, [corners], True, (0,0,255), 1, cv2.LINE_AA)

# write result to disk
cv2.imwrite("5_hearts_A_contour.png", contour)
cv2.imwrite("5_hearts_A_quadrilateral.png", result)

# display results
cv2.imshow("THRESH", thresh)
cv2.imshow("CONTOUR", contour)
cv2.imshow("QUAD", result)
cv2.waitKey(0)
cv2.destroyAllWindows()


轮廓图:

生成的四边形:

与图 B 类似:

图像 B 的轮廓:

图片 B 的结果:

一种可能会做得更好的方法是对阈值图像进行 Canny 边缘检测。然后霍夫线变换。然后计算直线的交点以找到角点。