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

时间:2021-03-06 21:42:39

因为需要,之前写了一个利用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进行了 升降采样。