OpenCV實(shí)戰(zhàn)之(1)圖片濾鏡

前言:之前寫過關(guān)于android中通過JNI使用NDK的demo,介紹了關(guān)于so文件的生成與使用,但僅僅是demo,總覺得脫離實(shí)際應(yīng)用的話相關(guān)的東西很快就會忘掉,最近準(zhǔn)備面試才發(fā)現(xiàn)之前關(guān)于Cmake的配置等步驟確實(shí)忘的差不多了,這兩天剛?cè)肼殻诸^還不忙,于是趕緊找了下OpenCV相關(guān)的實(shí)際應(yīng)用來練練手(OpenCV,高級android開發(fā)面試必備的)

如果對Cmake涉及的結(jié)構(gòu)和配置不了解建議先花10分鐘看看:
1.Cmake方式生成so
2.Cmake方式調(diào)用so

國際慣例:開局一張圖,實(shí)現(xiàn)慢慢侃


image.png

各種濾鏡native算法處理參考:https://blog.csdn.net/yangtrees
如圖:分別展示的是 原圖、灰度處理、高斯模糊、流金歲月、凹雕刻、突浮雕
其他各種效果參考上面鏈接中的系列文章,找到對應(yīng)算法稍加修改即可,注意事項(xiàng)下文中會提到。

OpenCV之濾鏡效果實(shí)現(xiàn)步驟梳理:

1.OpenCV Android資源包下載
下載地址
2.新建android項(xiàng)目,勾選c++支持(舊項(xiàng)目添加c++支持可以手動去新建CMake等文件再修改配置,具體可以參考之前的文章:so生成篇
3.main目錄下面新建jniLibs文件夾,將需要適配的cpu類型對應(yīng)的so文件復(fù)制進(jìn)去(文件在步驟1下載的OpenCV-android-sdk\sdk\native\libs中)
4.將include文件夾復(fù)制到cpp下(里面是opencv庫的頭文件,在你自己的c++代碼文件中導(dǎo)入頭文件就可以使用opencv的函數(shù)了)

image.png

5.(重點(diǎn))配置CMakeLists,配置so路徑和頭文件路徑,使的在自己的c++文件中可以導(dǎo)入頭文件,使用opencv,具體配置如下:

#CMake最低版本3.4.1
cmake_minimum_required(VERSION 3.4.1)
#作用不太清楚
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

#配置頭文件路徑,CMAKE_SOURCE_DIR為 CMakeList同級目錄,即app下,通過${CMAKE_SOURCE_DIR}再定位到include
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)
#添加opencv動態(tài)鏈接庫的引用
add_library(libopencv_java3 SHARED IMPORTED)
#設(shè)置opencv動態(tài)鏈接庫的引用的路徑,${ANDROID_ABI}根據(jù)設(shè)備cpu型號選文件夾
set_target_properties(
        libopencv_java3
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libopencv_java3.so)
#配置通過源碼文件testCodeName生成libso-lib.文件  JAVA中  System.loadLibrary("so-lib")去加載這個(gè)so
add_library( # Sets the name of the library.
        #這個(gè)是聲明引用so庫的名稱,在項(xiàng)目中,如果需要使用這個(gè)so文件,引用的名稱就是這個(gè)。
        #值得注意的是,實(shí)際上生成的so文件名稱是libso-lib。
        so-lib
        # 這個(gè)參數(shù)表示共享so庫文件,也就是在Run項(xiàng)目或者build項(xiàng)目時(shí)會在目錄
        SHARED
        #構(gòu)建so庫的源文件
        src/main/cpp/testCodeName.cpp)


#添加log庫配置
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)


#將NDK庫關(guān)聯(lián)到本地庫so-lib   ljnigraphics(高斯模糊算法用到) libopencv_java3(OpenCV)
target_link_libraries( # Specifies the target library.
        so-lib
        ${log-lib}
        -ljnigraphics
        libopencv_java3
        )

6.(重點(diǎn)中的重點(diǎn))編寫c++文件 實(shí)現(xiàn)各種濾鏡效果算法,函數(shù)按JNI命名規(guī)則,給JAVA層調(diào)用

testCodeName文件中導(dǎo)入的頭文件

#include <math.h>
#include <stdlib.h>
#include <jni.h>
//opencv
#include <jni.h>
#include<opencv2/opencv.hpp>
#include<iostream>

這里選取灰度效果來研究
JNI方法中JNIEnv *env, jobject thiz,為固定參數(shù),實(shí)際參數(shù)為 jintArray buf, jint w, jint h
對應(yīng)JAVA中的參數(shù)就是 int[] 數(shù)組,int 寬 int 高,
實(shí)際在調(diào)用的時(shí)候是傳入bitmap的像素?cái)?shù)組,bitmap寬度,bitmap高,
看看JAVA中的申明:

   //native方法聲明
    public native int[] gray(int[] buf, int w, int h);                                         

