关于HSV颜色空间
的介绍可以参考这篇博客:OpenCV中HSV颜色模型及颜色分量范围。
提取上图各种颜色c++代码如下test.cpp
,以提取蓝色、绿色、红色三种颜色为例:
#include <iostream>
#include <string>
#include <vector>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
//g++ test.cpp `pkg-config opencv --libs --cflags` -std=c++11 -o test
int main() {
cv::Mat origin_bgr_img = cv::imread("pic.png");
// 将BGR空间的图片转换到HSV空间
cv::Mat hsv;
// hsv为3通道,hsv.channels==3
cv::cvtColor(origin_bgr_img, hsv, cv::COLOR_BGR2HSV);
std::cout << "hsv.channels=" << hsv.channels() << std::endl;
// 在HSV空间中定义蓝色
cv::Scalar lower_blue = cv::Scalar(100, 50, 50);
cv::Scalar upper_blue = cv::Scalar(124, 255, 255);
// # 在HSV空间中定义绿色
cv::Scalar lower_green = cv::Scalar(35, 50, 50);
cv::Scalar upper_green = cv::Scalar(77, 255, 255);
// # 在HSV空间中定义红色,红色的h值有两个范围[0,10]和[156,180]
cv::Scalar lower_red_1 = cv::Scalar(0, 50, 50);
cv::Scalar upper_red_1 = cv::Scalar(10, 255, 255);
cv::Scalar lower_red_2 = cv::Scalar(156, 50, 50);
cv::Scalar upper_red_2 = cv::Scalar(180, 255, 255);
// 从HSV图像中截取出蓝色、绿色、红色,即获得相应的掩膜
// cv::inRange()函数是设置阈值去除背景部分,得到想要的区域
cv::Mat blue_mask, green_mask, red_mask, red_mask_1, red_mask_2;
// 把hsv中的像素值在范围内的置255,不在范围内的置0,输出为掩模mask
// blue_mask为单通道,blue_mask.channels==1
cv::inRange(hsv, lower_blue, upper_blue, blue_mask);
std::cout << "blue_mask.channels=" << blue_mask.channels() << std::endl;
// std::cout << blue_mask << std::endl;
cv::inRange(hsv, lower_green, upper_green, green_mask);
cv::inRange(hsv, lower_red_1, upper_red_1, red_mask_1);
cv::inRange(hsv, lower_red_2, upper_red_2, red_mask_2);
red_mask = red_mask_1 + red_mask_2;
// 将原图像和mask(掩膜)进行按位与
cv::Mat blue_res;
// 三通道图像进行单通道掩模操作后,输出图像还是三通道。相当于对三通道都做了掩模。
cv::bitwise_and(origin_bgr_img, origin_bgr_img, blue_res, blue_mask);
cv::Mat green_res;
cv::bitwise_and(origin_bgr_img, origin_bgr_img, green_res, green_mask);
cv::Mat red_res;
cv::bitwise_and(origin_bgr_img, origin_bgr_img, red_res, red_mask);
cv::Mat background_img = cv::Mat::zeros(1000, 1900, CV_8UC3);
// #最后得到要分离出的颜色图像
cv::Mat res = blue_res + green_res + red_res;
{
int x = 100, y = 40;
cv::Rect roi(x, y, origin_bgr_img.cols, origin_bgr_img.rows);
cv::putText(background_img, "origin", cv::Point(x, y - 10),
cv::FONT_HERSHEY_PLAIN, 1, CV_RGB(255, 255, 255), 1);
//将background_img复制到img中roi指定的矩形位置
origin_bgr_img.copyTo(background_img(roi));
}
{
int x = 500, y = 40;
cv::Rect roi(x, y, res.cols, res.rows);
cv::putText(background_img, "hsv", cv::Point(x, y - 10),
cv::FONT_HERSHEY_PLAIN, 1, CV_RGB(255, 255, 255), 1);
hsv.copyTo(background_img(roi));
}
{
int x = 900, y = 40;
cv::Rect roi(x, y, res.cols, res.rows);
cv::putText(background_img, "res", cv::Point(x, y - 10),
cv::FONT_HERSHEY_PLAIN, 1, CV_RGB(255, 255, 255), 1);
res.copyTo(background_img(roi));
}
{
int x = 100, y = 500;
cv::Rect roi(x, y, blue_res.cols, blue_res.rows);
cv::putText(background_img, "blue", cv::Point(x, y - 10),
cv::FONT_HERSHEY_PLAIN, 1, CV_RGB(255, 255, 255), 1);
blue_res.copyTo(background_img(roi));
}
{
int x = 500, y = 500;
cv::Rect roi(x, y, green_res.cols, green_res.rows);
cv::putText(background_img, "green", cv::Point(x, y - 10),
cv::FONT_HERSHEY_PLAIN, 1, CV_RGB(255, 255, 255), 1);
green_res.copyTo(background_img(roi));
}
{
int x = 900, y = 500;
cv::Rect roi(x, y, red_res.cols, red_res.rows);
cv::putText(background_img, "red", cv::Point(x, y - 10),
cv::FONT_HERSHEY_PLAIN, 1, CV_RGB(255, 255, 255), 1);
red_res.copyTo(background_img(roi));
}
cv::imwrite("pppp.png", background_img);
std::string win_name = "background_img";
cv::namedWindow(win_name, cv::WINDOW_KEEPRATIO);
cv::imshow(win_name, background_img);
cv::waitKey(0);
}
执行编译命令:
g++ test.cpp `pkg-config opencv --libs --cflags` -std=c++11 -o test
上面程序运行结果如下图:
值得说明的是:
- hsv为3通道;
- 掩模mask为单通道;
- 提取颜色使用HSV方法,只是通过hsv获得掩模mask,得到的掩模mask是用来和BGR图像做掩模操作;
- 三通道图像进行单通道掩模mask操作后,输出图像还是三通道,相当于对三通道都做了掩模mask。
cv::inRange()
的用法:
void inRange(InputArray src,
InputArray lowerb,
InputArray upperb,
OutputArray dst);
src:输入图像,CV2常用Mat类型;
lowerb:下限,scalar类型的像素值,单通道scalar取一个值就行,彩图3通道scalar三个值;
upperb:上限,类型与lowerb同理;
dst:输出图像,尺寸与src一致,类型是CV_8U,但没有指定通道数。
对于多通道的输入,输出结果是各个通道的结果相与
,当各通道结果都在上下限之内时,输出为255
,否则为0
。因此也有人将输出理解为掩码模板!
cv::bitwise_and()
是按位与
操作,此外还有bitwise_or
、bitwise_xor
、bitwise_not
这四个按位操作函数:
void bitwise_and(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray());//dst = src1 & src2
void bitwise_or(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray());//dst = src1 | src2
void bitwise_xor(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray());//dst = src1 ^ src2
void bitwise_not(InputArray src, OutputArray dst,InputArray mask=noArray());//dst = ~src
bitwise_and
是对二进制数据进行“与”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“与”
操作,1&1=1
,1&0=0
,0&1=0
,0&0=0
;
bitwise_or
是对二进制数据进行“或”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“或”
操作,1|1=1
,1|0=0
,0|1=0
,0|0=0
;
bitwise_xor
是对二进制数据进行“异或”
操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“异或”
操作,1^1=0
,1^0=1
,0^1=1
,0^0=0
;
bitwise_not
是对二进制数据进行“非”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“非”操作,~1=0
,~0=1
;