开始学习OpenCV,毛玻璃模糊效果目前网上流行的有三种办法:
- 使用java来编写一长串的像素处理办法算法来改变bitmap(性能教差,而且一堆算法代码,难理解,不优雅)
- 使用C语言的方式同样使用和java一样的算法来实现(性能好,同样一堆算法代码难理解,也不优雅)
- 使用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://d.android.com/studio/projects/add-native-code.html
# 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 )
# 编译的平台是armeabi
if(${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 {
/**
* 毛玻璃一张图片
* @param srcBitmap 原始图片
* @return 毛玻璃后的图片
*/
public static Bitmap blur(Bitmap srcBitmap){
// 获取原始图片的宽高
int width = srcBitmap.getWidth();
int height = srcBitmap.getHeight();
// 初始化一个用来存储图片所有像素的int数组
int[] pixels = new int[width * height];
// 把原始图片的所有原始存入数组中
srcBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
// 通过jni本地方法毛玻璃化图片
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);
// 加载so库
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 JNICALL
Java_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进一步的学习使用还会继续记录在博客中。