opencv 截取轮廓中的图像——实现PS中利用蒙版抠图的功能(Using Opencv extract area circled by contour)
顺手秀了一把英语~~
我时常感慨,要是PhotoShop要是开源的多好啊,这得造福多少从事计算机视觉的码农们啊~ 既然不开源,那就自己摸索吧,我希望从这篇博文开始我能一步步把PS中的功能给分解出来,欢迎指正交流
我们很容易用findContours()函数将图像中的轮廓提取出来,但是并没有将轮廓所包围的图像输出的函数,以下是几个有类似功能的函数:
cvimageroi():得到包围ROI(感兴趣区域)的矩形区域,可以直接把轮廓点集作为参数给进去然后返回包围这个轮廓的最佳矩形点集,然后再用Mat的成员函数Mat(Rec)把这个区域提取出来。遗憾的是这样只能提取矩形区域,无法提取不规则区域。
boundingRect():这个同上一个是一样的功能,也是得到矩形区域。
进入正题
首先将原图像灰度化,二值化,然后提取轮廓,进行排除、去噪处理之后用drawContours()函数把轮廓填充为白色。具体做法是:
Mat hole(res.size(), CV_8U, Scalar(0)); //新建一个黑色的遮罩图层
cv::drawContours(hole, contours1, -1, Scalar(255), CV_FILLED); //在遮罩图层上,将轮廓里面的空间用白色像素填充
之后将原图用copyTo()函数叠加到遮罩图层上,就大功告成了。
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
void main() {
Mat original = imread("D:\\res.png");
namedWindow("My original");
imshow("My original", original);
Mat gray = original;
cv::cvtColor(gray, gray, CV_RGB2GRAY);//灰度化
int thresh_size = (100 / 4) * 2 + 1; //自适应二值化阈值
adaptiveThreshold(gray, gray, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, thresh_size, thresh_size / 3);
morphologyEx(gray, gray, MORPH_OPEN, Mat());//形态学开运算去噪点
vector<vector<Point> > contours;
cv::findContours(gray, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //找轮廓
vector<vector<Point>> contours1;
for (int i = 0; i < contours.size(); ++i)
{
if (contours[i].size() > 200)//将比较小的轮廓剔除掉
{
contours1.push_back(contours[i]);
}
}
/*可以加入以下功能*/
//vector<vector<Point>> contours2;
//vector<Point> approx_poly;//存放顶点
//for (int i = 0; i < contours1.size(); ++i)
//{
//double eps = contours1[i].size()*0.08;//精度
//approxPolyDP(contours1[i], approx_poly, eps, true);//用另一条顶点较少的曲线来逼近一条曲线或者一个多边形
//if ((approx_poly.size() != 4) || (!isContourConvex(approx_poly)))//提取只有4个顶点的轮廓和凸多边形
//{
// continue;
//}
//else {
//contours2.push_back(contours1[i]);
//}
//}
Mat hole(gray.size(), CV_8U, Scalar(0)); //遮罩图层
cv::drawContours(hole, contours1, -1, Scalar(255), CV_FILLED); //在遮罩图层上,用白色像素填充轮廓
namedWindow("My hole");
imshow("My hole", hole);
Mat crop(original.rows, original.cols, CV_8UC3);
original.copyTo(crop, hole);//将原图像拷贝进遮罩图层
namedWindow("My warpPerspective");
imshow("My warpPerspective", crop);
waitKey(0);
}