開始學(xué)習(xí)OpenCV又兵,毛玻璃模糊效果目前網(wǎng)上流行的有三種辦法:
- 使用java來編寫一長串的像素處理辦法算法來改變bitmap(性能教差炎咖,而且一堆算法代碼,難理解,不優(yōu)雅)
- 使用C語言的方式同樣使用和java一樣的算法來實(shí)現(xiàn)(性能好乘盼,同樣一堆算法代碼難理解升熊,也不優(yōu)雅)
- 使用RenderScript這個有Api版本的限制。
現(xiàn)在我們可以利用OpenCV框架中濾波算法來實(shí)現(xiàn)圖片的模糊虛化绸栅。
準(zhǔn)備工作:
先到OpenCV官網(wǎng), 下載Android平臺的sdk包: http://www.opencv.org
解壓后:
sdk目錄里是openCV的一些動態(tài)庫级野,cmake構(gòu)建文件,以及java的一些api粹胯。
新建一個支持NDK的工程:
配置集成OpenCV庫到工程:
我這里只編譯支持了armeabi蓖柔,cpu架構(gòu)的平臺,需要在app风纠,module的build.gradle中做一些修改:
對了這里我使用AS自帶的cmake工具來構(gòu)建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")
# 設(shè)置動態(tài)庫文件的路徑屬性
set_target_properties(
opencv_java3
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi/libopencv_java3.so
)
endif(${ANDROID_ABI} STREQUAL "armeabi")
# opencv庫的頭文件路徑設(shè)置,在此是opencv-sdk的路徑臭增,當(dāng)然你也可以把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中l(wèi)ibopencv_java3.so文件拷貝到對應(yīng)的工程目錄下我這里是jniLibs為了方便不然還得配置gradle修改source目錄的映射路徑:
編寫java層的對外開發(fā)調(diào)用api
public class ImageProcessUtils {
/**
* 毛玻璃一張圖片
* @param srcBitmap 原始圖片
* @return 毛玻璃后的圖片
*/
public static Bitmap blur(Bitmap srcBitmap){
// 獲取原始圖片的寬高
int width = srcBitmap.getWidth();
int height = srcBitmap.getHeight();
// 初始化一個用來存儲圖片所有像素的int數(shù)組
int[] pixels = new int[width * height];
// 把原始圖片的所有原始存入數(shù)組中
srcBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
// 通過jni本地方法毛玻璃化圖片
blurImage(pixels, width, height);
// 創(chuàng)建一個新的圖片
Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
// 把處理后的圖片像素設(shè)置給新圖片
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來實(shí)現(xiàn)圖片的毛玻璃化
#include <jni.h>
#include <android/log.h>
#include <opencv2/opencv.hpp> // 引入opencv庫頭文件
#include <opencv2/highgui/highgui.hpp> // 引入opencv圖形界面,暫時沒用到
// 定義了log日志宏函數(shù)拗窃,方便打印日志在logcat中查看調(diào)試
#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中傳入的像素?cái)?shù)組值瞎领,jintArray轉(zhuǎn)化成jint指針數(shù)組
jint *c_pixels = env->GetIntArrayElements(jarr_pixels, JNI_FALSE);
if(c_pixels == NULL){
return;
}
LOGE("圖片寬度:%d, 高度:%d", j_width, j_height);
// 把c的圖片數(shù)據(jù)轉(zhuǎn)化成opencv的圖片數(shù)據(jù)
// 使用Mat創(chuàng)建圖片
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);
// 方框?yàn)V波
// boxFilter(temp, temp, -1, Size(85, 85));
// 均值濾波
blur(temp, temp, Size(85, 85));
// 使用高斯模糊濾波
// GaussianBlur(temp, temp, Size(45, 13), 0, 0);
// 將opencv圖片轉(zhuǎn)化成c圖片數(shù)據(jù),RGBA轉(zhuǎn)化成灰度圖4通道顏色數(shù)據(jù)
cvtColor(temp, temp, CV_RGBA2GRAY, 4);
// 更新java圖片數(shù)組和釋放c++中圖片數(shù)組的值
env->ReleaseIntArrayElements(jarr_pixels, c_pixels, JNI_FALSE);
}
看看效果圖對比圖:
簡單的利用了濾波算法函數(shù)處理随夸,來達(dá)到毛玻璃的效果默刚,當(dāng)然opencv的強(qiáng)大遠(yuǎn)遠(yuǎn)不限于此。關(guān)于opencv進(jìn)一步的學(xué)習(xí)使用還會繼續(xù)記錄在博客中逃魄。