在本教程中,我们将了解计算机视觉中经常使用的色彩空间,并将其用于基于颜色的分割。我们还将用C ++和Python分享演示代码。
RGB色彩空间
RGB颜色空间具有以下属性
1. 它是一种加色空间,其中颜色通过红色,绿色和蓝色值的线性组合获得。
2. 三个通道通过照射到表面的光量相关联。
让我们将这两个图像分成R,G和B分量并观察它们以更深入地了解色彩空间。
图1:RGB颜色空间的不同通道:蓝(B)绿(G)红(R)
如果你看一下蓝色通道,可以看到在室内光照条件下图像中的蓝色和白色部分看起来相似,但和室外的图像有明显区别。这种不均匀性使得在该颜色空间中基于颜色的分割非常困难。此外,两个图像的值之间存在总体差异。下面我们总结了与RGB颜色空间相关的固有问题:
1. 显着的感知不均匀性。
2.色度(颜色相关信息)和亮度(强度相关信息)数据的混合。
LAB色彩空间
Lab颜色空间有三个组成部分。
1. L - 亮度(强度)。
2. a - 颜色组成分布范围是从绿色到洋红色。
3. b - 颜色组成分布范围是从蓝色到黄色。
Lab颜色空间与RGB颜色空间完全不同。在RGB颜色空间中,颜色信息被分成三个通道,而且相同的三个通道也编码亮度信息。另一方面,在Lab颜色空间中,L通道独立于颜色信息并且只编码亮度。另外两个通道编码颜色。
它具有以下属性。
1. 感知上均匀的色彩空间近似于我们如何感知色彩。
2. 独立于设备(捕获或显示)。
3. 广泛用于Adobe Photoshop。
4. 通过复数变换方程与RGB颜色空间相关。
让我们看一下Lab颜色空间中的两个图像分成三个通道。
brightLAB = cv2.cvtColor(bright, cv2.COLOR_BGR2LAB)
darkLAB = cv2.cvtColor(dark, cv2.COLOR_BGR2LAB)
图2:LAB颜色空间中的亮度(L)和颜色分量(A,B)
1. 从图2中可以清楚地看出,光照的变化主要影响L分量。
2. 包含颜色信息的A和B组分没有经历大的变化。
3. 绿色,橙色和红色(它们是A成分的极值)的相应值在B组分中没有变化,同样地,蓝色和黄色(它们是B成分的极值)的相应值在A组分中也没有变化。
YCrCb色彩空间
YCrCb颜色空间源自RGB颜色空间,并具有以下三个组分。
1. Y – 在伽马校正后从RGB获得的亮度或亮度分量。
2. Cr = R - Y(红色分量离亮度有多远)。
3. Cb = B - Y(蓝色分量离亮度有多远)。
此颜色空间具有以下属性。
1. 将亮度和色度分量分成不同的通道。
2. 主要用于电视传输的压缩(Cr和Cb组件)。
3. 取决于设备。
YCrCb颜色空间中分成其通道的两个图像如下所示
brightYCB = cv2.cvtColor(bright, cv2.COLOR_BGR2YCrCb)
darkYCB = cv2.cvtColor(dark, cv2.COLOR_BGR2YCrCb)
图3:YCrCb颜色空间中的亮度(Y)和色度(Cr,Cb)分量
意见
1. 对于光照变化,可以针对强度和颜色分量对LAB进行类似的观察。
2. 与LAB相比,室外图像中红色和橙色之间的感知差异较小。
3. White已经在所有3个组件中发生了变化。
HSV色彩空间
HSV色彩空间具有以下三个组成部分
1. H-色调(主波长)。
2. S-饱和度(颜色的纯度/色调)。
3. V-值(强度)。
让我们列举一些属性。
1. 最好的是它只使用一个通道来描述颜色(H),这使得指定颜色变得非常直观。
2. 取决于设备。
两个图像的H,S和V分量如下所示。
brightHSV = cv2.cvtColor(bright, cv2.COLOR_BGR2HSV)
darkHSV = cv2.cvtColor(dark, cv2.COLOR_BGR2HSV)
图4:HSV颜色空间中的色调(H),饱和度(S)和值(V)分量
意见
1. H分量在两个图像中非常相似,这表明即使在光照变化下颜色信息也是完整的。
2. 两个图像中的S分量也非常相似。
3. V分量捕获落在其上的光量,因此它会因照明变化而发生变化。
4. 室外和室内图像的红色值之间存在巨大差异。这是因为Hue表示为圆形,红色表示起始角度。因此,它可能需要[300,360]和[0,60]之间的值。
如何使用这些颜色空间进行分割
最简单的方法
现在我们已经了解了不同的颜色空间,让我们首先尝试使用它们来检测立方体中的绿色。
第1步:获取特定颜色的颜色值
找到每个颜色空间的绿色值的近似范围。为此,我创建了一个交互式GUI,您可以通过将鼠标悬停在图像上来检查每个像素的所有颜色空间的值,如下所示:
图5:Demo显示室外图像的不同颜色空间中的像素及其值
第2步:应用分段阈值
从图像中提取具有接近绿色像素值的所有像素。我们可以为每个颜色空间采用+/- 40的范围,并检查结果的样子。我们将使用opencv函数inRange来查找绿色像素的掩模,然后使用bitwise_and操作来使用掩模从图像中获取绿色像素。
代码如下:
bgr = [40, 158, 16]
thresh = 40
minBGR = np.array([bgr[0] - thresh, bgr[1] - thresh, bgr[2] - thresh])
maxBGR = np.array([bgr[0] + thresh, bgr[1] + thresh, bgr[2] + thresh])
maskBGR = cv2.inRange(bright,minBGR,maxBGR)
resultBGR = cv2.bitwise_and(bright, bright, mask = maskBGR)
# 将1D数组转换为3D,然后将其转换为HSV,并获取第一个元素
# 这将与上面的图相同[65,229,158]
hsv = cv2.cvtColor( np.uint8([[bgr]] ), cv2.COLOR_BGR2HSV)[0][0]
minHSV = np.array([hsv[0] - thresh, hsv[1] - thresh, hsv[2] - thresh])
maxHSV = np.array([hsv[0] + thresh, hsv[1] + thresh, hsv[2] + thresh])
maskHSV = cv2.inRange(brightHSV, minHSV, maxHSV)
resultHSV = cv2.bitwise_and(brightHSV, brightHSV, mask = maskHSV)
# 将1D数组转换为3D,然后将其转换为YCrCb,并获取第一个元素
ycb = cv2.cvtColor( np.uint8([[bgr]] ), cv2.COLOR_BGR2YCrCb)[0][0]
minYCB = np.array([ycb[0] - thresh, ycb[1] - thresh, ycb[2] - thresh])
maxYCB = np.array([ycb[0] + thresh, ycb[1] + thresh, ycb[2] + thresh])
maskYCB = cv2.inRange(brightYCB, minYCB, maxYCB)
resultYCB = cv2.bitwise_and(brightYCB, brightYCB, mask = maskYCB)
# 将1D数组转换为3D,然后将其转换为LAB,并获取第一个元素
lab = cv2.cvtColor( np.uint8([[bgr]] ), cv2.COLOR_BGR2LAB)[0][0]
minLAB = np.array([lab[0] - thresh, lab[1] - thresh, lab[2] - thresh])
maxLAB = np.array([lab[0] + thresh, lab[1] + thresh, lab[2] + thresh])
maskLAB = cv2.inRange(brightLAB, minLAB, maxLAB)
resultLAB = cv2.bitwise_and(brightLAB, brightLAB, mask = maskLAB)
cv2.imshow("Result BGR", resultBGR)
cv2.imshow("Result HSV", resultHSV)
cv2.imshow("Result YCB", resultYCB)
cv2.imshow("Output LAB", resultLAB)
图6:RGB看起来不错,可能我们只是在这里浪费时间
因此,似乎RGB和LAB足以检测颜色,我们不需要多想。让我们看看更多的结果
图7:对室内图像应用相同的阈值无法检测所有颜色空间中的绿色立方体
因此,相同的阈值对暗图像不起作用。进行相同的实验以检测黄色会产生以下结果。
图8:尝试使用从明亮图像获得的相同技术和阈值(黄色)检测黄色碎片。HSV和YCrCb仍然表现不佳
可见阈值的设置对我们检测颜色是多么的重要
色彩空间的其他有用应用
1. 直方图均衡通常在灰度图像上完成。但是,你可以通过将RGB图像转换为YCbCr并仅对Y通道进行直方图均衡来执行彩色图像的均衡。
2. 通过将图像转换为Lab颜色空间,在两个图像之间进行颜色转换。
3. 智能手机相机应用程序(如Google相机或Instagram)中的许多滤镜都会利用这些色彩空间变换来创建这些炫酷效果!