- 图像视频滤镜与人像美颜美妆算法详解
- 胡耀武等
- 4702字
- 2025-02-17 13:45:48
1.2 图像颜色空间
从本节开始,我们将学习一些基础的图像处理理论知识,并用代码进行简单的实现。当然,你可以将这些知识理解为 PS 背后的秘密,毕竟在任何图像处理软件的背后,都是一些图像算法。颜色空间也称为颜色模式,本节主要介绍四种最常用的颜色空间:RGB 颜色空间、HSⅤ颜色空间、YUⅤ颜色空间和 CIELab颜色空间。这四种颜色空间在 PS算法实现与后续章节美颜美妆滤镜算法实现过程中经常会被用到。
1.2.1 RGB颜色空间
知识点
RGB 颜色空间是图像处理中常用的一种颜色模型。在该模型中,所表示的图像由三个分量图像组成,每个分量图像都是其原色图像,三个分量图像按照红、绿、蓝三基色混合产生一幅彩色图像[1-2],示意图如图 1.11 所示。通俗来讲,每张图像可以分为三个通道分量:Red 分量、Green分量、Blue分量,每个分量的图像都是由一个个值为 0~255的像素组成的,三个分量共同组成了一个彩色像素的 RGB值。比如,一张彩色图像(i, j)坐标位置的彩色像素P可以表示为P(R, G, B)=(255,0,0),那么P点像素即为红色点。

图1.11 彩色图像的R、G、B分量组成示意图
图像RGB模型在笛卡儿坐标系中表示为一个颜色立方体,如图1.12所示。

图1.12 RGB颜色立方体示意图
在该颜色立方体中,红、绿、蓝三种单色分别为立方体的三个顶点,黑、白、青、黄、深红分别为立方体的其他顶点,任何一种颜色都可以用 RGB 的三维坐标(r, g,b)来表示。R、G、B三个分量的取值范围为 0~255,也就是 256个值,因此该立方体可以表示的颜色种类为 256×256×256种,即224种颜色。
RGB颜色空间总结如下:
· 任何一张图像都是由一个个像素点组成的,可以将其理解为一张平面二维图,而每个像素点的值都可以用一个 RGB 三维坐标值来表示,三维坐标分别代表像素 R、G、B三个分量的值。
· RGB颜色空间在笛卡儿坐标系中表示为一个立方体,该立方体可以表示2 24种颜色。
图像S中的一个像素P,位置坐标为(i, j),它的像素值为R=r、G=g、B=b,那么可描述如下:

编程实现
下面开始本书第一个DEMO:像素RGB值获取DEMO。
该DEMO通过输入图像像素坐标来获取对应像素的RGB值,然后显示在屏幕中。读取像素值的算法接口由C代码实现,上层使用C#WinForm来调用。这个逻辑有些啰唆,因为这个简单功能完全可以直接使用 C#WinForm来实现。不过,这里的重点不是代码,而是教会大家一个做图像算法研究的常用逻辑框架,如图1.13所示。

图1.13 通用软件开发逻辑框架
在该框架中,将图像算法产品分为上层模块和底层模块两个部分。底层模块使用 C/C++实现算法API,提供给上层模块调用,上层模块执行调用API和一些界面功能的实现,最后得到不同平台的软件产品。
一般而言,使用C/C++进行图像算法API开发,具有安全、高效和方便多平台移植的优点,目前大多数图像软件都是基于C/C++来开发的。
本节使用 C#来做上层调用与界面设计,是因为 C#具有优秀的面向对象能力,界面设计方便快捷,而且对于图像读取、保存、显示已经做了良好的封装,避免了图像编解码的问题,相比使用MFC大大简化了开发逻辑,提升了开发效率。
言归正传,这里提供一个通用的基础 DEMO框架,该框架由 C#工程调用 C工程组成,C工程编译动态链接库。然后,C#调用动态链接库实现图像算法,在界面中显示效果。DEMO源码可参见本书附带代码包中 1.3.1文件夹中的文件,整个 DEMO包括 C#部分和 C部分。在C#部分中,包括两个模块:图像的读取、显示、保存模块和调用 C动态链接库模块;在 C部分主要实现算法API。
· 图像读取、显示、保存模块
下面直接给出模块代码,大家可以直接使用,这里不对 C#图像处理做具体解释,对于初学者,可以参考赵春江老师编著的《C#数字图像处理算法典型实例》一书,代码如下所示:




在该模块中包含Open、OK、Save三个按钮,分别用于打开图像、对图像算法进行调用和保存图像,界面如1.14所示。

图1.14 C#基础DEMO界面
界面中的 TC 标签用来显示算法调用时间,右边的矩形框用来显示图像。后面在做算法研究时,我们只需在OK按钮事件中调用底层算法API即可。
· C#调用C动态链接库模块
在C#中调用C/C++动态链接库需要引用System.Runtime.InteropServices命名空间,实例代码如下:


在这段代码中,由于图像模式为 RGB颜色模式,因此,图像格式为 PixelFormat.Format24-bppRgb;如果是 BGRA 颜色模式,则图像格式为 PixelFormat.Format32bppArgb。该代码可以作为模板,方便大家使用,这里定义了f_Test的接口API,提供给C#进行调用。
如果你是初学者,那么可以阅读以下代码注释:


· C层图像算法模块
该部分实现了一个空接口f_Test,该接口用于各种算法的实现,代码如下:

最后,在头文件中 EXPORT 即可。关于 EXPORT,这里指的是在对应接口的头文件.h中,让C/C++函数接口对外部可见,也就是使用extern关键字指定。这里给出一个通用的标准模板,如下所示:


有了上述定义,我们的接口就可以对外暴露了。也就是说,用 C#就可以调用到接口了,否则,是无法调用的。
在上述这个通用的基础 DEMO 中,我们实现了图像的打开、保存和显示,以及一个f_Test 的效果调用。可以以此为基础,仿照 f_Test 接口来实现各种图像算法,这样比起 MFC来说就事半功倍了。
构建C实现获取像素RGB值的API代码如下所示:

DEMO 效果如图 1.15 所示。在图中,用鼠标单击图像,界面上就会显示对应位置像素的RGB值。
在该DEMO中,随着光标的滑动,会动态显示光标所在位置对应图像像素的RGB值。
本节的所有代码工程及DEMO见代码包中1.3.1文件夹中的文件。

图1.15 像素获取DEMO界面图
至此,本节关于RGB颜色空间的内容讲述完毕,希望能给大家带来一些新的认识。
1.2.2 HSV颜色空间
知识点
HSⅤ(Hue、Saturation、Ⅴalue)颜色空间是根据颜色的直观特性,由A.R.Smith在1978年创建的一种颜色空间,也称六角锥体模型(Hexcone Model),在 Photoshop 中也可使用HSⅤ颜色空间。
HSⅤ的颜色特性如下。
· 色相(Hue):表示色彩,用一个 0°~360°的圆形表示不同色彩,如图 1.16 所示。其中 0°表示红色,60°表示黄色,120°表示绿色,180°表示青色,240°表示蓝色,300°表示深红色,以此与RGB的立方体顶点对应起来。
· 饱和度(Saturation):表示色彩的纯度或者颜色接近光谱色的程度。饱和度的取值范围通常为0~1.0,值越大,纯度越高,接近光谱色的程度也就越高,图像越鲜艳;反之,纯度越低,图像也就越接近灰度图。
· 明度(Ⅴalue):表示色彩的明亮程度,取值范围通常为 0~1.0,明度越高,色彩越亮;反之,色彩越暗。

图1.16 Hue色相圆
HSⅤ的颜色空间模型是一个六棱锥,如图1.17所示。

图1.17 HSⅤ颜色空间模型
H 参数表示色彩信息,即所处的光谱颜色的位置,该参数用一个角度量来表示,红、绿、蓝分别相隔120°,互补色相差180°。
S 为一个比值,范围为 0~1,它表示所选颜色的纯度和该颜色最大的纯度之间的比率。S=0时,只有灰度。
V表示色彩的明亮程度,范围为0~1。
了解了 HSⅤ的颜色特性之后,就可以在实际使用中将 RGB颜色值转换为 HSⅤ颜色值,然后对色相、饱和度和明度进行调整。达到效果需求之后,再转换为 RGB 值显示在屏幕上并保存结果。
HSⅤ与RGB的相互转换公式如下。
· RGB转HSⅤ

注意,r、g、b均为归一化后的值,范围为0~1。
· HSⅤ转RGB


编程实现
下面使用C语言编程实现HSⅤ与RGB的转换。



使用上述代码进行HSⅤ调节,效果如图1.18所示。

图1.18 HSⅤ调节效果图
本节主要讲述了 HSⅤ颜色模型,以及 HSⅤ颜色模型与 RGB颜色模型的相互转换,并给出了相应的 DEMO,教会大家如何使用 HSⅤ颜色模型对图像的色相、饱和度和明度进行调节。HSⅤ颜色模型作为基础内容,将在后面介绍人像美妆时发挥重要作用。
本节的所有代码工程及DEMO见代码包中1.3.2文件夹中的文件。
1.2.3 YUV颜色空间
知识点
YUⅤ 颜色空间是 PAL、NTSC 和 SECAM 三大符合颜色视频的标准所采用的颜色空间。黑白系统仅使用亮度 Y信息,与颜色信息 U和 V分离,对于黑白电视,只需使用 Y信息即可,而彩色电视则会对U和V颜色信息进行解码从而显示彩色画面。
为什么要介绍 YUⅤ 颜色空间呢?因为目前手机端的视频处理或者 Camera 实时处理数据大都是YUⅤ信号流,所以我们只有了解了YUⅤ颜色空间与RGB颜色空间的关系,才能做出一些基于视频和Camera的特效。
对于 YUⅤ 的分类,我们不做具体讲解,不同的分类只是存储信息的排列方式等存在差异,我们要掌握的是YUⅤ颜色空间与RGB颜色空间之间相互转换的方法。
基于Gamma校准的RGB与YUⅤ颜色空间的转换公式如下:

其中,R、G、B值的取值范围为[0,255],Y的取值范围为[0,255],U的取值范围为[-122,122], V的取值范围为[-157,157]。
编程实现
我们使用C语言实现,代码如下:

注意:在 YUⅤ 颜色空间转 RGB 颜色空间的时候要注意数据的溢出问题,需要对数值进行0~255的限定。
这里给出一个 DEMO,用来将一张图像转换为 YUⅤ 颜色空间,并把 Y、U、V 三个分量以图像的形式展示给大家。由于 U 和 V 分量的取值范围不在[0,255]内,因此我们做了像素偏移和归一化,将U和V分量归一化到[0,255]范围内。
RGB颜色空间转YUⅤ颜色空间的效果如图1.19所示。

图1.19 RGB颜色空间转YUⅤ颜色空间的效果
以上就是 YUⅤ 颜色空间与 RGB 颜色空间的相互转换情况。在实际应用中,如美颜磨皮算法,为了加快速度,往往只对Y分量进行保边滤波处理,以满足视频实时处理的需要。下面给出了基于Y分量进行双边滤波的磨皮效果,如图1.20所示。

图1.20 基于Y分量的双边滤波磨皮效果图(左图为原图,右图为处理后的效果图)
从图1.20中可以看到,在人脸区域经过双边滤波处理之后,Y分量上的皮肤斑点已经平滑,而整体效果并没有受U和V分量是否平滑的影响。
本节所有代码工程及DEMO见代码包中1.3.3文件夹中的文件。
1.2.4 CIELab颜色空间
知识点
CIELab颜色空间(Lab color space)是在1931年国际照明委员会(CIE)制定的颜色度量国际标准CIE-XYZ的基础上建立的,1976年经修订并被命名为CIELab[3],常缩写为Lab颜色空间。CIELab 颜色空间包括人眼所能看到的所有颜色(可见光谱),所以也是到目前为止色域最宽的颜色空间,其每一组色值对应一种确定的与设备无关的色彩。
在 Lab 颜色空间中,一种颜色由 L(明度)、a 颜色、b 颜色三个参数表示;在一幅图像中,每一个像素对应一个Lab值,L、a、b三个参数的取值范围如下所述。
L:取值范围为[0,100],表示纯黑色到纯白色范围。
a:取值范围为[-128,127],表示绿色到洋红色范围。
b:取值范围为[-128,127],表示蓝色到黄色范围。
在Lab取值中,正为暖色,负为冷色。
关于上述 Lab颜色空间中参数与颜色的变化,我们用 Photoshop中的 Lab颜色模式来说明,参见图1.21。

图1.21 Lab颜色模式测试效果图
在图 1.21 中可以看到,对于 L 分量,它的改变只会影响图像的明暗,而不会影响图像颜色本身;对于a分量,取值范围为从-100到100,对应颜色从绿色到洋红色;对于b分量,取值范围为从-100到100,对应颜色从蓝色到黄色,这些变化与上面的总结一一对应。
Lab颜色空间具有以下特点:
· Lab颜色空间中明度和颜色是分开的,L通道没有颜色,a通道和b通道只有颜色。
· 在Lab颜色空间中进行调节很简单,速度很快。
· 色域宽阔,不仅包含RGB、CMYK的所有色域,还能表现它们不能表现的色彩,人眼能感知的色彩都能通过Lab颜色空间表现出来。
· 弥补了 RGB颜色空间和 CMYK颜色空间色彩分布不均的不足,在 Photoshop中使用的是CIELab 50[4]。
RGB颜色空间不能直接转换为 Lab颜色空间,需要借助 XYZ颜色空间进行二次转换,公式如下。
RGB转Lab的公式:

Lab转RGB的公式:

上述就是关于Lab颜色空间的简单介绍,如果希望了解更多信息,可以参考MH Brill 与AR Robertson所著的Colorimetry:Understanding the CIE System一书。
编程实现
我们使用C语言实现如下(该代码未做任何优化):


这里给出一个 DEMO,用来将一张图像转换为 Lab 颜色空间,并把 L、a、b 三个分量以图像的形式展示给大家。由于 Lab颜色空间中分量的范围不在[0,255]内,因此我们做了范围扩展,将分量归一化到[0,255]范围内,这样 Lab颜色值就可以以像素值形式显示出来了,扩展方法如下:

Lab颜色空间分量显示的DEMO效果如图1.22所示。

图1.22 Lab DEMO分量显示效果图
在滤镜开发中经常会用到 Lab颜色空间,比如阿宝色滤镜,给出一组效果图,如图 1.23所示。

图1.23 基于Lab颜色空间的阿宝色滤镜效果图(左图为原图,右图为处理后的效果图)
阿宝色滤镜的算法与代码,在后续章节中会详细讨论,这里仅用来展示效果,本节所有代码工程及DEMO见代码包中1.3.4文件夹中的文件。