C++ 中利用 Opencv 得到不规则的ROI 区域(已知不规则区域)

因为需要,之前写了一个利用mask 得到不规则ROI 区域的程序。
现在需要修改,发现自己都看不懂是怎么做的了。。
所以把它整理下来。


首先利用 鼠标可以得到 你想要的不规则区域的 顶点信息。具体这里不再描述。
setMouseCallback("setROIParking_Image", on_MouseHandle, (void*)&SrcImage);
得到不规则区域的顶点之后之后,接下来生成mask.
具体程序如下

    void Image::GetROImage()
     {
        Mat srcImage = imread(srcImageName);
        for (int j = 0; j < ROInumber; j++)
        {
	        Point root_points[1][4];
	        root_points[0][0] = DrawPoints[j*4];
	        root_points[0][1] = DrawPoints[j*4 + 1];
	        root_points[0][2] = DrawPoints[j*4 + 2];
	        root_points[0][3] = DrawPoints[j*4 + 3];

	        const Point* ppt[1] = { root_points[0] };
	        int npt[] = { 4 };
                //	polylines(srcImage, ppt, npt, 1, 1, Scalar(0, 0, 0), 1, 8, 0);

	        vector <Mat>mv;
	        cv::Mat mask_ann, dst,dst1,dst2;
	        srcImage.copyTo(mask_ann);
	        mask_ann.setTo(cv::Scalar::all(0));
	        fillPoly(mask_ann, ppt, npt, 1, Scalar(255, 255, 255));
	        split(mask_ann, mv);
	        srcImage.copyTo(dst, mv[0]);
	        vector<Point> rectPoints = {}; //得到rectangle 的角点
	        rectPoints.push_back(DrawPoints[j * 4]);
	        rectPoints.push_back(DrawPoints[j * 4 +1]);
	        rectPoints.push_back(DrawPoints[j * 4 +2]);
	        rectPoints.push_back(DrawPoints[j * 4 +3]);
        	Rect rec =  boundingRect(Mat(rectPoints));
	        dst1 = dst(rec); //boundingRect(Mat(rectPoints))  //得到rectROImage
	        if (dst1.cols >= 160) 
	        {
		        resize(dst1, dst2, Size(160, 120),0,0,3); //得到rectROImage_resize  //降采样
	        }
	        else
	        {
		        resize(dst1, dst2, Size(160, 120),0,0,1);//放大
	        }
	         //默认为线性插值  INTER_NEAREST = 0(最近邻插值), 
	        //INTER_LINEAR = 1(线性插值,默认值),
	        //INTER_CUBIC = 2(三次样条插值),INTER_AREA  = 3(区域插值);INTER_LANCZOS4 = 4(Lanczos插值),
	         //INTER_MAX = 7, WARP_FILL_OUTLIERS = 8,
	           //降采样:3, 放大:2(效率不高,不推荐);1(效率高,推荐)
	            imwrite(ROImageNames[j], dst);
	            imwrite(rectROImageNames[j], dst1);
	            imwrite(rectROImageNames_resize[j], dst2);
	            imwrite(rectROImageNames_resize_[j], dst2);
            }
    }

我这里写的可能有些冗余,主要自己有点的也不是太懂,就根据自己的需要一点点添加得到自己想要的效果。

其中,DrawPoints里存储了不规则区域的顶点(我这里设定了是不规则四边形)。首先是 生成mask(我这里是mask_ann),

             srcImage.copyTo(mask_ann);
    	 mask_ann.setTo(cv::Scalar::all(0));

这一部分是生成和原图一样大小的mask 图像,然后将整个图像用黑色填充。

         const Point* ppt[1] = { root_points[0] };
         int npt[] = { 4 };
        fillPoly(mask_ann, ppt, npt, 1, Scalar(255, 255, 255));

这一部分是在mask 图像中将不规则区域的部分用白色填充,参考:http://blog.csdn.net/billbliss/article/details/43968291 可以看一下效果

    vector <Mat>mv;
split(mask_ann, mv);
srcImage.copyTo(dst, mv[0]);

我添加的这一部分代码,是跟通道分离有关,具体 也不是特别清楚。但是在我没有添加这一句时,最后得到的图像 有问题(会得到一个不规则ROI区域,但是不是自己想要的那一部分)。split 函数是将mask_ann的三个通道分别赋值给 mv . 因为这里的 mask_ann 是三通道的,而且三通道应该是一样的,我们后面利用mask得到想要的不规则区域时只用到的他的一个通道。mv[0] 即它的一个通道。

后面的

        srcImage.copyTo(dst, mv[0]); 

即得到想要的不规则区域。即除了不规则区域,其他区域全部为黑色。

    Rect rec =  boundingRect(Mat(rectPoints));
dst1 = dst(rec); //boundingRect(Mat(rectPoints))  //得到rectROImage

是我从上面得到的部分中进一步的裁剪,把多余的黑色去掉,提取出了以 ROI 区域为边界的的图片(规则四边形,周围区域用黑色填充,因为如果ROI区域太小,得到的图片中大部分都是黑色,所以进一步裁剪)。

因为我想得到最终 尺寸一样的图像,所以利用resize进行了 升降采样。

原文地址:https://www.cnblogs.com/lifeofershisui/p/7529993.html