Android高级UI开发(四十二)canva滤镜

举报
yd_57386892 发表于 2020/12/29 00:46:49 2020/12/29
【摘要】 一、矩阵简述 1、定义   M*n矩阵。 2、矩阵乘法   它的意思就是将第一个矩阵A的第一行,与第二个矩阵B的第一列的数字分别相乘,得到的结果相加,最终的值做为结果矩阵的第(1,1)位置的值(即第一行,第一列)。 同样,A矩阵的第一行与B矩阵的第二列的数字分别相乘然后相加,结果做为结果矩阵第(1,2)位置的值(即第一行第二列)。  矩阵A乘以矩阵B和矩...

一、矩阵简述

1、定义

 

M*n矩阵。

2、矩阵乘法

 

它的意思就是将第一个矩阵A的第一行,与第二个矩阵B的第一列的数字分别相乘,得到的结果相加,最终的值做为结果矩阵的第(1,1)位置的值(即第一行,第一列)。 
同样,A矩阵的第一行与B矩阵的第二列的数字分别相乘然后相加,结果做为结果矩阵第(1,2)位置的值(即第一行第二列)。 

  • 矩阵A乘以矩阵B和矩阵B乘以矩阵A的结果是不一样的。

 

 

色彩信息的矩阵表示

四阶表示 

 

如果想将色彩(0,255,0,255)更改为半透明时,可以使用下面的的矩阵运算来表示:

 

真正的运算使用五阶矩阵

考虑下面这个变换: 
1、红色分量值更改为原来的2倍; 
2、绿色分量增加100; 
则使用4阶矩阵的乘法无法实现,所以,应该在四阶色彩变换矩阵上增加一个“哑元坐标”,来实现所列的矩阵运算:

 

这个矩阵中,分量值用的是100

1*100+100

二、渲染举例

Alpha滤镜处理

1. 实现模糊效果:

 


  
  1. protected void onDraw(Canvas canvas) {
  2. super.onDraw(canvas);
  3. setLayerType(View.LAYER_TYPE_SOFTWARE,null);
  4. RectF rectF = new RectF(0,100,bitmap.getWidth(),bitmap.getHeight());
  5. paint.reset();
  6. paint.setColor(Color.RED);
  7. /**
  8. * Create a blur maskfilter.
  9. *
  10. * @param radius 阴影的半径
  11. * @param style NORMOL -- 整个图像都被模糊掉
  12. * SOLID -- 图像边界外产生一层与Paint颜色一致阴影效果,不影响图像的本身
  13. * OUTER -- 图像边界外产生一层阴影,并且将图像变成透明效果
  14. * INNER -- 在图像内部边沿产生模糊效果
  15. * @return
  16. */
  17. paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL));
  18. canvas.drawRect(rectF,paint);
  19. }

模糊效果有以下几种模式:

(1)NORMOL: 整个图形都被模糊,见上面的效果图;

(2)SOLID:图像边界模糊,图形本身保持原样。效果图如下:

(3)OUTER模式:图形边界外产生模糊阴影,图形内变成透明。

(4)INNER:跟SOLID相反,边界内边缘模糊,图像内部无影响。

2. 镜面效果、浮雕效果


  
  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. super.onDraw(canvas);
  4. setLayerType(View.LAYER_TYPE_SOFTWARE,null);
  5. RectF rectF = new RectF(0,100,bitmap.getWidth(),bitmap.getHeight());
  6. paint.reset();
  7. paint.setColor(Color.RED);
  8. /**
  9. * Create an emboss maskfilter
  10. *
  11. * @param direction 指定光源的位置,长度为xxx的数组标量[x,y,z]
  12. * @param ambient 环境光的因子 (0~1),越接近0,环境光越暗
  13. * @param specular 镜面反射系数 越接近0,镜面反射越强
  14. * @param blurRadius 模糊半径 值越大,模糊效果越明显
  15. */
  16. paint.setMaskFilter(new EmbossMaskFilter(new float[]{50,50,10},1f,0.2f,1000));
  17. //canvas.translate(200,0);
  18. canvas.drawBitmap(bitmap,200,100,paint);
  19. }

这里我们画了一张bitmap图片,在x=200,y=100的屏幕位置。Paint设置maskfilter为EmbossMaskFilter,构造函数的第一个参数代表光源x,y,z分别来自不同方向的光源,x是水平方向,y是垂直方向,z是垂直于手机屏幕的方向照射到屏幕上,数值越大,从各方向上照射过来的光的强度越大,第二个参数ambient环境光因子,值越小图片越暗。第三个参数镜面反射系统,越接近0,图片表面放光越强,视觉上的感受就和镜子在太阳光下一样,镜面越亮,甚至看不清镜子表面。

