Android 滤镜效果和颜色通道过滤

当今是靠脸吃饭的时代,平时的人像、风景照、美食照等都需要加上一款优美的滤镜,才能让照片更加精致,更加吸引人,这样的照片能够让你在朋友圈更加出众,别具一格。

因此一个智能手机当然少不了一款美颜APP,在商店中有众多的美颜APP,例如我比较喜欢的:Snapseed、InterPhoto、美颜相机和美人相机等等。这些相机都拥有非常美和优秀的滤镜,正因为有这些优秀的滤镜,才能让你的照片变得更美,因此作为开发者的我们需要了解这些滤镜是怎么做出来的,一般都是通过Android自带的滤镜处理、OpenGL处理或者通过颜色RGB的滤镜处理。本文我们不介绍OpenGL,因为OpenGL确实是一个很强大的图像处理技术。

Android的滤镜效果就是对图像进行一定的过滤加工处理,一般的使用Paint设置滤镜效果分为两类:

1、Android自带的滤镜效果,而该滤镜效果可以分为:

1)模糊遮罩滤镜(BlurMaskFilter);

2)浮雕遮罩滤镜(EmbossMaskFilter)。

2、颜色RGB的滤镜处理,可以通过ColorMatrix设置。

通过Android的滤镜效果和颜色通道过滤这两种方式,可以对图像做出很好的滤镜效果,接下来学习下如何处理滤镜。

Android自带的滤镜效果

Android的滤镜处理使用paint.setMaskFilter(maskfilter)方法设置,其中可以设置BlurMaskFilter和EmbossMaskFilter这两款滤镜,而这两款滤镜都是继承MaskFilter这个基类。

BlurMaskFilter

BlurMaskFilter:即模糊遮罩滤镜,通过该滤镜可以使图像呈现模糊效果。

使用:
public class MaskFilterView extends View {

    private int progress = 10;
    private Paint paint;

    public MaskFilterView(Context context) {
        super(context);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    }

    public MaskFilterView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //需要关闭硬件加速(没有关闭则没效果)
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        paint.setColor(Color.RED);
        RectF r = new RectF(100, 100, 300, 300);
        /**模糊遮罩滤镜效果
         * BlurMaskFilter.Blur.INNER
         * BlurMaskFilter.Blur.NORMAL
         * BlurMaskFilter.Blur.OUTER
         * BlurMaskFilter.Blur.SOLID
         */
		paint.setMaskFilter(new BlurMaskFilter(progress, BlurMaskFilter.Blur.NORMAL));
        canvas.drawRect(r , paint);

    }


    public void setProgress(int progress) {
        if (progress <= 0){
            return;
        }
        this.progress = progress;
        postInvalidate();
    }
}
复制代码

Activity:

public class MaskFilterActivity extends AppCompatActivity {

    private SeekBar mSeekBar;
    private MaskFilterView mFilterView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mask_filter);
        mSeekBar = (SeekBar)this.findViewById(R.id.seekBar);
        mFilterView = (MaskFilterView)this.findViewById(R.id.my_view);
        mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                mFilterView.setProgress(progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
    }
}
复制代码

效果图:

在MaskFilterView的onDraw方法中,首先需要new一个BlurMaskFilter对象,我们看下其构造方法:

public BlurMaskFilter(float radius, Blur style)

radius:模糊的半径,值越大模糊就越扩散。

style:模糊滤镜使用的类型,总共有四种类型可以选择,它们分别是:

1)INNER:在图像内部产生模糊;

2)NORMAL:将整个图像模糊掉;

3)OUTER:在Alpha边界外产生一层模糊,而且将原本的图像变透明。

4)SOLID:在图像的Alpha外边界产生一层与Paint颜色一致的模糊效果,但不影响图像本身。

注意:这里我们需要需要关闭硬件加速,否则没效果。

上图效果中我们使用了INNER,接下来我们看看其他三种效果。

NORMAL:
paint.setMaskFilter(new BlurMaskFilter(progress, BlurMaskFilter.Blur.NORMAL));
canvas.drawRect(r , paint);
复制代码

OUTER:
paint.setMaskFilter(new BlurMaskFilter(progress, BlurMaskFilter.Blur.OUTER));
canvas.drawRect(r , paint);
复制代码

SOLID:
paint.setMaskFilter(new BlurMaskFilter(progress, BlurMaskFilter.Blur.SOLID));
canvas.drawRect(r , paint);
复制代码

以上便是模糊遮罩滤镜的使用了,下面我们看看浮雕遮罩滤镜的使用效果。

EmbossMaskFilter

EmbossMaskFilter(浮雕遮罩滤镜)让图像呈现一种凹凸不平的面具效果。

使用
paint.setMaskFilter(new EmbossMaskFilter(new float[]{30,30,30}, 0.2f, 20, progress));
canvas.drawBitmap(bitmap, 100, 300, paint);
复制代码

