当今是靠脸吃饭的时代,平时的人像、风景照、美食照等都须要加上一款优美的滤镜,才能让照片更加精致,更加吸引人,这样的照片可以让你在朋友圈更加出众,别具一格。canvas
所以一个智能手机固然少不了一款美颜APP,在商店中有众多的美颜APP,例如我比较喜欢的:Snapseed、InterPhoto、美颜相机和美人相机等等。这些相机都拥有很是美和优秀的滤镜,正由于有这些优秀的滤镜,才能让你的照片变得更美,所以做为开发者的咱们须要了解这些滤镜是怎么作出来的,通常都是经过Android自带的滤镜处理、OpenGL处理或者经过颜色RGB的滤镜处理。本文咱们不介绍OpenGL,由于OpenGL确实是一个很强大的图像处理技术。数组
Android的滤镜效果就是对图像进行必定的过滤加工处理,通常的使用Paint设置滤镜效果分为两类:bash
1)模糊遮罩滤镜(BlurMaskFilter);ide
2)浮雕遮罩滤镜(EmbossMaskFilter)。函数
经过Android的滤镜效果和颜色通道过滤这两种方式,能够对图像作出很好的滤镜效果,接下来学习下如何处理滤镜。post
Android的滤镜处理使用paint.setMaskFilter(maskfilter)
方法设置,其中能够设置BlurMaskFilter和EmbossMaskFilter这两款滤镜,而这两款滤镜都是继承MaskFilter这个基类。学习
BlurMaskFilter:即模糊遮罩滤镜,经过该滤镜可使图像呈现模糊效果。ui
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:this
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) {
}
});
}
}
复制代码
效果图: spa
在MaskFilterView的onDraw方法中,首先须要new一个BlurMaskFilter对象,咱们看下其构造方法:
public BlurMaskFilter(float radius, Blur style)
radius:模糊的半径,值越大模糊就越扩散。
style:模糊滤镜使用的类型,总共有四种类型能够选择,它们分别是:
1)INNER:在图像内部产生模糊;
2)NORMAL:将整个图像模糊掉;
3)OUTER:在Alpha边界外产生一层模糊,并且将本来的图像变透明。
4)SOLID:在图像的Alpha外边界产生一层与Paint颜色一致的模糊效果,但不影响图像自己。
注意:这里咱们须要须要关闭硬件加速,不然没效果。
上图效果中咱们使用了INNER,接下来咱们看看其余三种效果。
paint.setMaskFilter(new BlurMaskFilter(progress, BlurMaskFilter.Blur.NORMAL));
canvas.drawRect(r , paint);
复制代码
paint.setMaskFilter(new BlurMaskFilter(progress, BlurMaskFilter.Blur.OUTER));
canvas.drawRect(r , paint);
复制代码
paint.setMaskFilter(new BlurMaskFilter(progress, BlurMaskFilter.Blur.SOLID));
canvas.drawRect(r , paint);
复制代码
以上即是模糊遮罩滤镜的使用了,下面咱们看看浮雕遮罩滤镜的使用效果。
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的滤镜处理是经过ColorMatrix来实现的,即颜色矩阵,而后将ColorMatrix设置到ColorMatrixColorFilter,经过setColorFilter方法设置ColorMatrixColorFilter,这样就完成了设置颜色过滤器。setColorFilter还能够设置全部ColorFilter的子类,包括LightingColorFilter和PorterDuffColorFilter。
ColorMatrix顾名思义就是颜色矩阵,那么滤镜的全部处理效果都是经过颜色矩阵的变换实现的。因此须要读者可以熟悉基本的矩阵运算方法。若是读者目前还不认识矩阵,怎么办?不要紧,接下来咱们简单介绍下矩阵,以及基本的运算方法。读者能够自行参考百度百科。
定义:
矩阵加法:
矩阵减法:
矩阵乘法:
第一个矩阵A的第一行,与第二个矩阵B的第一列的数字分别相乘,获得的结果相加,最终的值作为结果矩阵的第(1,1)位置的值(即第一行,第一列)。 一样,A矩阵的第一行与B矩阵的第二列的数字分别相乘而后相加,获得的值做为结果矩阵第(1,2)位置的值(即第一行第二列)。
色彩矩阵: 通常的色彩矩阵使用四阶表示,也就是RGBA
半透明的色彩矩阵,如:
在四阶矩阵的基础上,增长一阶,而第五阶表示偏移量,上图表示红色份量值更改成原来的2倍,绿色份量增长100(1*100+100);
调用红色(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其强大之处在于经过矩阵运算能够实现颜色通道过滤,咱们有必要学习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方法,能够设置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);
复制代码
设置色彩的缩放函数,上面已经介绍过该方法了.
该方法是色彩旋转函数
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:设置饱和度
方法内部已经运算好的了,咱们只须要传一个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);
复制代码
RGB转成YUV,对应的还有一个方法setYUV2RGB,也就是YUV转成RGB。
setConcat(ColorMatrix matA, ColorMatrix matB):将颜色矩阵matA和matB复合,至关与对图片进行matA矩阵处理再进行矩阵matB处理。
matrixA.preConcat(ColorMatrix prematrix):等价于setConcat(matrixA, prematrix)
matrixA.postConcat(ColorMatrix postmatrix):等价于setConcat(prematrix,matrixA)
复制代码
ColorFilter做为颜色过滤器,有三个子类来实现颜色过滤: 1)ColorMatrixColorFilter:即色彩矩阵的颜色过滤器,配合ColorMatrix使用。 2)LightingColorFilter:即光照颜色过滤器,能过滤颜色和加强色彩的方法。 3)PorterDuffColorFilter:即图形混合滤镜,该是图形学的一个理论飞跃。
上文中已经使用过了ColorMatrixColorFilter,而且配合ColorMatrix使用。接下来主要介绍LightingColorFilter和PorterDuffColorFilter。
光照颜色过滤器,也就是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);
复制代码
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);
复制代码