Android图像滤镜框架GPUImage从配置到应用

源作者博客地址:http://blog.csdn.net/it_zjyang/article/details/52268918

GPUImage简介
GPUImage 是iOS下一个开源的基于GPU的图像处理库,提供各种各样的图像处理滤镜,并且支持照相机和摄像机的实时滤镜。GPUImage for Android是它在Android下的实现,同样也是开源的。其中提供了几十多种常见的图片滤镜API,且其机制是基于GPU渲染,处理速度相应也比较快,是一个不错的图片实时处理框架。

GitHub地址:https://github.com/CyberAgent/android-gpuimageGPUImage使用
环境搭建
首先,要使用这个库自然是要先导入依赖,在app的gradle文件中添加:

    compile 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.4.1'

将要处理的图片素材放进Assets文件夹,如果目录中没有这个文件夹,可以自己新建一个:



我这里以名为link.jpg的图片作为素材复制进去:


素材原图link.jpg:


API调用:
GPUImage主要通过一个GPUImageFilter类来提供各种滤镜效果实现类,比如我们来实现一个将图片变成黑白的滤镜:

public class GPUActivity extends Activity{  

    private GPUImage gpuImage;  
    //显示处理结果  
    private ImageView resultIv;  

    protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_gpu);  
            resultIv = (ImageView) findViewById(R.id.resultIv);  

        //获得Assets资源文件  
        AssetManager as = 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(this);  
        gpuImage.setImage(bitmap);  
        gpuImage.setFilter(new GPUImageGrayscaleFilter());  
        bitmap = gpuImage.getBitmapWithFilterApplied();  
        //显示处理后的图片  
        resultIv.setImageBitmap(bitmap);  
    }  
}  

布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="horizontal"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
    <ImageView  
            android:id="@+id/resultIv"  
            android:layout_width="match_parent"  
            android:layout_height="wrap_content"  
            android:layout_gravity="center_vertical"  
            />  
</LinearLayout>  

效果:


可以看到,只是将Assets中的资源转换为bitmap,再通过GPUImage对象来设置图片(setImage)和过滤(setImage),在setFilter中传进了一个GPUImageGrayscaleFilter实例,表示设置为灰度滤镜,最终再通过调用getBitmapWithFilterApplied()来应用以上设置,并返回一个处理后的bitmap对象,再将其显示出来。

因此,如果你要使用其他滤镜,只需替换setFilter的参数便可以,GPUImage提供了50多种滤镜类。

调整饱和度|亮度
在GPUImage的一些滤镜类中,有一些是带有数值参数的构造方法,传进不同的值会有不同程度的效果。

调整饱和度主要通过这个方法:GPUImageSaturationFilter(float saturation)
代码:

public class GPUActivity extends Activity{  

    private GPUImage gpuImage;  
    //显示处理结果  
    private ImageView resultIv;  
    //进度条  
    private SeekBar seekbar;  

    protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_gpu);  
        resultIv = (ImageView) findViewById(R.id.resultIv);  

        seekbar = (SeekBar)this.findViewById(R.id.seekbar);  
        seekbar.setMax(10);  
        seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {  
                    @Override  
                    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {  
                //通过进度条的值更改饱和度  
                        resultIv.setImageBitmap(getGPUImageFromAssets(progress));  
                    }  

                    @Override  
                    public void onStartTrackingTouch(SeekBar seekBar) {  
  
                    }  

                    @Override  
                    public void onStopTrackingTouch(SeekBar seekBar) {  

                    }  
            });  
 
        //初始化图片  
        resultIv.setImageBitmap(getGPUImageFromAssets(0));  
    }  

//根据传进来的数值设置素材饱和度  
public Bitmap getGPUImageFromAssets(int progress){  
      
    //获得Assets资源文件  
    AssetManager as = 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(this);  
    gpuImage.setImage(bitmap);  
    gpuImage.setFilter(new GPUImageSaturationFilter(progress));  
    bitmap = gpuImage.getBitmapWithFilterApplied();  
    return bitmap;  
    }  
}  

布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
android:orientation="vertical"  
android:layout_width="match_parent"  
android:layout_height="match_parent"  
android:gravity="center_vertical">  
<ImageView  
        android:id="@+id/resultIv"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_gravity="center_vertical"  
        />  
<SeekBar  
        android:id="@+id/seekbar"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:visibility="visible"/>  
</LinearLayout>  

效果:


分析:我们这里通过一个seekbar进度条来调整其饱和度大小,一拖动进度条,便调用seekBar的onProgressChanged()方法,并将progress传递给getGPUImageFromAssets()方法,注意到在getGPUImageFromAssets()方法中gpuImage.setFilter(new GPUImageSaturationFilter(progress));将progress设置给了饱和度滤镜,从而调整图片的饱和度。

上面演示了如何通过GPUImage调整饱和度,要实现亮度的调整仅需将Filter改为GPUImageBrightnessFilter,并且在设置progress的时候在区间0-1之间设置便可,如下:

gpuImage.setFilter(new GPUImageBrightnessFilter(progress*0.1f));  

网络图片滤镜处理
上面的demo中的Bitmap都是从Assets文件夹中获取而来,但实际开发中可能还有很多情况是通过URL获取网络资源图片,可以通过如下方式:

public class GPUActivity extends Activity{  

private GPUImage gpuImage;  
//显示处理结果  
private ImageView resultIv;  

protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity_gpu);  
    resultIv = (ImageView) findViewById(R.id.resultIv);  

//开启异步线程加载图片并处理  
    MyAsynTask asynTask = new MyAsynTask();  
    asynTask.execute();  

}  

class MyAsynTask extends AsyncTask<Integer,Integer,Bitmap>{  

    @Override  
    protected Bitmap doInBackground(Integer... params) {  
        Bitmap bitmap = getGPUImageFromURL("http://pic36.nipic.com/20131225/15361977_174053547194_2.jpg");  
        return bitmap;  
    }  

    @Override  
    protected void onPostExecute(Bitmap bitmap) {  
        // 使用GPUImage处理图像  
        gpuImage = new GPUImage(getApplicationContext());  
        gpuImage.setImage(bitmap);  
        gpuImage.setFilter(new GPUImageGrayscaleFilter());  
        bitmap = gpuImage.getBitmapWithFilterApplied();  
        //显示处理后的图片  
        resultIv.setImageBitmap(bitmap);  
    }  
}  

public static Bitmap getGPUImageFromURL(String url) {  
    Bitmap bitmap = null;  
    try {  
        URL iconUrl = new URL(url);  
        URLConnection conn = iconUrl.openConnection();  
        HttpURLConnection http = (HttpURLConnection) conn;  
        int length = http.getContentLength();  
        conn.connect();  
        // 获得图像的字符流  
        InputStream is = conn.getInputStream();  
        BufferedInputStream bis = new BufferedInputStream(is, length);  
        bitmap = BitmapFactory.decodeStream(bis);  
        bis.close();  
        is.close();// 关闭流  
    } catch (Exception e) {  
        e.printStackTrace();  
    }  
    return bitmap;  
}  
}  

当然,还要记得在Application.xml中添加网络访问权限:

<uses-permission android:name="android.permission.INTERNET"></uses-permission>  

代码分析:由于访问网络图片,所以需要放在子线程中进行,所以这里通过AsynTask(Android异步线程,不清楚的可以度娘),现在子线程请求完网络图片并转换为Bitmap传递给主线程中对图片进行滤镜处理并显示出来。

最佳实践
在实际开发中可以将这些API封装成一个工具类,只需传入我们的图片资源以及滤镜类型,便可以对图片做出处理:

