赞
踩
为什么一定要转为HSV 颜色空间?
将图像从BGR颜色空间转换为HSV颜色空间是因为HSV颜色空间更适合进行颜色分割和提取操作。这是因为HSV颜色空间将颜色表示为色相(Hue)、饱和度(Saturation)和明度(Value),这使得颜色的分离更加直观和有效。具体原因如下:
色相(Hue)分离:
饱和度(Saturation)和明度(Value)独立:
处理光照变化:
HSV范围取色表
例如在H:35 -77 S:43-255 V:46-255 之间的可以认为是绿色。 有了这张图参考,我们能够更容易地过滤掉某种颜色。
以将一张蓝底的证件照换成红底证件照为例:
转为HSV颜色空间之后,我们要找出蓝色的底色所在区域。可以通过遍历像素的方式实现
// 根据范围创建 掩码图像 二值化图像 void customInRange(const Mat& src, Scalar lowerBound, Scalar upperBound, Mat& dst) { // 创建与源图像大小相同的掩码图像 dst = Mat::zeros(src.size(), CV_8UC1); // 遍历图像的每个像素 for (int y = 0; y < src.rows; y++) { for (int x = 0; x < src.cols; x++) { Vec3b pixel = src.at<Vec3b>(y, x); bool inRange = true; // 检查像素值是否在指定范围内 通过HSV范围表来指定 for (int c = 0; c < 3; c++) { if (pixel[c] < lowerBound[c] || pixel[c] > upperBound[c]) { inRange = false; break; } } // 如果在范围内,设置掩码图像中的对应位置为255 if (inRange) { dst.at<uchar>(y, x) = 255; } } } }
这里涉及到一个新概念 掩码图像
掩码(mask)在计算机视觉和图像处理领域中,是一种用于选择、过滤或操作图像中特定部分的工具。掩码本质上是一张与原图像大小相同的二值图像,其中每个像素要么是0,要么是1(在OpenCV中通常用0和255来表示)。掩码图像中值为1(或255)的部分表示感兴趣的区域(ROI,Region of Interest),而值为0的部分则表示不感兴趣的区域。
掩码的具体作用可以包括以下几种:
上述代码通过遍历可以找到蓝色底色的区域,并置为白色。其余的全部设置为黑色。
代码运行效果:(中间的白点,因为胖虎穿的偏蓝色领带,因此过滤出了一部分)
此时,基本上已经找出原来底色的区域,已经全部置成了白色。
主要目的是找到除了背景色的其他元素,这一步是选择 非背景色的元素 置为白色,因为除了背景色,其他像素均要移到新的背景色上去, 非背景色成为了ROI(感兴趣区域),背景色置为黑色,代表不再关注原来的背景色。遍历每个像素,用255减去原来的像素便可反转颜色,黑白颠倒。
// bitwise_not(mask,mask);
for (int y = 0; y < mask.rows; ++y) {
for (int x = 0; x < mask.cols; ++x) {
//对每个像素进行取反
mask.at<uchar>(y, x) = 255 - mask.at<uchar>(y, x);
}
}
效果如图:
//将非背景色像素移到事先准备好的背景上 void customCopyTo(const Mat& src, Mat& dst, const Mat& mask) { // 确保源图像和掩码图像的大小一致 if (src.size() != dst.size() || src.size() != mask.size()) { throw std::invalid_argument("Size of src, dst, and mask must be the same"); } // 遍历图像的每个像素 for (int y = 0; y < src.rows; y++) { for (int x = 0; x < src.cols; x++) { // 如果掩码中的值为非零(通常是255),则复制源图像的像素到目标图 if (mask.at<uchar>(y, x) != 0) { dst.at<Vec3b>(y, x) = src.at<Vec3b>(y, x); } } } }
遍历像素,与掩码图像对比,如果不是黑色,说明是ROI区域,将像素替换到准备好的纯色背景上面。就完成了背景换色
效果如下:
//将非背景色像素移到事先准备好的背景上 void customCopyTo(const Mat& src, Mat& dst, const Mat& mask) { // 确保源图像和掩码图像的大小一致 if (src.size() != dst.size() || src.size() != mask.size()) { throw std::invalid_argument("Size of src, dst, and mask must be the same"); } // 遍历图像的每个像素 for (int y = 0; y < src.rows; y++) { for (int x = 0; x < src.cols; x++) { // 如果掩码中的值为非零(通常是255),则复制源图像的像素到目标图像 if (mask.at<uchar>(y, x) != 0) { dst.at<Vec3b>(y, x) = src.at<Vec3b>(y, x); } } } } // 根据范围创建 掩码图像 二值化图像 void customInRange(const Mat& src, Scalar lowerBound, Scalar upperBound, Mat& dst) { // 创建与源图像大小相同的掩码图像 dst = Mat::zeros(src.size(), CV_8UC1); // 遍历图像的每个像素 for (int y = 0; y < src.rows; y++) { for (int x = 0; x < src.cols; x++) { Vec3b pixel = src.at<Vec3b>(y, x); bool inRange = true; // 检查像素值是否在指定范围内 for (int c = 0; c < 3; c++) { if (pixel[c] < lowerBound[c] || pixel[c] > upperBound[c]) { inRange = false; break; } } // 如果在范围内,设置掩码图像中的对应位置为255 if (inRange) { dst.at<uchar>(y, x) = 255; } } } } void inRange_dmeo(Mat &image){ Mat hsv; //先将图片转为HSV cvtColor(image,hsv,COLOR_BGR2HSV); // 提取左上角像素的HSV值 ,也就是对应底色的值 有利于更好控制提取 Vec3b hsvValue = hsv.at<Vec3b>(0, 0); cout<<hsvValue<<endl; Mat mask; //设置 下限 和上限根据设定的HSV颜色范围 生成一个二值化的掩码(mask),掩码中白色部分表示图像中符合设定颜色范围的部分,黑色部分表示不符合的部分。 customInRange(hsv,Scalar(100,43,46),Scalar(115,225,227),mask); imshow("mask",mask); //准备好一个背景颜色 以红色为例 Mat red_background = Mat::zeros(image.size(),image.type()); red_background = Scalar (40,40,200); //对掩码取反, 黑白颠倒,选择除了背景色的区域 ,也就是欲复制的区域 // bitwise_not(mask,mask); for (int y = 0; y < mask.rows; ++y) { for (int x = 0; x < mask.cols; ++x) { //对每个像素进行取反 mask.at<uchar>(y, x) = 255 - mask.at<uchar>(y, x); } } imshow("bitwise_not mask",mask); //使用掩码(mask)将输入图像中符合条件的部分复制到红色背景图像上 customCopyTo(image,red_background,mask); imshow("roi",red_background); }
OpenCV提供了生成掩码,掩码取反,复制非背景色元素到新背景的API 如下,
inRange 根据HSV范围 生成掩码
bitwise_not 掩码取反
copyTo 根据掩码复制到新背景色
void inRange_dmeo(Mat &image){ Mat hsv; //先将图片转为HSV cvtColor(image,hsv,COLOR_BGR2HSV); // 提取左上角像素的HSV值 ,也就是对应底色的值 有利于更好控制提取 Vec3b hsvValue = hsv.at<Vec3b>(0, 0); cout<<hsvValue<<endl; Mat mask; //设置 下限 和上限根据设定的HSV颜色范围 生成一个二值化的掩码(mask),掩码中白色部分表示图像中符合设定颜色范围的部分,黑色部分表示不符合的部分。 inRange(hsv,Scalar(100,43,46),Scalar(115,225,227),mask); imshow("mask",mask); //准备好一个背景颜色 以红色为例 Mat red_background = Mat::zeros(image.size(),image.type()); red_background = Scalar (40,40,200); //对掩码取反, 黑白颠倒,选择除了背景色的区域 ,也就是欲复制的区域 bitwise_not(mask,mask); imshow("bitwise_not mask",mask); //使用掩码(mask)将输入图像中符合条件的部分复制到红色背景图像上 image.copyTo(red_background,mask); imshow("roi",red_background); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。