// compact image comparison vactor generator
// mainly to be used via IPC in read-from-stdin mode
// requires CImg.h, adjust the include as needed
// cvs -d:pserver:anonymous@cimg.cvs.sourceforge.net:/cvsroot/cimg co CImg
// compile: g++ -o hashimg hashimg.cpp
// function ph_dct_matrix and the PHASH section of do_hash (ph_dct_imagehash)
// liberated from pHash.ccp which had the following blurb:
/*
pHash, the open source perceptual hash library
Copyright (C) 2009 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 .
Evan Klinger - eklinger@phash.org
D Grant Starkweather - dstarkweather@phash.org
*/
// based on ph_dct_imagehash from http://www.phash.org/
#define PHASH 1
// based on average hash from http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html
#define AHASH 1
// based on rgb4x4 from http://www.stonehenge.com/merlyn/LinuxMag/col50.html
#define RHASH 1
// enables for various debugprints all over the place. noisy.
#define DEBUG_PHASH 0
#define DEBUG_AHASH 0
#define DEBUG 0
#define cimg_debug 0
#define cimg_display 0
#include "CImg/CImg.h"
using namespace cimg_library;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define __STDC_CONSTANT_MACROS
#include
CImg* ph_dct_matrix(const int N){
CImg *ptr_matrix = new CImg(N,N,1,1,1/sqrt((float)N));
const float c1 = sqrt(2.0/N);
for (int x=0;xdata(x,y) = c1*cos((cimg::PI/2/N)*y*(2*x+1));
}
}
return ptr_matrix;
}
void hexprint(char *a, int count, int spacer){
int i;
char h[] = "0123456789abcdef";
for (i=0;i>4)&0x0f],h[a[i]&0x0f]);
}
}
int hashgen(CImg *data, char *hash, int bitcount, float limit, int doprint=0) {
int bc = 0;
for (int i=0;i< bitcount;i++){
float current = (*data)(i);
if (current >= limit) {
hash[int(i/8)] |= (0x80 >> (i%8));
bc++;
if (doprint) {
printf("1");
}
} else {
if (doprint) {
printf("0");
}
}
}
return bc;
}
int do_hash(char *file) {
if (!file){
return -1;
}
printf("FILE: %s", file);
CImg osrc;
try {
osrc.load(file);
} catch (CImgIOException ex){
return -1;
}
// working copy
CImg src = osrc;
float median, mean;
unsigned long long hash;
int bc;
CImg img;
CImg subsec;
#if PHASH
//
// PHASH SECTION
//
//int ph_dct_imagehash(const char* file,ulong64 &hash){
// img = src.get_convolve(meanfilter);
// img.save("test2.png");
CImg meanfilter(7,7,1,1,1);
CImg *C = ph_dct_matrix(32);
CImg Ctransp = C->get_transpose();
if (src.spectrum() == 3){
#if DEBUG_PHASH
printf(" b1");
#endif
img = src.RGBtoYCbCr().channel(0).get_convolve(meanfilter);
} else if (src.spectrum() == 4){
#if DEBUG_PHASH
printf(" b2");
#endif
int width = src.width();
int height = src.height();
int depth = src.depth();
img = src.crop(0,0,0,0,width-1,height-1,depth-1,2).RGBtoYCbCr().channel(0).get_convolve(meanfilter);
} else {
#if DEBUG_PHASH
printf(" b3");
#endif
img = src.channel(0).get_convolve(meanfilter);
}
// img.save("step3a.png");
img.resize(32,32);
#if DEBUG_PHASH
printf("\nimg:\n");
for (int i=0;i< 3;i++){
for (int j=0;j< 10;j++){
float v = img(j,i);
printf(" %f", v);
}
printf("\n");
}
// img.save("step3b.png");
printf("\nC:\n");
for (int i=0;i< 3;i++){
for (int j=0;j< 10;j++){
float v = (*C)(j,i);
printf(" %f", v);
}
printf("\n");
}
printf("\nCtransp:\n");
for (int i=0;i< 3;i++){
for (int j=0;j< 10;j++){
float v = Ctransp(j,i);
printf(" %f", v);
}
printf("\n");
}
#endif
CImg dctImage = (*C)*img*Ctransp;
// dctImage.save("step4b.png");
#if DEBUG_PHASH
printf("\ndctImage:\n");
for (int i=0;i< 3;i++){
for (int j=0;j< 10;j++){
float v = dctImage(j,i);
printf(" %f", v);
}
printf("\n");
}
#endif
dctImage.crop(1,1,8,8);
#if DEBUG_PHASH
printf("\nsec:\n");
for (int i=0;i< 8;i++){
for (int j=0;j< 8;j++){
float v = dctImage(j,i);
printf(" %15f", v);
}
printf("\n");
}
#endif
subsec = dctImage.unroll('x');;
median = subsec.median();
mean = subsec.mean();
#if DEBUG_PHASH
printf("median: %.10f\n", median);
printf("mean: %.10f\n", mean);
#endif
hash = 0;
printf("\nPHASH(median,%s): ", file);
bc = hashgen(&subsec, (char*)&hash, 64, median, 1);
printf(" %i %llu ", bc, hash);
hexprint((char*)&hash, 8, 8);
printf("\n");
hash = 0;
printf("\nPHASH(mean,%s): ", file);
bc = hashgen(&subsec, (char*)&hash, 64, mean, 1);
printf(" %i %llu ", bc, hash);
hexprint((char*)&hash, 8, 8);
printf("\n");
delete C;
#endif // PHASH
#if AHASH
//
// AHASH SECTION
//
src = osrc;
src.resize(8,8,-100,-100,2);
// src.save("test3ff.png");
// this seems to be an attempt to get rid of alpha channel by applying it
if (src.spectrum() == 4){
#if DEBUG_AHASH
printf(" c2");
#endif
int width = src.width();
int height = src.height();
int depth = src.depth();
src = src.crop(0,0,0,0,width-1,height-1,depth-1,2);
}
if (src.spectrum() == 3){
#if DEBUG_AHASH
printf(" c1");
#endif
#if MANUAL_GRAYSCALE
C = new CImg(8,8,1,1,0);
for (int i=0;i<8;i++){
for (int j=0;j<8;j++){
//(*C)(i,j) = 0.2989*src(i,j,0) + 0.5870*src(i,j,1) + 0.1140*src(i,j,2);
(*C)(i,j) = (src(i,j,0)*src(i,j,0)) + (src(i,j,1)*src(i,j,1)) + (src(i,j,2)*src(i,j,2));
//(*C)(i,j) = src(i,j,0) + src(i,j,1) + src(i,j,2);
//(*C)(i,j) = (src(i,j,0) + src(i,j,1) + src(i,j,2))/3;
}
}
img = (*C);
delete C;
#else
img = src.RGBtoYCbCr().channel(0); //.get_convolve(meanfilter);
#endif
} else {
#if DEBUG_AHASH
printf(" c3");
#endif
img = src.channel(0);
}
#if DEBUG_AHASH
printf("\nimg:\n");
for (int i=0;i< 8;i++){
for (int j=0;j< 8;j++){
float v = img(j,i);
printf(" %f", v);
}
printf("\n");
}
#endif
subsec = img.unroll('x');
median = subsec.median();
mean = subsec.mean();
#if DEBUG_AHASH
printf("median: %.10f\n", median);
printf("mean: %.10f\n", mean);
#endif
hash = 0;
printf("\nAHASH(median,%s): ", file);
bc = hashgen(&subsec, (char*)&hash, 64, median, 1);
printf(" %i %llu ", bc, hash);
hexprint((char *)&hash, 8, 8);
printf("\n");
hash = 0;
printf("\nAHASH(mean,%s): ", file);
bc = hashgen(&subsec, (char*)&hash, 64, mean, 1);
printf(" %i %llu ", bc, hash);
hexprint((char *)&hash, 8, 8);
printf("\n");
#endif // AHASH
#if RHASH
src = osrc;
src.resize(4,4,-100,-100,2);
//src.save("testnbid.png");
char buf[48];
for (int i=0;i<48;i++){
buf[i] = src(int(i/3)%4,int(i/12),i%3);
}
printf("\nRHASH(%s): urn:rgb4x4:", file);
hexprint(&buf[0], 48, 48);
printf("\n");
# endif // RHASH
return 0;
}
int main(int argc,char*argv[]){
// process files from commandline
if (argc > 1) {
for (int i=1;i