目录
- 1 HSV颜色空间
- 2 关于Matlab的hsv实现
- 3 关于OpenCV的hsv实现
1 HSV颜色空间
- 常见的颜色空间是RGB、HSV等,大部分图像都是RGB图像形式存在。但是在不同软件下RGB的读入内存的顺序不一样,比如, OpenCV中是以BGR的顺序排列,Qt和MATLAB是以RGB的顺序排列,不过都提供相关顺序转换函数,不用太担心。
- HSV颜色空间更加适合颜色的判断,比如想要找到蓝色车牌、黄色车牌等,这时候HSV比RGB更容易处理。
- HSV的第一个通道是H(Hue-色调),负责颜色;第二个通道是S(Saturation-饱和度),负责光的纯度,饱和度高,颜色则深而艳,比如S=0,就是灰度图片了;第二个通道是V(Value-亮度),负责亮度,比如V=0,就是黑色图片了,这三个值取值范围在不同工具会不同,但是标准的HSV的取值范围是一样的,只是转换了取值范围以适应自己的工具箱。下面我们会看到这个现象。
- 各种颜色空间本质对同一个事物的不同描述而已。
- 本次重点是OpenCV中怎么使用,MATLAB只是引子
2 关于Matlab的hsv实现
我参考了一篇文章,还很好,链接
下面就简单的看看选取蓝色的方法。
首先,最重要的是H与颜色的对应值,MATLAB的H通道是0-1,其具体对应图如下图所示。
在这里,我选取了蓝色,根据上图选择了0.55-0.7的范围,实际中你可以微调下阈值,以便更好适应。
close all;clear all;clc;
I = imread('78.bmp');%读入图片
figure,imshow(I);
I_h = rgb2hsv(I);%RGB转hsv
figure,imshow(I_h);
[height, width, c] = size(I);
for i = 1:height
for j = 1:width
h = I_h(i,j,1);
s = I_h(i,j,2);
v = I_h(i,j,3);
%通过将h通道颜色值特定范围内饱和度设为0,保留范围外颜色值
if h<0.55 || h>0.7
I_h(i,j,2) = 0; % 上面已经分析了s=0,会导致灰度化,结果是除了蓝色,其他都是灰色的!!!
end
end
end
I_r = hsv2rgb(I_h);
figure, imshow(I_r);
原图片
蓝色输出,其他是灰度的哈!!!
3 关于OpenCV的hsv实现
下面就在OpenCV中获取蓝色为例。也可以通过cvSplit
完成任务,下面直接访问像素
。
下面是OpenCV官网关于BGR->HSV的转换公式,以及注意事项 https://docs.opencv.org/3.2.0/de/d25/imgproc_color_conversions.html#color_convert_rgb_hsv
下面看看几个细节
- V和S的范围是0-255,实际上就是unsigned char,或者uchar;其作用和上面是一样的,V=0就是全黑,S=0就是灰度
- 最有意思的H,当然H就是控制颜色的,实际上H通道是在六棱锥上定义的,
一周即360°
,是角度单位,而OpenCV把它除以2,线性转换成0-180,成功装进uchar里
。也就是还是角度单位,后面的75没有使用。
为什么要这么做?
- 没有必要用两个uchar或者int更大存储范围的数据类型存储。
- 你可能会想,除以2会不会降低精度,实际上在MATLAB将H转换成0-1的double,所以担心没有必要。
- 最重要的是这样直接组成3个uchar,即
Vec3b
直接和BGR访问像素就通用了,方便了开发。
之后看看OpenCV中H通道和颜色对应关系
不难发现,蓝色对应100-124
下面,直接通过Vec3b访问HSV空间的像素。
下面的代码和访问BGR是一模一样的,不需要修改,因为OpenCV已经帮你处理好了哈。
cv::Mat src, dst;
src = cv::imread("hsv.png");
if (!src.data) {
cout << "Could't load image." << endl;
return -1;
}
namedWindow("Input image", CV_WINDOW_AUTOSIZE); //展示输入图片
cv::imshow("Input image", src);
cv::cvtColor(src, dst, cv::COLOR_BGR2HSV); // 转成灰度图片
int BlueCount = 0;
Mat out;
out.create(src.size(), src.type()); // 创建一幅和原图大小相等的空图像
for (size_t i = 0; i < dst.rows; i++) {
for (size_t j = 0; j < dst.cols; j++) {
int h = dst.at<cv::Vec3b>(i, j)(0);
int s = dst.at<cv::Vec3b>(i, j)(1);
int v = dst.at<cv::Vec3b>(i, j)(2);
// 目标:让不是蓝色的灰度显示
if (!(h > 100 && h < 124)) {
out.at<cv::Vec3b>(i, j)(1) = 0;
}
out.at<cv::Vec3b>(i, j)(0) = h;
out.at<cv::Vec3b>(i, j)(2) = v;
}
}
cv::cvtColor(out, out, COLOR_HSV2BGR);
cv::imshow("out", out);
cv::waitKey(0);
下面是绿色,看的更清楚,其他区域是灰度的哈