圖形圖像處理 - Android 濾鏡效果

年初來深圳正式開始從事音視頻開發(fā),為啥我想從事音視頻開發(fā)呢?有一個簡單的理由是我想建立起自己的技術(shù)壁壘,別人不能做的你能做,別人解決不了的你能解決。我們工作多年甚至于做了幾十個項目,如果我們不能從項目中去學(xué)習(xí)新的東西,那技術(shù)就只能停滯不前了。當(dāng)然有哥們建議我說,你學(xué)的東西太多了但是不精,因此同樣我也建議大家還是先把 Java 基礎(chǔ)和 Android 基礎(chǔ)打牢。后面我將寫下一些圖形圖像處理的文章,很多是我自己學(xué)來的,也有些是我工作中遇到的。感興趣的哥們可以看下,也希望可以幫大家少走一些彎路。文章和視頻主要還是以 NDK 為主,因此希望各位看官能有一些 c 和 c++ 的基礎(chǔ),有一些數(shù)據(jù)結(jié)構(gòu)和算法的基礎(chǔ),如果沒有建議大家去看看我之前寫的一些文章。

1. OpenCV 安裝

OpenCV 是一個計算視覺的開源庫,主要算法涉及圖像處理和機器學(xué)習(xí)。是 Intel 公司貢獻出來的,因為它可以免費應(yīng)用在商業(yè)和研究領(lǐng)域,且國內(nèi)大多數(shù)圖像處理相關(guān)的應(yīng)用程序中都采用的是 OpenCV,因此后面很大一部分內(nèi)容我們都基于 OpenCV 來講。官方給我們封裝了很多 java 層的接口,但總的來說可擴展性不是很高,因此后面我們主要采用 c++ 來寫,然后自己編譯成 so 庫來供 Android 調(diào)用。為了便于方法和算法的講解,我們暫時基于 VS 環(huán)境來編寫代碼,大家如果用的是 mac 電腦,可以去看看我之前的《NDK開發(fā)前奏 - 實現(xiàn)支付寶人臉識別功能》 ,也可以直接基于 android 環(huán)境開發(fā)。接下來我們一步步來搭建 VS 的開發(fā)環(huán)境:

首先我們找到 opencv 的官網(wǎng) https://opencv.org/opencv-4-0-0-rc.html ,目前最高版本是 4.0 點擊 Win pack 進行下載。下載下來是一個 exe 文件,我們不要安裝直接解壓就好。找到 build\x64\vc14\bin 下,把目錄進行拷貝配置環(huán)境變量:

環(huán)境變量配置

然后新建 VS 空項目,找到菜單欄的 調(diào)試窗口 -> 屬性 -> 配置屬性 -> VC++ 目錄


在包含目錄和庫目錄中新增我們 opencv 的解壓目錄。然后我們寫一個簡單實例測試能即可:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;

void main(){
    // 本地讀取一張圖片
    Mat src = imread("C:/Users/hcDarren/Desktop/android/NDK/NDK_Day56/test1.jpg");
    Mat gray;
    // 轉(zhuǎn)灰度
    cvtColor(src, gray, COLOR_BGR2GRAY);
    // 將灰度圖顯示到窗口
    namedWindow("test pic",CV_WINDOW_NORMAL);
    imshow("test pic", gray);
    waitKey(0);
}

大家按照我這個配置去做,可能還是會遇到很多問題。但所有的問題都離不開兩個方面,一個是頭文件,一個是實現(xiàn)的 dll 動態(tài)庫。

2. Android 濾鏡效果

我們來看一個比較常見同時也是非常簡單的例子,打開 QQ 空間發(fā)說說圖片時會有一個濾鏡功能,我們可以自己先去看看那些濾鏡效果。

實現(xiàn)這樣的效果有多種方案,Java 層用 ColorMatrix 矩陣來實現(xiàn),Java 層操作 Bitmap 像素,Native 層操作 Bitmap 像素指針等等。這里我把三種方案都寫上,希望大家能夠做到舉一反三。以彩色圖轉(zhuǎn)灰度圖為例:

2.1 Java 層用 ColorMatrix 矩陣來實現(xiàn)

    public static Bitmap gary(Bitmap bitmap) {
        Bitmap gary = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
        Canvas canvas = new Canvas(gary);
        Paint paint = new Paint();
        // 比較流行的方法。幾個加權(quán)系數(shù)0.3,0.59,0.11是根據(jù)人的亮度感知系統(tǒng)調(diào)節(jié)出來的參數(shù),是個廣泛使用的標準化參數(shù)
        ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                0.30f, 0.59f, 0.11f, 0, 0,
                0.30f, 0.59f, 0.11f, 0, 0,
                0.30f, 0.59f, 0.11f, 0, 0,
                0, 0, 0, 1f, 0
        });
        ColorMatrixColorFilter colorFilter = new ColorMatrixColorFilter(colorMatrix);
        paint.setColorFilter(colorFilter);
        canvas.drawBitmap(bitmap, 0, 0, paint);
        return gary;
    }

2.2 Java 層操作 Bitmap 像素

    public static Bitmap gary(Bitmap bitmap) {

        int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
        bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());

        for (int i = 0; i < pixels.length; i++) {
            int pixel = pixels[i];
            int a = (pixel >> 24) & 0xff;
            int r = (pixel >> 16) & 0xff;
            int g = (pixel >> 8) & 0xff;
            int b = pixel & 0xff;

            int gery = (int) (0.30f * r + 0.59f * g + 0.11f * b);
            pixels[i] = (a << 24) |  (gery << 16) |  (gery << 8)  |  gery;
        }

        Bitmap gary = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
        gary.setPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());

        return gary;
    }

2.3 Native 層操作 Bitmap 像素指針

extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_day51_BitmapUtil_gary(JNIEnv *env, jclass type, jobject bitmap) {
    // 獲取 Bitmap 信息
    AndroidBitmapInfo bitmapInfo;
    AndroidBitmap_getInfo(env, bitmap, &bitmapInfo);

    // 鎖定畫布
    void *pixels;
    AndroidBitmap_lockPixels(env, bitmap, &pixels);

    for (int i = 0; i < bitmapInfo.width * bitmapInfo.height; ++i) {
        uint32_t *p_pixel = reinterpret_cast<uint32_t *>(pixels) + i;
        uint32_t pixel = *p_pixel;
        int a = (pixel >> 24) & 0xff;
        int r = (pixel >> 16) & 0xff;
        int g = (pixel >> 8) & 0xff;
        int b = pixel & 0xff;
        int gery = r * 0.3f + g * 0.59f + b * 0.11f;
        *p_pixel = (a << 24) | (gery << 16) | (gery << 8) | gery;
    }
    
    // 解鎖畫布
    AndroidBitmap_unlockPixels(env, bitmap);
}

如果我們不是很了解矩陣的操作,可以去 Google 查查資料。上面的代碼也還會有些許問題,如果我們想用到項目中還得好好思考思考。

視頻地址:https://pan.baidu.com/s/1FqGwalxQimTwfoMKvIZNXw
視頻密碼:5xnx

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

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

  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 13,928評論 2 59
  • 在Android開發(fā)中,一般對圖像的處理就是Bitmap(位圖),它包含了圖像的全部數(shù)據(jù),即點陣和顏色值,點陣就是...
    李晨瑋閱讀 8,382評論 1 33
  • 今天老師帶我們?nèi)チ颂蔷茣俏覀兒孟癖划?dāng)成了免費的勞動力,幫著老師讓參展商填問卷,問卷一個小組就300份,期間還...
    skymemory7閱讀 424評論 0 0
  • 1 小時候,父親煮過一道菜:蒜子蒸鉗魚。那個蒜頭,一瓣一瓣的,蒸熟了出來,沒有了蒜的難聞的氣味,吃起來松松軟軟,還...
    小螢子閱讀 809評論 2 0
  • 5:15分,鬧鐘準時想起,起床嘍!穿上跑鞋,就感覺自己元氣滿滿! 這一段時間,淅淅瀝瀝的秋雨纏纏綿綿。歇了幾天的身...
    谷子_8e39閱讀 494評論 11 11

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