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

一、矩阵简述

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. 实现模糊效果:

 

    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);

        /**
         * Create a blur maskfilter.
         *
         * @param radius 阴影的半径
         * @param style  NORMOL -- 整个图像都被模糊掉
         *               SOLID -- 图像边界外产生一层与Paint颜色一致阴影效果,不影响图像的本身
         *               OUTER -- 图像边界外产生一层阴影,并且将图像变成透明效果
         *               INNER -- 在图像内部边沿产生模糊效果
         * @return
         */
        paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL));
        canvas.drawRect(rectF,paint);
    }

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

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

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

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

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

2. 镜面效果、浮雕效果

    @Override
    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);

        /**
         * Create an emboss maskfilter
         *
         * @param direction  指定光源的位置,长度为xxx的数组标量[x,y,z]
         * @param ambient    环境光的因子 (0~1),越接近0,环境光越暗
         * @param specular   镜面反射系数 越接近0,镜面反射越强
         * @param blurRadius 模糊半径 值越大,模糊效果越明显
         */
        paint.setMaskFilter(new EmbossMaskFilter(new float[]{50,50,10},1f,0.2f,1000));
        //canvas.translate(200,0);
        canvas.drawBitmap(bitmap,200,100,paint);
}

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

效果图下:

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

 

3. 颜色矩阵

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        setLayerType(View.LAYER_TYPE_SOFTWARE,null);

        paint.reset();
        paint.setColor(Color.RED);
        RectF rectF = new RectF(0,100,bitmap.getWidth(),100+bitmap.getHeight());
        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                1, 0,0,0,0,
                0,1,0,0,0,
                0,0,1,0,0,
                0,0,0,1,0,
        });

        paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));
        canvas.drawBitmap(bitmap,null,rectF,paint);
}

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

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

      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,
        });

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

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

        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                1, 0,0,0,0,
                0,1,0,0,100,
                0,0,1,0,100,
                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,
        });

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

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

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

       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,
        });

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

还可以显示黑白照片,只需将RGB三通道中的各颜色值(RGB颜色值)设置相同。为了让图形亮度不变,每一个通道里的RGB值加起来等于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,
        });

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

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

        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                1, 0,0,0,0,
                1,0,0,0,0,
                0,0,1,0,0,
                0,0,0,1,0,
        });

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

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

        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                1, 0,0,0,0,
                0,1,0,0,0,
                1,0,0,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,
        });

显示图片的效果如下:

颜色通道过滤,将绿色通道和蓝色通道清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,
        });

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

除了直观的修改矩阵中的RGB三行通道中的RGB值,还可以使用API,如下代码:
    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);
        ColorMatrix colorMartrix = new ColorMatrix();
        colorMartrix.setScale(1.2f,1.2f,1.2f,1);
        paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));
        canvas.drawBitmap(bitmap,null, rectF,paint);
    }
其中 以下两行代码:
ColorMatrix colorMartrix = new ColorMatrix();
colorMartrix.setScale(1.2f,1.2f,1.2f,1);
效果同矩阵:
       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,
        });

 

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

 

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

效果图如下:

LightingColorFilter,它的构造函数有2个参数:
   /**
     * Create a colorfilter that multiplies the RGB channels by one color,
     * and then adds a second color. The alpha components of the mul and add
     * arguments are ignored.
     */
    public LightingColorFilter(@ColorInt int colorMultiply, @ColorInt int colorAdd) {
        mMul = mul;
        mAdd = add;
    }

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

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

实例核心代码如下:

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

运行效果如下:

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

 

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

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

        ColorMatrix colorMartrixA = new ColorMatrix(new float[]{
                1, 0,0,0,0,
                0,1,0,0,0,
                0,0,1,0,0,
                0,0,0,1,0,
        });



        ColorMatrix colorMartrixB = 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,1.2F,0,
        });
        ColorMatrix colorMartrix = new ColorMatrix();
        colorMartrix.setConcat(colorMartrixA,colorMartrixB);
        paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));
        canvas.drawBitmap(bitmap,null, rectF,paint);

运行效果图如下:

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

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

 

    paint.setColorFilter(new PorterDuffColorFilter(Color.argb(255,140,90,200), PorterDuff.Mode.MULTIPLY));
        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模式,相当于用透明的红色塑料片 叠加到原图之上 形成的 效果。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冉航--小虾米

希望得到您的鼓励和交流

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值