public class GPUImageUtil {  

private static GPUImageFilter filter;  
  
//饱和度、亮度等参数指数  
private static int count;  

/** 
 * 获取过滤器 
 * @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 getGPUImageFromAssets(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 iconUrl = new URL(url);  
        URLConnection conn = iconUrl.openConnection();  
        HttpURLConnection http = (HttpURLConnection) conn;  
        int length = http.getContentLength();  
        conn.connect();  
        // 获得图像的字符流  
        InputStream is = conn.getInputStream();  
        BufferedInputStream bis = new BufferedInputStream(is, length);  
        bitmap = BitmapFactory.decodeStream(bis);  
        bis.close();  
        is.close();// 关闭流  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    return bitmap;  
}  

//调整饱和度、亮度等  
public static void changeSaturation(int curCount){  
    GPUImageUtil.count = curCount;  
}  
}  

这里只列举了部分作为举例,可以根据自己实际开发想要的滤镜进行添加。

作了一个小Demo,可以进行滤镜切换和饱和度调整,效果如下:


感兴趣的朋友可以下载源码:点此下载

附录
附上部分滤镜类型的API中文参照,便于查阅:
"GPUImageFastBlurFilter" 【模糊】"GPUImageGaussianBlurFilter" 【高斯模糊】"GPUImageGaussianSelectiveBlurFilter" 【高斯模糊,选择部分清晰】"GPUImageBoxBlurFilter" 【盒状模糊】"GPUImageTiltShiftFilter" 【条纹模糊,中间清晰,上下两端模糊】"GPUImageMedianFilter.h" 【中间值,有种稍微模糊边缘的效果】"GPUImageBilateralFilter" 【双边模糊】"GPUImageErosionFilter" 【侵蚀边缘模糊,变黑白】"GPUImageRGBErosionFilter" 【RGB侵蚀边缘模糊,有色彩】"GPUImageDilationFilter" 【扩展边缘模糊,变黑白】"GPUImageRGBDilationFilter" 【RGB扩展边缘模糊,有色彩】"GPUImageOpeningFilter" 【黑白色调模糊】"GPUImageRGBOpeningFilter" 【彩色模糊】"GPUImageClosingFilter" 【黑白色调模糊,暗色会被提亮】"GPUImageRGBClosingFilter" 【彩色模糊,暗色会被提亮】"GPUImageLanczosResamplingFilter" 【Lanczos重取样,模糊效果】"GPUImageNonMaximumSuppressionFilter" 【非最大抑制,只显示亮度最高的像素,其他为黑】"GPUImageThresholdedNonMaximumSuppressionFilter" 【与上相比,像素丢失更多】"GPUImageCrosshairGenerator" 【十字】"GPUImageLineGenerator" 【线条】"GPUImageTransformFilter" 【形状变化】"GPUImageCropFilter" 【剪裁】"GPUImageSharpenFilter" 【锐化】"GPUImageUnsharpMaskFilter" 【反遮罩锐化】"GPUImageSobelEdgeDetectionFilter" 【Sobel边缘检测算法(白边,黑内容,有点漫画的反色效果)】"GPUImageCannyEdgeDetectionFilter" 【Canny边缘检测算法(比上更强烈的黑白对比度)】"GPUImageThresholdEdgeDetectionFilter" 【阈值边缘检测(效果与上差别不大)】"GPUImagePrewittEdgeDetectionFilter" 【普瑞维特(Prewitt)边缘检测(效果与Sobel差不多,貌似更平滑)】"GPUImageXYDerivativeFilter" 【XYDerivative边缘检测,画面以蓝色为主,绿色为边缘,带彩色】"GPUImageHarrisCornerDetectionFilter" 【Harris角点检测,会有绿色小十字显示在图片角点处】"GPUImageNobleCornerDetectionFilter" 【Noble角点检测,检测点更多】"GPUImageShiTomasiFeatureDetectionFilter" 【ShiTomasi角点检测,与上差别不大】"GPUImageMotionDetector" 【动作检测】"GPUImageHoughTransformLineDetector" 【线条检测】"GPUImageParallelCoordinateLineTransformFilter" 【平行线检测】"GPUImageLocalBinaryPatternFilter" 【图像黑白化,并有大量噪点】"GPUImageLowPassFilter" 【用于图像加亮】"GPUImageHighPassFilter" 【图像低于某值时显示为黑】"GPUImageSketchFilter" 【素描】"GPUImageThresholdSketchFilter" 【阀值素描,形成有噪点的素描】"GPUImageToonFilter" 【卡通效果(黑色粗线描边)】"GPUImageSmoothToonFilter" 【相比上面的效果更细腻,上面是粗旷的画风】"GPUImageKuwaharaFilter" 【桑原(Kuwahara)滤波,水粉画的模糊效果;处理时间比较长,慎用】"GPUImageMosaicFilter" 【黑白马赛克】"GPUImagePixellateFilter" 【像素化】"GPUImagePolarPixellateFilter" 【同心圆像素化】"GPUImageCrosshatchFilter" 【交叉线阴影,形成黑白网状画面】"GPUImageColorPackingFilter" 【色彩丢失,模糊(类似监控摄像效果)】"GPUImageVignetteFilter" 【晕影,形成黑色圆形边缘,突出中间图像的效果】"GPUImageSwirlFilter" 【漩涡,中间形成卷曲的画面】"GPUImageBulgeDistortionFilter" 【凸起失真,鱼眼效果】"GPUImagePinchDistortionFilter" 【收缩失真,凹面镜】"GPUImageStretchDistortionFilter" 【伸展失真,哈哈镜】"GPUImageGlassSphereFilter" 【水晶球效果】"GPUImageSphereRefractionFilter" 【球形折射,图形倒立】 "GPUImagePosterizeFilter" 【色调分离,形成噪点效果】"GPUImageCGAColorspaceFilter" 【CGA色彩滤镜,形成黑、浅蓝、紫色块的画面】"GPUImagePerlinNoiseFilter" 【柏林噪点,花边噪点】"GPUImage3x3ConvolutionFilter" 【3x3卷积,高亮大色块变黑,加亮边缘、线条等】"GPUImageEmbossFilter" 【浮雕效果,带有点3d的感觉】"GPUImagePolkaDotFilter" 【像素圆点花样】"GPUImageHalftoneFilter" 【点染,图像黑白化,由黑点构成原图的大致图形】混合模式 Blend"GPUImageMultiplyBlendFilter" 【通常用于创建阴影和深度效果】"GPUImageNormalBlendFilter" 【正常】"GPUImageAlphaBlendFilter" 【透明混合,通常用于在背景上应用前景的透明度】"GPUImageDissolveBlendFilter" 【溶解】"GPUImageOverlayBlendFilter" 【叠加,通常用于创建阴影效果】"GPUImageDarkenBlendFilter" 【加深混合,通常用于重叠类型】"GPUImageLightenBlendFilter" 【减淡混合,通常用于重叠类型】"GPUImageSourceOverBlendFilter" 【源混合】"GPUImageColorBurnBlendFilter" 【色彩加深混合】"GPUImageColorDodgeBlendFilter" 【色彩减淡混合】"GPUImageScreenBlendFilter" 【屏幕包裹,通常用于创建亮点和镜头眩光】"GPUImageExclusionBlendFilter" 【排除混合】"GPUImageDifferenceBlendFilter" 【差异混合,通常用于创建更多变动的颜色】"GPUImageSubtractBlendFilter" 【差值混合,通常用于创建两个图像之间的动画变暗模糊效果】"GPUImageHardLightBlendFilter" 【强光混合,通常用于创建阴影效果】"GPUImageSoftLightBlendFilter" 【柔光混合】"GPUImageChromaKeyBlendFilter" 【色度键混合】"GPUImageMaskFilter" 【遮罩混合】"GPUImageHazeFilter" 【朦胧加暗】"GPUImageLuminanceThresholdFilter" 【亮度阈】"GPUImageAdaptiveThresholdFilter" 【自适应阈值】"GPUImageAddBlendFilter" 【通常用于创建两个图像之间的动画变亮模糊效果】"GPUImageDivideBlendFilter" 【通常用于创建两个图像之间的动画变暗模糊效果】

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 最近需要给直播项目中添加美颜的功能,调研了很多SDK和开源代码(视决,涂图,七牛,金山云,videoCore等),...
    未来的路就在那阅读 1,918评论 1 1
  • 不同图像灰度不同,边界处一般会有明显的边缘,利用此特征可以分割图像。需要说明的是:边缘和物体间的边界并不等同,边缘...
    大川无敌阅读 13,631评论 0 29
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,612评论 4 59
  • 时间:2016年5月25日18:31:01作者:JustDo23说明:在录入用户信息的时候有时候会需要填写居民身份...
    JustDo23阅读 11,077评论 6 11
  • 大一下学期,我发现不管我起得多早,最后还是等室友们一起出门去上课,而且基本踩点。就是因为不知什么时候开始形成的模式...
    蔓茯苓阅读 179评论 10 1