HSV 即使用色相(Hue)、饱和度(Saturation)、明度(Value)来表示色彩的一种方式,是一种在人们生活中常用的颜色系统,因为它符合人们描述颜色的方式——是什么颜色、颜色有多深、颜色有多亮。
其中:
H(色相,Hue):将颜色用0°~360°来表示,常见的色相与数值按照下表对应:
如果画成一张图的话:
S(饱和度,saturation):是指色彩的纯度,也可以理解为色彩的深浅度。对于同种色彩下饱和度越低则颜色越黯淡,并且有s∈[0,1)
V(明度,value):即颜色的明暗程度。数值越高越接近白色,数值越低越接近黑色且V∈[0,1)
由于HSV是一种比较直观的颜色模型,所以在计算机图形学中应用比较广泛。但这也决定了它不适合使用在光照模型中,许多光线混合运算、光强运算等都无法直接使用HSV来实现。
HSV颜色空间的模型对应于圆柱坐标系中的一个圆锥形子集,圆锥的顶面对应于V=1. 它包含RGB模型中的R=1,G=1,B=1 三个面,所代表的颜色较亮。色彩H由绕V轴的旋转角给定。红色对应于 角度0° ,绿色对应于角度120°,蓝色对应于角度240°。在HSV颜色模型中,每一种颜色和它的补色相差180° 。 饱和度S取值从0到1,所以圆锥顶面的半径为1。HSV颜色模型所代表的颜色域是CIE色度图的一个子集,这个 模型中饱和度为百分之百的颜色,其纯度一般小于百分之百。在圆锥的顶点(即原点)处,V=0,H和S无定义, 代表黑色。圆锥的顶面中心处S=0,V=1,H无定义,代表白色。从该点到原点代表亮度渐暗的灰色,即具有不同 灰度的灰色。对于这些点,S=0,H的值无定义。可以说,HSV模型中的V轴对应于RGB颜色空间中的主对角线。 在圆锥顶面的圆周上的颜色,V=1,S=1,这种颜色是纯色。HSV模型对应于画家配色的方法。画家用改变色浓和 色深的方法从某种纯色获得不同色调的颜色,在一种纯色中加入白色以改变色浓,加入黑色以改变色深,同时 加入不同比例的白色,黑色即可获得各种不同的色调。
RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是运用最广的颜色系统之一。比如,电脑屏幕上的所有颜色,都由这红色绿色蓝色三种色光按照不同的比例混合而成的。一组红色绿色蓝色就是一个最小的显示单位。屏幕上的任何一个颜色都可以由一组RGB值来记录和表达。RGB色彩空间的三个颜色的不同组合可以形成几乎所有的其他颜色。利用三个颜色分量的线性组合来表示颜色,任何颜色都与这三个分量有关,而且这三个分量是高度相关的,所以连续变换颜色时并不直观,想对图像的颜色进行调整需要更改这三个分量才行。但是人眼对这三种颜色分量的敏感程度是不一样的。在单色中,人眼对红色最不敏感,蓝色最敏感。所以RGB颜色空间是一种均匀性较差的颜色空间。对于某一种颜色,我们很难推测出较为精确的三个分量数值来表示。所以,RGB颜色空间适合于显示系统,却并不适合于图像处理。
直观的理解,只要把RGB三维坐标的中轴线立起来,并扁化,就能形成HSV的锥形模型了。
更具体地说,RGB图像与硬件输出相对应(RGB图像与相机传感器输出的原始数据相对应),而HSV图像则更符合人眼的直观视觉
i.原理
在讲转换原理之前,首先我们以8位彩色图为例来明确一下RGB图像、HSV图像中各通道像素值的取值范围,对于图像中任意坐标点,其取值范围如下:
然而在Opencv中,为了对HSV图像进行可视化,通常将其像素值转换到0~255之间:
对于图像中任意坐标点,其RGB颜色空间为(R,G,B),HSV颜色空间为(H,S,V),首先需要将R、G、B值转换到0~1之间:
然后计算H、S、V值:
如果计算得到的H值小于0,将该值再加上360,得到最终的H值:
由于Opencv需要做HSV图像的可视化,因此最后还需要将各个值转换到0~255之间:
ii.代码(c++)
Opencv提供了cvtColor函数,调用该函数可以非常方便地实现不同颜色空间的转换。
cv::Mat RGB2HSV(cv::Mat img)
{
cv::Mat hsv(img.size(), CV_32FC3);
float r=0.0, g=0.0, b = 0.0;
float _max = 0.0, _min = 0.0;
float h = 0.0, s = 0.0, v = 0.0;
for (int row = 0; row < img.rows; row++)
{
cv::Vec3b *currentData = img.ptr(row);
for (int col = 0; col < img.cols; col++)
{
r = (*(currentData + col))[2] / 255;
g = (*(currentData + col))[1] / 255;
b = (*(currentData + col))[0] / 255;
_max = max(r, max(g, b));
_min = min(r, min(g, b));
v = _max;
if (v == 0)
{
s = 0;
}
else
{
s = (v - _min) / v;
}
if (v == r)
{
h = 60 * (g - b) / (s*v);
}
else if (v == g)
{
h = 60 * (2 + (b - r) / (s*v));
}
else if (v == b)
{
h = 60 * (4 + (r - g) / (s*v));
}
else if (v == 0)
{
h = 0;
}
else
{
h = h + 360;
}
hsv.at(row, col)[0] = h;
hsv.at(row, col)[1] = s;
hsv.at(row, col)[2] = v;
}
}
return hsv;
}
然后丢给他一张图片
void rgb_hsv(void)
{
//读取原图像
Mat img = imread("pic_name", CV_LOAD_IMAGE_COLOR);
Mat img_hsv;
cvtColor(img, img_hsv, CV_BGR2HSV); //将RGB图像转换为HSV图像
}
iii)结果呈现
参考文章:数字图像处理——RGB与HSV图像互相转换原理_萌萌哒程序猴的博客-CSDN博客_rgb转hsv
数字图像处理(五)HSV变换_做个爱笑的大男孩的博客-CSDN博客_hsv变换
OpenCV学习笔记——HSV颜色空间超极详解&inRange函数用法及实战_小天狼星不来客的博客-CSDN博客_hsv函数