admin管理员组文章数量:1122846
For my bridge training lessons I 'm trying to analyse a deal played in Bridge Base Online, by capturing the image and then try to find where are the 52 cards.
The reference image is this one (capture.jpg)
And I have also 52 images (41x68) of the cards, like the five of spades:
Now when doing pattern matching in OpenCV:
Mat1f result;
matchTemplate(org_gray, template_gray, result, TM_CCOEFF_NORMED);
double thresh = 0.8;
threshold(result, result, thresh, 1., THRESH_BINARY);
Mat1b resb;
result.convertTo(resb, CV_8U, 255);
std::vector<std::vector<Point>> contours;
findContours(resb, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); ++i)
{
Mat1b mask(result.rows, result.cols, uchar(0));
drawContours(mask, contours, i, Scalar(255), cv::FILLED);
Point max_point,min_point;
double max_val;
minMaxLoc(result, NULL, &max_val, &min_point, &max_point, mask);
rectangle(img, Rect(max_point.x, max_point.y, ptpw->m.cols, ptpw->m.rows), Scalar(0, 255, 0), 2);
}
imshow("b", ptpw->m);
imshow("a",img);
The result is this one. It did detect the location of S5 but it also detected 7 more cards...
How can I enhance my algorithm?
If I raise the threshold to 0.87 it finds only one card, but the 5 of clubs instead. I can adjust the threshold to find only one card, but why the 5C instead of 5S?
Thanks.
For my bridge training lessons I 'm trying to analyse a deal played in Bridge Base Online, by capturing the image and then try to find where are the 52 cards.
The reference image is this one (capture.jpg)
And I have also 52 images (41x68) of the cards, like the five of spades:
Now when doing pattern matching in OpenCV:
Mat1f result;
matchTemplate(org_gray, template_gray, result, TM_CCOEFF_NORMED);
double thresh = 0.8;
threshold(result, result, thresh, 1., THRESH_BINARY);
Mat1b resb;
result.convertTo(resb, CV_8U, 255);
std::vector<std::vector<Point>> contours;
findContours(resb, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); ++i)
{
Mat1b mask(result.rows, result.cols, uchar(0));
drawContours(mask, contours, i, Scalar(255), cv::FILLED);
Point max_point,min_point;
double max_val;
minMaxLoc(result, NULL, &max_val, &min_point, &max_point, mask);
rectangle(img, Rect(max_point.x, max_point.y, ptpw->m.cols, ptpw->m.rows), Scalar(0, 255, 0), 2);
}
imshow("b", ptpw->m);
imshow("a",img);
The result is this one. It did detect the location of S5 but it also detected 7 more cards...
How can I enhance my algorithm?
If I raise the threshold to 0.87 it finds only one card, but the 5 of clubs instead. I can adjust the threshold to find only one card, but why the 5C instead of 5S?
Thanks.
Share Improve this question edited Nov 21, 2024 at 11:41 Christoph Rackwitz 15.1k5 gold badges38 silver badges49 bronze badges asked Nov 21, 2024 at 8:46 Michael ChourdakisMichael Chourdakis 11k3 gold badges46 silver badges87 bronze badges 9- This question is similar to: matchTemplate() missing detections and giving false positives, what can I do?. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. – Christoph Rackwitz Commented Nov 21, 2024 at 9:05
- matchTemplate doesn't test multiple scales. – Christoph Rackwitz Commented Nov 21, 2024 at 9:07
- @ChristophRackwitz If I use TM_SQDIFF_NORMED I get 50 completely out of place contours. The question is actually why, with the best threshold of 0.87 , it finds first the 5 club instead of the 5 spade. – Michael Chourdakis Commented Nov 21, 2024 at 9:10
- 1 I've been hasty. I'll look into this more thoroughly. – Christoph Rackwitz Commented Nov 21, 2024 at 9:14
- the one "exact" instance on the left isn't exact because the template has a wide white border while the instance is narrower, having the border of an adjacent card within the area of the template's best fit. that makes the match worse. – Christoph Rackwitz Commented Nov 21, 2024 at 9:20
1 Answer
Reset to default 1As is the case with everyone who asks, the matching mode is bad. For perfect data without brightness variations, the TM_SQDIFF*
modes are the best choice.
matchTemplate(org_gray, template_gray, result, TM_SQDIFF_NORMED);
double thresh = 0.1;
threshold(result, result, thresh, 1., THRESH_BINARY_INV);
You will get a difference if the instance is red/gray, so you should consider converting to grayscale by simply taking the green or blue channel of the image (red text on white background is just all bright in the red channel). You could do that by split
ting the source channels or with mixChannels
, or even with transform
and a custom mixing matrix.
Further, your template has a wide white border. It's too wide. On the expected perfect match, it overlaps onto the image of a neighboring card (black border, black number), reducing the quality of the match.
Trim it down. That'll do better.
SQDIFF_NORMED
on the original template:
With template cropped more closely:
Even here it's not perfect because of JPEG compression artefacts. I also think the card instance's rounded edge intrudes on the square template.
And then you'll need Non-Maximum Suppression (NMS). If you just threshold the scores array, you'll get adjacent "on" pixels for the same detection, or even extrema that are almost adjacent for some reason. So don't just threshold, but do a little more. This is a general recipe with steps that were needed in various situations.
Sketch in Python:
nms_threshold = 0.10 # looking for minima
nms_radius = 5
localmin = cv.erode(scores, None, iterations=nms_radius)
extrema = (scores == localmin) & (scores <= nms_threshold)
extrema = cv.morphologyEx(extrema.astype(np.uint8), cv.MORPH_CLOSE, None, iterations=nms_radius)
# and then connected components, with stats for centroid
# will also handle minima larger than 1 pixel
(nlabels, labels, stats, centroids) = cv.connectedComponentsWithStats(extrema.astype(np.uint8))
本文标签: cOpenCV Template Matching for Playing CardsStack Overflow
版权声明:本文标题:c++ - OpenCV Template Matching for Playing Cards - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736312357a1935073.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论