Face recongnized at LFW (人脸识别在lfw的准确率预测)

1.准备pair 对数据 (大概3000对相同的人脸数据, 3000对不同的人脸数据)

2.训练好识别模型 (可以基于 CASIA数据集 共 10575)

3. 预测各对,根据结果选择最优阈值。

(代码使用了 三种判断方式,L1距离, L2距离, Cos角度, 选择阈值的方式也比较简单,直接根据 相同对的均值 和 不同对的均值 的中点作为阈值)

#include <iostream>
#include <vector>
#include <fstream>
#include <istream>
#include <string>
#include <io.h>
#include <direct.h>

#include "../CascadRegression/MCLC.h"
#include <opencv2/opencv.hpp>
#include "util.h"
using namespace glasssix;
using namespace std;
using namespace caffe;
using namespace cv;

#define DEVICE 0
#define FEATUREDIM 128

struct PairImg
{
	string filename1;
	string filename2;
	vector<float> feature1;
	vector<float> feature2;
	float distanceL2;
	float distanceL1;
	float distanceCos;
	bool isPair;
};

struct PairDistance
{
	float distanceL2;
	float distanceL1;
	float distanceCos;
	bool isPair;
};
template <class Type>
Type stringToNum(const string& str)
{
	istringstream iss(str);
	Type num;
	iss >> num;
	return num;
}
void clearFileData(string filePath)
{
	if (filePath == "")
	{
		return;
	}
	ofstream in;
	in.open(filePath, ios::trunc);
	in.close();
}
double extractFeature(MCLC & mclc, int id, Mat &img, int dims, vector<float> & feature)
{
	double time = 0;
	double t0 = (double)cvGetTickCount();
	vector<Mat> imgdata;
	imgdata.push_back(img);
	//cout << "img info:" << img.rows <<"  "<< img.cols <<"  "<< img.channels() << endl;
	unordered_map<std::string, DataBlob> result = mclc.Forward(imgdata, id);

	double t1 = (double)cvGetTickCount();
	time = (t1 - t0) / ((double)cvGetTickFrequency() * 1000);
	//cout << "time is:" << time << " ms" << endl;
	for (unordered_map<string, DataBlob>::iterator iter = result.begin(); iter != result.end(); iter++) {
		//cout << "key value is" << iter->first << " the mapped value is " << " result" << endl;
		string key = iter->first;
		DataBlob result = iter->second;
		if (result.name == "fc5")
		{
			for (int i = 0; i < dims; i++)
			{
				float x = *(result.data);
				feature.push_back(x);
				//cout << "x :" << x << endl;
				(result.data)++;
			}
		}
	}
	return time;
}

void getFeatureImg(DataPrepareUtil &dpu, Mat &src, Mat &dst)
{
	const int scale = 9;
	Mat garyImg;
	cvtColor(src, garyImg, CV_BGR2GRAY);
	Mat dst1;
	dpu.getMultiScaleBlockLBPFeature(garyImg, dst1, scale);
	vector<Mat> merge_dst1;
	for (int j = 0; j < 3; j++)
	{
		Mat dst0(dst1.rows, dst1.cols, CV_8UC1);
		dst1.copyTo(dst0);
		merge_dst1.push_back(dst0);
	}
	merge(merge_dst1, dst);
}

void getSplitLbpFeature(DataPrepareUtil &dpu, Mat &src, Mat &dst)
{
	int scale = 9;
	vector<Mat> splitMat3;
	vector<Mat> merge_dst3;
	split(src, splitMat3);
	Mat dst3_0, dst3_1, dst3_2, dst3_11, dst3_22;
	splitMat3[0].copyTo(dst3_0);
	dpu.lbp_normal(splitMat3[1], dst3_1);
	dpu.getMultiScaleBlockLBPFeature(splitMat3[2], dst3_2, scale);

	copyMakeBorder(dst3_1, dst3_11, 1, 1, 1, 1, BORDER_CONSTANT, 0);
	copyMakeBorder(dst3_2, dst3_22, 4, 4, 4, 4, BORDER_CONSTANT, 0);

	merge_dst3.push_back(dst3_0);
	merge_dst3.push_back(dst3_11);
	merge_dst3.push_back(dst3_22);
	merge(merge_dst3, dst);
}

