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

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

1. OpenCV 安裝

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

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

然後新建 VS 空項目,找到菜單欄的 調試窗口 -> 屬性 -> 配置屬性 -> 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;
	// 轉灰度
	cvtColor(src, gray, COLOR_BGR2GRAY);
	// 將灰度圖顯示到窗口
	namedWindow("test pic",CV_WINDOW_NORMAL);
	imshow("test pic", gray);
	waitKey(0);
}

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

2. Android 濾鏡效果

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

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

2.1 Java 層用 ColorMatrix 矩陣來實現

    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();
        // 比較流行的方法。幾個加權係數0.3,0.59,0.11是根據人的亮度感知系統調節出來的參數,是個廣泛使用的標準化參數
        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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章