自定义控件三部曲之绘图篇(八)——Paint之ColorMatrix与滤镜效果

本文深入探讨了Android中ColorMatrix的使用,讲解了矩阵乘法及其在色彩变换中的应用。通过实例展示了如何使用ColorMatrix进行色彩平移、缩放、旋转等操作,实现图像的蓝色通道输出、色彩饱和度调整、色彩反色和照片变旧等效果。此外,还介绍了Android提供的setSaturation、setScale、setRotate等便捷函数。
摘要由CSDN通过智能技术生成

前言:虽然梦想为了现实暂时会妥协,但终有一天,它将会实现
 

 

相关文章:

《Android自定义控件三部曲文章索引》http://blog.csdn.net/harvic880925/article/details/50995268

这篇主要讲解ColorMatrix的相关知识,这里将涉及到矩阵乘法的相关知识。所以这篇是比较有难度的。

一、矩阵概述

1、定义

 

称为m*n矩阵

2、矩阵乘法

矩阵乘法其实并不难,它的意思就是将第一个矩阵A的第一行,与第二个矩阵B的第一列的数字分别相乘,得到的结果相加,最终的值做为结果矩阵的第(1,1)位置的值(即第一行,第一列)。
同样,A矩阵的第一行与B矩阵的第二列的数字分别相乘然后相加,结果做为结果矩阵第(1,2)位置的值(即第一行第二列)。
再如,A矩阵的第二行与B矩阵的第一列的数字分别相乘,然后相加,结果做为结果矩阵的第(2,1)位置的值(即第二行第一列)
算法其实并不难,这里要说明一个问题:

  • A矩阵的列数必须与B矩阵的行数相同,才能相乘!因为我们需要把A中的一行中的各个数字与B矩阵中的一列中的各个数字分别相乘,所以A的列数与B的行数必须相同才行!
  • 矩阵A乘以矩阵B和矩阵B乘以矩阵A的结果必然是不一样的。

 

 

二、色彩矩阵

对于色彩的存储,Bitmap类使用一个32位的数值来保存。红、绿、蓝及透明度各占8位,每一个色彩分量的取值范围是0-255。透明度为0表示完全透明,为255时,色彩完全可见。
 

1、色彩信息的矩阵表示

四阶表示
由于一个色彩信息包含R、G、B、Alpha信息,所以,我们必然要使用一个4阶色彩变换矩阵来修改色彩的每一个分量值:

 

 

 

注意:对于色彩变换矩阵,这里的色彩顺序是R、G、B、A而不是A、R、G、B!!!
如果想将色彩(0,255,0,255)更改为半透明时,可以使用下面的的矩阵运算来表示:

为什么使用五阶矩阵
上面使用四阶矩阵完全可以改变图片的RGBA值了,但考虑一种情况,如果我们只想在原有的R色上增加一些分量呢?
这时,我们就得再多加一阶来表示平移变换。所以,一个既包含线性变换,又包含平移变换的组合变换,称为仿射变换。使用四阶的色彩变换矩阵来修改色彩,只能够对色彩的每一个分量值进行乘(除)运算,如果要对这些分量值进行加减法的运算(平移变换),只能通过五阶矩阵来完成。
考虑下面这个变换:
1、红色分量值更改为原来的2倍;
2、绿色分量增加100;
则使用4阶矩阵的乘法无法实现,所以,应该在四阶色彩变换矩阵上增加一个“哑元坐标”,来实现所列的矩阵运算:

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

三、Android中的色彩矩阵

1、概述

在上面的所有讲解之后,大家也应该看出来了,色彩变换矩阵的表示形式,肯定是五阶的那种,所以大家看一下,在默认情况下,色彩变换矩阵的形式:

 

Android中的色彩矩阵是用ColorMatrics类来表示的。使用ColorMatrix的方法如下

 

// 生成色彩矩阵  
ColorMatrix colorMatrix = new ColorMatrix(new float[]{  
        1, 0, 0, 0, 0,  
        0, 1, 0, 0, 0,  
        0, 0, 1, 0, 0,  
        0, 0, 0, 0.5, 0,  
});  
mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));  

有关setColorFilter()函数的其它用法,下篇文章我们将会详细讲述,这篇我们只知道怎么设置ColorMatrix对象就可以了。

2、示例1(单个颜色的蓝色通道输出)

下面我们举个例子来简单看一下,我们对一个颜色值进行ColorMatrix操作会怎样:

 

 

public class MyView extends View {
    private Paint mPaint = new Paint();
    private Bitmap bitmap;// 位图

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);   
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setAntiAlias(true);
        mPaint.setARGB(255,200,100,100);
        // 绘制原始位图
        canvas.drawRect(0,0,500,600,mPaint);

        canvas.translate(550,0);
        // 生成色彩矩阵
        ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                0, 0, 0, 0, 0,
                0, 0, 0, 0, 0,
                0, 0, 1, 0, 0,
                0, 0, 0, 1, 0,
        });
        mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        canvas.drawRect(0,0,500,600,mPaint);
    }
}

在上面中,我们先将图笔颜色值设为(255,200,100,100),然后对其进行ColorMatrix颜色值运算,把红色和绿色都去掉,仅显示蓝色值;只显示蓝色值的效果在Photoshop中叫做蓝色通道。效果图如下:
左侧是原图,右侧是该图对应的蓝色通道

 

这里只是对一个颜色值,而ColorMatrics的最厉害的地方在于,能够很批量地改变图像中的所有颜色值。下面我们就对图像应用ColorMatrics的例子来看看,如果只显示图像中的蓝色通道会怎样

3、示例2(图片多颜色的蓝色通道输出)

下面我们就举个给Bitmap应用ColorMatrix的例子:

 

 

public class MyView extends View {
    private Paint mPaint = new Paint();
    private Bitmap bitmap;// 位图

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mPaint.setAntiAlias(true);
        // 获取位图
        bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.dog);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 绘制原始位图
        canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500 * bitmap.getHeight() / bitmap.getWidth()), mPaint);

        canvas.translate(510, 0);
        // 生成色彩矩阵
        ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                0, 0, 0, 0, 0,
                0, 0, 0, 0, 0,
                0, 0, 1, 0, 0,
                0, 0, 0, 1, 0,
        });
        mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500 * bitmap.getHeight() / bitmap.getWidth()), mPaint);
    }
}

这里分两次绘制了一个bitmap,第一次绘制了一个原始图像,然后利用ColorMatrix生成了一个仅包含蓝色的图像,用过PhotoShop的同学应该很清楚这个跟Photoshop中的蓝色通道的效果是一致的。效果图如下:

 

大家注意哦,不要在onDraw里new Paint对象,上节中我为了省事就直接在onDraw()函数中直接new 了Paint对象,由于onDraw函数在刷新时会连续调用多次,所以如果在其中不断的new对象,会造成程序不断的GC(内存回收),是会严重影响性能的!在程序中,我有时会了为了方便理解,就直接在o

评论 49
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值