void getAllFeatureData(MCLC & mclc, int id, vector<PairImg> &data, string path)
{
	vector<PairImg>::iterator itor;
	itor = data.begin();
	//int length = data.size();
	DataPrepareUtil dpu;
	int i = 0;
	for (itor; itor != data.end();)
	{
		i++;
		if (i % 1000 == 0)
		{
			cout << "extractFeature is:" << i << endl;
		}
		vector<float> feature1;
		vector<float> feature2;

		string img_path1 = path + (*itor).filename1;
		if (_access(img_path1.c_str(), 0) == -1)
		{
			cout << "coun't found filename" << img_path1 << endl;
			data.erase(itor);
			continue;
		}
		string img_path2 = path + (*itor).filename2;
		if (_access(img_path2.c_str(), 0) == -1)
		{
			cout << "coun't found filename" << img_path1 << endl;
			data.erase(itor);
			continue;
		}

		Mat img1 = imread(img_path1, CV_LOAD_IMAGE_COLOR);
		Mat img2 = imread(img_path2, CV_LOAD_IMAGE_COLOR);

		Mat dst1, dst2;
		//getFeatureImg(dpu, img1, dst1);
		//getFeatureImg(dpu, img2, dst2);
		getSplitLbpFeature(dpu, img1, dst1);
		getSplitLbpFeature(dpu, img2, dst2);

		//cout << "img2.path:" << path + data[i].filename2 << endl;
		//cout <<img1.rows<<" "<<img1.cols<<" " <<img1.channels() << endl;
		//cout << img2.rows << " " << img2.cols << " " << img2.channels() << endl;
		//imshow("img", img1);
		//waitKey(0);
		extractFeature(mclc, id, dst1, FEATUREDIM, feature1);
		extractFeature(mclc, id, dst2, FEATUREDIM, feature2);
		//data[i].feature1.insert(data[i].feature1.end(), feature1.begin(), feature1.end());
		//data[i].feature2.insert(data[i].feature2.end(), feature2.begin(), feature2.end());
		(*itor).feature1 = feature1;
		(*itor).feature2 = feature2;
		itor++;
	}
}
void  splitString(const string& s, vector<string>& v, const string& c)
{
	string::size_type pos1, pos2;
	pos2 = s.find(c);
	pos1 = 0;
	while (string::npos != pos2)
	{
		v.push_back(s.substr(pos1, pos2 - pos1));
		pos1 = pos2 + c.size();
		pos2 = s.find(c, pos1);
	}
	if (pos1 != s.length()) {
		v.push_back(s.substr(pos1));
	}
}
void parseData(string buf, PairImg& mark)
{
	vector<string> result;
	splitString(buf, result, "\t");

	if (result.size() == 3)
	{
		mark.isPair = true;
		mark.filename1 = result[0] + "\\" + result[0] + "_" + ((result[1].size() == 1) ? "000" : "00") + result[1] + ".jpg";
		mark.filename2 = result[0] + "\\" + result[0] + "_" + ((result[2].size() == 1) ? "000" : "00") + result[2] + ".jpg";
	}
	else if (result.size() == 4)
	{
		mark.isPair = false;
		mark.filename1 = result[0] + "\\" + result[0] + "_" + ((result[1].size() == 1) ? "000" : "00") + result[1] + ".jpg";
		mark.filename2 = result[2] + "\\" + result[2] + "_" + ((result[3].size() == 1) ? "000" : "00") + result[3] + ".jpg";
	}
}
void readData(string filePath, vector<PairImg> & result, int count = INT_MAX)
{
	ifstream fileA(filePath);
	if (!fileA)
	{
		cout << "没有找到需要读取的  " << filePath << " 请将文件放到指定位置再次运行本程序。" << endl << "  按任意键以退出";
		return;
	}
	for (int i = 0; !fileA.eof() && (i < count); i++)
	{
		PairImg atb;
		string buf;
		getline(fileA, buf, '\n');
		if (buf == "")
		{
			cout << "buf is empty." << endl;
			continue;
		}
		parseData(buf, atb);
		result.push_back(atb);
	}
	fileA.close();
}
void writeDatatoFile(std::string filePath, vector<PairImg> & data)
{
	if (filePath == "" || data.size() == 0)
	{
		return;
	}
	ofstream pair_text;
	pair_text.open(filePath, ios::app);
	int length = data.size();
	for (int i = 0; i < length; i++)
	{
		string line = to_string((int)data[i].isPair);
		line.append(" ");
		line.append(to_string(data[i].distanceL2));
		line.append(" ");
		line.append(to_string(data[i].distanceL1));
		line.append(" ");
		line.append(to_string(data[i].distanceCos));
		pair_text << line << "\n";
	}
	pair_text.close();
}

