Android使用GPUImage实现滤镜效果精炼详解(一)

一、前期基础知识详解

“滤镜通常用于相机镜头作为调色、添加效果之用。如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用于承载图片

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />
</LinearLayout> 

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<Integer, Integer, Bitmap> {

        //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从配置到应用

猜你喜欢

转载自blog.csdn.net/weixin_41101173/article/details/80374455
今日推荐