使用的时候,需要new一个EmbossMaskFilter对象,并通过paint.setMaskFilter方法设置,我们主要看EmbossMaskFilter的构造方法参数。

public EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius)
复制代码

direction:指定长度为xxx的数组标量[x,y,z],用来指定光源的位置;

ambient:指定周边背景光源(0~1);

specular:指镜面反射系数;

blurRadius:指定模糊半径。

注意:使用EmbossMaskFilter同样需要关闭硬件加速,否则没效果。

颜色RGB的滤镜处理

颜色RGB的滤镜处理是通过ColorMatrix来实现的,即颜色矩阵,然后将ColorMatrix设置到ColorMatrixColorFilter,通过setColorFilter方法设置ColorMatrixColorFilter,这样就完成了设置颜色过滤器。setColorFilter还可以设置所有ColorFilter的子类,包括LightingColorFilter和PorterDuffColorFilter。

ColorMatrix顾名思义就是颜色矩阵,那么滤镜的所有处理效果都是通过颜色矩阵的变换实现的。所以需要读者能够熟悉基本的矩阵运算方法。如果读者目前还不认识矩阵,怎么办?没关系,接下来我们简单介绍下矩阵,以及基本的运算方法。读者可以自行参考百度百科。

矩阵

定义:

矩阵加法:

矩阵减法:

矩阵乘法:

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

色彩矩阵: 一般的色彩矩阵使用四阶表示,也就是RGBA

半透明的色彩矩阵,如:

Android色彩矩阵使用五阶矩阵

在四阶矩阵的基础上,增加一阶,而第五阶表示偏移量,上图表示红色分量值更改为原来的2倍,绿色分量增加100(1*100+100);

ColorMatrix的使用

调用红色(R),绿色增加两倍。

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //需要关闭硬件加速(没有关闭则没效果)
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        paint.setColor(Color.RED);
        ColorMatrix matrix = new ColorMatrix(new float[]{
				0,0,0,0,0,
				0,1,0,0,200,
				0,0,1,0,0,
				0,0,0,1,0,
		});
        paint.setColorFilter(new ColorMatrixColorFilter(matrix ));
        canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
    }
复制代码

先new一个ColorMatrixColorFilter对象,并把ColorMatrix设置进去,setColorFilter方法把ColorMatrixColorFilter对象设置进去就可以完成设置颜色过滤器。

反相效果
ColorMatrix matrix = new ColorMatrix(new float[]{
				-1,0,0,0,255,
				0,-1,0,0,255,
				0,0,-1,0,255,
				0,0,0,1,0,
		});
paint.setColorFilter(new ColorMatrixColorFilter(matrix ));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

颜色增强

颜色增强:可以起到一个变亮的效果,通过矩阵缩放方式。

ColorMatrix matrix = 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,
		});
paint.setColorFilter(new ColorMatrixColorFilter(matrix ));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

黑白图片

去色原理:只要把RGB三通道的色彩信息设置成一样;即:R=G=B,那么图像就变成了灰色,并且,为了保证图像亮度不变,同一个通道中的R+G+B=1。 如:0.213+0.715+0.072=1;也就是RGB分别为:0.213,0.715,0.072; 三个数字是根据色彩光波频率及色彩心理学计算出来的。

ColorMatrix matrix = 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, 1f, 0,
        });
paint.setColorFilter(new ColorMatrixColorFilter(matrix ));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

发色效果

发色效果:如红色和绿色交换——把第一行和第二行交换。

ColorMatrix matrix = new ColorMatrix(new float[]{
			0,1f,0,0,0,
			1f,0,0,0,0,
			0,0,1f,0,0,
			0,0,0,1f,0,
		});
paint.setColorFilter(new ColorMatrixColorFilter(matrix ));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

复古风格
ColorMatrix matrix = 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,1f,0,
			});
paint.setColorFilter(new ColorMatrixColorFilter(matrix ));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

色彩运算

ColorMatrix色彩矩阵,除了以上直接设置矩阵的方式,还可以使用ColorMatrix类的方法来设置进行色彩运算:

1)色彩的缩放运算(matrix.setScale):也就是四阶矩阵RGBA对应的乘法运算。

ColorMatrix matrix = new ColorMatrix();
//setScale(float rScale, float gScale, float bScale, float aScale)
matrix.setScale(2, 2, 2f, 1);
paint.setColorFilter(new ColorMatrixColorFilter(matrix ));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

上图中RGB都方法原来的两倍。

2)色彩的平移运算,也就是矩阵加法运算。

ColorMatrix的API

通过上面的学习我们知道ColorMatrix其强大之处在于通过矩阵运算可以实现颜色通道过滤,我们有必要学习ColorMatrix的API。

构造方法

三个构造方法,可以不需要参数,可以传一个float数组(矩阵),也可以ColorMatrix对象作为参数。