void getDistance(vector<PairImg> &data)
{
	int length = data.size();
	for (int i = 0; i < length; i++)
	{
		float distanceL2 = 0, distanceL1 = 0, distanceCos = 0;
		float nor_feature1 = 0, nor_feature2 = 0;
		for (int j = 0; j < FEATUREDIM; j++)
		{
			distanceL2 += pow((data[i].feature1[j] - data[i].feature2[j]), 2);
			distanceL1 += abs(data[i].feature1[j] - data[i].feature2[j]);

			distanceCos += data[i].feature1[j] * data[i].feature2[j];
			nor_feature1 += pow(data[i].feature1[j], 2);
			nor_feature2 += pow(data[i].feature2[j], 2);
		}
		data[i].distanceL2 = sqrt(distanceL2) / FEATUREDIM;
		data[i].distanceL1 = distanceL1 / FEATUREDIM;
		data[i].distanceCos = distanceCos / (sqrt(nor_feature1)*sqrt(nor_feature2));
	}
}

void readPairDistanceData(string pair_dis, vector<PairDistance> &data1, vector<PairDistance> &data2)
{
	ifstream fileA(pair_dis);
	if (!fileA)
	{
		cout << "没有找到需要读取的  " << pair_dis << " 请将文件放到指定位置再次运行本程序。" << endl << "  按任意键以退出";
		return;
	}
	for (int i = 0; !fileA.eof(); i++)
	{
		PairDistance dis1;
		PairDistance dis2;
		string buf;
		getline(fileA, buf, '\n');
		if (buf == "")
		{
			cout << "buf is empty." << endl;
			continue;
		}

		vector<string> result1;
		splitString(buf, result1, " ");
		if (result1[0] == "1")
		{
			dis1.distanceL2 = stringToNum<float>(result1[1]);
			dis1.distanceL1 = stringToNum<float>(result1[2]);
			dis1.distanceCos = stringToNum<float>(result1[3]);
			data1.push_back(dis1);
		}
		else if (result1[0] == "0")
		{
			dis2.distanceL2 = stringToNum<float>(result1[1]);
			dis2.distanceL1 = stringToNum<float>(result1[2]);
			dis2.distanceCos = stringToNum<float>(result1[3]);
			data2.push_back(dis2);
		}
	}
	fileA.close();
}
void getMean(vector<PairDistance> &data1, vector<PairDistance> &data2, float mean1[], float mean2[])
{
	int length1 = data1.size();
	int length2 = data2.size();
	float mean1_L2 = 0, mean1_L1 = 0, mean1_Cos = 0;
	float mean2_L2 = 0, mean2_L1 = 0, mean2_Cos = 0;
	for (int i = 0; i < length1; i++)
	{
		mean1_L2 += data1[i].distanceL2;
		mean1_L1 += data1[i].distanceL1;
		mean1_Cos += data1[i].distanceCos;
	}
	mean1_L2 = mean1_L2 / length1;
	mean1_L1 = mean1_L1 / length1;
	mean1_Cos = mean1_Cos / length1;
	mean1[0] = mean1_L2;
	mean1[1] = mean1_L1;
	mean1[2] = mean1_Cos;
	for (int i = 0; i < length2; i++)
	{
		mean2_L2 += data2[i].distanceL2;
		mean2_L1 += data2[i].distanceL1;
		mean2_Cos += data2[i].distanceCos;
	}
	mean2_L2 = mean2_L2 / length2;
	mean2_L1 = mean2_L1 / length2;
	mean2_Cos = mean2_Cos / length2;
	mean2[0] = mean2_L2;
	mean2[1] = mean2_L1;
	mean2[2] = mean2_Cos;
	cout << "mean1 is:" << mean1_L2 << " " << mean1_L1 << " " << mean1_Cos << endl;
	cout << "mean2 is:" << mean2_L2 << " " << mean2_L1 << " " << mean2_Cos << endl;
}

