OpenCV3.4.0学习笔记(四)——cv::Mat掩膜操作与多边形roi区域的提取

本文详细介绍了如何使用OpenCV的cv::Mat掩膜操作进行不规则区域的访问,特别是多边形roi区域的提取方法。通过fillPoly和copyTo函数组合,可以精确地从图像中提取出由多边形定义的感兴趣区域。

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对象中。

需要注意:

  1. mask.type()一般为CV_8U型,mask.size()必须与当前对象的size一致。
  2. 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

末尾注:以上为作者学习过程中自己认识的记录,如有问题,敬请指正。

<think>好的,我现在需要在C++中使用OpenCVcv::Mat来绘制掩膜并计算感兴趣区域ROI)的均值。让我先理清楚步骤,然后一步步解决。 首先,用户的问题是关于如何创建掩膜、定义ROI,然后计算该区域的均值。我需要回忆OpenCV的相关函数和流程。 第一步,绘制掩膜。通常掩膜是一个二值图像,其中白色区域(255)表示感兴趣的区域,黑色(0)表示被忽略的部分。用户可能需要手动绘制形状,比如矩形、圆形,或者根据某种条件生成掩膜。例如,使用cv::rectangle或cv::circle函数在掩膜上绘制形状。不过,这些函数需要先创建一个全黑的Mat,然后在上面画白色图形。 第二步,定义ROIROI通常是通过Rect来指定一个矩形区域,或者通过掩膜的非零区域来定义。如果使用掩膜,那么ROI就是掩膜中值为255的部分。不过,计算均值时,可以直接使用掩膜作为参数,这样函数会自动处理非零区域。 第三步,计算均值。OpenCV中有mean函数,可以接受掩膜作为参数。函数原型大概是cv::mean(InputArray src, InputArray mask),返回一个Scalar,包含各通道的均值。需要注意的是,如果图像是多通道的,比如BGR,那么均值也会分别计算每个通道。 接下来,我需要考虑可能的错误和注意事项。例如,掩膜必须和原图尺寸相同,否则会报错。另外,掩膜的数据类型应该是CV_8U,否则可能不被接受。还有,当使用Rect定义ROI时,要确保Rect的边界不超过原图的范围,否则会引发异常。 然后,代码的结构应该是这样的:首先读或创建原图像,然后创建掩膜,可能通过绘制几何形状或者根据某种阈值生成。接着,应用掩膜计算均值。或者,如果使用Rect,可以直接从原图中提取ROI,然后计算该区域的均值。 不过用户明确提到的是使用掩膜mask),所以重点应该放在掩膜的创建和mean函数的使用上。例如: 1. 创建原图同尺寸的掩膜,初始化为0。 2.掩膜上绘制需要的ROI区域为255。 3. 使用cv::mean函数,传入原图和掩膜,得到均值。 或者,如果ROI是矩形,也可以直接使用Rect来提取子矩阵,再计算其均值,这样可能更高效,但用户的问题可能更偏向于任意形状的掩膜。 可能的代码示例: 创建掩膜cv::Mat mask = cv::Mat::zeros(image.size(), CV_8UC1); cv::rectangle(mask, cv::Rect(x, y, width, height), cv::Scalar(255), cv::FILLED); 或者使用圆形: cv::circle(mask, center, radius, cv::Scalar(255), cv::FILLED); 然后计算均值: cv::Scalar mean_val = cv::mean(image, mask); 但是,如果图像是多通道的,比如3通道的BGR,那么mean_val会有个值(包括alpha通道如果有的话),但通常第三个通道之后可能为0,如果图像是三通道的话,前三项是各通道的均值。 此外,用户可能需要将掩膜应用到图像上,提取ROI,但计算均值时,直接使用mean函数带mask参数会更直接,不需要先提取ROI,因为mask已经指定了哪些像素需要考虑。 现在,检查是否有相关的OpenCV函数或者需要注意的地方。例如,calcHist函数在引用[2]中提到,但这里需要的是mean计算。所以可能不需要用到calcHist,除非用户需要更复杂的统计。 另外,关于引用的问题,用户提供的引用[1]和[2]可能当前问题关联不大,但可能需要确认是否有其他相关引用需要参考。例如,cvWarpPerspectiveQMatrix可能不相关,但calcHist的参数说明可能对掩膜的使用有帮助,因为在calcHist中,mask参数是InputArray类型,同样在mean函数中也是如此。因此,mask的创建和使用方法类似,可能可以引用这一点。 在编写代码时,需要注意: - 确保mask的类型是CV_8UC1。 - mask和image的尺寸一致。 - 如果使用非矩形区域,必须使用掩膜方法。 现在,编写一个完整的示例代码: #include <opencv2/opencv.hpp> int main() { // 读图像 cv::Mat image = cv::imread("image.jpg"); if(image.empty()) return -1; // 创建掩膜(示例:矩形区域cv::Mat mask = cv::Mat::zeros(image.size(), CV_8UC1); cv::rectangle(mask, cv::Rect(100, 100, 200, 200), 255, cv::FILLED); // 计算均值 cv::Scalar mean = cv::mean(image, mask); // 输出结果 std::cout << "Mean: " << mean << std::endl; return 0; } 这样应该可以实现用户的需求。需要注意,如果用户需要手动绘制掩膜,比如通过交互式操作,可能需要用到其他方法,比如鼠标回调函数,但用户的问题可能只需要代码层面的生成。 另外,如果用户想用ROI而不是掩膜,可以用: cv::Mat roi = image(cv::Rect(x,y,w,h)); cv::Scalar mean = cv::mean(roi); 但这种方法仅适用于矩形区域,而掩膜适用于任意形状。 总结步骤: 1. 创建掩膜,指定ROI区域为255。 2. 使用cv::mean函数,传入原图和掩膜3. 处理结果。 现在,根据用户提供的引用[2],calcHist函数中的mask参数的使用方式此类似,因此可以引用这一点来说明mask的使用方法,尽管这里是mean函数。因此,在回答中可以引用[^2]来说明mask参数的正确应用。 可能的错误点: - 掩膜类型不是CV_8UC1。 - 掩膜尺寸原图不一致。 - 忘记将掩膜区域填充为255(即使用0和255之外的数值,但OpenCV通常要求非零区域作为有效区域)。 另外,用户可能需要了解如何生成非矩形的掩膜,比如多边形,这时候可以使用cv::fillPoly函数。 例如: std::vector<cv::Point> points; points.push_back(cv::Point(50, 50)); points.push_back(cv::Point(300, 100)); points.push_back(cv::Point(400, 400)); cv::fillPoly(mask, points, cv::Scalar(255)); 这样可以在掩膜上绘制多边形区域。 最后,确保在回答中涵盖这些可能性,并提供示例代码,同时引用相关的文档说明。</think>在C++中使用OpenCV的`cv::Mat`绘制掩膜并计算感兴趣区域ROI)均值的步骤如下: ### 步骤详解 1. **创建掩膜** 掩膜是一个原始图像尺寸相同的二值图像,通常通过以下方式生成: - **矩形掩膜**:使用`cv::rectangle`在掩膜上绘制白色矩形。 - **圆形/多边形掩膜**:使用`cv::circle`或`cv::fillPoly`绘制任意形状。 ```cpp cv::Mat mask = cv::Mat::zeros(image.size(), CV_8UC1); // 全黑掩膜 cv::rectangle(mask, cv::Rect(100, 100, 200, 200), 255, cv::FILLED); // 绘制白色矩形 ``` 2. **计算ROI均值** 使用`cv::mean`函数,传入原始图像和掩膜作为参数: ```cpp cv::Scalar mean = cv::mean(image, mask); ``` ### 完整示例代码 ```cpp #include <opencv2/opencv.hpp> int main() { // 读图像 cv::Mat image = cv::imread("image.jpg"); if (image.empty()) return -1; // 创建掩膜(示例:矩形ROIcv::Mat mask = cv::Mat::zeros(image.size(), CV_8UC1); cv::rectangle(mask, cv::Rect(100, 100, 200, 200), 255, cv::FILLED); // 计算掩膜区域的均值 cv::Scalar mean = cv::mean(image, mask); // 输出结果(BGR三通道均值) std::cout << "均值: " << mean << std::endl; return 0; } ``` ### 注意事项 - **掩膜类型**:必须为`CV_8UC1`(单通道8位无符号),且尺寸原始图像一致[^2]。 - **非矩形区域**:可通过`cv::fillPoly`绘制多边形掩膜。 - **性能优化**:若ROI为矩形,直接提取子矩阵更高效: ```cpp cv::Mat roi = image(cv::Rect(100, 100, 200, 200)); cv::Scalar mean = cv::mean(roi); // 仅适用于矩形区域 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值