【计算机视觉(二)】常用颜色空间及其转换

前情提要

【计算机视觉(一)图像数据表示】中,我介绍了RGB灰度两种颜色空间,并且介绍了像素的概念以及在程序上如何访问。

本期内容

接下来介绍从RGB到灰度的转换,以及两种我常用的颜色空间HSV二值空间(严格来说属于灰度,只是只有0和255两个值)。

一、RGB转灰度

假如先不谈原理,RGB转灰度你会怎么做?先从我们知道的信息入手,RGB是三通道的,灰度只有一个通道,很自然的会联想到怎么把三个通道“融合”成一个通道,最直接的想法,也许是对于同一个RGB像素值,我们把这三个通道值求一个平均值作为灰度值。用公式表示一下就是:Gray = R * 1/3 + G * 1/ 3 + B * 1/3 。
好,那我们先来写这个程序看看效果。

# coding: utf-8
import cv2
import numpy as np

'''
函数名:rgb2gray_mean
功能:通过求通道平均值得到灰度图
输入:
img    输入的彩图
返回:
result    灰度图
'''
def rgb2gray_mean(img):
    ratio = 1.0 / 3
    # 转换类型
    int_img = img.astype(np.int32)
    
    result = ratio * (int_img[...,0]+int_img[...,1]+int_img[...,2])
    return result.astype(np.uint8)

# 程序入口
def main():
    # 读取lena图
    color = cv2.imread('../lena.jpg')
    # 转灰度
    gray = rgb2gray_mean(color)

    # 显示
    cv2.imshow('color', color)
    cv2.imshow('gray', gray)
    cv2.waitKey(0)

if __name__ == '__main__':
    main()

注意:在rgb2gray_mean函数中我对img做了一个类型转换并存放在int_img中,img的类型是numpy.uint8,也就是8位无符号整数,直接对里面的值进行相加很可能造成数值溢出,也就是255+1会变成0,因此要先用一个能容纳更大的值范围的矩阵装起来,比如int32类型的。这是新手经常会遇到的坑,切记切记。

好那我们来看看运行效果,再一次使用lena测试。


lena

运行的结果:


均值灰度

看起来还行。
OpenCV中也有自带的转换灰度的函数,cvtColor,代码也贴在这里:

gray = cv2.cvtColor(color, cv2.COLOR_BGR2GRAY)

注意第二个参数是BGR2GRAY,是的,OpenCV中默认的彩图通道排列是BGR(蓝绿红)而不是RGB,具体原因我也是道听途说,是因为一开始相机制造商从Sensor拿到的数据就是BGR的,这是他们制定的标准,尽管后来有很多软件也是默认采用RGB。
那么这个cvtColor的效果怎么样呢,请看


OpenCV转灰度

不知道你能否看出区别,不能的话请注意看头发的明暗交界处,cvtColor在本来该黑的地方更黑,该白的地方更白,就是对比度更强烈,还是看不出来的话用程序帮我们看看,数一下灰度值不相等的地方有多少个。

print np.sum(gray != cv_gray)

结果是:244157, 原图的大小是512x512,也就是总共262144个像素点,那这么看下来绝大部分的像素值都不一样,虽然我们看起来也要费点力才能看出来不同。这就说明OpenCV转灰度的方法跟我们拍脑门想的是不一样的,也就是对应到三个通道各自乘的系数是不一样的,假设:

Gray = a * R + b * G + c * B (a + b + c = 1)

a、b、c三个值应该怎么取能让图像看起来比较舒服呢?其实人眼对三原色的“偏好”是不一样的,研究表明人眼对红绿蓝的权重接近3:6:1,更精确的,对于上面的公式,a=0.299,b=0.587,c=0.114,这就是通常所说的心理学模型。在OpenCV中,为了减少浮点运算(浮点运算在一般的CPU中很耗时),使用了类似下面的转换方式:

'''
函数名:心理学模型转换灰度
输入:
img    输入的彩图
返回:
result    灰度图
'''
def rgb2gray_mental(img):
    # 转换类型
    int_img = img.astype(np.int32)
    result = (int_img[...,2]*299 + int_img[...,1]*587 + int_img[...,0]*114 + 500) / 1000
    return result.astype(np.uint8)

经过测试,这跟OpenCV自带的转换函数cvtColor的效果是一模一样的。

二、HSV空间

HSV空间是由RGB空间演变过来的,RGB空间在几何上是一个正方体(详情请查阅【计算机视觉(一)图像数据表示】),而当你从正方体的一个顶点看向离它最远的另一个顶点时,就会看到一个六角锥体,这就是HSV空间的几何表达,如下图:

六角锥体

通常,我们会把顶上的这个六边形近似成一个圆,就变成了一个圆锥,像这样:
HSV圆锥

HSV三个轴的走动方向也在图上标出了,可以理解为一个有深度的极坐标系,我们只看Hue轴,沿着圆周方向走,可以看到每转动一定的角度,所表示的颜色就变了,而且不止红绿蓝,事实上这对应了我们认知上的所有颜色,因此,使用HSV空间的好处就是只要一个维度我们就能表示物体本来的颜色。那其他两个轴是表达什么信息的呢?具体可以参考百度百科,我这里只说些个人见解。S维度表示饱和度,更通俗的说,是打在物体上的白灯的亮度,比如你在黑夜中用手电筒照着个苹果,电量足够的话苹果看上去当然是正常的红色,电量不够也许看上去是暗红色,关掉手电也就啥都看不到黑漆漆一片了,这就是S维度的信息。V维度表示了一种物体自身的材质信息,是不是透明的,透明度有多少,同样拿照苹果这个例子,如果现在这个苹果换成了水晶苹果,灯光打上去以后看到的颜色也是不一样的,即使当初涂的颜色跟真实的苹果颜色一样,这是由于一些漫反射和折射造成的。

HSV的值域跟RGB的并不一样,其中H维度的值域是0-180,其他两个维度都是0-255,H不取到0-360也许是因为超过了uchar的范围。

HSV空间对颜色的描述是用户友好的,而RGB是硬件友好的。HSV空间在我日常学习中更多是作为颜色筛选的基础,人眼能区分的不同颜色的范围对应HSV的值都比较固定,下面是一个对照表:


HSV颜色对照表

现在举个实际应用的案例,比如我要对下面的图片做车牌识别,我的第一步是要把车牌的区域抠出来,车牌的底色是蓝色的,当然宝马的标志也有蓝色,但我们可以不管三七二十一先把蓝色的东西都抠出来再做筛选,这时候就可以用HSV空间。


车车

图片刚读入的时候是BGR格式的,这时候又要用到cvtColor转换到HSV,示例代码如:

hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV)

显示HSV的效果如下:


hsv.jpg

现在我们要的是蓝色区域,查找上面的对照表就可以知道,我们要的是H值在100到124,S值在43到255,V值在46到255之间的像素点。怎么表达这个“要”跟“不要”呢?我们可以这么考虑,对于每个像素点只有“要”和“不要”两种状态,就像一盏灯的开关一样,于是我们可以创建一幅等大的图,在上面,“要”的像素点设为一个值,“不要”的像素点设为另一个值,这就是接下来要说的二值图,我也喜欢称其为掩码图。

三、二值图(掩码图)

二值图本质上是灰度图,只是只用了0和255两个值,用0表示“不要”,255表示“要”,整幅图看起来就是符合条件的区域是白色的,不符合的是黑色的。对上面的HSV图作这种条件筛选处理,叫做二值化,OpenCV已经为我们准备了对应的函数cv2.inRange,示例代码如下:

mask = cv2.inRange(hsv, np.array([100,43,46]), np.array([124,255,255]))

处理完的结果如下图:


mask.jpg

可以看到,尽管有很多干扰的白色区域,车牌区域还是在里面,我们只要采取进一步的手段就可以把车牌区域筛选出来,这就要涉及一些形态学处理,敬请期待下一篇文章。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容