Android 图像混合技术
色彩知识
色彩
光学三原色
光学三原色由:红、绿、蓝组成。
色值分别是:
- 红(red ):#FF0000 RGB(255,0,0)
- 绿(green):#00FF00 RGB(0,255,0)
- 蓝(blue):#0000FF RGB(0,0,255)
光学三原色又光透过三棱镜分解得出。RGB是上面三个颜色的混合。通常用于灯光色彩中。
光学三原色为相加混色(可以理解为光的叠加),混合后颜色的明度提高,三色混合即为白色。
显示器采用RGB模式,就是因为显示器是电子光束轰击荧光屏上的荧光材料发出亮光从而产生颜色,当没有光的时候为黑色,光线加到最大时为白色。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2gEGtEoQ-1672235871843)(null)]
(https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2021%2F0110%2Fbcb0236ep00qmpidg000qc000u000j9m.png&thumbnail=660x2147483647&quality=80&type=jpg)
颜料三原色
颜料三原色由:品红、黄、青组成。
色值分别是:
- 品红(magenta):#FF00FF CMYK(42,64,0,0)
- 黄(yellow):#F8F400 CMYK(0,11,92,0)
- 青(cyan):#00FFFF00FFFF CMYK(38,0,16,0)
颜料三原色采用相减混色(可以理解为光的吸收),混合后颜色的明度和纯度都会下降,三个混合即为黑色。与光学三原色不同。人眼看到颜料和颜色,是因为其他颜色被吸收了,而反射出的颜色,就是我们看到的颜色。
CMYK就是 Cyan Magenta Yellow Black。上面三种颜色加一个黑。CMYK模式,绘画和印刷领域。
其中CMYK和RGB,都是对于颜色描述的一种方式,但是由于底层原理不同,所以是有了不同的模式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L9EyXmjF-1672235842627)(null)]
(https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2021%2F0110%2Fbd255e12p00qmpidg000pc000u000j9m.png&thumbnail=660x2147483647&quality=80&type=jpg)
HSL/HSB
颜色的三个属性分别为:色相(Hue)、明度(Brightness)、饱和度(Saturation)。
既然我们已经有了RGB,为什么还要用到HSB呢?
RGB对于图像彩色生成而言是理想的,但对于颜色描述而言,则存在很多限制,不能很好地描述人类实际解释的颜色。例如,已知每种原色的百分比,我们不能给出一辆汽车的颜色。此外,一张彩色图像也不是由3幅原色图像合成的单幅图像。因为,RGB,三原色并不能描述所有色彩。
需要注意的是,HSL和HSB,虽然含义相同,但是,他们是有缺别的。
Brightness(明度)是被认为是”光的量“,可以是任何颜色。
Lightness(亮度)是作为”白的量“来理解的
色相
色相指的是这些不同波长的色的情况。波长最长的是红色,最短的是紫色。
色彩是由于物体上的物理性的光反射到人眼视神经上所产生的感觉。色的不同是由光的波长的长短差别所决定的。把红、橙、黄、绿、蓝、紫和处在它们各自之间的红橙、黄橙、黄绿、蓝绿、蓝紫、红紫这 6 种中间色——共计 12 种色作为色相环。在色相环上排列的色是纯度高的色,被称为纯色。
其实就可以理解为他,他是一个什么颜色。
明度
明度是表示色所具有的亮度和暗度。计算明度的基准是灰度测试卡。
对于黑白图像来说,调整的就是这个明度,也就是亮度。如果定义明度的范围是[0,1]的话,0就是黑,1就是白。
饱和度
饱和度是用数值表示色的鲜艳或鲜明的程度。
饱和度为 0 时,就是黑白灰。有彩色的各种色都具有彩度值,无彩色的色的彩度值为0,对于有彩色的色的彩度(纯度)的高低,区别方法是根据这种色中含灰色的程度来计算的。
色相就是说,这个是什么个颜色。比如红色
明度是说,这个色,有亮。亮的红色
饱和度就是说,这个色,有多色。比如很红的亮红色。
理解
现在祭出来,UI那边经常能看到的一个页面。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OwnFX6Yn-1672235842618)(null)]
(https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2021%2F0110%2Faf5fdc6cp00qmpidg002bc000u000j9m.png&thumbnail=660x2147483647&quality=80&type=jpg)
但是这张图片不能有效的让我们理解,HSL的色彩模型。下面一张图,我们来看一下,HSL是如何描述一个颜色的。
中心轴上所有的点,他的饱和度(Saturation)都是0,所以可以看到,中心轴上只有黑白灰,就是最基础的明度(Lightenss),也就是黑白电视。
而越远离中心轴,其饱和度,就越高,具体的计算是,与中心轴做垂线。
而中心平面,最外圈的环,其实就是色相环。
那么色相环是怎么来的呢?我们知道,计算机表示颜色,是使用的RGB。如果我们将其理解为三维坐标系的话,那么我们可以得到一个色彩空间,如下图左。
然后我们将三原色相互混合而成的边。拉伸成一个圆形,其周长所在的颜色,就形成了色相环,如上图右。而这个圆形,就是色相盘。同时,也是上面梭形的上表面。
如果我们用关键点来看上面的三维坐标。他应该是这样的。
OK,我们在现在再来看一下色相盘。色相环上的六大主色,用作基本参照:360°/0°红、60°黄、120°绿、180°青、240°蓝、300°洋红,它们在色相环上按照60°圆心角的间隔排列。
对于色相的调整
上面的图像,一个是绿螃蟹,一个是红螃蟹。其实就是对于其色相的改变。改了其本来的颜色。也就是从绿的变成了红的。
如果是对于一张图片的调整,可以理解为,将这张图片所有的颜色,延上面梭形中心轴垂直方向,旋转X度。
对于饱和度的调整
对于饱和度的调整,效果在于逐渐"丧失色彩"也就是,没那么“红”,逐渐偏向于原本亮度的黑白灰。其数值越大,颜色中的灰色越少,颜色越鲜艳,呈现一种从灰度到纯色的变化。
Android 图像合成技术
传统的Xfermode
Xfermode就是我们经常用的一个Paint的一个属性。我们常用的,一般就是里面,根据透明度,进行的交并补,做去留。但是,如果我们细心去看,里面也有一部分融合相关的参数。
下面是最基础的用法。用Clear
属性,来画出一个同心圆。
canvas.drawCircle(90, 90, 90, paint);
//设置运算方式
paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.CLEAR));
//源
canvas.drawCircle(90, 90, 30, paint);
交并补部分,就不再叙述,很好理解。我们主要关注其他几个属性,也是图像融合的几个属性。
具体属性可以参照Google文档
ADD
将源像素添加到目标像素,并使结果饱和。其实就是两个颜色叠加。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jBZAtUGg-1672235844732)(null)]
(https://developer.android.com/static/reference/android/images/graphics/composite_ADD.png)
DARKEN
在小的基础上,加上他们两个的融合。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-urQJ5cKC-1672235844683)(null)]
(https://developer.android.com/static/reference/android/images/graphics/composite_DARKEN.png)
LIGHTEN
在大的基础上,加上他们两个的融合。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lVsKLunV-1672235844548)(null)]
(https://developer.android.com/static/reference/android/images/graphics/composite_LIGHTEN.png)
MULTIPLY
将源像素和目标像素相乘。这个也叫"正片叠底"。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AEOsP4TI-1672235844564)(null)]
(https://developer.android.com/static/reference/android/images/graphics/composite_MULTIPLY.png)
OVERLAY
根据目标颜色将源和目标相乘或显示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WTA416KB-1672235844725)(null)]
(https://developer.android.com/static/reference/android/images/graphics/composite_OVERLAY.png)
SCREEN
添加源像素和目标像素,然后减去源像素乘以目标像素。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OP1dMrTH-1672235844691)(null)]
(https://developer.android.com/static/reference/android/images/graphics/composite_SCREEN.png)
关注点
我们需要关注的在于,Xfermode
他对于图片的操作,都是基于颜色,也就是RGB
。上面这些,具体的计算公式在文档里都是可以找到的。而在UI
使用的很多软件中,许多效果都是基于HSL/HSB
,比如,明度叠加。使用Xfermode
就实现不了。
BlendMode
BlendMode
也是Paint
的属性。但是在Api 29
开始,很多基于HSL/HSB
的运算方法才被添加。但是,好消息是,我很很轻易的就可以写出以下代码。
mLPaint = Paint()
mLPaint.isAntiAlias = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
mLPaint.blendMode = BlendMode.LUMINOSITY
} else {
mLPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.LIGHTEN)
}
在Api 29
以下,使用颜色运算来找到一种近似的效果。而在Api 29
以上就可以还原UI
对图像的操作。
COLOR
将目标的色相和饱和度替换为源的色相和饱和度,亮度不变。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rEmOGANX-1672235844699)(null)]
(https://developer.android.com/static/reference/android/images/graphics/blendmode_COLOR.png)
HUE
将目标色相替换为源色相,保持饱和度和光度不变。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cbbLkiot-1672235844717)(null)]
(https://developer.android.com/static/reference/android/images/graphics/blendmode_HUE.png)
LUMINOSITY
将目标亮度替换为源亮度,保持色相和饱和度不变。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RMk4hVar-1672235844557)(null)]
(https://developer.android.com/static/reference/android/images/graphics/blendmode_LUMINOSITY.png)
关注点
其实我们需要注意的是,BlendMode
对于HSL/HSB
的操作不止局限于我列出的这几个。还有很多。并且,BlendMode
对Xfermode
原有的计算模式做了继承并扩展。更多效果,同样可以查看Google文档。
总结
BlendMode
对Xfermode
原有的计算模式做了继承并扩展。在Api 29
以上,我们应积极的使用BlendMode
,而不是Xfermode