看下ColorMatrix()方法里面的reset()方法。

/**
     * Set this colormatrix to identity:
     * <pre>
     * [ 1 0 0 0 0   - red vector
     *   0 1 0 0 0   - green vector
     *   0 0 1 0 0   - blue vector
     *   0 0 0 1 0 ] - alpha vector
     * </pre>
     */
    public void reset() {
        final float[] a = mArray;
        Arrays.fill(a, 0);
        a[0] = a[6] = a[12] = a[18] = 1;
    }
复制代码

该方法主要是初始化一个矩阵,而且将RGBA都设置为1。

set方法

提供两个set方法,可以设置float数组(矩阵),也可以设置ColorMatrix对象,跟构造方法对应起来。

matrix.set(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,1f,0,
        });
paint.setColorFilter(new ColorMatrixColorFilter(matrix ));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

setScale方法

设置色彩的缩放函数,上面已经介绍过该方法了.

setRotate

该方法是色彩旋转函数

axis:代表绕哪一个轴旋转,0,1,2 (0红色,1绿色,2蓝色);

degrees:旋转的度数。

该函数已经做好了矩阵的设置和运算了。

matrix.setRotate(0,progress);
paint.setColorFilter(new ColorMatrixColorFilter(matrix ));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

setSaturation

setSaturation:设置饱和度

方法内部已经运算好的了,我们只需要传一个float类型参数sat。

sat:1表示是原来不变,0表示灰色;如果大于1增加饱和度。

matrix.setSaturation(progress);
paint.setColorFilter(new ColorMatrixColorFilter(matrix ));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

setRGB2YUV

RGB转成YUV,对应的还有一个方法setYUV2RGB,也就是YUV转成RGB。

setConcat
setConcat(ColorMatrix matA, ColorMatrix matB):将颜色矩阵matA和matB复合,相当与对图片进行matA矩阵处理再进行矩阵matB处理。

matrixA.preConcat(ColorMatrix prematrix):等价于setConcat(matrixA, prematrix)

matrixA.postConcat(ColorMatrix postmatrix):等价于setConcat(prematrix,matrixA)
复制代码

ColorFilter

ColorFilter作为颜色过滤器,有三个子类来实现颜色过滤: 1)ColorMatrixColorFilter:即色彩矩阵的颜色过滤器,配合ColorMatrix使用。 2)LightingColorFilter:即光照颜色过滤器,能过滤颜色和增强色彩的方法。 3)PorterDuffColorFilter:即图形混合滤镜,该是图形学的一个理论飞跃。

上文中已经使用过了ColorMatrixColorFilter,并且配合ColorMatrix使用。接下来主要介绍LightingColorFilter和PorterDuffColorFilter。

LightingColorFilter

光照颜色过滤器,也就是ColorMatrixColorFilter的简化版本。

public LightingColorFilter(@ColorInt int mul, @ColorInt int add) {
        mMul = mul;
        mAdd = add;
    }
复制代码

通过构造方法设置过滤颜色,参数解析:

mul:multiply,也就是乘法 ;

add:加法,也就是颜色偏移量。

paint.setColorFilter(new LightingColorFilter(0x00ff00, 0xff0000));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

PorterDuffColorFilter
public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
        mColor = color;
        mMode = mode;
    }
复制代码

color:源颜色, mode:色彩的混合模式:

1)PorterDuff.Mode.CLEAR:所绘制不会提交到画布上 ;

2)PorterDuff.Mode.SRC:显示上层绘制图片 ;

3)PorterDuff.Mode.DST:显示下层绘制图片 ;

4)PorterDuff.Mode.SRC_OVER:正常绘制显示,上下层绘制叠盖 ;

5)PorterDuff.Mode.DST_OVER:上下层都显示,下层居上显示 ;

6)PorterDuff.Mode.SRC_IN:取两层绘制交集,显示上层;

7)PorterDuff.Mode.DST_IN:取两层绘制交集。显示下层;

8)PorterDuff.Mode.SRC_OUT:取上层绘制非交集部分;

9)PorterDuff.Mode.DST_OUT:取下层绘制非交集部分;

10)PorterDuff.Mode.SRC_ATOP:取下层非交集部分与上层交集部分;

11)PorterDuff.Mode.DST_ATOP:取上层非交集部分与下层交集部分;

12)PorterDuff.Mode.XOR:异或:去除两图层交集部分;

13)PorterDuff.Mode.DARKEN:取两图层全部区域,交集部分颜色加深;

14)PorterDuff.Mode.LIGHTEN:取两图层全部,点亮交集部分颜色;

15)PorterDuff.Mode.MULTIPLY:取两图层交集部分叠加后颜色;

16)PorterDuff.Mode.SCREEN:取两图层全部区域,交集部分变为透明色。

paint.setColorFilter(new PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 400, 400*bitmap.getHeight()/bitmap.getWidth()), paint);
复制代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值