我正在做一个项目,只是为了娱乐,我的目标是玩在线扑克,并让程序识别桌子上的纸牌。我正在将OpenCV与python一起使用来隔离卡片将要放置的区域。我已经能够拍摄该区域的图像,对其进行灰度处理并对其进行阈值处理,并在卡的边缘周围绘制轮廓。我现在停留在前进的方向。
到目前为止,这是我的代码:
import cv2
from PIL import ImageGrab
import numpy as np
def processed(image):
grayscaled = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresholded = cv2.Canny(grayscaled, threshold1 = 200, threshold2 = 200)
return thresholded
def drawcard1():
screen = ImageGrab.grab(bbox = (770,300,850,400))
processed_img = processed(np.array(screen))
outside_contour, dummy = cv2.findContours(processed_img.copy(), 0,2)
colored = cv2.cvtColor(processed_img, cv2.COLOR_GRAY2BGR)
cv2.drawContours(colored, outside_contour, 0, (0,255,0),2)
cv2.imshow('resized_card', colored)
while True:
drawcard1()
if cv2.waitKey(25) & 0xFF == ord('w'):
cv2.destroyAllWindows()
break
这是我到目前为止的结果:
我需要能够吸收轮廓的内部,并去除轮廓之外的任何东西。然后生成的图像应该只是卡,我需要将其缩放到49x68像素。一旦使它可行,我的计划就是获取等级和西装的轮廓,并用白色像素填充,然后将其与一组图像进行比较,以确定最佳拟合。
我对OpenCV和图像处理非常陌生,但是我发现这些东西令人着迷!我已经可以通过Google达到这一目标,但是这次我什么也找不到。
这是我目前用来替换游戏的图像:
这是我用来比较桌卡的图像之一:
答案 0 :(得分:3)
这种情况非常适合template matching。这个想法是在较大图像中搜索并找到模板图像的位置。为了执行此方法,模板在输入图像上滑动(类似于2D卷积),在此执行比较方法以确定像素相似度。这是模板匹配的基本思想。不幸的是,这种基本方法有缺陷,因为它仅在模板图像大小与输入图像中所需的项目相同时才起作用。因此,如果您的模板图像小于要在输入图像中找到的所需区域,则此方法将无效。
要解决此限制,我们可以使用np.linspace()
通过动态缩放图像来实现缩放比例模板匹配。每次迭代时,我们都会调整输入图像的大小并跟踪比率。我们继续调整大小,直到模板图像的大小大于调整大小的图像,同时跟踪最高的相关值。相关值越高,匹配越好。遍历各种尺度后,我们找到匹配度最大的比率,然后计算边界框的坐标以确定ROI。
使用模板图片:
此处检测到的卡以绿色突出显示。要可视化动态模板匹配的过程,请取消注释代码中的部分。
代码
import cv2
import numpy as np
# Resizes a image and maintains aspect ratio
def maintain_aspect_ratio_resize(image, width=None, height=None, inter=cv2.INTER_AREA):
# Grab the image size and initialize dimensions
dim = None
(h, w) = image.shape[:2]
# Return original image if no need to resize
if width is None and height is None:
return image
# We are resizing height if width is none
if width is None:
# Calculate the ratio of the height and construct the dimensions
r = height / float(h)
dim = (int(w * r), height)
# We are resizing width if height is none
else:
# Calculate the ratio of the 0idth and construct the dimensions
r = width / float(w)
dim = (width, int(h * r))
# Return the resized image
return cv2.resize(image, dim, interpolation=inter)
# Load template and convert to grayscale
template = cv2.imread('template.png')
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
(tH, tW) = template.shape[:2]
cv2.imshow("template", template)
# Load original image, convert to grayscale
original_image = cv2.imread('1.jpg')
gray = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
found = None
# Dynamically rescale image for better template matching
for scale in np.linspace(0.1, 3.0, 20)[::-1]:
# Resize image to scale and keep track of ratio
resized = maintain_aspect_ratio_resize(gray, width=int(gray.shape[1] * scale))
r = gray.shape[1] / float(resized.shape[1])
# Stop if template image size is larger than resized image
if resized.shape[0] < tH or resized.shape[1] < tW:
break
# Threshold resized image and apply template matching
thresh = cv2.threshold(resized, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
detected = cv2.matchTemplate(thresh, template, cv2.TM_CCOEFF)
(_, max_val, _, max_loc) = cv2.minMaxLoc(detected)
# Uncomment this section for visualization
'''
clone = np.dstack([thresh, thresh, thresh])
cv2.rectangle(clone, (max_loc[0], max_loc[1]), (max_loc[0] + tW, max_loc[1] + tH), (0,255,0), 2)
cv2.imshow('visualize', clone)
cv2.waitKey(50)
'''
# Keep track of correlation value
# Higher correlation means better match
if found is None or max_val > found[0]:
found = (max_val, max_loc, r)
# Compute coordinates of bounding box
(_, max_loc, r) = found
(start_x, start_y) = (int(max_loc[0] * r), int(max_loc[1] * r))
(end_x, end_y) = (int((max_loc[0] + tW) * r), int((max_loc[1] + tH) * r))
# Draw bounding box on ROI
cv2.rectangle(original_image, (start_x, start_y), (end_x, end_y), (0,255,0), 5)
cv2.imshow('detected', original_image)
cv2.imwrite('detected.png', original_image)
cv2.waitKey(0)