人臉識別效果
創(chuàng)建項目
這里沒什么好說的欲间,使用AS創(chuàng)建一個支持C++的項目即可
如果你的AS暫不支持NDK開發(fā)渺杉,請下載這三個工具音半,并且在Open Module Settings中配置NDK的路徑琴儿,
導入OpenCV頭文件和so庫文件
-
下載OpenCV庫
-
在main文件夾下創(chuàng)建jniLibs文件夾
-
導入頭文件孕索,把這個include文件夾復制到jniLibs中
-
導入so文件夯巷,把需要兼容的so庫也復制到jniLibs中
- 在CMakeLists.txt中配置頭文件位置
include_directories(../jniLibs/include)
注意:有些教程中的CMakeLists.txt文件是在app文件夾下面的赛惩,此項目是在cpp文件夾下路徑是../jniLibs/include,..表示的是cpp的父文件夾,如果你的CMakeLists.txt在app文件夾下趁餐,路徑應該這么寫src/main/jniLibs/include
- 在CMakeLists.txt中配置so文件位置
#第一步
set(distribution_DIR ${CMAKE_SOURCE_DIR}/jniLibs)
add_library(opencv_java4
SHARED
IMPORTED)
set_target_properties(
opencv_java4
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_java4.so)
#第二步
target_link_libraries( # Specifies the target library.
native-lib
jnigraphics #此庫是NDK bitmap所在地
opencv_java4 #OpenCV庫
# Links the target library to the log library
# included in the NDK.
${log-lib})
完整的CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
include_directories(../jniLibs/include)
set(distribution_DIR ${CMAKE_SOURCE_DIR}/jniLibs)
add_library(opencv_java4
SHARED
IMPORTED)
set_target_properties(
opencv_java4
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_java4.so)
add_library(
native-lib
SHARED
native-lib.cpp)
find_library(
log-lib
log)
target_link_libraries(
native-lib
jnigraphics
opencv_java4
${log-lib})
bitMap2Mat
void bitmap2Mat(JNIEnv *env, jobject bitmap, Mat &mat) {
AndroidBitmapInfo info;
AndroidBitmap_getInfo(env, bitmap, &info);
Mat newMat(info.height, info.width, CV_8UC4);
void *pixels;
AndroidBitmap_lockPixels(env, bitmap, &pixels);
if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {//ARGB_8888
Mat tem(info.height, info.width, CV_8UC4, pixels);//創(chuàng)建一個空矩陣
tem.copyTo(newMat);
tem.release();
} else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) {//RGB_565
Mat tem(info.height, info.width, CV_8UC2, pixels);
tem.copyTo(newMat, COLOR_BGR5652BGRA);
tem.release();
}
newMat.copyTo(mat);
newMat.release();
AndroidBitmap_unlockPixels(env, bitmap);
}
mat2Bitmap
void mat2Bitmap(JNIEnv *env, Mat mat, jobject bitmap) {
AndroidBitmapInfo info;
AndroidBitmap_getInfo(env, bitmap, &info);
void *pixels;
AndroidBitmap_lockPixels(env, bitmap, &pixels);
if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
Mat tem(info.height, info.width, CV_8UC4, pixels);
switch (mat.type()) {
case CV_8UC4:
mat.copyTo(tem);
break;
case CV_8UC2:
cvtColor(mat, tem, COLOR_BGR5652BGRA);
break;
case CV_8UC1:
cvtColor(mat, tem, COLOR_GRAY2BGRA);
break;
}
} else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) {
Mat tem(info.height, info.width, CV_8UC2, pixels);
switch (mat.type()) {
case CV_8UC4:
cvtColor(mat, tem, COLOR_BGRA2BGR565);
break;
case CV_8UC2:
mat.copyTo(tem);
break;
case CV_8UC1:
cvtColor(mat, tem, COLOR_GRAY2BGR565);
break;
}
}
AndroidBitmap_unlockPixels(env, bitmap);
}
加載人臉識別的級聯(lián)分類器
-
從OpenCV中復制文件至Android raw文件夾
獲取該文件的路徑
private void initCascadePath() {
File mCascadeFile;
try {
// load cascade file from application resources
InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
if (mCascadeFile.exists()) {
cascadePath=mCascadeFile.getAbsolutePath();
return;
}
FileOutputStream os = new FileOutputStream(mCascadeFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
is.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
- 定義一個native方法喷兼,將路徑傳遞給native層
public native void loadCascade(String filePath);
- 加載級聯(lián)分類器
CascadeClassifier cascadeClassifier;
JNIEXPORT void JNICALL
Java_com_intent_opencv01_MainActivity_loadCascade(JNIEnv *env, jobject thiz, jstring file_path) {
cascadeClassifier.load(env->GetStringUTFChars(file_path, 0));
}
識別人臉
Java_com_intent_opencv01_MainActivity_faceDetection(JNIEnv *env, jobject thiz, jobject bitmap) {
Mat mat, grayMat;
//1、bitmap轉mat
Bitmap2Mat(env, bitmap, mat);
//2后雷、灰度圖
cvtColor(mat, grayMat, COLOR_BGRA2GRAY);
//3季惯、直方圖均衡補償
Mat equalizeMat;
/*
* 注意:此處第一個參數一定要使用灰度圖
* 原圖報異常(-215:Assertion failed) _src.type() == CV_8UC1 in function 'equalizeHist'
* */
equalizeHist(grayMat, equalizeMat);
//4、檢測人臉
std::vector<Rect> faces;
cascadeClassifier.detectMultiScale(equalizeMat, faces, 1.1, 5);
//CV_HAAR_SCALE_IMAGE(4.2.0無此參數了臀突,有文章稱用CASCADE_SCALE_IMAGE替換)
//cascadeClassifier.detectMultiScale(equalizeMat, faces, 1.1, 5, 0 | CASCADE_SCALE_IMAGE,
//Size(160, 160));
if (faces.size() == 1) {
Rect faceRect = faces[0];
//rectangle(mat, faceRect, CV_RGB(0, 255, 255));
//在原圖mat上繪制圓形
circle(mat, Point(faceRect.x+ faceRect.width / 2, faceRect.y + faceRect.height / 2), 100,CV_RGB(255,0,0));
//將繪制好的mat轉換成bitmap
Mat2Bitmap(env, mat, bitmap);
}
}
參考鏈接
1勉抓、Android native 中 Bitmap Mat 互轉
2、NDK調用第三方so文件
3候学、cmake語法總結