OpenCV C++ 中的掩码(Mask)操作
掩码(Mask)是图像处理中常用的技术,它允许我们只对图像的特定部分进行操作。在OpenCV C++中,掩码通常是一个与原始图像尺寸相同的二值图像(0和255),用于指定哪些像素需要处理。
基本掩码操作
1. 创建掩码
#include <opencv2/opencv.hpp>int main() {// 创建一个黑色图像(全0)cv::Mat mask = cv::Mat::zeros(cv::Size(500, 500), CV_8UC1);// 在掩码上画一个白色矩形(255)cv::rectangle(mask, cv::Rect(100, 100, 200, 200), cv::Scalar(255), cv::FILLED);cv::imshow("Mask", mask);cv::waitKey(0);return 0;
}
2. 使用掩码复制图像区域
cv::Mat src = cv::imread("image.jpg");
cv::Mat dst = cv::Mat::zeros(src.size(), src.type());// 只复制mask中非零像素对应的src区域到dst
src.copyTo(dst, mask);
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 1. 读取源图像Mat src = imread("image.jpg");if (src.empty()) {cout << "无法加载图像!" << endl;return -1;}// 2. 创建目标图像(初始化为黑色)Mat dst = Mat::zeros(src.size(), src.type());// 3. 创建掩码(与源图像同尺寸的单通道图像)Mat mask = Mat::zeros(src.size(), CV_8UC1);// 4. 在掩码上绘制白色区域(255表示要复制的区域)// 示例1: 绘制一个圆形区域circle(mask, Point(src.cols/2, src.rows/2), 150, Scalar(255), -1);// 示例2: 或者绘制矩形区域// rectangle(mask, Rect(100, 100, 300, 200), Scalar(255), -1);// 5. 使用掩码复制图像区域src.copyTo(dst, mask);// 6. 显示结果imshow("原始图像", src);imshow("掩码", mask);imshow("结果图像", dst);waitKey(0);return 0;
}
3. 位运算与掩码
// 与操作
cv::bitwise_and(src1, src2, dst, mask);// 或操作
cv::bitwise_or(src1, src2, dst, mask);// 非操作
cv::bitwise_not(src, dst, mask);// 异或操作
cv::bitwise_xor(src1, src2, dst, mask);
4.复制圆形区域
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 1. 读取源图像Mat src = imread("image.jpg");if (src.empty()) {cout << "无法加载图像!" << endl;return -1;}// 2. 创建目标图像(初始化为黑色)Mat dst = Mat::zeros(src.size(), src.type());// 3. 创建掩码(单通道,与源图像同尺寸)Mat mask = Mat::zeros(src.rows, src.cols, CV_8UC1);// 4. 在掩码上绘制圆形区域(255表示要复制的区域)circle(mask, Point(src.cols/2, src.rows/2), 150, Scalar(255), -1);// 5. 使用掩码复制图像区域src.copyTo(dst, mask);// 6. 显示结果imshow("原始图像", src);imshow("掩码图像", mask);imshow("结果图像", dst);waitKey(0);return 0;
}
常见应用场景
1. ROI(感兴趣区域)处理
cv::Mat image = cv::imread("image.jpg");
cv::Mat roiMask = cv::Mat::zeros(image.size(), CV_8UC1);// 设置ROI区域
cv::Rect roi(50, 50, 200, 200);
roiMask(roi).setTo(255);// 只处理ROI区域
cv::Mat blurred;
cv::GaussianBlur(image, blurred, cv::Size(5, 5), 0);
blurred.copyTo(image, roiMask);
2. 图像合成
cv::Mat foreground = cv::imread("foreground.png", cv::IMREAD_UNCHANGED);
cv::Mat background = cv::imread("background.jpg");// 从带alpha通道的图像创建掩码
cv::Mat fgMask;
cv::extractChannel(foreground, fgMask, 3); // 提取alpha通道// 合成图像
cv::Mat fgBGR;
cv::cvtColor(foreground, fgBGR, cv::COLOR_BGRA2BGR);
fgBGR.copyTo(background(cv::Rect(100, 100, fgBGR.cols, fgBGR.rows)), fgMask);
3. 基于颜色的掩码
cv::Mat image = cv::imread("image.jpg");
cv::Mat hsv;
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);// 创建颜色掩码(例如提取红色区域)
cv::Mat redMask;
cv::inRange(hsv, cv::Scalar(0, 70, 50), cv::Scalar(10, 255, 255), redMask);// 应用掩码
cv::Mat redOnly;
image.copyTo(redOnly, redMask);
4.提取特定颜色区域
#include <opencv2/opencv.hpp>int main() {Mat src = imread("fruits.jpg");Mat hsv, mask, result;// 转换为HSV颜色空间cvtColor(src, hsv, COLOR_BGR2HSV);// 创建颜色掩码(提取红色区域)inRange(hsv, Scalar(0, 70, 50), Scalar(10, 255, 255), mask);// 应用掩码src.copyTo(result, mask);imshow("Original", src);imshow("Mask", mask);imshow("Red Objects", result);waitKey(0);return 0;
}
高级技巧
1. 掩码的膨胀与腐蚀
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));// 膨胀掩码
cv::dilate(mask, mask, kernel);// 腐蚀掩码
cv::erode(mask, mask, kernel);
2. 掩码边缘模糊
cv::Mat blurredMask;
cv::GaussianBlur(mask, blurredMask, cv::Size(5, 5), 0);// 归一化到0-1范围用于混合
blurredMask.convertTo(blurredMask, CV_32F, 1.0/255);
3.掩码边缘羽化
// 创建模糊边缘的掩码
Mat blurredMask;
GaussianBlur(mask, blurredMask, Size(21,21), 0);// 转换为浮点型用于混合
blurredMask.convertTo(blurredMask, CV_32F, 1.0/255);// 使用混合函数实现羽化效果
Mat result;
src.convertTo(src, CV_32F);
dst.convertTo(dst, CV_32F);
multiply(src, blurredMask, src);
multiply(dst, Scalar::all(1.0)-blurredMask, dst);
add(src, dst, result);
result.convertTo(result, CV_8U);
4. 多掩码组合
// 创建两个不同的掩码
Mat mask1 = Mat::zeros(src.size(), CV_8UC1);
Mat mask2 = Mat::zeros(src.size(), CV_8UC1);
circle(mask1, Point(200,200), 100, Scalar(255), -1);
rectangle(mask2, Rect(150,150,200,200), Scalar(255), -1);// 掩码组合操作
Mat combinedMask;
bitwise_or(mask1, mask2, combinedMask); // 逻辑或
// bitwise_and(mask1, mask2, combinedMask); // 逻辑与
// bitwise_xor(mask1, mask2, combinedMask); // 逻辑异或src.copyTo(dst, combinedMask);