3

高级UI之Paint(滤镜,颜色通道,矩阵运算)

 2 years ago
source link: https://my.oschina.net/u/5032144/blog/5255321
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

高级UI之Paint(滤镜,颜色通道,矩阵运算) - 小新聊Android的个人空间 - OSCHINA - 中文开源技术交流社区

在之前的几次课当中我们已经详细了解到整个android程序,从启动再到绘制的整体流程,从这中间我们又牵扯出了Canvas绘制图形的画板和我们的Paint控制色彩样式的画笔,那么之前基础篇我们就不进行详细的解释,那些API在之前的基础篇已经公布出来,我也注释的非常详细,今天我门来了解Paint高级篇真正需要了解的滤镜

1.滤镜效果

760b2f9f-a6a3-46ca-a0a4-309d891fd0c2.png image.png

从上图我们可以看到 四张滤镜效果图像,其色彩的显示效果各不一样,也就是说所谓滤镜其实只不过是对于原本图像色彩进行调整,那么需要对图像的色彩进行调整操作,我们会需要知道几个概念,那就是我们的图像构成,颜色通道,颜色模式以及颜色举证

2.图像构成

在具体讲滤镜之前,今天我们先来系统化真正认识一下在我们计算机当中我们的图像到底是什么,我们都知道在计算机体系当中我们的图像有各种各样的格式,比如jpg,png,gif等等...

那么我们同样也知道我们计算机当中的图像文件其实实际也就是一个二进制的字节码文件,那么这个图像本质上来说是一个二进制文件,然后我们的cpg,gpu对二进制文件进行识别再显示到我们的屏幕上,那么我们现在需要关注的是,这些文件当中他到底保存的是什么?

其实一个图像文件当中,他保存的数据总体分为两块

  1. 图像的信息
  2. 图像的数据

后者好理解,我们可以理解为图像具体的那些像素点的数据,那么前者其实我们可以理解为,是一组信息,这组信息的作用是让我们的cpg,gpu在显示图像的时候,基于我门设定的这组信息的规则不同,那么显示的效果不一样, 以一种格式(PNG)为例,我在网上扒出了对于这个图像的结构的解释(粗略看一下就好)

    PNG的文件结构

对于一个PNG文件来说,其文件头总是由位固定的字节来描述的:

十进制数 137 80 78 71 13 10 26 10
    十六进制数 89 50 4E 47 0D 0A 1A 0A
    其中第一个字节0x89超出了ASCII字符的范围,这是为了避免某些软件将                PNG文件当做文本文件来处理。文件中剩余的部分由3个以上的PNG的数据块(Chunk)按照特定的顺序组成,因此,一个标准的PNG文件结构应该如下:

PNG文件标志 PNG数据块 …… PNG数据块
    PNG数据块(Chunk)

PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了4个标准数据块,每个PNG文件都必须包含它们,PNG读写软件也都必须要支持这些数据块。虽然PNG文件规范没有要求PNG编译码器对可选数据块进行编码和译码,但规范提倡支持可选数据块。

下表就是PNG中数据块的类别,其中,关键数据块部分我们使用深色背景加以区分。
    为了简单起见,我们假设在我们使用的PNG文件中,这4个数据块按以上先后顺序进行存储,并且都只出现一次。

数据块结构

PNG文件中,每个数据块由4个部分组成,如下:

名称 字节数 说明
    Length (长度) 4字节 指定数据块中数据域的长度,其长度不超过(231-1)字节
    Chunk Type Code (数据块类型码) 4字节 数据块类型码由ASCII字母(A-Z和a-z)组成
    Chunk Data (数据块数据) 可变长度 存储按照Chunk Type Code指定的数据
    CRC (循环冗余检测) 4字节 存储用来检测是否有错误的循环冗余码

从上面这一段解释当中我门可以看出,其实所谓的各个图像格式只不过是发布的标准不一样,那么们cpu解析的规则也不一致,同时一张图片里面包含了多个数据块,如下图

657ebc29-5cec-439d-97b3-fef00c91e843.png image.png

这是我打开的一张jpg图的数据,这时我门看到的是16进制的数据,尽管我们不知道这些数据是什么,那么此时我们结合上述所说,假定第一行的数据是这个jpg的标志,第2-8行可能记录的是解析规则等等信息类似,后面的为数据,那么这样去看待一张图形,我们就能大致明白一个意思, 标志+图像信息+数据--》最终构成一张完整的图像,图像根据数据和所为的解析规则计算显示出来的。那么对于今天的滤镜,我门需要了解到图像当中比较重要的两个信息颜色通道,颜色模式

3.颜色通道,颜色模式

颜色通道: 保存图像颜色信息的通道称为颜色通道。这句话是颜色通道的基本定义,我门可以理解为记录色彩信息的那一段数据,每个图像都有一个或者多个颜色通道,图像中默认的颜色通道信息取决于颜色模式

颜色模式: 颜色模式我门可以理解为将某种颜色表现为数字形式的模型,或者说是一种记录图像颜色的方式。分为:RGB模式、CMYK模式、HSB模式、Lab颜色模式、位图模式、灰度模式、索引颜色模式、双色调模式和多通道模式等。

其实实际上我们就认为,现在我要显示的色彩这个时候是用数字表示,最经典的RGB模式我们可以理解为R(255) G(0) B(0)当前这个像素,显示,在识别的时候为红色,他由红 绿 蓝 三种色彩进行混合,显示出我们要的颜色其程度数值是0-255的范围

总结: 也就是说,其实图像的显示,每个点都是由模式所决定的色彩数值混合形成我们想要的颜色,那么我们的滤镜效果实现,其实实际上就是去对于颜色通道进行过滤操作,在其原本的模式数值上面进行操作,达到更改图像色彩效果的目的,这就是我们所为的滤镜

4.颜色矩阵

在android当中,他所采用的颜色模式是RGBA模式,也就是在红绿蓝的基础上加入了Alpha透明度的概念,那么也就是他现在是一个四通道的模式。在Android当中当android将图像信息获取出来时候,当前图像的颜色通道信息他用的是一个矩阵在进行保存。用一个数组来表示的话就是

93e75f0c-d61b-4def-bb87-32f8e26efe5a.png image.png e3e94e0a-a108-457d-9071-37701ac00dc1.png image.png

上面这里看到的是一个四通道形式的表示方式,我门会发现在

1-1 2-2 3-3 4-4

的位置都是一个1的数值,那么几个数值我们把他理解为颜色的系数,1为原本数值不动,若0.5那么当前对应的rgba四个选项按比例处理。如果想要更改为半透明的,那么,当前a的值改为0.5就OK了红色翻一倍就改为2。但是如果在这种情况下

7a0092be-4be3-418f-8d67-3d21f0494329.png image.png

这个四介矩阵做不到,在android当中真正的表现方式他应用了一个4*5的矩阵

c987cb14-6c72-4b32-8302-aa79c7f59917.png image.png

最后方加入一列,作为所为的亚元坐标,其实也就是分量值,那么下面这个颜色的矩阵如果想要将我们的颜色值达到上诉效果,第二行的100表示在之前的颜色基础上增加100个绿色数值,那么这种是我们最为简单的理解,而真正的他当中的实现实际上是采用矩阵的计算

4.矩阵运算

6cd06bb1-ea77-4e9b-83bd-d74e39359564.png image.png 001b4147-e794-492f-83e3-dd5bf8cb5079.png image.png

矩阵的运算规则是矩阵A的一行乘以矩阵C的一列作为矩阵R的一行,C矩阵是图片中包含的ARGB信息,R矩阵是用颜色矩阵应用于C之后的新的颜色分量,运算结果如下:

R' = aR + bG + cB + dA + e;

G' = fR + gG + hB + iA + j;

B' = kR + lG + mB + nA + o;

A' = pR + qG + rB + sA + t;

颜色矩阵并不是看上去那么深奥,其实需要使用的参数很少,而且很有规律第一行决定红色第二行决定绿色 第三行决定蓝色,第四行决定了透明度,第五列是颜色的偏移量。下面是一个实际中使用的颜色矩阵。

170cd78f-9fec-4e44-81d0-c0f8cc1b8025.png image.png

如果把这个矩阵作用于各颜色分量的话,R=A*C,计算后会发现,各个颜色分量实际上没有任何的改变(R'=R G'=G B'=B A'=A)。

09b42ab2-ea4a-45da-af5a-7516caab2bfd.png image.png

图1.5所示矩阵计算后会发现红色分量增加100,绿色分量增加100,这样的效果就是图片偏黄,因为红色和绿色混合后得到黄色,黄色增加了100,图片当然就偏黄了。

e4e1ec73-538f-43aa-99f8-c356ba3608df.png image.png

改变各颜色分量不仅可以通过修改第5列的颜色偏移量也可如上面矩阵所示将对应的颜色值乘以一个倍数,直接放大。上图1.6是将绿色分量乘以2变为原来的2倍。至此已经明白了如何通过颜色矩阵来改变各颜色分量。

5.滤镜实现

那么在对于的实现上面android的使用非常简单,只需要依赖于一个API就好

  // 颜色通道过滤
    /*ColorMatrix colorMartrix = new ColorMatrix(new float[]{
            1, 0,0,0,0,
            0,0,0,0,0,
            0,0,0,0,0,
            0,0,0,1,0,
    });
  paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));

那么下面是我的demo代码,大家可以去试试效果

 protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    setLayerType(View.LAYER_TYPE_SOFTWARE,null);
    RectF rectF = new RectF(0,100,bitmap.getWidth(),bitmap.getHeight());
    paint.reset();
    paint.setColor(Color.RED);

canvas.drawBitmap(bitmap,null, rectF,paint);
    // 平移运算---加法
    /*ColorMatrix colorMartrix = new ColorMatrix(new float[]{
            1, 0,0,0,0,
            0,1,0,0,100,
            0,0,1,0,0,
            0,0,0,1,0,
    });*/

// 反相效果 -- 底片效果
   /* ColorMatrix colorMartrix = new ColorMatrix(new float[]{
            -1, 0,0,0,255,
            0,-1,0,0,255,
            0,0,-1,0,255,
            0,0,0,1,0,
    });*/
    // 缩放运算---乘法 -- 颜色增强
    /*ColorMatrix colorMartrix = new ColorMatrix(new float[]{
            1.2f, 0,0,0,0,
            0,1.2f,0,0,0,
            0,0,1.2f,0,0,
            0,0,0,1.2f,0,
    });*/

// 黑白照片
    // 去色原理:只要把R G B 三通道的色彩信息设置成一样,那么图像就会变成灰色,
    // 同时为了保证图像亮度不变,同一个通道里的R+G+B =1
    //
    /*ColorMatrix colorMartrix = new ColorMatrix(new float[]{
            0.213f, 0.715f,0.072f,0,0,
            0.213f, 0.715f,0.072f,0,0,
            0.213f, 0.715f,0.072f,0,0,
            0,0,0,1,0,
    });*/

// 发色效果---(比如红色和绿色交换)
    /*ColorMatrix colorMartrix = new ColorMatrix(new float[]{
            0,1,0,0,0,
            1, 0,0,0,0,
            0,0,1,0,0,
            0,0,0,1,0,
    });*/
    // 复古效果
    /*ColorMatrix colorMartrix = new ColorMatrix(new float[]{
            1/2f,1/2f,1/2f,0,0,
            1/3f, 1/3f,1/3f,0,0,
            1/4f,1/4f,1/4f,0,0,
            0,0,0,1,0,
    });*/
    // 颜色通道过滤
   ColorMatrix colorMartrix = new ColorMatrix(new float[]{
            1, 0,0,0,0,
            0,0,0,0,0,
            0,0,0,0,0,
            0,0,0,1,0,
    });

RectF rectF2 = new RectF(600,100,600 + bitmap.getWidth(),bitmap.getHeight());
    paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));
        canvas.drawBitmap(bitmap,null, rectF2,paint);
    }

那么关于滤镜其他的反转,光影等效果课上讲,大家可以试试这里最基础的一些操作

看完三件事❤️

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:

  1. 点点再看和点赞,有你们的 『点赞和再看』,才是我创造的动力。
  2. 关注公众号 『 小新聊Android 』,不定期分享原创知识。
  3. 同时可以期待后续文章ing🚀
  4. 关注后回复【666】扫码即可获取Android进阶学习资料包
9eab4150-0378-4087-a059-f8b185705a59.png - END -

本文分享自微信公众号 - 小新聊Android(gh_44b363ab5571)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK