使用感知哈希方法,進行縮略圖比較,來判斷圖像的相似度
先把目錄下的所有圖片都讀取出來,再進行判斷
優點:速度快
缺點:獲取所有圖像的指紋需要較多內存和時間來進行處理
#include <iostream>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;
//使用感知哈希算法進行圖片去重
//構建一個結構體,用於存儲對應名稱和要比較的內容
typedef struct MatStruct{
string name;
unsigned char buf[64];
MatStruct(){
name = "";
memset(buf, 0, 64);
}
MatStruct(const struct MatStruct &ms){
name = ms.name;
memset(buf, 0, 64);
memcpy(buf, ms.buf, 64);
}
//重載比較函數
bool operator<(const struct MatStruct &ms)const {
return name < ms.name;
}
}MatStruct;
int getdirimages(string path, std::vector<MatStruct> &images)
{
std::vector<MatStruct> tmpimages;
DIR *dir;
struct dirent *ptr;
dir = opendir(path.c_str());
while((ptr = readdir(dir)) != NULL) {
if((strcmp(ptr->d_name,".") == 0) || (strcmp(ptr->d_name, "..") == 0)) {
continue;
}
string fullname = path + "/" + ptr->d_name;
Mat img = imread(fullname);
if(img.empty()){
continue;
}
MatStruct ms;
ms.name = ptr->d_name;
Mat gray, res;
//縮放成8x8大小灰度圖
resize(img, res, Size(8,8));
cvtColor(res, gray, CV_BGR2GRAY);
//獲取灰度平均值
double mn = mean(gray)[0];
//比較像素灰度,獲取圖像指紋
for(int i = 0; i < 8; i++){
for(int j = 0; j < 8; j++){
ms.buf[i*8 + j] = (gray.at<unsigned char>(i,j) > mn) ? 1 : 0;
}
}
cout << "get " << fullname << endl;
tmpimages.push_back(ms);
}
closedir(dir);
std::sort(tmpimages.begin(), tmpimages.end());
tmpimages.swap(images);
}
int main(int argc, char* argv[])
{
if(argc <= 1){
cout << argv[0] << " picpath" << endl;
return -1;
}
struct stat st;
if(stat(argv[1], &st) != 0 || (st.st_mode & S_IFDIR) != S_IFDIR){
cout << argv[1] << " is not dir" << endl;
return -1;
}
int startpos = 0;
int curpos = 0;
std::vector<MatStruct> images;
cout << "start getdir" << endl;
getdirimages(argv[1], images);
cout << "start compare" << endl;
std::vector<MatStruct>::iterator it1 = images.begin();
while(it1 != images.end()){
std::vector<MatStruct>::iterator it2 = it1;
curpos = 0;
//存儲需要刪除的迭代對象
std::vector<std::vector<MatStruct>::iterator> delImages;
cout << it1->name << endl;
while(it2 != images.end()){
int diff = 0;
if(it2 == it1){
it2++;
continue;
}
//比較兩個圖片的相似度,不同的地方不超過5,則爲相似的圖片
for(int i = 0; i < 64; i++){
if(it1->buf[i] != it2->buf[i]){
diff++;
}
}
if(diff < 5){
delImages.push_back(it2);
}
it2++;
}
if(delImages.size() > 0){
//刪除圖像
for(int i = 0; i < delImages.size(); i++){
cout << "remove " << delImages[i]->name << endl;
string fullpath = string(argv[1]) + "/" + delImages[i]->name;
unlink(fullpath.c_str());
images.erase(delImages[i]);
}
it1 = images.begin();
for(int index = 0; index < startpos; index++)
it1++;
continue;
}
startpos++;
it1++;
}
return 0;
}