Android上的人脸识别
Posted
技术标签:
【中文标题】Android上的人脸识别【英文标题】:Face Recognition on Android 【发布时间】:2012-07-26 20:05:02 【问题描述】:我正在尝试在 android 上开发人脸识别应用,由于我不想在项目中使用 NDK(只是没有时间切换),我坚持使用Java,因此我遇到了一些问题:
似乎 Contrib 模块未包含在 OpenCV 2.4.2 中。有没有在项目中使用它?
我尝试使用 JavaCV 来使用 Contrib 模块的“FaceRecognizer”类。有两个类可用,称为“FaceRecognizer”和“FaceRecognizerPtr”。有人知道这两者有什么区别吗?
上面提到的类有一个名为“Train”的方法,它(在 C++ 中)接收两个类型为“Mat & Integer”(model->train(images,labels) & train(Vector<mat> theImages, Vector<int> theLabels
)的向量。我尝试在 Java 中传递ArrayList<mat> & ArrayList<integer>
和 Vectors,但似乎该方法明确接受了我不确定如何获取的“CvArr”数据类型......这是错误:
类型中的方法train(opencv_core.CvArr, opencv_core.CvArr) opencv_contrib.FaceRecognizer 不适用于参数 (数组列表,数组列表)
有人知道如何将我的 ArrayList 更改为 CvArr 吗?!
这是我的第一篇文章,我不确定是在一个帖子中还是在三个帖子中提出所有三个问题,非常抱歉给您带来不便......如果您需要有关该项目的任何其他信息,请随时提问。
【问题讨论】:
有什么理由需要使用 OpenCV? Android SDK 内置了 android.media.FaceDetector 类。检查此示例项目:developer.com/ws/android/programming/… 实际上我正在寻找一个人脸识别库,而不仅仅是一个人脸检测库,因此我不能只使用 Android SDK 人脸检测... @Cypher,你是如何在安卓中集成人脸识别的? 【参考方案1】:更新
下面的文章是Petter Christian Bjelland写的,所以所有的功劳都是他的。我发在这里,因为他的博客目前似乎处于维护模式,但我认为值得分享。
用JavaCV做人脸识别(来自http://pcbje.com)
我找不到任何关于如何使用 OpenCV 和 Java 执行人脸识别的教程,所以我决定在这里分享一个可行的解决方案。该解决方案的当前形式效率非常低,因为每次运行都会构建训练模型,但它显示了使其工作所需的条件。
下面的类有两个参数:包含训练人脸的目录的路径和要分类的图像的路径。并不是所有图像都必须具有相同的大小,并且必须从原始图像中裁剪出人脸(如果您还没有进行人脸检测,请看这里)。
为简单起见,该课程还要求训练图像的文件名格式为:<label>-rest_of_filename.png
。例如:
...等等。
代码:
import com.googlecode.javacv.cpp.opencv_core;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_contrib.*;
import java.io.File;
import java.io.FilenameFilter;
public class OpenCVFaceRecognizer
public static void main(String[] args)
String trainingDir = args[0];
IplImage testImage = cvLoadImage(args[1]);
File root = new File(trainingDir);
FilenameFilter pngFilter = new FilenameFilter()
public boolean accept(File dir, String name)
return name.toLowerCase().endsWith(".png");
;
File[] imageFiles = root.listFiles(pngFilter);
MatVector images = new MatVector(imageFiles.length);
int[] labels = new int[imageFiles.length];
int counter = 0;
int label;
IplImage img;
IplImage grayImg;
for (File image : imageFiles)
// Get image and label:
img = cvLoadImage(image.getAbsolutePath());
label = Integer.parseInt(image.getName().split("\\-")[0]);
// Convert image to grayscale:
grayImg = IplImage.create(img.width(), img.height(), IPL_DEPTH_8U, 1);
cvCvtColor(img, grayImg, CV_BGR2GRAY);
// Append it in the image list:
images.put(counter, grayImg);
// And in the labels list:
labels[counter] = label;
// Increase counter for next image:
counter++;
FaceRecognizer faceRecognizer = createFisherFaceRecognizer();
// FaceRecognizer faceRecognizer = createEigenFaceRecognizer();
// FaceRecognizer faceRecognizer = createLBPHFaceRecognizer()
faceRecognizer.train(images, labels);
// Load the test image:
IplImage greyTestImage = IplImage.create(testImage.width(), testImage.height(), IPL_DEPTH_8U, 1);
cvCvtColor(testImage, greyTestImage, CV_BGR2GRAY);
// And get a prediction:
int predictedLabel = faceRecognizer.predict(greyTestImage);
System.out.println("Predicted label: " + predictedLabel);
该类需要 OpenCV Java 接口。如果您使用的是 Maven,则可以使用以下 pom.xml 检索所需的库:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.pcbje</groupId>
<artifactId>opencvfacerecognizer</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>opencvfacerecognizer</name>
<url>http://pcbje.com</url>
<dependencies>
<dependency>
<groupId>com.googlecode.javacv</groupId>
<artifactId>javacv</artifactId>
<version>0.3</version>
</dependency>
<!-- For Linux x64 environments -->
<dependency>
<groupId>com.googlecode.javacv</groupId>
<artifactId>javacv</artifactId>
<classifier>linux-x86_64</classifier>
<version>0.3</version>
</dependency>
<!-- For OSX environments -->
<dependency>
<groupId>com.googlecode.javacv</groupId>
<artifactId>javacv</artifactId>
<classifier>macosx-x86_64</classifier>
<version>0.3</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>javacv</id>
<name>JavaCV</name>
<url>http://maven2.javacv.googlecode.com/git/</url>
</repository>
</repositories>
</project>
原帖
引用我对http://answers.opencv.org/question/865/the-contrib-module-problem的回复。
在没有使用过 javacv 的情况下,让我们看看只看接口能走多远!项目在googlecode上,方便浏览代码:http://code.google.com/p/javacv。
首先看看cv::FaceRecognizer
是如何被包装的(opencv_contrib.java, line 845 at time of writing this):
@Namespace("cv") public static class FaceRecognizer extends Algorithm
static Loader.load();
public FaceRecognizer()
public FaceRecognizer(Pointer p) super(p);
public /*abstract*/ native void train(@ByRef MatVector src, @Adapter("ArrayAdapter") CvArr labels);
public /*abstract*/ native int predict(@Adapter("ArrayAdapter") CvArr src);
public /*abstract*/ native void predict(@Adapter("ArrayAdapter") CvArr src, @ByRef int[] label, @ByRef double[] dist);
public native void save(String filename);
public native void load(String filename);
public native void save(@Adapter("FileStorageAdapter") CvFileStorage fs);
public native void load(@Adapter("FileStorageAdapter") CvFileStorage fs);
啊哈,所以您需要为图像传递MatVector
!您可以在CvArr
(一行或一列)中传递标签。 MatVector
定义在 opencv_core, line 4629 (at time of writing this) 中,如下所示:
public static class MatVector extends Pointer
static load();
public MatVector() allocate();
public MatVector(long n) allocate(n);
public MatVector(Pointer p) super(p);
private native void allocate();
private native void allocate(@Cast("size_t") long n);
public native long size();
public native void resize(@Cast("size_t") long n);
@Index @ValueGetter public native @Adapter("MatAdapter") CvMat getCvMat(@Cast("size_t") long i);
@Index @ValueGetter public native @Adapter("MatAdapter") CvMatND getCvMatND(@Cast("size_t") long i);
@Index @ValueGetter public native @Adapter("MatAdapter") IplImage getIplImage(@Cast("size_t") long i);
@Index @ValueSetter public native MatVector put(@Cast("size_t") long i, @Adapter("MatAdapter") CvArr value);
再看代码,我猜可以这样使用:
int numberOfImages = 10;
// Allocate some memory:
MatVector images = new MatVector(numberOfImages);
// Then fill the MatVector, you probably want to do something useful instead:
for(int idx = 0; idx < numberOfImages; idx++)
// Load an image:
CvArr image = cvLoadImage("/path/to/your/image");
// And put it into the MatVector:
images.put(idx, image);
您可能希望自己编写一个方法,将 Java ArrayList
转换为 MatVector
(如果 javacv 中尚不存在这样的函数)。
现在回答你的第二个问题。 FaceRecognizer
等同于 cv::FaceRecognizer
。本机 OpenCV C++ 类返回一个cv::Ptr<cv::FaceRecognizer>
,它是一个指向cv::FaceRecognizer
的(智能)指针。这也必须包装。在这里看到一个模式?
FaceRecognizerPtr
的界面现在是这样的:
@Name("cv::Ptr<cv::FaceRecognizer>")
public static class FaceRecognizerPtr extends Pointer
static load();
public FaceRecognizerPtr() allocate();
public FaceRecognizerPtr(Pointer p) super(p);
private native void allocate();
public native FaceRecognizer get();
public native FaceRecognizerPtr put(FaceRecognizer value);
因此,您可以从此类中获取FaceRecognizer
,也可以将FaceRecognizer
放入其中。您应该只关心get()
,因为指针由创建具体FaceRecognizer
算法的方法填充:
@Namespace("cv") public static native @ByVal FaceRecognizerPtr createEigenFaceRecognizer(int num_components/*=0*/, double threshold/*=DBL_MAX*/);
@Namespace("cv") public static native @ByVal FaceRecognizerPtr createFisherFaceRecognizer(int num_components/*=0*/, double threshold/*=DBL_MAX*/);
@Namespace("cv") public static native @ByVal FaceRecognizerPtr createLBPHFaceRecognizer(int radius/*=1*/,
int neighbors/*=8*/, int grid_x/*=8*/, int grid_y/*=8*/, double threshold/*=DBL_MAX*/);
因此,一旦获得 FaceRecognizerPtr,您就可以执行以下操作:
// Holds your training data and labels:
MatVector images;
CvArr labels;
// Do something with the images and labels... Probably fill them?
// ...
// Then get a Pointer to a FaceRecognizer (FaceRecognizerPtr).
// Java doesn't have default parameters, so you have to add some yourself,
// if you pass 0 as num_components to the EigenFaceRecognizer, the number of
// components is determined by the data, for the threshold use the maximum possible
// value if you don't want one. I don't know the constant in Java:
FaceRecognizerPtr model = createEigenFaceRecognizer(0, 10000);
// Then train it. See how I call get(), to get the FaceRecognizer inside the FaceRecognizerPtr:
model.get().train(images, labels);
这会学习一个特征脸模型。就是这样!
【讨论】:
谢谢 Philipp...但是我在尝试将数据加载到 CvArr 时遇到了一些麻烦...我已经将标签作为数据字符串...但我似乎找不到一种将这些标签作为数组插入到 CvArr 的方法......让我们称之为缺乏 OpenCV 知识......有人可以帮我解决这个问题吗?! 要么使用一个 QA 页面,要么使用另一个,在这两个页面上都问我有点矫枉过正。我只能写我在 OpenCV QA 页面上说的话。我可以确定如何在 OpenCV C++ 中执行此操作,但您要问的是 JavaCV。因此,最好在 JavaCV 邮件列表中询问此类问题,该邮件列表位于:https://groups.google.com/forum/?fromgroups#!forum/javacv 我想知道这是否有效?我之前尝试过实现这一点,但据我所知,JavaCV 并没有很好地实现 facerec 库 请查看完整源代码示例的更新答案。 做得很好.. 太棒了 :-) .. 需要一个信息,对于每个算法运行,它总是发回一些 predictLabel ,即使面部根本不匹配,所以我们如何管理这个部分?【参考方案2】:我使用 opencv 制作了一个用于人脸识别的安卓应用。为了获得良好的识别,您需要更好的检测,您可以从以下位置查看:https://github.com/yaylas/AndroidFaceRecognizer 希望对你有帮助。
【讨论】:
以上是关于Android上的人脸识别的主要内容,如果未能解决你的问题,请参考以下文章