一、颜色空间讲解
颜色空间也称彩色模型,在计算机视觉的角度来看就是组成一张图片的多组RGB所构成的一个数据集,通过对特定范围内的色域进行筛选就可以实现图像分割。那么如何进行筛选呢,这时候需要先介绍几组颜色空间的类别。
1.RGB颜色空间
RGB(红绿蓝)是依据人眼识别的颜色定义出的空间,可表示大部分颜色。但在科学研究一般不采用RGB颜色空间,因为它的细节难以进行数字化的调整。它将色调,亮度,饱和度三个量放在一起表示,很难分开。自然环境下获取的图像容易受自然光照、遮挡和阴影等情况的影响,即对亮度比较敏感。而 RGB 颜色空间的三个分量都与亮度密切相关,即只要亮度改变,三个分量都会随之相应地改变,而没有一种更直观的方式来表达。但是人眼对于这三种颜色分量的敏感程度是不一样的,在单色中,人眼对红色最不敏感,蓝色最敏感,所以 RGB 颜色空间是一种均匀性较差的颜色空间。如果颜色的相似性直接用欧氏距离来度量,其结果与人眼视觉会有较大的偏差。对于某一种颜色,我们很难推测出较为精确的三个分量数值来表示。它是最通用的面向硬件的彩色模型。该模型用于彩色监视器和一大类彩色视频摄像。
2.HSV
在图像处理中使用较多的是 HSV 颜色空间,它比 RGB 更接近人们对彩色的感知经验。非常直观地表达颜色的色调、鲜艳程度和明暗程度,方便进行颜色的对比。
HSV由三部分组成:
- Hue:色调(色调是指图像的相对明暗程度,在彩色图像上表现为颜色。)
- Saturation:饱和度
- Value:明度(明度是眼睛对光源和物体表面的明暗程度的感觉)
3.CMY/CMYK
CMY是工业印刷采用的颜色空间。它与RGB对应。简单的类比RGB来源于是物体发光,而CMY是依据反射光得到的。具体应用如打印机:一般采用四色墨盒,即CMY加黑色墨盒。其中各个英文字母缩写代表如下青(Cyan)、洋红(或品红)(Magenta)、黄(Yellow)和黑色(Black)。
4.HLS
HLS颜色空间,三个分量分别是色相(H)、亮度(L)、饱和度(S),这三个分量进行数字化处理,HLS与HSV比较类似,唯一区别就是Value表示明度,Light表示亮度。
5.Lab(CIELAB)
Lab是由一个亮度通道(channel)和两个颜色通道组成的。在Lab颜色空间中,每个颜色用L、a、b三个数字表示,各个分量的含义是这样的:
- L*代表亮度
- a*代表从绿色到红色的分量
- b*代表从蓝色到黄色的分量
Lab有个很好的特性——设备无关(device-independent)。也就是说,在给定了颜色空间白点(white point)(下图中表示了一种颜色空间的白点)之后,这个颜色空间就能明确地确定各个颜色是如何被创建和显示的,与使用的显示介质没有关系。
6.YUV
YUV色彩模型利用人类视觉对亮度的敏感度比对色度的敏感度高的特点获得较RGB色彩模型的优势,为彩色电视系统广泛使用。YUV色彩模型将亮度信息从色度信息中分离了出来,并且对同一帧图像的亮度和色度采用了不同的采样率。在YUV色彩模型中,亮度信息Y与色度信息U\V相互独立。Y信号分量为黑白灰度图。U、V信号分量为单色彩色图。黑白电视只利用Y分量,也解决了黑白电视和彩色电视的兼容问题。
YUV的采样格式如图所示:
4:4:4,YUV三个分量具有相同的水平和垂直解析度。4:2:2,YUV三个分量具有相同的垂直解析度,但在水平方向上,UV两个分量的解析度是Y的一半。即每4个亮度分量样本值,对应有2个U和2个V色度分量样本值。4:2:0,在水平方向上和垂直方向上,UV两个分量的解析度是Y的一半,即每4个亮度分量样本值,对应有1个U和1个V色度分量样本值。
二、使用
使用颜色空间进行图像分割的本质就是设置一个mask层,mask就是自己设置一个hsv颜色范围。通过对颜色的过滤得到自己想要的图像区域。这里需要的python库为opencv-python numpy matplotlib ,numpy不需要导入,opencv需要numpy,所以导入opencv的过程中,自动下载numpy
pip3 install opencv-python
pip install matplotlib
1.图像降噪
噪声一般被认为是平均值为零的随机变量。考虑一个有噪声的像素,p=p0+n,其中p0是像素的真实值,n是该像素中的噪声。可以从不同的图像中获取大量相同的像素(例如n),并计算它们的平均值。理想情况下,你应该得到p=p0,因为噪声的平均值是零。
opencv提供了这种技术的四种变体。
cv2.fastnlmeansdenosing()-用于单个灰度图像
cv2.fastnlmeansdenisingcolored()-用于彩色图像。
cv2.fastnlmeansdenisingmulti()-处理短时间内捕获的图像序列(灰度图像)
cv2.fastnlmeansdenisingcoloredmulti()-与上面相同,但用于彩色图像。
共同参数有:
- h : 决定过滤器强度。h 值高可以很好的去除噪声,但也会把图像的细节抹去。(取 10 的效果不错)
- hForColorComponents : 与 h 相同,但使用与彩色图像。(与 h 相同,10)
- templateWindowSize : 奇数。(推荐值为 7)
- searchWindowSize : 奇数。(推荐值为 21)
下面就最基本的cv2.fastnlmeansdenosing()函数进行探究:
L-Means的全称是:Non-Local Means,直译过来是非局部平均,在2005年由Baudes提出,该算法使用自然图像中普遍存在的冗余信息来去噪声。与常用的双线性滤波、中值滤波等利用图像局部信息来滤波不同的是,它利用了整幅图像来进行去噪,以图像块为单位在图像中寻找相似区域,再对这些区域求平均,能够比较好地去掉图像中存在的高斯噪声。与我们以前学习的平滑技术相比这种算法要消耗更多的时间,但是结果很好。对于彩色图像,要先转换到 CIELAB 颜色空间,然后对 L 和 AB 成分分别去噪。
实操
import cv2
import matplotlib.pyplot as plt
import numpy as np
soil=cv2.imread('img/800-3.jpeg')
soil=cv2.cvtColor(soil,cv2.COLOR_BGR2RGB)#保持图片本来的颜色
dst = cv2.fastNlMeansDenoisingColored(soil, None, 10, 10, 7, 21)
plt.subplot(1, 2, 1)
plt.imshow(soil)
plt.subplot(1, 2, 2)
plt.imshow(dst)
plt.show()
2.查看颜色空间
一般来说图像分割选取HSV,抱着学习的态度,我同时查看的RGB颜色空间和HSV颜色空间
上图是原图,通过函数可得到HSV颜色空间
def getHSV(soil):
hsv_soil = cv2.cvtColor(soil, cv2.COLOR_RGB2HSV)
h, s, v = cv2.split(hsv_soil)
fig = plt.figure()
axis = fig.add_subplot(1, 1, 1, projection="3d")
pixel_colors = soil.reshape((np.shape(soil)[0] * np.shape(soil)[1], 3))
norm = colors.Normalize(vmin=-1., vmax=1.)
norm.autoscale(pixel_colors)
pixel_colors = norm(pixel_colors).tolist()
axis.scatter(h.flatten(), s.flatten(), v.flatten(), facecolors=pixel_colors, marker=".")
axis.set_xlabel("Hue")
axis.set_ylabel("Saturation")
axis.set_zlabel("Value")
plt.savefig("hsv.png")
plt.show()
通过函数可得到RGB颜色空间
def getRGB(soil):
r,g,b = cv2.split(soil)
fig = plt.figure()
axis = fig.add_subplot(1,1,1,projection="3d")
pixel_colors = soil.reshape((np.shape(soil)[0] * np.shape(soil)[1], 3))
norm = colors.Normalize(vmin=-1., vmax=1.)
norm.autoscale(pixel_colors)
pixel_colors = norm(pixel_colors).tolist()
axis.scatter(r.flatten(), g.flatten(), b.flatten(), facecolors=pixel_colors, marker=".")
axis.set_xlabel("Red")
axis.set_ylabel("Green")
axis.set_zlabel("Blue")
plt.savefig("rgb.png")
plt.show()
我们想做的是图片中的泥土识别,显然在HSV空间中泥土色更加本地化,视觉上更加分离,我们可以通过HUE坐标轴上的数值选取确定大概的HSV颜色空间。
3.mask制作
这个板块内容相对较好理解,但是难点是确认颜色范围,因为我们的想法是不可控的,所以并没有一个参考表给我们用来选取颜色范围,那么如何选择自己的颜色空间呢?这里我提供一个自己的思路:
3.1 观看HSV图
通过查看HSV图,我们大致确定泥土的颜色位于(0,50,0)到(50,255,255)之间,这里的数值范围为0~255,在初次选择范围时,尽量选择范围相对较大,这样可以把自己的想要的事物包含在里面。
3.2 查看颜色选择器,缩小范围(鸡肋)
在线拾色器
RGB转HSV
大概的操作过程就是在拾色器里选好RGB颜色后,复制颜色编码然后到转化网址输入编码输入convert,得到HSV颜色。
3.3 查看颜色选择范围以及效果
话不多说上代码:
light_brown = (15, 43, 46)
#查看选的颜色范围
dark_brown = (17, 255, 255)
lo_square = np.full((10, 10, 3), light_brown, dtype=np.uint8) / 255.0
do_square = np.full((10, 10, 3), dark_brown, dtype=np.uint8) / 255.0
plt.subplot(1, 2, 1)
plt.imshow(hsv_to_rgb(do_square))
plt.subplot(1, 2, 2)
plt.imshow(hsv_to_rgb(lo_square))
plt.show()
#查看图像分割结果
hsv_soil = cv2.cvtColor(soil, cv2.COLOR_RGB2HSV)
mask = cv2.inRange(hsv_soil, light_brown, dark_brown)
result = cv2.bitwise_and(soil, soil, mask=mask)
plt.subplot(1, 2, 1)
plt.imshow(mask, cmap="gray")
plt.subplot(1, 2, 2)
plt.imshow(result)
plt.show()
我们再次回顾一下原图
可以看到两块大面积沙土
下面是我们选择颜色范围
为了提高检测范围,我没有设置s和v,只对颜色的具体范围进行了设置。左边是灰度图,右边是分割后的有色图。效果相对还行。
3.4 调参
懂得都懂,化身成为大聪明
4.总结
由于opencv并没有类似于机器学习训练与预测,我们只是使用了物体的颜色进行图像分割,所以,算法的迁移性并不好,一个物体可能在不同的光强下,拍摄出的图片用分割出的结果存在误差。而且我们也要考虑相似颜色的其他物体对图像分割的影响。例如泥土和铁锈。
三、参考
这篇文章参考了以下内容,感谢各位作者
https://zhuanlan.zhihu.com/p/67930839
https://blog.csdn.net/jane_6091/article/details/80633680
https://blog.csdn.net/gdymind/article/details/82357139
https://blog.csdn.net/zhangping1987/article/details/73699335
https://zhuanlan.zhihu.com/p/28741691
https://zhuanlan.zhihu.com/p/67930839
https://www.cnblogs.com/fydeblog/p/9737261.html
https://blog.csdn.net/xiao_lxl/article/details/95346589
https://blog.csdn.net/qq_38410428/article/details/93046099