Use OpencV for face recognition of pictures to learn notes. 1. Integrate OpencV 2, transfer the picture to native layer 3, process the picture 4, detect the face 5, and save the characteristic value

Integration of opencv

1, download OpencV, decompress it and find all the supported dynamic link libraries in OpencV-Android-SDK \ SDK \native\libs. Import libopencv_java3.so into jniLibs. 2, import Opencv-Android-sdk SDK native jni include into jniLibs


Cmake_minimum_required (VERSION 3.4.1 track)#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
# check compiler type, if GCC compiler, add c++11 support to compiler options
if(CMAKE_COMPILER_IS_GNUCXX)
    set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
    message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)

We need to import our header file based on this configured directory
include_directories(src/main/jniLibs/include)

# Add dependency opencv.so library
set(distribution_DIR ${CMAKE_SOURCE_DIR}/.. /.. /.. /.. /src/main/jniLibs) add_library( opencv_java3 SHARED IMPORTED) set_target_properties( opencv_java3 PROPERTIES IMPORTED_LOCATION .. /.. /.. /.. /src/main/jniLibs/armeabi/libopencv_java3.so) add_library( native-lib SHARED src/main/cpp/native-lib.cpp ) find_library(log-lib
        log )
target_link_libraries(
        native-lib opencv_java3
        jnigraphics  Add the dependency library
        ${log-lib} )
Copy the code

Transfer images to native layer

Define native methods and implement them in CPP.

Bitmap  bitmap = 
BitmapFactory.decodeResource(getResources(), 
R.mipmap.face5);

mFaceDetection.faceDetectionSaveInfo(bitmap);

public native int faceDetectionSaveInfo(Bitmap bitmap);

extern "C" JNIEXPORT jint JNICALLJava_com_example_faceapplication_FaceDetection_faceDetectionSaveInfo(JNIEnv *env, jobject thiz, jobject bitmap) {}Copy the code

Processing images

1. Convert bitmap into Mat matrix object in c++. 2. Grayscale processing is carried out on the picture, and the colored picture is converted into grayscale picture. Direct equalization compensation.

A bitmap is transformed into a Mat matrix

RGB_565 corresponds to CV_8UC2. RGBA_8888 corresponds to CV_8UC4

Mat mat;
bitmap2Mat(env, mat, bitmap);

void bitmap2Mat(JNIEnv *env, Mat &mat, jobject bitmap) {
    // Get bitmap information
    AndroidBitmapInfo info;// Class provided by Android to get bitmap information.
     AndroidBitmap_getInfo(env, bitmap, &info);
    // Set mat's header pointer to bitmap's
    // To manipulate bitmap, lock the canvas
   void *pixels;// Decode the image and get the address pointer saved in memory after decoding the pixel
  AndroidBitmap_lockPixels(env, bitmap, &pixels);  // You need to use this method to lock the memory address of the image before operating the bitmap.
   mat.create(info.height, info.width, CV_8UC4); // Create memory for MAT that is the same size as bitmap. To rGBA_8888 format.
    if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
        // The mat should be 8uc4
        Mat temp(info.height, info.width, CV_8UC4, pixels);
        // Copy data from temp to the master MAT
        temp.copyTo(mat);
    } else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) {
        // The mat should be 8uc2
        Mat temp(info.height, info.width, CV_8UC2, pixels);
        // Convert 8UC2 to 8UC4
        cvtColor(temp, mat, COLOR_BGR5652BGRA);
    } else {
        // Others automatically go to conversion
    }
    AndroidBitmap_unlockPixels(env, bitmap);
}
Copy the code

Gray processing

In order to improve the efficiency of the algorithm, it can also be directly recognized, but the effect is very poor, mainly because the original image contains too much information. Each pixel of gray image is 255, while color image is 255* 255* 255. R+G+B = 255 = 0.33r + 0.33g + 0.33b = 0.3r + 0.59g + 0.11b (suitable for human eyes)

Call the OpencV method for processing. Turn color to grey. The lines of the image are then deepened by compensating for the straight-square equalization. The texture is clearer.

Mat gray_mat; cvtColor(mat, gray_mat, COLOR_BGRA2GRAY); Mat equalize_MAT; equalizeHist(gray_mat, equalize_mat);Copy the code

Recognize faces

1, load face classifier file 2, recognition

Load the face classifier file

The lBPCascade_frontalface. XML file is in the opencV directory. Put it locally. The absolute path passes into the native layer.

	   private void copyCascadeFile(a) {
        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())
                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();
            cascadeDir.delete();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    
    
    mFaceDetection.loadCascade(mCascadeFile.getAbsolutePath());
public native void loadCascade(String absolutePath);


CascadeClassifier cascadeClassifier;

extern "C"
JNIEXPORT void JNICALL
Java_com_example_faceapplication_FaceDetection_loadCascade(JNIEnv *env, jobject thiz, jstring filePath_) {

    const char *filePath = env->GetStringUTFChars(filePath_, 0);
    cascadeClassifier.load(filePath);
    LOGE("Classifier file loaded successfully");
    env->ReleaseStringUTFChars(filePath_, filePath);

}
  
Copy the code

identify

CascadeClassifier. DetectMultiScale (equalize_mat, faces, 1.1, 5); The first parameter: mat matrix of the picture the second parameter: put all recognized faces into the set the third parameter: 1.1 default parameter the fourth parameter: The Times of detection. Fifth parameter: minimum face size sixth parameter: maximum face size

 // To recognize the face, also need to load the face classifier file
    std: :vector<Rect> faces; 
    cascadeClassifier.detectMultiScale(equalize_mat, faces, 1.1.5);
    LOGE("Number of faces: %d",faces.size());

    if(faces.size() >= 1) {for (int i = 0; i < faces.size(); ++i) {
            Rect faceRect = faces[i];
            rectangle(mat,faceRect,Scalar(255.155.155),8); // Draw the box
        }
        mat2Bitmap(env, mat, bitmap);
    }
Copy the code

Saving characteristic data

Mat face_info_mat(equalize_mat,faceRect); // Intercept a portion of the face (recT from the Equalize matrix)Copy the code

The effect

Code links: pan.baidu.com/s/1ZUsJ6qTt… Extraction code: 3NYt