void showAverage(vector<PairDistance> &data1, vector<PairDistance> &data2, float mean1[], float mean2[])
{
	float threadL2 = 0, threadL1 = 0, threadCos = 0;
	threadL2 = (mean1[0] + mean2[0]) / 2;
	threadL1 = (mean1[1] + mean2[1]) / 2;
	threadCos = (mean1[2] + mean2[2]) / 2;

	int length1 = data1.size();
	int length2 = data2.size();
	cout << "length1 is:" << length1 << " length2 is:" << length2 << endl;
	float avg_L2 = 0, avg_L1 = 0, avg_Cos = 0;
	int errorL2 = 0, errorL1 = 0, errorCos = 0;
	for (int i = 0; i < length1; i++)
	{
		if (data1[i].distanceL2 >= threadL2)
		{
			errorL2++;
		}
		if (data1[i].distanceL1 >= threadL1)
		{
			errorL1++;
		}
		if (data1[i].distanceCos <= threadCos)
		{
			errorCos++;
		}
	}
	for (int i = 0; i < length2; i++)
	{
		if (data2[i].distanceL2 <= threadL2)
		{
			errorL2++;
		}
		if (data2[i].distanceL1 <= threadL1)
		{
			errorL1++;
		}
		if (data2[i].distanceCos >= threadCos)
		{
			errorCos++;
		}
	}
	cout << "accuracy L2 is:" << (1 - (float)errorL2 / (length1 + length2)) << "  with threadholdL2 is:"<< threadL2<< endl;
	cout << "accuracy L1 is:" << (1 - (float)errorL1 / (length1 + length2)) << "  with threadholdL1 is:" << threadL1 << endl;
	cout << "accuracy Cos is:" << (1 - (float)errorCos / (length1 + length2)) << "  with threadholdCos is:" << threadCos << endl;
}

string dis_text = "E:\\work\\face_recongnized\\dis_pair_2.txt";
void generate_distance()
{
	//string base = "E:\\work\\other_attribution\\model\\";
	//string protext = "E:\\work\\other_attribution\\model\\test_500000.prototxt";
	//string model = "E:\\work\\other_attribution\\model\\save_path\\_iter_500000.caffemodel";
	string base = "E:\\work\\face_recongnized\\lbp_model\\";
	string protext = base + "test.prototxt";
	string model = base + "save_path2\\_iter_init.caffemodel";

	MCLC mclc;
	int id = mclc.AddNet(protext, model, DEVICE);
	string dir_img = "E:\\work\\face_recongnized\\Alignment_LFW_Equalized\\";
	string text = "E:\\work\\face_recongnized\\pair.txt";
	
	vector<PairImg> data;
	readData(text, data);
	getAllFeatureData(mclc, id, data, dir_img);
	getDistance(data);
	clearFileData(dis_text);
	writeDatatoFile(dis_text, data);
}

void predict_distance()
{
	vector<PairDistance>data1;
	vector<PairDistance>data2;
	readPairDistanceData(dis_text, data1, data2);
	float mean1[3], mean2[3];
	getMean(data1, data2, mean1, mean2);

	showAverage(data1, data2, mean1, mean2);
}

int main()
{
	generate_distance();
	predict_distance();

	system("PAUSE");
	return 0;
}
#pragma once
#include <opencv2\opencv.hpp>