效果图下:

是不是图片表面有镜面反光的效果。

 

3. 颜色矩阵


  
  1. protected void onDraw(Canvas canvas) {
  2. super.onDraw(canvas);
  3. setLayerType(View.LAYER_TYPE_SOFTWARE,null);
  4. paint.reset();
  5. paint.setColor(Color.RED);
  6. RectF rectF = new RectF(0,100,bitmap.getWidth(),100+bitmap.getHeight());
  7. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  8. 1, 0,0,0,0,
  9. 0,1,0,0,0,
  10. 0,0,1,0,0,
  11. 0,0,0,1,0,
  12. });
  13. paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));
  14. canvas.drawBitmap(bitmap,null,rectF,paint);
  15. }

第一行的1表示R通道,第二行的1表示G绿色通道,第三行的1表示B蓝色通道,第四行的1表示透明度通道。目前都为1,表示正常显示,效果如下:

如果给绿色通道+100,颜色矩阵如下:


  
  1. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  2. 1, 0,0,0,0,
  3. 0,1,0,0,100,
  4. 0,0,1,0,0,
  5. 0,0,0,1,0,
  6. });

则整个图片将会绿色更重,效果如下图:

我们接着给蓝色通道+100, 矩阵如下:


  
  1. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  2. 1, 0,0,0,0,
  3. 0,1,0,0,100,
  4. 0,0,1,0,100,
  5. 0,0,0,1,0,
  6. });

 图片将会凸显出蓝色和绿色的混合色,效果如下图:

反相效果,将矩阵改变成如下:


  
  1. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  2. -1, 0,0,0,255,
  3. 0,-1,0,0,255,
  4. 0,0,-1,0,255,
  5. 0,0,0,1,0,
  6. });

我们发现RGB的1都变成了-1,这意味着如果原来R的值是100的话,那么现在将变成255+(-100)=155,是255的另一半,所以叫反相。

这时图片的显示效果如下:

要想颜色增强,将矩阵改变成:


  
  1. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  2. 1.2f, 0,0,0,0,
  3. 0,1.2f,0,0,0,
  4. 0,0,1.2f,0,0,
  5. 0,0,0,1.2f,0,
  6. });

我们发现RGBA4个通道都变成了原来的1.2倍,表现为图片效果则是亮度增加,如下图:

还可以显示黑白照片,只需将RGB三通道中的各颜色值(RGB颜色值)设置相同。为了让图形亮度不变,每一个通道里的RGB值加起来等于1,现在的矩阵如下所示:


  
  1. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  2. 0.213f, 0.715f,0.072f,0,0,
  3. 0.213f, 0.715f,0.072f,0,0,
  4. 0.213f, 0.715f,0.072f,0,0,
  5. 0,0,0,1,0,
  6. });

 第1行,第2行,第3行,这3个通道中的 第一列(R),第二列(G),第三列(B)的值都相等。且每一个通道的RGB值加起来还是1,与原来每一行只有1个1的情况一样,图像的亮度不会变,效果如下:

如果想要发色效果,例如将红色和绿色交换,矩阵如下:


  
  1. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  2. 1, 0,0,0,0,
  3. 1,0,0,0,0,
  4. 0,0,1,0,0,
  5. 0,0,0,1,0,
  6. });

我们发现第二行的通道中,将绿色为0,红色为1.显示效果如下,颜色有点泛红:

同理,将第三通道中的蓝色和红色交换,矩阵如下:


  
  1. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  2. 1, 0,0,0,0,
  3. 0,1,0,0,0,
  4. 1,0,0,0,0,
  5. 0,0,0,1,0,
  6. });

 这次发出红色的效果更明显些,效果图如下:

如果想要复古效果,矩阵如下:


  
  1. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  2. 1/2f,1/2f,1/2f,0,0,
  3. 1/3f, 1/3f,1/3f,0,0,
  4. 1/4f,1/4f,1/4f,0,0,
  5. 0,0,0,1,0,
  6. });

显示图片的效果如下:

颜色通道过滤,将绿色通道和蓝色通道清0后的矩阵如下:


  
  1. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  2. 1, 0,0,0,0,
  3. 0,0,0,0,0,
  4. 0,0,0,0,0,
  5. 0,0,0,1,0,
  6. });

 运行出的图片效果只剩红色,效果图如下:

除了直观的修改矩阵中的RGB三行通道中的RGB值,还可以使用API,如下代码:

 

  
  1. protected void onDraw(Canvas canvas) {
  2. super.onDraw(canvas);
  3. setLayerType(View.LAYER_TYPE_SOFTWARE,null);
  4. RectF rectF = new RectF(0,100,bitmap.getWidth(),bitmap.getHeight());
  5. paint.reset();
  6. paint.setColor(Color.RED);
  7. ColorMatrix colorMartrix = new ColorMatrix();
  8. colorMartrix.setScale(1.2f,1.2f,1.2f,1);
  9. paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));
  10. canvas.drawBitmap(bitmap,null, rectF,paint);
  11. }

  
  1. 其中 以下两行代码:
  2. ColorMatrix colorMartrix = new ColorMatrix();
  3. colorMartrix.setScale(1.2f,1.2f,1.2f,1);
效果同矩阵:
 

  
  1. ColorMatrix colorMartrix = new ColorMatrix(new float[]{
  2. 1.2f, 0,0,0,0,
  3. 0,1.2f,0,0,0,
  4. 0,0,1.2f,0,0,
  5. 0,0,0,1.2f,0,
  6. });

 


  
  1. 使用如下两行代码还可以设置色彩的饱和度
  2. ColorMatrix colorMartrix = new ColorMatrix();
  3. colorMartrix.setSaturation(2f);
  4. //colorMartrix.setSaturation(0f);
  5. 当设置为0时,图片变为黑白照片。当设置为2色彩很重,效果如下图所示;

 


  
  1. 还可以旋转颜色,
  2. ColorMatrix colorMartrix = new ColorMatrix();
  3. colorMartrix.setRotate(0,30); //红色旋转30度
  4. colorMartrix.setRotate(1,30);//绿色旋转
  5. colorMartrix.setRotate(2,30);//蓝色旋转

效果图如下:

LightingColorFilter,它的构造函数有2个参数:

 

  
  1. /**
  2. * Create a colorfilter that multiplies the RGB channels by one color,
  3. * and then adds a second color. The alpha components of the mul and add
  4. * arguments are ignored.
  5. */
  6. public LightingColorFilter(@ColorInt int colorMultiply, @ColorInt int colorAdd) {
  7. mMul = mul;
  8. mAdd = add;
  9. }

将原矩阵乘以 colorMultiply,然后再加上colorAdd.  假设原来矩阵的颜色值是RGB,经过LightingColorFilter后,R'G'B'的值如下:


  
  1. * Given a source color RGB, the resulting R'G'B' color is computed thusly:
  2. * <pre>
  3. * R' = R * colorMultiply.R + colorAdd.R
  4. * G' = G * colorMultiply.G + colorAdd.G
  5. * B' = B * colorMultiply.B + colorAdd.B
  6. * </pre>

实例核心代码如下:


  
  1. paint.setColorFilter(new LightingColorFilter(0x00ff00,0x0000ff));
  2. canvas.drawBitmap(bitmap,null, rectF,paint);

运行效果如下:

反正绿色增强了(乘绿色),然后蓝色也增强了(加蓝色)。

 

colorMartrix.setConcat(matA,matB);同时应用两个矩阵的效果,先应用A的效果,然后再应用B的效果。源码注释如下:
 

如下代码将2个矩阵效果叠加起来,第一个矩阵是原样,第二个矩阵加亮:


  
  1. ColorMatrix colorMartrixA = new ColorMatrix(new float[]{
  2. 1, 0,0,0,0,
  3. 0,1,0,0,0,
  4. 0,0,1,0,0,
  5. 0,0,0,1,0,
  6. });
  7. ColorMatrix colorMartrixB = new ColorMatrix(new float[]{
  8. 1.2F, 0,0,0,0,
  9. 0,1.2F,0,0,0,
  10. 0,0,1.2F,0,0,
  11. 0,0,0,1,1.2F,0,
  12. });
  13. ColorMatrix colorMartrix = new ColorMatrix();
  14. colorMartrix.setConcat(colorMartrixA,colorMartrixB);
  15. paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));
  16. canvas.drawBitmap(bitmap,null, rectF,paint);

运行效果图如下:

paint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DARKEN));
 

可以将红色像素与原图像素以指定的混合模式混合成新的像素。效果图如下:

 


  
  1. paint.setColorFilter(new PorterDuffColorFilter(Color.argb(255,140,90,200), PorterDuff.Mode.MULTIPLY));
  2. canvas.drawBitmap(bitmap,null,rectF,paint);

 

paint.setColorFilter(new PorterDuffColorFilter(Color.GREEN, PorterDuff.Mode.MULTIPLY));效果如下:
 

 

paint.setColorFilter(new PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.MULTIPLY));效果如下: 

paint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY));的效果图如下:
 

我们发现MULTIPLY模式,相当于用透明的红色塑料片 叠加到原图之上 形成的 效果。

 

文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/105308681

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。