这是我当年在安卓上用的一个人脸识别的算法。主要是用了PCA降维的方式,然后用欧式距离比较下最近的人脸。
趁热来一波刚出炉的Javacv写的特征脸算法,写得不是很好,但是也是费了一小番心思做的。我知道还有很多写得不好不对的地方,望请大家指正。不多说了,知道你们想看代码。
import org.bytedeco.javacpp.opencv_core; import org.bytedeco.javacpp.opencv_core.*; import org.bytedeco.javacv.JavaCV; import org.opencv.core.Core; import android.util.Log; import org.opencv.core.CvType; import org.opencv.imgproc.Imgproc; import static org.bytedeco.javacpp.opencv_core.*; import static org.bytedeco.javacpp.opencv_highgui.*; import static org.bytedeco.javacpp.opencv_imgproc.equalizeHist; /** * 特征脸算法 * @author 火烫火烫的 * */ public class Eigenface { private double threshold = -1; //阈值,不设置返回最相似的距离的标签 private int num_components = -1; private PCA pca = null; private Mat result; //经过投影后的矩阵 private Mat labels; public double getThreshold() { return threshold; } public void setThreshold(double threshold) { this.threshold = threshold; } public int getNum_components() { return num_components; } public void setNum_components(int num_components) { this.num_components = num_components; } public Eigenface() { } public Eigenface(int num_components, double threshold) { super(); this.threshold = threshold; this.num_components = num_components; } /** * 训练方法 * @param images * @param labels */ public void train(MatVector images, Mat labels) { this.labels = labels; Mat allsamples = new Mat(); //所有样本以行存放 Mat mat; Mat convertMat = new Mat(); //转变后的矩阵 Mat placeholder = new Mat(); for (int i = 0; i < images.size(); ++i) { //遍历每一个Mat mat = images.get(i); mat.reshape(1, 1).row(0).convertTo(convertMat, CV_32FC1); allsamples.push_back(convertMat); } if (num_components != -1) { //说明最大维度为设置过 pca = new PCA(allsamples, placeholder, CV_PCA_DATA_AS_ROW, num_components); //pca } else { pca = new PCA(allsamples, placeholder, CV_PCA_DATA_AS_ROW); //pca } result = pca.project(allsamples); Log.e("The size of result", result.rows() + "|" + result.cols()); } /** * 进行识别 * @param testImage * @return 识别的标签,-1代表失败,-2代表没训练 */ public int predict(Mat testImage) { if (pca != null) { Mat convertMat = new Mat(); testImage.reshape(1, 1).row(0).convertTo(convertMat, CV_32FC1); IntBuffer labelsBuf = labels.getIntBuffer(); double[] distance = new double[result.rows()]; Mat testResult = pca.project(convertMat); Log.e("The size of testResult", testResult.rows() + "|" + testResult.cols()); double min_distance = 0; int min_i = -1; for (int i = 0; i < result.rows(); i++){ //对每个向量进行求欧式距离 distance[i] = norm(testResult, result.row(i)); Log.e("distance", "" + distance[i]); if (i == 0) { min_distance = distance[0]; min_i = i; } else if (min_distance > distance[i]){ //说明新的这个距离更小 min_distance = distance[i]; min_i = i; } } int label = -1; //识别标签 for (int i = 0; i <= min_i; ++i) { //对应着取几次 if (labelsBuf.hasRemaining()) { label = labelsBuf.get(); } else { label = -1; } } if (threshold >= 0) { //说明阈值被设置过 if (threshold > min_distance) { //是否超过阈值 return label; } else { return -1; } } else { return label; } } else { return -2; } } /** * 用来求欧式距离的 * @param mat1 * @param mat2 * @return */ public double norm(Mat mat1, Mat mat2) { return cvNorm(mat1.asCvMat(), mat2.asCvMat()); } }