Android Opencv smile(微笑) 识别开发

  最近研究opencv,主要的是以Android平台的为主。废话不多说直接来干货。

 一: SDK下载:https://opencv.org/   我使用的是opencv 2.4.10的

 二:IDE我是使用eclipse的,也可以使用AS进行开发,需要NDK, eclipse的opencv配置请参考:https://blog.****.net/roboman/article/details/42883399 博主的。

   三:我使用的是samples文件夹的 face-detection 示例,把示例加入工程,添加 opencv libs。在Android Opencv smile(微笑) 识别开发detectionBasedTracker.java 中添加smile本地方法->

 //smile
    public float  data(Mat imageGray, MatOfRect faces){
        float data = 0;
        data = nativateSmileData(mNativeObj, imageGray.getNativeObjAddr(), faces.getNativeObjAddr());
        return data ;
    }
    private static native float    nativateSmileData(long thiz, long inputImage, long faces);
四:再在jni文件夹中的 .h 文件中添加jni接口

/*
 * smile
 * */
JNIEXPORT jfloat JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativateSmileData
  (JNIEnv *, jclass, jlong, jlong, jlong);
五:修改.cpp文件 添加->

//smile 处理
JNIEXPORT jfloat JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativateSmileData(
        JNIEnv * jenv, jclass, jlong thiz, jlong imageGray, jlong facess) {

    Mat img;
    Mat gray, smallImg;
    double scale = 1;
    bool tryflip = 0;
    float smile_max = 0;
    vector<Rect> faces, faces2;
    img = *((Mat*) imageGray);
    CascadeClassifier nestedCascade, cascade;
    if (!cascade.load(
            "/data/data/org.opencv.samples.facedetect/app_cascade/haarcascade_frontalface_alt2.xml")) { //分类器存放的位置
        return 11;
    }
    if (!nestedCascade.load(
            "/data/data/org.opencv.samples.facedetect/app_cascade/haarcascade_smile.xml")) { //分类器存放的位置
        return 11;
    }
    const static Scalar colors[] = { Scalar(255, 0, 0), Scalar(255, 128, 0),
            Scalar(255, 255, 0), Scalar(0, 255, 0), Scalar(0, 128, 255), Scalar(
                    0, 255, 255), Scalar(0, 0, 255), Scalar(255, 0, 255) };
    cvtColor(img, gray, COLOR_BGR2GRAY);

    double fx = 1 / scale;
    resize(gray, smallImg, Size(), fx, fx, INTER_LINEAR);
    equalizeHist(smallImg, smallImg);

    cascade.detectMultiScale(smallImg, faces, 1.1, 2, 0
            | CASCADE_SCALE_IMAGE, Size(30, 30));
    if (tryflip)
        {
            flip(smallImg, smallImg, 1);
            cascade.detectMultiScale(smallImg, faces2,
                1.1, 2, 0
                | CASCADE_SCALE_IMAGE,
                Size(30, 30));
            for (vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r)
            {
                faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
            }
        }
    for (size_t i = 0; i < faces.size(); i++) {
        Rect r = faces[i];
        Mat smallImgROI;
        vector<Rect> nestedObjects; //微笑处理
        Point center;
        Scalar color = colors[i % 8];
        int radius;

        double aspect_ratio = (double) r.width / r.height;
        if (0.75 < aspect_ratio && aspect_ratio < 1.3) {
            center.x = cvRound((r.x + r.width * 0.5) * scale);
            center.y = cvRound((r.y + r.height * 0.5) * scale);
            radius = cvRound((r.width + r.height) * 0.25 * scale);
            circle(img, center, radius, color, 3, 8, 0);
        } else
            rectangle(img, cvPoint(cvRound(r.x * scale), cvRound(r.y * scale)),
                    cvPoint(cvRound((r.x + r.width - 1) * scale),
                            cvRound((r.y + r.height - 1) * scale)), color, 3, 8,
                    0);

        const int half_height = cvRound((float) r.height / 2);
        r.y = r.y + half_height;
        r.height = half_height - 1;
        smallImgROI = smallImg(r);

        //微笑处理&识别度
        nestedCascade.detectMultiScale(smallImgROI, nestedObjects, 1.1, 0, 0
                | CASCADE_SCALE_IMAGE, Size(30, 30));
        // The number of detected neighbors depends on image size (and also illumination, etc.). The
        // following steps use a floating minimum and maximum of neighbors. Intensity thus estimated will be
        //accurate only after a first smile has been displayed by the user.
        const int smile_neighbors = (int) nestedObjects.size();
        static int max_neighbors = -1;
        static int min_neighbors = -1;
        if (min_neighbors == -1)
            min_neighbors = smile_neighbors;
        max_neighbors = MAX(max_neighbors, smile_neighbors);

        // Draw rectangle on the left side of the image reflecting smile intensity
        float intensityZeroOne = ((float) smile_neighbors - min_neighbors)
                / (max_neighbors - min_neighbors + 1);
        smile_max = intensityZeroOne;
    }
    LOGE("jni_smile_ok_->3");
    return (jfloat) smile_max;
}
六:Java调用

在    public Mat onCameraFrame(CvCameraViewFrame inputFrame){

    // 这里获取相机拍摄到的原图,彩色图
        mRgba = inputFrame.rgba();
        // 这里获取相机拍摄到的灰度图,用来给下面检测人脸使用。
        mGray = inputFrame.gray();

       MatOfRect faces2 = new MatOfRect();
                    float sm =  mNativeDetector.data(mRgba, faces2);
                    Log.e("微笑强度-->", ""+sm);

return mRgba;

}

总结:整个工程对smile识别还是不错的,cpp算法是结合windows工程加进去改进的,其Android 是通过jni方法,NDK 调用opencv算法,的出结果 反馈给上层应用。