上篇文章介绍了 Android 的人脸检测,这篇文章来介绍 openCV 的人脸检测。由于在 Android 平台上能直接使用 JavaCV,而 JavaCV 包含 openCV。所以,这篇文章就在 JavaCV 的基础上来实现 openCV 的人脸检测。
下载地址
需要下载的包:javacv-bin.zip 和 opencv-2.4.3-android-arm.zip
分别解压下载的包。将 javacv-bin 中的 javacpp.jar 和 javacv.jar 拷贝到项目的 libs 下,并引用。
将 opencv-2.4.3-android-arm 中 libs 下的 armeabi 和 armeabi-v7a 中的 .so 文件拷贝到项目的 libs 下的 armeabi 和 armeabi-v7a 中。
public void init() throws IOException {
File classifierFile = Loader.extractResource(getClass(),
"/com/ifenghui/face/camera/haarcascade_frontalface_alt2.xml", getCacheDir(), "classifier",
".xml");//获取分类器文件
if (classifierFile == null || classifierFile.length() <= 0) {
throw new IOException("Could not extract the classifier file from Java resource.");
}
// Preload the opencv_objdetect module to work around a known bug.
Loader.load(opencv_objdetect.class);//加载分类器
classifier =
new opencv_objdetect.CvHaarClassifierCascade(cvLoad(classifierFile.getAbsolutePath()));//获取分类器对象
classifierFile.delete();
if (classifier.isNull()) {
throw new IOException("Could not load the classifier file.");
}
storage = opencv_core.CvMemStorage.create();
}
注:第 2,3,4 行中使用的分类器文件 haarcascade_frontalface_alt2.xml 在 openCV 安装路径下的 data/haarcascades/ 下。
protected void detectorFaceFromImage(Bitmap faceBitmap, int width, int height) {
// First, downsample our image and convert it into a grayscale IplImage
int f = SUBSAMPLING_FACTOR;//图片缩小倍数
if (grayImage == null || grayImage.width() != width / f || grayImage.height() != height / f) {
grayImage = opencv_core.IplImage.create(width / f, height / f, opencv_core.IPL_DEPTH_8U,
1);//创建缩小后的 IplImage
}
opencv_core.IplImage faceIplImage = opencv_core.IplImage.create(width, height, IPL_DEPTH_8U, 4);
faceBitmap.copyPixelsToBuffer(faceIplImage.getByteBuffer());//bitmap 转成 IplImage
opencv_core.IplImage bitGray = opencv_core.IplImage.create(width, height, IPL_DEPTH_8U, 1);
opencv_imgproc.cvCvtColor(faceIplImage, bitGray, opencv_imgproc.CV_BGR2GRAY);// 转换成灰度图片
opencv_imgproc.cvResize(bitGray, grayImage, opencv_imgproc.CV_INTER_LINEAR);
opencv_imgproc.cvEqualizeHist(grayImage, grayImage);//直方图均衡化,不知道干啥用的
cvClearMemStorage(storage);
facesCV = cvHaarDetectObjects(grayImage, classifier, storage, 1.1, 2,
opencv_objdetect.CV_HAAR_DO_CANNY_PRUNING);//调用人脸检测
RectF rectF = new RectF();
float scaleX = SUBSAMPLING_FACTOR;
float scaleY = SUBSAMPLING_FACTOR;
int total = facesCV.total();
for (int i = 0; i < total; i++) {//获取人脸范围的矩形,一便绘制
opencv_core.CvRect r = new opencv_core.CvRect(cvGetSeqElem(facesCV, i));
int x = r.x(), y = r.y(), w = r.width(), h = r.height();
rectF.set(x * scaleX, y * scaleY, (x + w) * scaleX, (y + h) * scaleY);
//canvas.drawRect(x*scaleX, y*scaleY, (x+w)*scaleX, (y+h)*scaleY, paint);
}
}
openCV 的人脸检测的效率很高,但是需要先加载分类器,这会影响检测的效率。如果需要检测的图片很少,加载分类器使用的时间所占的比重就大。在需要检测的图片不是太多的情况下使用 Android 的人脸检测似乎比 openCV 更好一些。