再看看Activity中的調(diào)用(這里直接在Activity中l(wèi)oadLib了,并且Native函數(shù)聲明gary也在activity中)


image.png

核心代碼

       //獲取bitmap寬高,新建一個(gè)像素?cái)?shù)組(此時(shí)還沒寫入像素信息)
       int w = bitmap.getWidth();
        h = bitmap.getHeight();
        int[] pix = new int[w * h];
      

       //灰度處理

        //往pix中寫入像素信息
        bitmap.getPixels(pix, 0, w, 0, 0, w, h);  

        //將pix信息和bitmap的寬高  通過Native方法 gray傳進(jìn)去處理像素pix,處理好后返回
        int[] resultPixes = gray(pix, w, h);

        //根據(jù)經(jīng)過灰度處理后的resultPixes像素去創(chuàng)建Bitmap,給Imageview顯示
        Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
        result.setPixels(resultPixes, 0, w, 0, 0, w, h);
        iv1.setImageBitmap(result);
   

毫無疑問,這里的核心是JNI層中的gray方法,下面重點(diǎn)分析

JNI中函數(shù):

1.

extern "C" JNIEXPORT jintArray JNICALL

Java_com_example_lunwang_ndktest_MainActivity_gray(JNIEnv *env, jobject thiz, jintArray buf, jint w,
                                                   jint h) {

    jint *cbuf;
    jboolean ptfalse = false;
    cbuf = env->GetIntArrayElements(buf, &ptfalse);
    if (cbuf == NULL) {
        return 0;
    }

    Mat imgData(h, w, CV_8UC4, (unsigned char *) cbuf);    // 注意,Android的Bitmap是ARGB四通道,而不是RGB三通道

這部分代碼的作用就是根據(jù)傳入的Bitmap的像素,寬,高去建立一個(gè) Mat對象
Mat是opencv中的圖像對象, Mat對象封裝了圖像在內(nèi)存中的信息,用于表示一副加載到內(nèi)存中的圖像,
實(shí)際的濾鏡效果就是通過opencv提供的函數(shù)去處理Mat對象得到的,所以得到如下結(jié)論:

1.Mat是opencv處理圖片的一個(gè)很重要的對象
2.JAVA->JNI->OpenCV處理的轉(zhuǎn)化過程涉及到Bitmap->jintArray->Mat的轉(zhuǎn)化
3.Android的Bitmap是ARGB四通道,而不是RGB三通道,所以這里生成Mat用的是CV_8UC4,網(wǎng)上找的濾
鏡效果算法可能用的是CV_8UC3,要注意改過來,對應(yīng)的算法中如果遇到類似:float R = P0[3* x + 2];的結(jié)構(gòu)注意
改成float R = P0[4 * x + 2];

2.

   cvtColor(imgData, imgData, CV_BGRA2GRAY);
   cvtColor(imgData, imgData, CV_GRAY2BGRA);

//這兩行就是調(diào)用opencv的方法去處理Mat,其他效果這里的處理會不同

3.

    int size = w * h;
    jintArray result = env->NewIntArray(size);
    env->SetIntArrayRegion(result, 0, size, (jint *) imgData.data);
    env->ReleaseIntArrayElements(buf, cbuf, 0);
    return result;
}

//這幾行就是拿到處理后的Mat,去生成像素?cái)?shù)組,返回給JAVA層
//在這個(gè)demo中,除了高斯模糊外,幾乎所有的濾鏡效果的實(shí)現(xiàn)1和3不變,就是改變2的處理。

項(xiàng)目demo地址:https://gitee.com/lunguoguo/OpencvProject

這種導(dǎo)入so的方式會造成APK體積巨大,下篇嘗試通過其他方式僅僅導(dǎo)入使用到的資源去實(shí)現(xiàn)!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 貨幣通道與銀行融通是融通工具的一體兩面,貨幣主導(dǎo)市場經(jīng)濟(jì)的融通,銀行主導(dǎo)貨幣載體的融通… 擁有貨幣是財(cái)富的象征,所...
    光瞄芭比閱讀 127評論 0 0
  • 【Day29課后實(shí)踐】周日自習(xí) 這是2018年9月2日“崔律·100天精力和時(shí)間管理訓(xùn)練營”第4.7講(自習(xí))的課...
    吖吖_學(xué)語閱讀 215評論 0 0

友情鏈接更多精彩內(nèi)容