Face Detection using OpenCV Haarcascades in Android

本文介绍如何在Android应用中使用OpenCV Haar级联实现人脸检测。通过将XML文件从Java层传递到JNI层,实现了原生代码层面的人脸检测功能,并展示了具体的实现步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Face Detection using OpenCV Haarcascades in Android

Posted on 22 March 2014
Under Blog
Tagged Android
Tweet  

I was working on this app which required face detection and pose estimation. I was already using Native code for some other processes (edge detection, etc) so I figured I’d use Haarcascades in native code only. It was a bit of hassle to configure how to send xml file to JNI or whether it would load the cascade once I pass the filename to the native code.

So I looked around a bit. I tried to look into the examples provided with opencv sdk and found out that I had to write the whole xml file to FileOutputStream so that it could be accessed in the native code.

Making XML available to the native code

First I stored the XML file in assets/ folder.

final InputStream is;
FileOutputStream os;
try {
    is = getResources().getAssets().open("face_frontal.xml");
    File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
    mCascadeFile = new File(cascadeDir, "face_frontal.xml");
    
    FileOutputStream os;
    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) {
    Log.i(TAG, "face cascade not found");
}
Once this is done, you can pass the file and relevant Mat objects to the native code.

JNI call

faceFound = detectFace(mCascadeFile.getAbsolutePath(),
                       mRgba.getNativeObjAddr(),
                       mretVal.getNativeObjAddr());

// Image is loaded in mRgba
// mretVal will contain the output Mat 

// At the end of the class declaring the native function
public native int detectFace(String filename, long matAddrRgba,
                             long matAddrRetVal);
Native code

I’m not editing the native function name here so you need to change it appropriately.

JNIEXPORT jint JNICALL Java_com_fenchtose_cardscanner_ScanActivity_detectFace(JNIEnv* jenv, jobject, jstring jFileName, jlong addrRgba, jlong addrRetVal)
{
    const char* jnamestr = jenv->GetStringUTFChars(jFileName, NULL);
    string stdFileName(jnamestr);

    Mat& mRgba = *(Mat*)addrRgba;
    Mat& retValMat = *(Mat*)addrRetVal;
    Mat gray;
    vector<Rect> faces;

    jint retVal;
    int faceFound=0;

    mRgba.copyTo(retValMat);

    cvtColor(mRgba, gray, CV_RGBA2GRAY);

    CascadeClassifier face_cascade;
    face_cascade.load(stdFileName);
    LOGD("cascade loaded\n");

    face_cascade.detectMultiScale(gray, faces, 2, 1,
                CV_HAAR_FIND_BIGGEST_OBJECT |  CV_HAAR_SCALE_IMAGE,
                Size(30, 30), Size(900, 900));
    LOGD("detectMultiScale\n");

    if (faces.size() > 0)
    {
        int index;
        Rect face;
        for(index=0; index<faces.size(); index++){
            face = faces[index];
            rectangle(retValMat, face, Scalar(255, 0, 0), 3);
        }
        faceFound = 1;
        LOGD("face found\n");
    }
    else
    {
        LOGD("face not found\n");
        faceFound = 0;
    }
    
    retVal = (jint)faceFound;

    return retVal;
}
This returns if face is found or not. If face is found it draws on the retvalMat. So this was pretty easy to do and return a good output.

P.S. Learning more about Android OpenCV.


If you have some feedback or questions regarding this post, please add comments. I'd be happy to get some feedback.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值