在图像处理中,颜色转换是常见模块。为什么要用上颜色转换呢?因为我们拍摄的图像通常是RGB格式的,五颜六色。这种颜色对计算机是好识别的,但是对人的肉眼不友好,因为人的肉眼对红色等很多颜色不敏感。这样我们就需要RGB格式转换为HSV,HSL,YUV颜色模型进行处理。
也就是说:RGB图像与相机传感器输出的原始数据相对应,HSV图像则与我们人类的直观视觉更相符。
RGB
RGB 代表红绿蓝(Red, Green, Blue)
在 RGB 模型中,颜色由不同强度的红色、绿色和蓝色光的组合来创建。这三种基本颜色的不同组合产生了各种颜色。
在 RGB 模型中,每个颜色通道的强度通常以数字值表示,取值范围为 0 到 255,其中 0 表示没有该颜色的强度,255 表示该颜色通道的最大强度。
例如,RGB 代码 RGB(255, 0, 0) 表示纯红色,其中:
255
表示红色通道的强度为最大(红色)。0
表示绿色通道的强度为零(没有绿色)。0
表示蓝色通道的强度为零(没有蓝色)。
这样对比地引出了HSV颜色模型
HSV
HSV 代表色相(Hue)、饱和度(Saturation)和明度(Value)。 这个模型是通过人类对颜色的感知方式设计的,更符合人们对颜色的主观感受。
以下是HSV 模型的三个组成部分:
-
H(色相 - Hue): 表示颜色的种类,它是一个在0到360度之间的角度值。色相值对应于光谱上的不同颜色,比如红色、绿色、蓝色等。
-
S(饱和度 - Saturation): 表示颜色的纯度或强度。饱和度为0表示灰度,即一种无色。饱和度为100%表示颜色是纯净的,没有被白色或其他颜色混合。也就是说 S 控制纯色中混入白色的量,值越大,白色越少,颜色越纯;
-
V(明度 - Value): 表示颜色的亮度。明度为0表示黑色,明度为100%表示白色。。也就是说V 控制纯色中混入黑色的量,值越大,黑色越少,明度越高
HSV 模型的优势在于它更符合人们对颜色的感知。
HSV 和 HSL 在字面意思上是一样的:
- H 指的是色相(Hue),就是颜色名称,例如“红色”、“蓝色”;
- S 指的是饱和度(Saturation),即颜色的纯度;
- L(Lightness) 和 V(Value)是明度,颜色的明亮程度
在原理和表现上,HSL 和 HSB 中的 H(色相) 完全一致,但二者的 S(饱和度)不一样, L 和 B (明度 )也不一样:
- HSV 中的 S 控制纯色中混入白色的量,值越大,白色越少,颜色越纯;
- HSV 中的 V 控制纯色中混入黑色的量,值越大,黑色越少,明度越高
- HSL 中的 S 和黑白没有关系,饱和度不控制颜色中混入黑白的多寡;
- HSL 中的 L 控制纯色中的混入的黑白两种颜色。
Opencv提供了cvtColor函数,调用该函数可以非常方便地实现不同颜色空间的转换。不过为了可视化,调用该函数得到的HSV图像,其H、S、V三通道的取值范围是经过转换的0~180、0~255、0~255。
import cv2 as cv cv.cvtColor(src, code[,dst[,dstCn]])
其中,src代表原图像,code表示转换的类型。例如:对于BGR→HSV,我们使用标志cv.COLOR_BGR2HSV。
举例:
img = cv2.imread("./images/test.jpg") # 换到 HSV hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
RGB到HSV的转换是如何进行的?
RGB到HSV的转换使用数学计算进行。
- 首先,将RGB值标准化,即将每个成分的值转换为0到1的范围。
- 然后找到最小值(R、G、B中的最小值)和最大值(R、G、B中的最大值)。
- 计算色相(Hue)。如果最大值等于最小值,则色相为0。
- 计算饱和度(Saturation)。饱和度计算为(max-min)/max。
- 计算明度(Value)。明度与最大值相同。
比如
RGB是(255,0,0)的最小值是0,最大值是255, 在R通道,以最大值为准,H色度为红色,S饱和度 (255-0)/255=1 ,没有混入白色。明度是255,最大,故按比例缩放是1,没有混入黑色。所以是纯红。再按照比例转成hsv 模型,如下图的六角锥形。可见红色是0度。进一步地,再转换为0~180、0~255、0~255范围
注意:
- 从一个色彩空间转换到另一个色彩空间,信息传递会损失;
- HSV的色相范围为[0,179],饱和度范围为[0,255],值范围为[0,255]。
-
色彩空间转换可能可逆,也可能不可逆。A转成了B.B再转成A,可能可以回到原图,可能无法回到原图。比如BRG转成HSV,再转回BRG,可以回到原图。
import cv2 as cv def reversible_demo(): img = cv.imread('./images/butterfly.jpg') cv.imshow('Original Image', img) hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV) cv.imshow('BGR2HSV Image', hsv) # 逆转原图 hsv2bgr = cv.cvtColor(hsv, cv.COLOR_HSV2BGR) cv.imshow('HSV2BGR Image', hsv2bgr) cv.waitKey(0) cv.destroyAllWindows() if __name__ == "__main__": reversible_demo()
可逆
BGR转成GRAY 类型(GRAY色彩空间:GRAY(灰度图像)通常指8位灰度图,其具有256个灰度级,像素值的 范围是[0,255]。)再转回BGR类型
import cv2 as cv def irreversible_demo(): img = cv.imread('./images/butterfly.jpg') cv.imshow('Original Image', img) gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) cv.imshow('BGR2GRAY Image', gray) # 逆转原图 gray2bgr = cv.cvtColor(gray, cv.COLOR_GRAY2BGR) cv.imshow('GRAY2BGR Image', gray2bgr) cv.waitKey(0) cv.destroyAllWindows() if __name__ == "__main__": irreversible_demo()
不可逆
实际案例分析
将一个红色的密封圈实物特征提取出来。根据下图模块流程。
注意读取源图像时需选择RGB格式
不能选择MONO8格式,MONO8格式为灰度图。
我们发现改成RGB格式,模块就变绿了,没报错。报错原因就是选择的图像的格式不对。
接着,二值化把HSV图像的第一通道的阈值在245-255,即红色(红色的色度范围是0-10,或者156-180)的特征----图像特征提取出来
目前存疑的是,红色的色度为156-180,因为色度范围是0-180.转为二值化阈值应该按照比例换算过来。阈值范围是0-255。所以二值化阈值应该不是156-180.应该是245-255
怎么样才是准确地提取红色的实物?