OpenCV 图像色彩空间转换与抠图
一、知识点:
1、色彩空间转换函数
(1)、void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0, AlgorithmHint hint = cv::ALGO_HINT_DEFAULT );
(2)、将图像从一种颜色空间转换为另一种。
(3)、参数说明:
src: 输入图像,即要进行颜色空间变换的原图像。
dst: 输出图像,即进行颜色空间变换后的图像。
code: ColorConversionCodes枚举值,确定从什么颜色空间转换到什么颜色空间,如: COLOR_BGR2RGB、 COLOR_BGRA2RGBA、 COLOR_BGR2GRAY、 COLOR_BGR2HSV。
dstCn: 指定目标图像的通道数,若为0,则通道数由src和code决定。
hint: 算法提示。
(5)、注意:
对于RGB色彩空间,OpenCV的通道顺序是BGR,即标准24位彩色图像,第一个字节是蓝色分量,第二个字节是绿色分量,第三个字节是红色分量,第四、第五、第六依次是第二个像素的蓝、绿、红分量,以此类推。
cvtColor用COLOR_BGR2RGB和用COLOR_RGB2BGR来转换原RGB色彩空间的图像,效果是一样的。
本质上内部调用mixChannels()函数,都是将原先的B通道拷贝给目标的R通道,将原先的G通道拷贝给目标的G通道,将原先的R通道拷贝给目标的B通道。
2、HSV颜色空间
(1)、H: 色相,即什么颜色,opencv中取值范围[0, 180]。
(2)、S: 饱和度,即颜色有多深,opencv中取值范围[0, 255]。
(3)、V: 色调、纯度、亮度,即颜色有多亮,opencv中取值范围[0, 255]。
(4)、HSV颜色范围:
黑: H[0, 180],S[0, 255],V[0, 46]。
灰: H[0, 180],S[0, 43],V[46, 220]。
白: H[0, 180],S[0, 30],V[221, 255]。
红: H[0, 10]、[156、 180], S[43, 255],V[46, 255]。
橙: H[11, 25],S[43, 255],V[46, 255]。
黄: H[26, 34],S[43, 255],V[46, 255]。
绿: H[35, 77],S[43, 255],V[46, 255]。
青: H[78, 99],S[43, 255],V[46, 255]。
蓝: H[100, 124],S[43, 255],V[46, 255]。
紫: H[125, 155],S[43, 255],V[46, 255]。
(5)、HSV比RGB更容易区分出颜色。
3、void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);
(1)、创建一个掩码dst,将原始图像src中满足给定范围[lowerb, upperb]条件的像素置255,其余置0。
(2)、参数说明:
src: 输入图像。
lowerb: 下界,与输入图像类型和通道数相同的标量。
upperb: 上界,与输入图像类型和通道数相同的标量。
dst: 输出掩码,类型为CV_8UC1。
二、示例代码: 从原始绿色背景图像中抠出人物到红色背景图像中
#include <iostream>
#include <opencv2/opencv.hpp>int main()
{cv::Mat src1 = cv::Mat::zeros(3, 3, CV_8UC3);src1 = cv::Scalar(100, 20, 200);std::cout << "src1:" << std::endl << src1 << std::endl;//先把原B通道给目标R通道,再把原G通道给目标G通道,再把原R通道给目标B通道。cv::Mat dst2;cv::cvtColor(src1, dst2, cv::COLOR_BGR2RGB);std::cout << "dst2:" << std::endl << dst2 << std::endl;//先把原R通道给目标B通道,再把原G通道给目标G通道,再把原B通道给目标R通道。//所以dst2和dst3的结果是一样的。cv::Mat dst3;cv::cvtColor(src1, dst3, cv::COLOR_RGB2BGR);std::cout << "dst3:" << std::endl << dst3 << std::endl;cv::Mat src2 = cv::imread("../images/9.png");if (src2.empty()){std::cout << "load src2 image error..." << std::endl;return -1;}else{std::cout << "load src2 image ok..." << std::endl;cv::imshow("原始图像", src2);}//转换成HSV色彩空间后,显示的HSV图像颜色变了,猜测是imshow把hsvImage还是按BGR的方式显示。cv::Mat hsvImage;cv::cvtColor(src2, hsvImage, cv::COLOR_RGB2HSV);cv::imshow("HSV图像", hsvImage);//绿色的HSV最小值cv::Scalar(35, 43, 46),最大值cv::Scalar(77, 255, 255)。//把图像的绿色背景在mask中对应位置置255,其余置0。cv::Mat mask;cv::inRange(hsvImage, cv::Scalar(35, 43, 46), cv::Scalar(77, 255, 255), mask);cv::imshow("mask", mask);//mask取反,绿色背景在mask中对应位置置0,其余置255。cv::bitwise_not(mask, mask);cv::imshow("mask not", mask);//创建一个红色背景图cv::Mat redbackImage = cv::Mat::zeros(src2.size(), src2.type());redbackImage = cv::Scalar(40, 40, 200);//抠图拷贝到红色背景图上src2.copyTo(redbackImage, mask);cv::imshow("ROI区域提取", redbackImage);cv::waitKey(0);return 0;
}
输出结果:
src1:
[100, 20, 200, 100, 20, 200, 100, 20, 200;
100, 20, 200, 100, 20, 200, 100, 20, 200;
100, 20, 200, 100, 20, 200, 100, 20, 200]
dst2:
[200, 20, 100, 200, 20, 100, 200, 20, 100;
200, 20, 100, 200, 20, 100, 200, 20, 100;
200, 20, 100, 200, 20, 100, 200, 20, 100]
dst3:
[200, 20, 100, 200, 20, 100, 200, 20, 100;
200, 20, 100, 200, 20, 100, 200, 20, 100;
200, 20, 100, 200, 20, 100, 200, 20, 100]
load src2 image ok...