一、前期基础知识详解
“滤镜通常用于相机镜头作为调色、添加效果之用。如UV镜、偏振镜、星光镜、各种色彩滤光片。滤镜也是绘图软件中用于制造特殊效果的工具统称,以Photoshop为例,它拥有风格化、画笔描边、模糊、扭曲、锐化、视频、素描、纹理、像素化、渲染、艺术效果、其他等12个滤镜。
滤镜也可以制作或下载。滤镜直接使用效果很不自然,要合理搭配才能得到好的效果。”
以上是维基百科中对于滤镜的定义,而在Android中滤镜,和Photoshop中一样,而且通过各种算法的调用,可以更加丰富的效果。Android应用中的相机应用和各种美颜修图软件更是将滤镜用到了极致。
滤镜处理的对象,通常分为两类:①静态图片;②实时相机预览
本文先分析第一种滤镜的使用——为静态图片添加滤镜效果。实现方式有多种,比如通过调用Android系统提供的图像处理API,可以设置图片的色调、饱和度、亮度,也可以调用ColorMatrix进行更加精确的图片色彩调控,还可以使用更加精细化的像素处理方式—提取图片像素点,然后对每个像素点进行处理,使图片变换不同的色彩效果,以上的方式都是调用Android系统提供的API进行处理,难点在于图像处理算法的研究,这也是专业图像处理人员的工作之一,尝试不同色彩矩阵的配合,可以创建出不同的色彩效果。
本文介绍另一种实现方式,使用GPUImage库进行各种滤镜效果实现,GPUImage是iOS的一个开源库,后来也有了Android的版本,可以实现五十多种的滤镜效果,不用开发者自己进行滤镜算法的实现,处理起来更加的方便,而且GPUImage可以做到的不仅仅是像ColorMatrix一样的色彩特效,还可以进一步实现美颜相机需要的其他特效,比如磨皮,美白等,功能会更加强大。
二、上代码,具体实现
①build.gradle文件中添加依赖;
compile'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.4.1'
②GPUImage API调用示例-黑白滤镜实现
1)创建布局文件,创建一个ImageView用于承载图片
2)Activity代码中调用API处理
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ImageView imageView;
private GPUImage gpuImage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.image);
//获得Assert资源文件,放入到Bitmap中
AssetManager asm = getAssets();
InputStream isp =null;
Bitmap bitmap = null;
try {
isp = asm.open("android30.jpg");
bitmap = BitmapFactory.decodeStream(isp);
isp.close();
} catch (IOException e) {
e.printStackTrace();
}
//也可以直接从Drawable中通过Bitmap的获取方式直接获取
//bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.android26);
/**核心代码:使用GPUImage处理图像
*setImage():Sets the image on which the filter should be applied.
*setFilter():Sets the filter which should be applied to the image.
*getBitmapWithFilterApplied():Gets the current displayed image with applied filter as a Bitmap.
*/
gpuImage = new GPUImage(this);
gpuImage.setImage(bitmap);
//设置灰度的滤镜
gpuImage.setFilter(new GPUImageGrayscaleFilter());
bitmap = gpuImage.getBitmapWithFilterApplied();
//显示处理后的图片
imageView.setImageBitmap(bitmap);
}
}
可以看到,设置黑白滤镜的步骤非常简单,调用GPUImage中的几个关键方法即可实现:
setImage():Sets the image onwhich the filter should be applied.里面传入的参数是bitmap,这个bitmap可以调用Bitmap常用的四种加载方式来获得;
setFilter():Sets the filter whichshould be applied to the image.里面传入的参数是一个具体的滤镜对象,想要实现什么样的效果,就传入什么的滤镜实例即可;
getBitmapWithFilterApplied():Getsthe current displayed image with applied filter as a Bitmap.最后调用该方法,将创建好的滤镜设置到bitmap对象中;
最后,只要把设置好滤镜的bitmap传给ImageView进行显示即可,整个过程结束。
原图:
运行效果如图:
三、GPUImage灵活一点的使用方式
(1)创建一个SeekBar,实现随着进度条变化,图像饱和度滤镜变化,实现的滤镜实例是new GPUImageSaturationFilter(), 代码如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ImageView imageView;
private GPUImage gpuImage;
private SeekBar seekbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.image);
seekbar = (SeekBar) findViewById(R.id.seekbar);
seekbar.setMax(12);
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//方法的调用,这里用到了回调的思想:我丢一个Progress给你,你处理后返还一个bitmap给我
imageView.setImageBitmap(getGPUImageWithBar(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
//初始化图片
imageView.setImageBitmap(getGPUImageFromAssets(0));
}
//方法的定义,定义一个有参数,有返回值的方法,参数接收SeekBar传过来的progress,返回值为bitmap
public Bitmap getGPUImageWithBar(int progress) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.android26);
gpuImage = new GPUImage(this);
gpuImage.setImage(bitmap);
//设置饱和度的滤镜
gpuImage.setFilter(new GPUImageSaturationFilter(progress));
bitmap = gpuImage.getBitmapWithFilterApplied();
return bitmap;
}
}
这里我们创建了一个getGPUImageWithBar()方法,里面传入int progress参数,然后在SeekBar的监听事件中调用这个方法,传入progress参数,然后方法返回一个bitmap,传给setImageBitmap()作为参数。这里用到了回调思想。
运行效果如图:
(2)封装一个工具类,把滤镜实现的代码封装
//Activity代码部分
public class MainActivity extends AppCompatActivity {
......
private GPUImageUtil gpuImageUtil;
private Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
......
context = getApplicationContext();
gpuImageUtil = new GPUImageUtil();
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
imageView.setImageBitmap(gpuImageUtil.getGpuImage(context,bitmap,progress));
Log.d(TAG, "onProgressChanged: ");
}
......
});
//初始化图片
imageView.setImageBitmap(gpuImageUtil.getGpuImage(context,bitmap, 0));
}
}
// GPUImage工具类部分
public class GPUImageUtil {
private static final String TAG = "GPUImageUtil";
private GPUImage gpuImage;
//把图片加载和图片滤镜处理放在同一个方法中完成,供外界进行调用
public Bitmap getGpuImage(Context context,Bitmap bitmap, int progress) {
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.android26);
gpuImage = new GPUImage(context);
gpuImage.setImage(bitmap);
gpuImage.setFilter(new GPUImageSaturationFilter(progress));
bitmap = gpuImage.getBitmapWithFilterApplied();
Log.d(TAG, "getGpuImage: "+progress);
return bitmap;
}
}
GPUImage工具类中的方法和(1)中类似,运行效果如图:
(3)请求网络图片,然后对图片设置滤镜效果
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private GPUImageUtil gpuImageUtil;
private Bitmap bitmap;
private ImageView imageView;
private Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
imageView = (ImageView) findViewById(R.id.image);
gpuImageUtil = new GPUImageUtil();
//开启异步线程加载图片并处理
MyAsyncTask asynTask = new MyAsyncTask();
asynTask.execute();
}
//创建内部类,继承自抽象类AsyncTask,指定三个泛型参数,第三个参数为返回值类型
class MyAsyncTask extends AsyncTask {
//doInBackground()中处理耗时操作,返回值类型定为Bitmap
@Override
protected Bitmap doInBackground(Integer... params) {
Bitmap bitmap = getGPUImageFromURL("http://himg2.huanqiu.com/attachment2010/2012/0808/20120808100424609.jpg");
return bitmap;
}
//onPostExecute()中处理UI操作,接收的参数来自doInBackground()方法中返回的
@Override
protected void onPostExecute(Bitmap bitmap) {
gpuImageUtil.getGpuImage(context, bitmap);
imageView.setImageBitmap(bitmap);
}
}
//通过HttpURLConnection获取网络图片
private Bitmap getGPUImageFromURL(String url) {
try {
URL imageUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) imageUrl.openConnection();
// 获得图像的字符流
InputStream ips = connection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(ips);
bitmap = BitmapFactory.decodeStream(bis);
bis.close();
ips.close();// 关闭流
} catch (java.io.IOException e) {
e.printStackTrace();
}
return bitmap;
}
}
1)网络请求是一个耗时操作,需要开启支线程;
2)网络请求之后得到的图片会在界面中展示,涉及到UI界面的变化,需在主线程中进行界面操作;
所以,我们这里使用AsyncTask进行异步线程的处理,重写两个关键方法:doInBackground()中处理耗时操作,返回值类型定为Bitmap;onPostExecute()中进行UI操作,接收的参数来自doInBackground()方法中返回的bitmap,然后调用GPUImage工具类的中的方法进行滤镜设置。
3)这里使用HTTPURLConnection进行网络图片的请求;
4)记得不要忘记添加网络请求权限!
(4)封装一个较为完整的GPUImage工具类,外界调用时,只需传入图片资源和滤镜类型,便可对图片进行相应的处理,代码如下:
public class GPUImageUtil {
private static GPUImageFilter filter;
/**
* 获取过滤器
* @param GPUFlag
* @return 滤镜类型
*/
public static GPUImageFilter getFilter(int GPUFlag){
switch (GPUFlag){
case 1:
filter = new GPUImageGrayscaleFilter();
break;
case 2:
filter = new GPUImageAddBlendFilter();
break;
case 3:
filter = new GPUImageAlphaBlendFilter();
break;
case 4:
filter = new GPUImageBilateralFilter();
break;
case 5:
filter = new GPUImageBoxBlurFilter();
break;
case 6:
filter = new GPUImageBrightnessFilter();
break;
case 7:
filter = new GPUImageBulgeDistortionFilter();
break;
case 8:
filter = new GPUImageCGAColorspaceFilter();
break;
case 9:
filter = new GPUImageChromaKeyBlendFilter();
break;
case 10:
filter = new GPUImageColorBalanceFilter();
break;
case 11:
filter = new GPUImageSaturationFilter(count);
break;
}
return filter;
}
public static Bitmap getGpuImage(Context context,GPUImage gpuImage,int FilterFlag){
AssetManager as = context.getAssets();
InputStream is = null;
Bitmap bitmap = null;
try {
is = as.open("link.jpg");
bitmap = BitmapFactory.decodeStream(is);
is.close();
} catch (IOException e) {
Log.e("GPUImage", "Error");
}
// 使用GPUImage处理图像
gpuImage = new GPUImage(context);
gpuImage.setImage(bitmap);
gpuImage.setFilter(getFilter(FilterFlag));
bitmap = gpuImage.getBitmapWithFilterApplied();
return bitmap;
}
public static Bitmap getGPUImageFromURL(String url) {
Bitmap bitmap = null;
try {
URL imageUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) imageUrl.openConnection();
// 获得图像的字符流
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bitmap = BitmapFactory.decodeStream(bis);
bis.close();
is.close();// 关闭流
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
}
总结:本文主要是使用了GPUImage实现了图片色彩特效的变换,这也是滤镜效果的一种,可以看见使用GPUImage对于静态图片的处理还是比较简单的,只要拿到Bitmap对象,然后对这个bitmap对象设置好滤镜效果即可。
最后附上iOS中GPUImage的滤镜效果汇总,便于之后查阅(iOS的滤镜效果更多一些,Android没有这么多):
1)Coloradjustments: 31 filters, 颜色处理相关
2)Image processing: 40 filters, 图像处理相关.
3)Blending modes: 29 filters, 混合模式相关.
4)Visual effects: 25 filters, 视觉效果相关.
#import "GPUImageBrightnessFilter.h" //亮度
#import "GPUImageExposureFilter.h" //曝光
#import "GPUImageContrastFilter.h" //对比度
#import "GPUImageSaturationFilter.h" //饱和度
#import "GPUImageGammaFilter.h" //伽马线
#import "GPUImageColorInvertFilter.h" //反色
#import "GPUImageSepiaFilter.h" //褐色(怀旧)
#import "GPUImageLevelsFilter.h" //色阶
#import "GPUImageGrayscaleFilter.h" //灰度
#import "GPUImageHistogramFilter.h" //色彩直方图,显示在图片上
#import "GPUImageHistogramGenerator.h" //色彩直方图
#import "GPUImageRGBFilter.h" //RGB
#import "GPUImageToneCurveFilter.h" //色调曲线
#import "GPUImageMonochromeFilter.h" //单色
#import "GPUImageOpacityFilter.h" //不透明度
#import "GPUImageHighlightShadowFilter.h" //提亮阴影
#import "GPUImageFalseColorFilter.h" //色彩替换(替换亮部和暗部色彩)
#import "GPUImageHueFilter.h" //色度
#import "GPUImageChromaKeyFilter.h" //色度键
#import "GPUImageWhiteBalanceFilter.h" //白平横
#import "GPUImageAverageColor.h" //像素平均色值
#import "GPUImageSolidColorGenerator.h" //纯色
#import "GPUImageLuminosity.h" //亮度平均
#import "GPUImageAverageLuminanceThresholdFilter.h" //像素色值亮度平均,图像黑白(有类似漫画效果)
#import "GPUImageLookupFilter.h" //lookup 色彩调整
#import "GPUImageAmatorkaFilter.h" //Amatorka lookup
#import "GPUImageMissEtikateFilter.h" //MissEtikate lookup
#import "GPUImageSoftEleganceFilter.h" //SoftElegance lookup
#pragma mark - 图像处理 Handle Image
#import "GPUImageCrosshairGenerator.h" //十字
#import "GPUImageLineGenerator.h" //线条
#import "GPUImageTransformFilter.h" //形状变化
#import "GPUImageCropFilter.h" //剪裁
#import "GPUImageSharpenFilter.h" //锐化
#import "GPUImageUnsharpMaskFilter.h" //反遮罩锐化
//#import "GPUImageFastBlurFilter.h" //模糊
#import "GPUImageGaussianBlurFilter.h" //高斯模糊
#import "GPUImageGaussianSelectiveBlurFilter.h" //高斯模糊,选择部分清晰
#import "GPUImageBoxBlurFilter.h" //盒状模糊
#import "GPUImageTiltShiftFilter.h" //条纹模糊,中间清晰,上下两端模糊
#import "GPUImageMedianFilter.h" //中间值,有种稍微模糊边缘的效果
#import "GPUImageBilateralFilter.h" //双边模糊
#import "GPUImageErosionFilter.h" //侵蚀边缘模糊,变黑白
#import "GPUImageRGBErosionFilter.h" //RGB侵蚀边缘模糊,有色彩
#import "GPUImageDilationFilter.h" //扩展边缘模糊,变黑白
#import "GPUImageRGBDilationFilter.h" //RGB扩展边缘模糊,有色彩
#import "GPUImageOpeningFilter.h" //黑白色调模糊
#import "GPUImageRGBOpeningFilter.h" //彩色模糊
#import "GPUImageClosingFilter.h" //黑白色调模糊,暗色会被提亮
#import "GPUImageRGBClosingFilter.h" //彩色模糊,暗色会被提亮
#import "GPUImageLanczosResamplingFilter.h" //Lanczos重取样,模糊效果
#import "GPUImageNonMaximumSuppressionFilter.h" //非最大抑制,只显示亮度最高的像素,其他为黑
#import "GPUImageThresholdedNonMaximumSuppressionFilter.h" //与上相比,像素丢失更多
#import "GPUImageSobelEdgeDetectionFilter.h" //Sobel边缘检测算法(白边,黑内容,有点漫画的反色效果)
#import "GPUImageCannyEdgeDetectionFilter.h" //Canny边缘检测算法(比上更强烈的黑白对比度)
#import "GPUImageThresholdEdgeDetectionFilter.h" //阈值边缘检测(效果与上差别不大)
#import "GPUImagePrewittEdgeDetectionFilter.h" //普瑞维特(Prewitt)边缘检测(效果与Sobel差不多,貌似更平滑)
#import "GPUImageXYDerivativeFilter.h" //XYDerivative边缘检测,画面以蓝色为主,绿色为边缘,带彩色
#import "GPUImageHarrisCornerDetectionFilter.h" //Harris角点检测,会有绿色小十字显示在图片角点处
#import "GPUImageNobleCornerDetectionFilter.h" //Noble角点检测,检测点更多
#import "GPUImageShiTomasiFeatureDetectionFilter.h" //ShiTomasi角点检测,与上差别不大
#import "GPUImageMotionDetector.h" //动作检测
#import "GPUImageHoughTransformLineDetector.h" //线条检测
#import "GPUImageParallelCoordinateLineTransformFilter.h" //平行线检测
#import "GPUImageLocalBinaryPatternFilter.h" //图像黑白化,并有大量噪点
#import "GPUImageLowPassFilter.h" //用于图像加亮
#import "GPUImageHighPassFilter.h" //图像低于某值时显示为黑
#pragma mark - 视觉效果 Visual Effect
#import "GPUImageSketchFilter.h" //素描
#import "GPUImageThresholdSketchFilter.h" //阀值素描,形成有噪点的素描
#import "GPUImageToonFilter.h" //卡通效果(黑色粗线描边)
#import "GPUImageSmoothToonFilter.h" //相比上面的效果更细腻,上面是粗旷的画风
#import "GPUImageKuwaharaFilter.h" //桑原(Kuwahara)滤波,水粉画的模糊效果;处理时间比较长,慎用
#import "GPUImageMosaicFilter.h" //黑白马赛克
#import "GPUImagePixellateFilter.h" //像素化
#import "GPUImagePolarPixellateFilter.h" //同心圆像素化
#import "GPUImageCrosshatchFilter.h" //交叉线阴影,形成黑白网状画面
#import "GPUImageColorPackingFilter.h" //色彩丢失,模糊(类似监控摄像效果)
#import "GPUImageVignetteFilter.h" //晕影,形成黑色圆形边缘,突出中间图像的效果
#import "GPUImageSwirlFilter.h" //漩涡,中间形成卷曲的画面
#import "GPUImageBulgeDistortionFilter.h" //凸起失真,鱼眼效果
#import "GPUImagePinchDistortionFilter.h" //收缩失真,凹面镜
#import "GPUImageStretchDistortionFilter.h" //伸展失真,哈哈镜
#import "GPUImageGlassSphereFilter.h" //水晶球效果
#import "GPUImageSphereRefractionFilter.h" //球形折射,图形倒立
#import "GPUImagePosterizeFilter.h" //色调分离,形成噪点效果
#import "GPUImageCGAColorspaceFilter.h" //CGA色彩滤镜,形成黑、浅蓝、紫色块的画面
#import "GPUImagePerlinNoiseFilter.h" //柏林噪点,花边噪点
#import "GPUImage3x3ConvolutionFilter.h" //3x3卷积,高亮大色块变黑,加亮边缘、线条等
#import "GPUImageEmbossFilter.h" //浮雕效果,带有点3d的感觉
#import "GPUImagePolkaDotFilter.h" //像素圆点花样
#import "GPUImageHalftoneFilter.h" //点染,图像黑白化,由黑点构成原图的大致图形
#pragma mark - 混合模式 Blend
#import "GPUImageMultiplyBlendFilter.h" //通常用于创建阴影和深度效果
#import "GPUImageNormalBlendFilter.h" //正常
#import "GPUImageAlphaBlendFilter.h" //透明混合,通常用于在背景上应用前景的透明度
#import "GPUImageDissolveBlendFilter.h" //溶解
#import "GPUImageOverlayBlendFilter.h" //叠加,通常用于创建阴影效果
#import "GPUImageDarkenBlendFilter.h" //加深混合,通常用于重叠类型
#import "GPUImageLightenBlendFilter.h" //减淡混合,通常用于重叠类型
#import "GPUImageSourceOverBlendFilter.h" //源混合
#import "GPUImageColorBurnBlendFilter.h" //色彩加深混合
#import "GPUImageColorDodgeBlendFilter.h" //色彩减淡混合
#import "GPUImageScreenBlendFilter.h" //屏幕包裹,通常用于创建亮点和镜头眩光
#import "GPUImageExclusionBlendFilter.h" //排除混合
#import "GPUImageDifferenceBlendFilter.h" //差异混合,通常用于创建更多变动的颜色
#import "GPUImageSubtractBlendFilter.h" //差值混合,通常用于创建两个图像之间的动画变暗模糊效果
#import "GPUImageHardLightBlendFilter.h" //强光混合,通常用于创建阴影效果
#import "GPUImageSoftLightBlendFilter.h" //柔光混合
#import "GPUImageChromaKeyBlendFilter.h" //色度键混合
#import "GPUImageMaskFilter.h" //遮罩混合
#import "GPUImageHazeFilter.h" //朦胧加暗
#import "GPUImageLuminanceThresholdFilter.h" //亮度阈
#import "GPUImageAdaptiveThresholdFilter.h" //自适应阈值
#import "GPUImageAddBlendFilter.h" //通常用于创建两个图像之间的动画变亮模糊效果
#import "GPUImageDivideBlendFilter.h" //通常用于创建两个图像之间的动画变暗模糊效果
---->>>>NEXT,GLSL语法掌握,为复杂片元着色器做准备
参考文章(重点):
基于GPUImage的实时美颜滤镜
iOS GPUImage研究总结
Android图像滤镜框架GPUImage从配置到应用