namespace glasssix
{
	class DataPrepareUtil
	{
	public :
		void getMultiScaleBlockLBPFeature(cv::Mat & src, cv::Mat & dst, int scale);
		void lbp_normal(cv::Mat& src, cv::Mat &dst);
	};
}

#include "util.h"
#include <iostream>
//原始LBP特征计算

using namespace glasssix;
using namespace cv;

template <typename _tp>
void getOriginLBPFeature(Mat & src, Mat & dst, int cellsize)
{
	dst.create(src.rows - 2 * cellsize, src.cols - 2 * cellsize, CV_8UC1);
	dst.setTo(0);
	for (int i = cellsize; i<src.rows - cellsize; i = i + 1)
	{
		for (int j = cellsize; j<src.cols - cellsize; j = j + 1)
		{
			_tp center = src.at<_tp>(i, j);
			unsigned char lbpCode = 0;
			lbpCode |= (src.at<_tp>(i - cellsize, j - cellsize) > center) << 7;
			lbpCode |= (src.at<_tp>(i - cellsize, j) > center) << 6;
			lbpCode |= (src.at<_tp>(i - cellsize, j + cellsize) > center) << 5;
			lbpCode |= (src.at<_tp>(i, j + cellsize) > center) << 4;
			lbpCode |= (src.at<_tp>(i + cellsize, j + cellsize) > center) << 3;
			lbpCode |= (src.at<_tp>(i + cellsize, j) > center) << 2;
			lbpCode |= (src.at<_tp>(i + cellsize, j - cellsize) > center) << 1;
			lbpCode |= (src.at<_tp>(i, j - cellsize) > center) << 0;
			dst.at<uchar>(i - cellsize, j - cellsize) = lbpCode;
		}
	}
}
//MB-LBP特征的计算
void DataPrepareUtil::getMultiScaleBlockLBPFeature(Mat & src, Mat & dst, int scale)
{
	//定义并计算积分图像
	int cellSize = scale / 3;
	int offset = cellSize / 2;
	Mat cellImage(src.rows - 2 * offset, src.cols - 2 * offset, CV_8UC1);
	for (int i = offset; i<src.rows - offset; i++)
	{
		for (int j = offset; j<src.cols - offset; j++)
		{
			int temp = 0;
			for (int m = -offset; m<offset + 1; m++)
			{
				for (int n = -offset; n<offset + 1; n++)
				{
					temp += src.at<uchar>(i + n, j + m);
				}
			}
			temp /= (cellSize*cellSize);
			cellImage.at<uchar>(i - cellSize / 2, j - cellSize / 2) = uchar(temp);
		}
	}
	getOriginLBPFeature<uchar>(cellImage, dst, cellSize);
}

void DataPrepareUtil::lbp_normal(Mat& src, Mat &dst)
{
	dst.create(src.rows - 2, src.cols - 2, CV_8UC1);
	// 循环处理图像数据
	for (int i = 1; i < src.rows - 1; i++)
	{
		for (int j = 1; j < src.cols - 1; j++)
		{
			uchar tt = 0;
			int tt1 = 0;
			uchar u = src.at<uchar>(i, j);
			if (src.at<uchar>(i - 1, j - 1) > u) { tt += 1 << tt1; }
			tt1++;
			if (src.at<uchar>(i - 1, j) > u) { tt += 1 << tt1; }
			tt1++;
			if (src.at<uchar>(i - 1, j + 1) > u) { tt += 1 << tt1; }
			tt1++;
			if (src.at<uchar>(i, j + 1) > u) { tt += 1 << tt1; }
			tt1++;
			if (src.at<uchar>(i + 1, j + 1) > u) { tt += 1 << tt1; }
			tt1++;
			if (src.at<uchar>(i + 1, j) > u) { tt += 1 << tt1; }
			tt1++;
			if (src.at<uchar>(i + 1, j - 1) > u) { tt += 1 << tt1; }
			tt1++;
			if (src.at<uchar>(i - 1, j) > u) { tt += 1 << tt1; }
			tt1++;
			dst.at<uchar>(i - 1, j - 1) = tt;
		}
	}
}

猜你喜欢

转载自blog.csdn.net/u011808673/article/details/80913650