年初來深圳正式開始從事音視頻開發(fā)味抖,為啥我想從事音視頻開發(fā)呢?有一個簡單的理由是我想建立起自己的技術壁壘灰粮,別人不能做的你能做仔涩,別人解決不了的你能解決。我們工作多年甚至于做了幾十個項目粘舟,如果我們不能從項目中去學習新的東西熔脂,那技術就只能停滯不前了佩研。當然有哥們建議我說,你學的東西太多了但是不精霞揉,因此同樣我也建議大家還是先把 Java 基礎和 Android 基礎打牢旬薯。后面我將寫下一些圖形圖像處理的文章,很多是我自己學來的适秩,也有些是我工作中遇到的绊序。感興趣的哥們可以看下,也希望可以幫大家少走一些彎路秽荞。文章和視頻主要還是以 NDK 為主骤公,因此希望各位看官能有一些 c 和 c++ 的基礎,有一些數(shù)據(jù)結(jié)構和算法的基礎扬跋,如果沒有建議大家去看看我之前寫的一些文章阶捆。
1. OpenCV 安裝
OpenCV 是一個計算視覺的開源庫,主要算法涉及圖像處理和機器學習钦听。是 Intel 公司貢獻出來的洒试,因為它可以免費應用在商業(yè)和研究領域,且國內(nèi)大多數(shù)圖像處理相關的應用程序中都采用的是 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)境變量:
然后新建 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();
// 比較流行的方法。幾個加權系數(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