OpenCV截取ROI区域——多种形状
背景:在做一个中国象棋机器人的项目,项目中需要识别象棋棋子上的汉字,计划采用CNN的方式实现这一功能。在制作CNN训练的数据集的时候,需要一个截取象棋中心文字的问题。当我们定位到一个象棋的位置之后,我首先将包裹象棋的一个50*50的矩形取阈截取出来,但是,发现如果只是做矩形的截取的话,截取的图像仍然会包含一部分的棋盘,导致训练时的干扰,因此就考虑再做圆形的截取
语言:C++(Opencv3.4.1)
1、截取矩形的ROI:
1 /* cut off each piece */ 2 Rect piece_ROI(Point(center.x-piece_roi_size/2,center.y-piece_roi_size/2),Point(center.x+piece_roi_size/2,center.y+piece_roi_size/2)); 3 Mat piece_cutoff = piece_image(piece_ROI);
可以看到,在截取一个矩形的时候,比较简单,可以直接定义一个Opencv中的Rect对象,输入需要截取的矩形区域的坐标即可
这是大致的截取效果:
2、截取圆形的ROI:
这里涉及到截取一个不是矩形的区域,不管是截取一个圆形、椭圆,或者是截取一个不规则多边形,其方法都是使用contour(轮廓)来指定ROI。
比如,要截取一个多边形的ROI区域:
1 Mat dst; 2 Mat roi = Mat::zeros(img.size(),CV_8U); 3 4 vector<vector<Point>> contour; 5 vector<Point> pts; 6 pts.push_back(Point(30,45)); 7 pts.push_back(Point(100,15)); 8 pts.push_back(Point(300,145)); 9 pts.push_back(Point(330,240)); 10 pts.push_back(Point(50,250)); 11 contour.push_back(pts); 12 13 drawContours(roi,contour,0,Scalar::all(255),-1); 14 img.copyTo(dst,roi); 15 16 imshow("roi",roi); 17 imshow("img",img); 18 imshow("dst",dst);
如果要截取一个圆形区域,方法相似:
1 Mat dst = Mat::zeros(image.size(), image.type()); 2 Mat mask = Mat::zeros(image.size(),CV_8U); 3 4 Point circleCenter(mask.cols / 2, mask.rows / 2); 5 int radius = min(mask.cols, mask.rows)/2; 6 // 画圆 7 circle(mask, circleCenter, radius, Scalar(255),-1); 8 9 image.copyTo(dst, mask);
如果要截取一个椭圆呢?也是一样的方法:
1 ellipse(mask,circleCenter,Size(240,146),10,-180,180,Scalar(255),-1);
3、项目实例:
在我的象棋机器人项目中,我用如下代码实现此功能(分为两步,因为两步的结果,我都需要),可供参考:
1 /* cut off each piece */ 2 Rect piece_ROI(Point(center.x-piece_roi_size/2,center.y-piece_roi_size/2),Point(center.x+piece_roi_size/2,center.y+piece_roi_size/2)); 3 Mat piece_cutoff = piece_image(piece_ROI); 4 Mat piece_save = Mat::zeros(Size(piece_roi_size,piece_roi_size),CV_8UC3); 5 static Mat piece_mask = Mat::zeros(Size(piece_roi_size,piece_roi_size),CV_8UC1); 6 circle(piece_mask,Point(piece_roi_size/2,piece_roi_size/2),radius-3,Scalar(255),-1); 7 piece_cutoff.copyTo(piece_save,piece_mask); 8 9 /* show the piece roi to save */ 10 //imshow("piece cutoff",piece_cutoff); 11 //imshow("piece mask",piece_mask);
截取的效果如下:
4、copyTo函数
官方手册说明:
eg:
1 src.copyTo(dst, mask);
说明:将 src 的位于 mask 中的部分,拷贝到 dst 中。这里,mask是一个“掩膜”, 其中非零的位置既是指定了 src 中的那些需要拷贝的部分。