Sye*_*aan 14 python opencv contour opencv-contour image-morphology
我正在尝试检测扑克牌并使用 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()
Run Code Online (Sandbox Code Playgroud)
结果:
这不是我想要的,我只想选择矩形卡片,但由于它们相互遮挡,我没有得到我所期望的。我相信我需要应用形态学技巧或其他操作来将它们分开或使边缘更加突出或可能是其他东西。如果您能分享您解决此问题的方法,将不胜感激。
其他研究员要求的更多示例:
有很多方法可以在图像中找到重叠的对象。您可以确定的信息是,您的卡片都是矩形,大部分是白色的,并且大小相同。你的变量是亮度,角度,可能是一些透视失真。如果您想要一个强大的解决方案,您需要解决所有这些问题。
我建议使用 Hough 变换来查找卡片边缘。首先,运行常规边缘检测。比你需要清理的结果,因为许多短边将属于“面”卡。我建议使用 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)
Run Code Online (Sandbox Code Playgroud)
这将为您提供以下信息:
另一种获得更好结果的方法是去掉边缘检测/线检测部分(我个人更喜欢)并在图像预处理后找到轮廓。
下面是我的代码和结果:
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)
Run Code Online (Sandbox Code Playgroud)
结果 -
有了这个,我们得到了图像中卡片的边界。为了检测和分离每张卡片,需要更复杂的算法,或者可以通过使用深度学习模型来完成。