基于上周的工作,我继续研究了第五种算法:全局LBP算法。
对一张图像中的每个像素,计算其相邻的八个像素与它的像素值比较,得到一个0和1组成八位的码;这个码可以表达局部特征。那么这个码值的取值有2的八次方即256中选择,可以组成一个256个bin的直方图。使得我们可以使用基于直方图的相似度度量方法来衡量lbp下两张图片的相似度。
string Texture_global_LBP(int srcPicNum, int mode) {
Mat src, graySrc;
int hist[256];
memset(hist, 0, 256 * sizeof(int));
if (mode == 0) {
src = imread(getPath(srcPicNum), CV_LOAD_IMAGE_COLOR);
}
else {
src = UserChosenMat;
}
cvtColor(src, graySrc, CV_RGB2GRAY);
resize(graySrc, graySrc, Size(graySrc.rows/4, graySrc.rows/4));
int total = (graySrc.rows - 2)*(graySrc.cols - 2);
int neighbor[8];//左上角,顺时针,到左边
for (int i = 1; i < graySrc.rows-1; i++) {
for (int j = 1; j < graySrc.cols - 1; j++) {
memset(neighbor, 0, 8 * sizeof(int));
uchar mid = graySrc.at<uchar>(i, j);
neighbor[0] = (graySrc.at<uchar>(i - 1, j - 1) > mid) ? 1 : 0;
neighbor[1] = (graySrc.at<uchar>(i - 1, j) > mid) ? 1 : 0;
neighbor[2] = (graySrc.at<uchar>(i - 1, j + 1) > mid) ? 1 : 0;
neighbor[3] = (graySrc.at<uchar>(i, j + 1) > mid) ? 1 : 0;
neighbor[4] = (graySrc.at<uchar>(i + 1, j + 1) > mid) ? 1 : 0;
neighbor[5] = (graySrc.at<uchar>(i + 1, j ) > mid) ? 1 : 0;
neighbor[6] = (graySrc.at<uchar>(i + 1, j - 1) > mid) ? 1 : 0;
neighbor[7] = (graySrc.at<uchar>(i, j - 1) > mid) ? 1 : 0;
int bin = 0;
for (int t = 0; t < 8; t++) {
bin *= 2;
bin += neighbor[t];
}
hist[bin]++;
}
}
string result = to_string(total);
result.push_back(',');
for (int i = 0; i < 256; i++) {
result.append(to_string(hist[i]));
if (i != 255) result.push_back(',');
}
//cout << result << endl;
return result;
}
检索:
int Retrieval_Texture_lbp() {
ifstream in;
in.open("texture_lbp.txt", ios::in);
if (in.fail()) return -1;
string lbp = Texture_global_LBP(-1, TEST_MODE);
double dstArr[256];
vector<string> strvec = split(lbp, ",");
int total = stoi(strvec[0]);
for (int i = 0; i < 255; i++) {
dstArr[i] = (double)(stoi(strvec[i + 1]))/(double)total;
}
string line;
double maxRes = 0;
int winner = -1;
double res = 0;
double curbin;
for (int i = 1; i <= MAX_PICNNUM; i++) {
getline(in, line, '\n');
res = 0;
strvec.clear();
strvec = split(line, ",");
total = stoi(strvec[0]);
for (int i = 0; i < 255; i++) {
curbin = (double)(stoi(strvec[i + 1])) / (double)total;
res += min(curbin, dstArr[i]);
}
if (res>maxRes) {
cout << maxRes << endl;
maxRes = res;
winner = i;
}
if (i % 200 == 0) cout << "处理完毕" << i << endl;
}
cout << "lbp算法选出的图片是:" << winner << endl;
cout << "结果数值是" << maxRes << endl;
return winner;
}
经过试验,发现全局lbp算法对于人脸检测效果很好,但对于一般的图片表现一般,且检索速度较慢。于是经过比较,我决定融合hsv直方图和灰度共生矩阵方法,作为最终网站使用的检索系统的检索方法。
int Retrieval_both() {
ifstream inh;
inh.open("E:\\programming\\C++workbench\\test\\Image_Retrieval\\Image_Retrieval\\color_hsvhist.txt", ios::in);
if (inh.fail()) return -1;
string hsvcode = Color_hsv_hist(-1, TEST_MODE);
int dstArr[64], curArr[64];
memset(dstArr, 0, 64 * sizeof(int));
memset(curArr, 0, 64 * sizeof(int));
vector<string> strvech = split_str(hsvcode, ",");
for (int i = 0; i < 64; i++) {
dstArr[i] = stoi(strvech[i]);
}
string line;
ifstream ing;
double min[4], range[4];
//ing.open("texture_glcm_minmax.txt", ios::in);
//getline(ing, line, '\n');
//vector<string> minstr = split(line, ",");
//getline(ing, line, '\n');
//vector<string> maxstr = split(line, ",");
for (int i = 0; i < 4; i++) {
min[i] = min_glcm_feature[i];
range[i] = max_glcm_feature[i] - min_glcm_feature[i];
}
//ing.close();
ing.open("E:\\programming\\C++workbench\\test\\Image_Retrieval\\Image_Retrieval\\texture_glcm.txt", ios::in);
if (ing.fail()) return -1;
string gclm_feature = Texture_GLCM(-1, TEST_MODE);
vector<string> strvecg = split_str(gclm_feature, ",");
double vec[4];
double alen = 0;
for (int i = 0; i < 4; i++) {
vec[i] = (stod(strvecg[i]) - min[i]) / range[i];
alen += vec[i] * vec[i];
}
alen = sqrt(alen);
double maxRes = -2;
double cosRes = 0;
double curvec[4];
double blen = 0;
double product = 0;
int winner = -1;
int res = 0;
double curRes = 0.0;
for (int i = 1; i <= MAX_PICNNUM; i++) {
if (i % 100 == 0) cout << i << " 处理完成" << endl;
getline(inh, line, '\n');
res = 0;
curRes = 0;
memset(curArr, 0, 64 * sizeof(int));
strvech.clear();
strvech = split_str(line, ",");
for (int i = 0; i < 64; i++) {
curArr[i] = stoi(strvech[i]);
res += (int)(sqrt(curArr[i] * dstArr[i]));
}
curRes += 1 * (double)res / (45 * 45);
getline(ing, line, '\n');
cosRes = 0;
blen = 0;
product = 0;
strvecg.clear();
strvecg = split_str(line, ",");
for (int i = 0; i < 4; i++) {
curvec[i] = (stod(strvecg[i]) - min[i]) / range[i];
product += curvec[i] * vec[i];
blen += curvec[i] * curvec[i];
}
blen = sqrt(blen);
cosRes = product / (alen*blen);
curRes += 1 * cosRes;
if (curRes > maxRes) {
cout << i << " : " << maxRes << endl;
maxRes = curRes;
winner = i;
}
}
cout << "联合算法选出的图片是:" << winner << endl;
cout << setprecision(14) << "总相似度是" << maxRes << endl;
return winner;
}
对这个代码进行一个简单的封装,使得它可以接受一个原始图片地址和一个想要保存的目标图片地址,这样网站就可以使用系统命令行对该程序进行调用了。