如何使用OpenCV在此图像中检测中国象棋棋子?
我尝试过使用HoughCircles
,但没有找到圆圈.
Mat src = imread( "x.jpg", CV_LOAD_IMAGE_GRAYSCALE); GaussianBlur( src, src, Size(9, 9), 2, 2 ); vectorcircles; 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 ); vectorkps; 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);
Patrick Yu.. 5
当从图像m中隔离红色时可能出现的一个问题是棋子与红色背景的混合.运行时inRange()
,会发生这种情况:
乍看之下判断跳棋的位置真是太难了!但是我们可以使用技巧克隆扩张和侵蚀来移除次要部分(网格),同时保留重要部分(圆形检查器).
这是解决检查问题的扩张和侵蚀的代码:
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #includeusing 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 > contours; //vector 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,我们知道它是噪音,我们可以把它丢弃.否则,我们可以将它绘制到屏幕上.
当从图像m中隔离红色时可能出现的一个问题是棋子与红色背景的混合.运行时inRange()
,会发生这种情况:
乍看之下判断跳棋的位置真是太难了!但是我们可以使用技巧克隆扩张和侵蚀来移除次要部分(网格),同时保留重要部分(圆形检查器).
这是解决检查问题的扩张和侵蚀的代码:
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #includeusing 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 > contours; //vector 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,我们知道它是噪音,我们可以把它丢弃.否则,我们可以将它绘制到屏幕上.