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

開始學習OpenCV,毛玻璃模糊效果目前網上流行的有三種辦法:

  1. 使用java來編寫一長串的像素處理辦法算法來改變bitmap(性能教差,而且一堆算法代碼,難理解,不優雅)
  2. 使用C語言的方式同樣使用和java一樣的算法來實現(性能好,同樣一堆算法代碼難理解,也不優雅)
  3. 使用RenderScript這個有Api版本的限制。

現在我們可以利用OpenCV框架中濾波算法來實現圖片的模糊虛化。


準備工作:

先到OpenCV官網, 下載Android平臺的sdk包: http://www.opencv.org

解壓后:
sdk目錄里是openCV的一些動態庫,cmake構建文件,以及java的一些api。


image.png

新建一個支持NDK的工程:

勾選c++的支持.png
選擇stdC++11的標準.png

配置集成OpenCV庫到工程:

我這里只編譯支持了armeabi,cpu架構的平臺,需要在app,module的build.gradle中做一些修改:

image.png

對了這里我使用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目錄的映射路徑:

image.png
image.png

編寫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);
}

看看效果圖對比圖:

原圖.png
毛玻璃后效果圖.png

簡單的利用了濾波算法函數處理,來達到毛玻璃的效果,當然opencv的強大遠遠不限于此。關于opencv進一步的學習使用還會繼續記錄在博客中。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容