⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 phash.cpp

📁 pHash is an implementation of various perceptual hashing algorithms. A perceptual hash is a fingerpr
💻 CPP
字号:
/*    pHash, the open source perceptual hash library    Copyright (C) 2008 Aetilius, Inc.    All rights reserved.     This program is free software: you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation, either version 3 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program.  If not, see <http://www.gnu.org/licenses/>.    Evan Klinger - eklinger@phash.org    David Starkweather - dstarkweather@phash.org*/#include "pHash.h"#include "cimgffmpeg.h"const char phash_project[] = "pHash %d.%d.%d. Copyright 2008 David Starkweather & Evan Klinger";char phash_version[255] = {0};const char* ph_about(){	int major, minor, point;	if(PHASH_VERSION < 100)		major = 0;	else		major = PHASH_VERSION/100;	if(PHASH_VERSION < 10)	{		minor = 0;		point = PHASH_VERSION;	}	else	{		minor = (PHASH_VERSION%100)/10;		point = PHASH_VERSION%10;	}	snprintf(phash_version, sizeof(phash_version), phash_project, major, minor, point);    return phash_version;}int ph_radon_projections(const CImg<uint8_t> &img,int N,Projections &projs){    int width = img.dimx();    int height = img.dimy();    int D = (width > height)?width:height;    float x_center = (float)width/2;    float y_center = (float)height/2;    int x_off = (int)std::floor(x_center + ROUNDING_FACTOR(x_center));    int y_off = (int)std::floor(y_center + ROUNDING_FACTOR(y_center));    projs.R = new CImg<uint8_t>(N,D,1,1,0);    projs.nb_pix_perline = (int*)calloc(N,sizeof(int));    if (!projs.R || !projs.nb_pix_perline)	return EXIT_FAILURE;    projs.size = N;    CImg<uint8_t> *ptr_radon_map = projs.R;    int *nb_per_line = projs.nb_pix_perline;    for (int k=0;k<N/4+1;k++){        double theta = k*cimg::valuePI/N;        double alpha = std::tan(theta);        for (int x=0;x < D;x++){	    double y = alpha*(x-x_off);            int yd = (int)std::floor(y + ROUNDING_FACTOR(y));            if ((yd + y_off >= 0)&&(yd + y_off < height) && (x < width)){		ptr_radon_map->at(k,x) = img(x,yd + y_off);                nb_per_line[k] += 1;	    }            if ((yd + x_off >= 0) && (yd + x_off < width) && (k != N/4) && (x < height)){		ptr_radon_map->at(N/2-k,x) = img(yd + x_off,x);                nb_per_line[N/2-k] += 1;	    }	}    }    int j= 0;    for (int k=3*N/4;k<N;k++){	double theta = k*cimg::valuePI/N;        double alpha = std::tan(theta);        for (int x=0;x < D;x++){	    double y = alpha*(x-x_off);            int yd = (int)std::floor(y + ROUNDING_FACTOR(y));            if ((yd + y_off >= 0)&&(yd + y_off < height) && (x < width)){		ptr_radon_map->at(k,x) = img(x,yd + y_off);                nb_per_line[k] += 1;	    }            if ((y_off - yd >= 0)&&(y_off - yd<width)&&(2*y_off-x>=0)&&(2*y_off-x<height)&&(k!=3*N/4)){		ptr_radon_map->at(k-j,x) = img(-yd+y_off,-(x-y_off)+y_off);                nb_per_line[k-j] += 1;	    }            	}        j += 2;    }    return EXIT_SUCCESS;}int ph_feature_vector(const Projections &projs, Features &fv){    CImg<uint8_t> *ptr_map = projs.R;    CImg<uint8_t> projection_map = *ptr_map;    int *nb_perline = projs.nb_pix_perline;    int N = projs.size;    int D = projection_map.dimy();    fv.features = (double*)malloc(N*sizeof(double));    fv.size = N;    if (!fv.features)	return EXIT_FAILURE;    double *feat_v = fv.features;    double sum = 0.0;    double sum_sqd = 0.0;    for (int k=0; k < N; k++){	double line_sum = 0.0;        double line_sum_sqd = 0.0;        int nb_pixels = nb_perline[k];	for (int i=0;i<D;i++){	    line_sum += projection_map(k,i);    	    line_sum_sqd += projection_map(k,i)*projection_map(k,i);	}	feat_v[k] = (line_sum_sqd/nb_pixels) - (line_sum*line_sum)/(nb_pixels*nb_pixels);        sum += feat_v[k];        sum_sqd += feat_v[k]*feat_v[k];    }    double mean = sum/N;    double var  = sqrt((sum_sqd/N) - (sum*sum)/(N*N));    for (int i=0;i<N;i++){    	feat_v[i] = (feat_v[i] - mean)/var;    }    return EXIT_SUCCESS;} int ph_dct(const Features &fv,Digest &digest){    int N = fv.size;    const int nb_coeffs = 40;    digest.coeffs = (uint8_t*)malloc(nb_coeffs*sizeof(uint8_t));    if (!digest.coeffs)	return EXIT_FAILURE;    digest.size = nb_coeffs;    double *R = fv.features;    uint8_t *D = digest.coeffs;    double D_temp[nb_coeffs];    double max = 0.0;    double min = 0.0;    for (int k = 0;k<nb_coeffs;k++){	double sum = 0.0;        for (int n=0;n<N;n++){	    double temp = R[n]*cos((cimg::valuePI*(2*n+1)*k)/(2*N));            sum += temp;	}        if (k == 0)	    D_temp[k] = sum/sqrt((double)N);        else            D_temp[k] = sum*SQRT_TWO/sqrt((double)N);        if (D_temp[k] > max)            max = D_temp[k];        if (D_temp[k] < min)            min = D_temp[k];    }           for (int i=0;i<nb_coeffs;i++){	D[i] = (uint8_t)(UCHAR_MAX*(D_temp[i] - min)/(max - min));    }        return EXIT_SUCCESS;}int ph_crosscorr(const Digest &x,const Digest &y,double &pcc,double threshold){    int N = y.size;    int result = 0;    uint8_t *x_coeffs = x.coeffs;    uint8_t *y_coeffs = y.coeffs;    double *r = new double[N];    double sumx = 0.0;    double sumy = 0.0;    for (int i=0;i < N;i++){	sumx += x_coeffs[i];        sumy += y_coeffs[i];    }    double meanx = sumx/N;    double meany = sumy/N;    double max = 0;    for (int d=0;d<N;d++){        double num = 0.0;        double denx = 0.0;        double deny = 0.0;	for (int i=0;i<N;i++){	    num  += (x_coeffs[i]-meanx)*(y_coeffs[(i-d)%N]-meany);            denx += pow((x_coeffs[i]-meanx),2);            deny += pow((y_coeffs[(i-d)%N]-meany),2);	}        r[d] = num/sqrt(denx*deny);        if (r[d] > max)	    max = r[d];    }    delete[] r;    pcc = max;    if (max > threshold)	    result = 1;    return result;}#ifdef max#undef max#endifint ph_image_digest(const CImg<uint8_t> &img,double sigma, double gamma,Digest &digest, int N){        int result = EXIT_FAILURE;    CImg<uint8_t> graysc;    if (img.dimv() >= 3){	graysc = img.get_RGBtoYCbCr().channel(0);    }    else if (img.dimv() == 1){	graysc = img;    }    else {	return result;    }	     graysc.blur((float)sigma);     (graysc/graysc.max()).pow(gamma);         Projections projs;    if (ph_radon_projections(graysc,N,projs) < 0)	goto cleanup;     Features features;    if (ph_feature_vector(projs,features) < 0)	goto cleanup;        if (ph_dct(features,digest) < 0)        goto cleanup;     result = EXIT_SUCCESS;cleanup:    free(projs.nb_pix_perline);    free(features.features);    delete projs.R;    return result;}#define max(a,b) (((a)>(b))?(a):(b))int ph_image_digest(const char *file, double sigma, double gamma, Digest &digest, int N){        CImg<uint8_t> *src = new CImg<uint8_t>(file);    int result = ph_image_digest(*src,sigma,gamma,digest,N);    delete src;    return result;}int ph_compare_images(const CImg<uint8_t> &imA,const CImg<uint8_t> &imB,double &pcc, double sigma, double gamma,int N,double threshold){    int result = 0;    Digest digestA;    if (ph_image_digest(imA,sigma,gamma,digestA,N) < 0)	goto cleanup;    Digest digestB;    if (ph_image_digest(imB,sigma,gamma,digestB,N) < 0)	goto cleanup;    if (ph_crosscorr(digestA,digestB,pcc,threshold) < 0)	goto cleanup;    if  (pcc  > threshold)        result = 1;cleanup:    delete &imA;    delete &imB;    free(digestA.coeffs);    free(digestB.coeffs);    return result;}int ph_compare_images(const char *file1, const char *file2,double &pcc, double sigma, double gamma, int N,double threshold){    CImg<uint8_t> *imA = new CImg<uint8_t>(file1);    CImg<uint8_t> *imB = new CImg<uint8_t>(file2);        int res = ph_compare_images(*imA,*imB,pcc,sigma,gamma,N,threshold);    return res;}CImg<float>* ph_dct_matrix(const int N){    CImg<float> *ptr_matrix = new CImg<float>(N,N,1,1,1/sqrt((float)N));    for (int x=0;x<N;x++){	for (int y=1;y<N;y++){	    ptr_matrix->at(x,y) = SQRT_TWO*cos((cimg::valuePI/2/N)*y*(2*(x+1)));	}    }    return ptr_matrix;}int ph_dct_imagehash(const char* file,ulong64 &hash){    if (!file){	return -1;    }    CImg<uint8_t> src(file);    CImg<float> meanfilter(7,7,1,1,1);    CImg<float> img;    if (src.dimv() >= 3){        img = src.RGBtoYCbCr().channel(0).get_convolve(meanfilter);    } else if (img.dimv() ==1){	img = src.get_convolve(meanfilter);    }    img.resize(32,32);    CImg<float> *C  = ph_dct_matrix(32);    CImg<float> Ctransp = C->get_transpose();    CImg<float> dctImage = (*C)*img*Ctransp;    CImg<float> subsec = dctImage.crop(1,1,8,8).unroll('x');;       float median = subsec.median();    ulong64 one = 0x0000000000000001;    hash = 0x0000000000000000;    for (int i=0;i< 64;i++){	float current = subsec(i);        if (current > median)	    hash |= one;	one = one << 1;    }      delete C;    return 0;}int ph_dct_videohash(const char* file,ulong64 &hash){    long nb_frames = GetNumberVideoFrames(file);    if (nb_frames <= 0)	return -1;    CImgList<uint8_t> *pframeList = new CImgList<uint8_t>();    int frames_read = ReadFrames(file,pframeList,0,nb_frames,1,nb_frames);    if (frames_read < 0){	printf("error reading frames\n");	exit(1);    }    CImg<float> video_cube = pframeList->get_append('z');    CImg<float> meanfilter(1,1,41,1,(float)(1.0/41.0));    video_cube.convolve(meanfilter).resize(32,32,64);    CImgList<float> *pDCTList = new CImgList<float>();    CImg<float> *C = ph_dct_matrix(32);    CImg<float> C_transp = C->get_transpose();    CImg<float> *C2 = ph_dct_matrix(64);    cimg_forZ(video_cube,Z){	CImg<float> current = video_cube.get_slice(Z);	CImg<float> dctcurrent = (*C)*current*(C_transp);	(*pDCTList) << dctcurrent;    }    video_cube = pDCTList->get_append('z');     pDCTList->clear();    video_cube.permute_axes("xzyv");    cimg_forZ(video_cube,Z){	CImg<float> current = video_cube.get_slice(Z);	CImg<float> dctcurrent = (*C2)*current;	(*pDCTList) << dctcurrent;    }    video_cube.permute_axes("xzyv");    CImg<float> coeffs = video_cube.get_crop(1,1,1,4,4,4).unroll('x');    float median = coeffs.median();    hash        = 0x0000000000000000ULL;    ulong64 one = 0x0000000000000001ULL;    for (int i=0;i<64;i++){	if (coeffs(i) >= median)	    hash |= one;	one = one << 1;    }       delete pframeList;    delete pDCTList;    return 0;}int ph_hamming_distance(const ulong64 hash1,const ulong64 hash2){    ulong64 x = hash1^hash2;    const ulong64 m1  = 0x5555555555555555ULL;    const ulong64 m2  = 0x3333333333333333ULL;    const ulong64 h01 = 0x0101010101010101ULL;    const ulong64 m4  = 0x0f0f0f0f0f0f0f0fULL;    x -= (x >> 1) & m1;    x = (x & m2) + ((x >> 2) & m2);    x = (x + (x >> 4)) & m4;    return (x * h01)>>56;}int ph_rash_videodigest(const char* file,CImg<uint8_t> *p_videodigest){    int S = 10;    int L = 50;    int alpha1 = 3;    int alpha2 = 2;        CImgList<uint8_t> *pframes = new CImgList<uint8_t>();        long N = GetNumberVideoFrames(file);    printf("number of video frames %li\n",N);    int frames_read = ReadFrames(file,pframes,0,N,1,N);    if (frames_read < 0){	printf("unable to read frames\n");	exit(1);    }    printf("frames read %d\n",frames_read);    printf("frame list is size = %d\n",pframes->size);#ifdef max#undef max    CImg<double> dist(N,1,1,1,0);    CImg<double> prev(64,1,1,1,0);    cimglist_for(*pframes,I){	CImg<int> hist = pframes->at(I).get_histogram(64);        CImg<double> hist_normd = hist/hist.max();	CImg<int> diff = hist_normd - prev;	dist(I) = abs(diff.norm(1));	prev = hist_normd;    }    uint8_t bnds[N];    bnds[0] = 1;    bnds[N-1] = 1;    int lstart,lend,gstart,gend;    for (int k=1;k<N-1;k++){        lstart = (k-S < 0)?0:k-S;	lend   = (k+S > N-1)?N-1:k+S;	gstart = (k-L < 0)?0:k-L;	gend   = (k+L > N-1)?N-1:k+L;	CImg<double> local_win = dist.get_crop(lstart,0,lend,0);	CImg<double> global_win = dist.get_crop(gstart,0,gend,0);	double Tg = global_win.mean() + alpha1*global_win.variance();        int local_win_size = local_win.dimx();	double Tl = alpha2*local_win.kth_smallest(local_win_size-1);	double localmax = local_win.max();        double thresh = (Tg >= Tl) ? Tg : Tl;	if  ((dist(k) >=  thresh) && (dist(k) >= localmax))	    bnds[k] = 1;	else	    bnds[k] = 0;    }#endif    printf("boundaries\n");    for (int i=0;i<N;i++){	printf("%d",bnds[i]);    }    printf("END\n");    delete pframes;    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -