使用c++ opencv實現圖片去重

使用感知哈希方法,進行縮略圖比較,來判斷圖像的相似度

先把目錄下的所有圖片都讀取出來,再進行判斷

優點:速度快

缺點:獲取所有圖像的指紋需要較多內存和時間來進行處理

#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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章