Android的毛玻璃模糊效果,我使用OpenCV来搞

521 阅读4分钟
原文链接: mp.weixin.qq.com

作者:JerryloveEmily

地址:http://www.jianshu.com/p/d0d7809007a1

声明:本文是JerryloveEmily原创,已获其授权发布,未经原作者允许请勿转载

开始学习OpenCV,毛玻璃模糊效果目前网上流行的有三种办法:

1、使用java来编写一长串的像素处理办法算法来改变bitmap(性能教差,而且一堆算法代码,难理解,不优雅)

2、使用C语言的方式同样使用和java一样的算法来实现(性能好,同样一堆算法代码难理解,也不优雅)

3、使用RenderScript这个有Api版本的限制。

现在我们可以利用OpenCV框架中滤波算法来实现图片的模糊虚化。

准备工作

先到OpenCV官网, 下载Android平台的sdk包: http://www.opencv.org  

解压后:sdk目录里是openCV的一些动态库,cmake构建文件,以及java的一些api。

新建一个支持NDK的工程:

配置集成OpenCV库到工程:

我这里只编译支持了armeabi,cpu架构的平台,需要在app,module的build.gradle中做一些修改:

对了这里我使用AS自带的cmake工具来构建NDK库的链接和编译的支持,所以不需要再写Android.mk的配置文件,这里配置下CMakeLists.txt就可以,更加简单:

# For more information about using CMake with Android Studio, read the

# documentation: https:# Sets the minimum version of CMake required to build the native library.cmake_minimum_required(VERSION 3.4.1)# 添加我们自己要编译的so库,以及源码文件add_library(             image_process             SHARED             src/main/cpp/image_process.cpp )# 增加opencv库add_library( opencv_java3 SHARED IMPORTED )# 编译的平台是armeabiif(${ANDROID_ABI} STREQUAL "armeabi")# 设置动态库文件的路径属性set_target_properties(    opencv_java3    PROPERTIES IMPORTED_LOCATION    ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi/libopencv_java3.so    )endif(${ANDROID_ABI} STREQUAL "armeabi")# opencv库的头文件路径设置,在此是opencv-sdk的路径,当然你也可以把include目录拷贝到工程中include_directories(    D:/opencv-3.2.0-android-sdk/OpenCV-android-sdk/sdk/native/jni/include)find_library( # Sets the name of the path variable.              log-lib              # Specifies the name of the NDK library that              # you want CMake to locate.              log )# 需要链接的库target_link_libraries( # Specifies the target library.                       image_process                       opencv_java3                       # Links the target library to the log library                       # included in the NDK.                       ${log-lib} )

上面的添加依赖库,和自己要编译的so库的写法都是差不多的,就是这些套路。(自古深情留不住,总是套路得人心)同时把sdk中libopencv_java3.so文件拷贝到对应的工程目录下我这里是jniLibs为了方便不然还得配置gradle修改source目录的映射路径:

编写java层的对外开发调用api

public class ImageProcessUtils {

     public static Bitmap blur(Bitmap srcBitmap){                int width = srcBitmap.getWidth();        int height = srcBitmap.getHeight();                int[] pixels = new int[width * height];                srcBitmap.getPixels(pixels, 0, width, 0, 0, width, height);                blurImage(pixels, width, height);                Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);                newBitmap.setPixels(pixels, 0, width, 0, 0, width, height);        return newBitmap;    }        public static native void blurImage(int[] pixels, int w, int h);        static {        System.loadLibrary("image_process");        System.loadLibrary("opencv_java3");    }}

接下来是在NDK中使用opencv来实现图片的毛玻璃化

#include <jni.h>

#include <android/log.h>#include <opencv2/opencv.hpp>    // 引入opencv库头文件#include <opencv2/highgui/highgui.hpp> // 引入opencv图形界面,暂时没用到// 定义了log日志宏函数,方便打印日志在logcat中查看调试#define TAG "Jerry-NDK-Image-Pro"#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , TAG, __VA_ARGS__)#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , TAG, __VA_ARGS__)#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , TAG, __VA_ARGS__)#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , TAG, __VA_ARGS__)using namespace cv;extern "C"JNIEXPORT void JNICALLJava_com_jerry_jerryopencvdemo_imageprocess_ImageProcessUtils_blurImage(        JNIEnv *env,        jclass jcls,        jintArray jarr_pixels,        jint j_width,        jint j_height) {    // 获取java中传入的像素数组值,jintArray转化成jint指针数组    jint *c_pixels = env->GetIntArrayElements(jarr_pixels, JNI_FALSE);    if(c_pixels == NULL){        return;    }    LOGE("图片宽度:%d, 高度:%d", j_width, j_height);    // 把c的图片数据转化成opencv的图片数据    // 使用Mat创建图片    Mat mat_image_src(j_height, j_width, CV_8UC4, (unsigned char*) c_pixels);    // 选择和截取一段行范围的图片    Mat temp = mat_image_src.rowRange(j_height / 3, 2 * j_height / 3);    // 方框滤波//    boxFilter(temp, temp, -1, Size(85, 85));    // 均值滤波    blur(temp, temp, Size(85, 85));    // 使用高斯模糊滤波//    GaussianBlur(temp, temp, Size(45, 13), 0, 0);    // 将opencv图片转化成c图片数据,RGBA转化成灰度图4通道颜色数据    cvtColor(temp, temp, CV_RGBA2GRAY, 4);    // 更新java图片数组和释放c++中图片数组的值    env->ReleaseIntArrayElements(jarr_pixels, c_pixels, JNI_FALSE);}

原图:

毛玻璃后效果图:

简单的利用了滤波算法函数处理,来达到毛玻璃的效果,当然opencv的强大远远不限于此。关于opencv进一步的学习使用还会继续记录在博客中。

推荐阅读

1、编程语言高质量资料(视频+文档+实战)| 学习资料分享 07

2、Android DataBinding & MVVM

3、为什么程序员没有职业资格证