更新
以下文章由Petter Christian Bjelland撰写,所有功劳归属于他。我在此发布它,因为他的博客目前似乎处于维护模式,但我认为这值得分享。
我找不到任何关于如何使用OpenCV和Java执行人脸识别的教程,所以我决定在这里分享一个可行的解决方案。当前形式下,该解决方案非常低效,因为每次运行都会构建训练模型,但是它展示了使其正常工作所需的内容。
下面的类需要两个参数:包含训练面部图像的目录路径和要分类的图像的路径。请注意,所有图像必须具有相同的大小,并且面部已经从其原始图像中裁剪出来(如果您尚未进行面部检测,请查看此处)。
为了简化本文,该类还要求训练图像具有文件名格式:<label>-rest_of_filename.png
。例如:
1-jon_doe_1.png
1-jon_doe_2.png
2-jane_doe_1.png
2-jane_doe_2.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) {
img = cvLoadImage(image.getAbsolutePath());
label = Integer.parseInt(image.getName().split("\\-")[0]);
grayImg = IplImage.create(img.width(), img.height(), IPL_DEPTH_8U, 1);
cvCvtColor(img, grayImg, CV_BGR2GRAY);
images.put(counter, grayImg);
labels[counter] = label;
counter++;
}
FaceRecognizer faceRecognizer = createFisherFaceRecognizer();
faceRecognizer.train(images, labels);
IplImage greyTestImage = IplImage.create(testImage.width(), testImage.height(), IPL_DEPTH_8U, 1);
cvCvtColor(testImage, greyTestImage, CV_BGR2GRAY);
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>
<dependency>
<groupId>com.googlecode.javacv</groupId>
<artifactId>javacv</artifactId>
<classifier>linux-x86_64</classifier>
<version>0.3</version>
</dependency>
<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,在撰写本文时为第845行):
@Namespace("cv") public static class FaceRecognizer extends Algorithm {
static { Loader.load(); }
public FaceRecognizer() { }
public FaceRecognizer(Pointer p) { super(p); }
public native void train(@ByRef MatVector src, @Adapter("ArrayAdapter") CvArr labels);
public native int predict(@Adapter("ArrayAdapter") CvArr src);
public 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
(一行或一列) 传递标签。在opencv_core, line 4629(本文编写时)中定义了 MatVector
,它看起来像这样:
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;
MatVector images = new MatVector(numberOfImages);
for(int idx = 0; idx < numberOfImages; idx++){
CvArr image = cvLoadImage("/path/to/your/image");
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, double threshold);
@Namespace("cv") public static native @ByVal FaceRecognizerPtr createFisherFaceRecognizer(int num_components, double threshold);
@Namespace("cv") public static native @ByVal FaceRecognizerPtr createLBPHFaceRecognizer(int radius,
int neighbors, int grid_x, int grid_y, double threshold);
所以,一旦您获得了FaceRecognizerPtr,您可以执行以下操作:
MatVector images;
CvArr labels;
FaceRecognizerPtr model = createEigenFaceRecognizer(0, 10000);
model.get().train(images, labels);
这将教你一个Eigenfaces模型。就是这样!