背景:在做一個中國象棋機器人的項目,項目中需要識別象棋棋子上的漢字,計划采用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 中的那些需要拷貝的部分。