cv::Mat掩膜操作与多边形roi区域的提取
关于 cv::Mat 的矩形roi,特定行、列的访问已经在之前的博客中有所记录。本篇博文则用于记录 cv::Mat 掩膜操作的学习心得,并附上一种基于掩膜操作的多边形roi区域提取方法。
cv::Mat 的掩膜操作(mask)
对与 cv::Mat 中不规则区域的访问,除了指针+循环的基本访问方式外,opencv还提供了常用的掩膜操作。这里先介绍cv::Mat常用的两个掩膜操作方法:
//函数声明
void cv::Mat::setTo(InputArray value, InputArray mask=noArray());
void cv::Mat::copyTo(inputArray array, InputArray mask=noArray()) const;
其中,成员函数 setTo 将当前cv::Mat对象中mask对应的值改为value。
而成员函数 copyTo 则是将当前cv::Mat对象中mask对应的值复制到array对象中。
需要注意:
- mask.type()一般为CV_8U型,mask.size()必须与当前对象的size一致。
- mask在执行过程中被二值化,mask非0像素标志着该点为目标点。相应,mask的0像素点则代表着非目标点。
多边形roi区域的提取
这里提供一种基于 cv::Mat::copyTo 方法的多边形roi区域提取。
提取多边形roi的关键在于生成目标区域的mask,而opencv提供了绘制实心多边形函数:
void fillPoly(InputOutputArray img, //被绘制的图片
InputArrayOfArrays pts, //多边形角点点列,一般为vector<vector<Point>>
const Scalar& color, //绘制的实心多边形颜色
int lineType = LINE_8, //绘制边缘类型
int shift = 0, //坐标精度(小数点后位数)
Point offset = Point() //角点坐标总体偏移
);
利用 fillPoly+copyTo 获取多边形roi的方法如下:
std::vector<std::vector<cv::Point>> cornerList;
//可以绘制一次绘制多个实心多边形,若只需要绘制一个,仅赋值cornerList[0]
initial(cornerList); //求解出需要多边形的角点坐标
//srcImg为需要提取roi的目标图像
cv::Mat mask = cv::Mat::zeros(srcImg.size(), CV_8UC1);
//生成多边形mask
//生成多边形为实心多边形。非实心多边形参见polylines
cv::fillPoly(mask, cornerList, cv::Scalar(255));
//掩膜操作提取多边形roi到desImg
srcImg.copyTo(desImg, mask);
可以看到,提取非矩形roi的关键在于生成目标目标roi的mask。而多边形可以拟合任何一种形状。而对于非简单图形(如中间有孔洞,不连通等),也可以通过多边形mask的 &、|、~ 操作进行拟合。
以下提供几种常用的非矩形mask生成时可以用到的函数:
//绘制实心目标时,一般将thickness设为-1即可
//圆形
void cv::circle(InputOutputArray img, //绘制的图形,用于提取roi时为mask
cv::Point center, //圆心
int radius, //半径
const cv::Scalar& color, //绘制边界的颜色
int thickness = 1, //绘制线段的粗细程度
int lineType = LINE_8, //绘制线段的类型
int shift = 0 //坐标精度(小数点后位数)
)
//椭圆
void cv::ellipse(InputOutputArray img, //绘制的图形,用于提取roi时为mask
cv::Point center, //椭圆中心
cv::Size axes, //半长轴a * 半短轴b
double angle, //椭圆旋转角度
double startAngle, //绘制椭圆的起始角度,若绘制全椭圆,此为0
double endAngle, //绘制椭圆的终止角度,若绘制全椭圆,此为360
const cv::Scalar& color, //绘制边界的颜色
int thickness = 1, //绘制线段的粗细程度
int lineType = LINE_8, //绘制线段的类型
int shift = 0 //坐标精度(小数点后位数)
)
//绘制全椭圆时还有更简单的,利用RotatedRect代表椭圆的重载函数,
//参考opencv document