如何使用OpenCV在此图像中检测中国象棋棋子?
我尝试过使用HoughCircles
,但未找到任何圈子。
Mat src = imread( "x.jpg", CV_LOAD_IMAGE_GRAYSCALE);
GaussianBlur( src, src, Size(9, 9), 2, 2 );
vector<Vec3f> circles;
HoughCircles( src, circles, CV_HOUGH_GRADIENT, 1, src.rows/16);
cout << circles.size() << endl;
// The output is: 0
还测试了斑点检测器,但结果不正确。
Mat im = imread( "x.jpg", IMREAD_GRAYSCALE );
vector<KeyPoint> kps;
SimpleBlobDetector().detect(im, kps);
Mat im_kps;
drawKeypoints( im, kps, im_kps, Scalar(0,0,255), DrawMatchesFlags::DRAW_RICH_KEYPOINTS );
imshow("keypoints", im_kps );
waitKey(0);
答案 0 :(得分:5)
从图像m中隔离红色时可能出现的一个问题是棋子与红色背景的混合。运行inRange()
时会发生这种情况:
乍看之下判断跳棋的位置真是太难了!但我们可以使用一个技巧克隆膨胀和侵蚀来移除次要部分(网格),同时保留重要部分(圆形检查器)。
这是解决检查问题的扩张和侵蚀的代码:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
Mat getElement(int erosion_size)
{
return getStructuringElement(cv::MORPH_ELLIPSE,
cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1),
cv::Point(erosion_size, erosion_size) );
}
int main( )
{
vector<vector<Point> > contours;
//vector<Vec4i> hierarchy;
//int largest_area,largest_contour,largest_contour_index;
//RotatedRect bounding_ellipse;
Mat image,dst,filtered;
Mat a1,a2;
//Color ranging red (from both left & right spectrums)
image = imread("circles.jpg");
cvtColor(image,filtered,CV_BGR2HSV);
Scalar low = Scalar(0, 100, 50);
Scalar up = Scalar(10, 255, 255);
Scalar low2 = Scalar(160, 100, 50);
Scalar up2 = Scalar(179, 255, 255);
inRange(filtered, low2, up2, a1);
inRange(filtered, low2, up2, a2);
bitwise_or(a1,a2,filtered);
imshow("troll", filtered);
// Fill in small holes from Chinese lettering
dilate(filtered,filtered,getElement(11));
imshow("better", filtered);
// Erode to remove minor (like square lines) objects
erode(filtered,filtered,getElement(25));
imshow("best",filtered);
findContours(filtered, contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
for( int i = 0; i< contours.size(); i++ )
{
//Only draw big contours, not minor details
double area =contourArea( contours[i],false);
if(area > 1500)
{
drawContours(image, contours, i, Scalar(0,255,0), 5);
}
}
imshow( "Result window", image );
waitKey(0);
return 0;
}
我们从膨胀开始,它允许图像的较亮部分“扩展”在“较暗”的部分上。所以,在这里,我们将使用它来删除中文字母(因此,当扩张时,我们将不会在圆圈中间有大洞):
如您所见,现在圆圈已经填满,我们可以继续侵蚀。我们需要扩大更多而不是我们侵蚀的数量,因为我们需要从图像中移除网格条。应用侵蚀,我们只得到棋盘上的棋子(以及我们稍后会处理的一些噪音):
现在,我们可以处理检查器,但我们需要滤除图像周围的噪音。为此,我们将从侵蚀结果中运行findContours()
,但我们还将检查轮廓区域contourArea()
,以确保它是我们的检查器。如果面积小于1500,我们知道它是噪音,我们可以把它丢弃。否则,我们可以将它绘制到屏幕上。