您的位置:首页 > 移动开发 > Android开发

Face Detection using OpenCV Haarcascades in Android

2015-12-22 18:22 435 查看
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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: