python - 带有轮廓的扑克牌的 4 个角
问题描述
我试图找到一张扑克牌的 4 个角的坐标,这样我就可以用它来扭曲卡片的透视图,然后再用于识别。我曾尝试使用 cv.boundingRect,但由于我使用的是实时视频源,我只需要卡片,而不需要卡片最近的矩形。现在它使用boundingRect工作,但如果我倾斜图像的角度,坐标是boundingRect而不是扑克牌。见图片: 直角 ... 弯角
然后我需要我的轮廓坐标用于扑克牌的 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 边缘检测。然后霍夫线变换。然后计算线的交点以找到拐角。