openCV与C++的图像识别(二)——pHash

/*

参考博客:https://blog.csdn.net/akadiao/article/details/79779634
配置环境参考:https://blog.csdn.net/qq_28584889/article/details/87914831

*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
using namespace std;
using namespace cv;
 
#define PI 3.1415926
#define hashLength 64
 
/*
	功能:获取DCT系数
	n:矩阵大小
	quotient: 系数
	quotientT: 系数转置
*/
void coefficient(const int &n, double **quotient, double **quotientT){
	double sqr = 1.0/sqrt(n+0.0);
	for(int i = 0; i < n; i++){
		quotient[0][i] = sqr;
		quotientT[i][0] =  sqr;
	}
 
	for(int i = 1; i < n; i++){
		for(int j = 0; j < n; j++){
			quotient[i][j] = sqrt(2.0/n)*cos(i*(j+0.5)*PI/n);  // 由公式得到
			quotientT[j][i] = quotient[i][j];
		}
	}
 
}
/*
	功能:两矩阵相乘
	A和B:源输入矩阵
	result:输出矩阵
*/
void matrixMultiply(double **A, double **B, int n, double **result){  
	double t = 0;
	for(int i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
			t = 0;
			for(int k = 0; k < n; k++)
				t += A[i][k]*B[k][j];   
			result[i][j] = t;
		}
	}
}
 
 
void DCT(Mat_ image, const int &n, double **iMatrix){
	for(int i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
			iMatrix[i][j] = (double)image(i,j);
		}
	}
 
	// 为系数分配空间
	double **quotient = new double*[n];
	double **quotientT = new double*[n];
	double **tmp = new double*[n];
	for(int i = 0; i < n; i++){
		quotient[i] = new double[n];
		quotientT[i] = new double[n]; 
		tmp[i] = new double[n];
	}
	// 计算系数矩阵
	coefficient(n, quotient, quotientT);
	matrixMultiply(quotient, iMatrix, n, tmp);  // 由公式成绩结果
	matrixMultiply(tmp, quotientT, n, iMatrix);
 
	for(int i = 0; i < n; i++){
		delete []tmp[i];
		delete []quotient[i];
		delete []quotientT[i];
	}
	delete []tmp;
	delete []quotient;
	delete []quotientT;
}
 
// 计算8*8图像的平均灰度
float calcAverage(double **iMatrix, const int &size){
	float sum = 0;
	for(int i = 0 ; i < size; i++){
		for(int j = 0; j < size; j++){
			sum += iMatrix[i][j];
		}
	}
	return sum/(size*size);
}
 
/* 计算hash值
	image:8*8的灰度图像
	size: 图像大小  8*8
	phash:存放64位hash值
	averagePix: 灰度值的平均值
*/
void fingerPrint(double **iMatrix, const int &size, bitset &phash, const float &averagePix){
	for(int i = 0; i < size; i++){
		int pos = i * size;
		for(int j = 0; j < size; j++){
			phash[pos+j] = iMatrix[i][j] >= averagePix ? 1:0;
		}
	}
}
 
/*计算汉明距离*/
int hammingDistance(const bitset &query, const bitset &target){
	int distance = 0;
	for(int i = 0; i < hashLength; i++){
		distance += (query[i] == target[i] ? 0 : 1);
	}
	return distance;
}
 
string bitTohex(const bitset &target){
	string str;
	for(int i = 0; i < hashLength; i=i+4){
		int sum = 0;
		string s;
		sum += target[i] + (target[i+1]<<1) + (target[i+2]<<2) + (target[i+3]<<3);
		stringstream ss;
		ss << hex <> s;
		str += s;
	}
	return str;
}
 
 
 
 
 
int main(){
	Mat img = imread("F:\\www\\person.jpg", 1);
	if(!img.data){
		cout << "the image is not exist" << endl;
		return 0;
	}
	int size = 32;  // 图片缩放后大小
 
	resize(img, img, Size(size,size));      // 缩放到32*32
	cvtColor(img, img, COLOR_BGR2GRAY);       // 灰度化
 
	double **iMatrix = new double*[size];
	for(int i = 0; i < size; i++)
		iMatrix[i] = new double[size];
	DCT(img, size, iMatrix);   // 离散余弦变换
	float averagePix = calcAverage(iMatrix, 8);
	cout << averagePix << endl;
	bitset phash;
	fingerPrint(iMatrix, 8, phash, averagePix);
 
	//cout << phash << endl;
	string str = bitTohex(phash);
	cout << str << endl;
	/*namedWindow("img");
	imshow("img", img);
	waitKey(0);*/
	
 
	string img_dir = "F:\\www\\";
	for(int i = 1; i <= 18; i++){
		string pos;
		stringstream ss;
		ss << i;
		ss >> pos;
		string img_name = img_dir + "person" + pos +".jpg"; 
		Mat target = imread(img_name, 1);
		if(!target.data){
			cout << "the target image" << img_name << " is not exist" << endl;
			continue;
		}
		resize(target, target, Size(size,size));
		cvtColor(target, target, COLOR_BGR2GRAY);
		DCT(target, size, iMatrix);
 
		float averagePix2 = calcAverage(iMatrix, 8);
		bitset phash2;
		fingerPrint(iMatrix, 8, phash2, averagePix2);
 
		//cout << averagePix2 << endl;
		int distance = hammingDistance(phash, phash2);      // 计算汉明距离
		cout <<"【" << i <<"-" <<  distance << "】 ";
	}
	cout << endl;
	for(int i = 0; i < size; i++)
		delete []iMatrix[i];
	delete []iMatrix;
 	system("pause");
	return 0;
}
 

总结:本次编程采用pHash中的DCT系数进行比较,结果也依旧差强人意,但还是具有借鉴意义。

你可能感兴趣的:(C,汇总)