int ph_dct_imagehash(const char* file,ulong64 &hash){ if (!file){ return -1; } CImg<uint8_t> src; try { src.load(file); } catch (CImgIOException ex){ return -1; } CImg<float> meanfilter(7,7,1,1,1); CImg<float> img; if (src.spectrum() == 3){ img = src.RGBtoYCbCr().channel(0).get_convolve(meanfilter); } else if (src.spectrum() == 4){ int width = img.width(); int height = img.height(); int depth = img.depth(); img = src.crop(0,0,0,0,width-1,height-1,depth-1,2).RGBtoYCbCr().channel(0).get_convolve(meanfilter); } else { img = src.channel(0).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_bmb_imagehash(const char *file, uint8_t method, BinHash **ret_hash) { CImg<uint8_t> img; const uint8_t *ptrsrc; // source pointer (img) uint8_t *block; int pcol; // "pointer" to pixel col (x) int prow; // "pointer" to pixel row (y) int blockidx = 0; //current idx of block begin processed. double median; // median value of mean_vals const int preset_size_x=256; const int preset_size_y=256; const int blk_size_x=16; const int blk_size_y=16; int pixcolstep = blk_size_x; int pixrowstep = blk_size_y; int number_of_blocks; uint32_t bitsize; // number of bytes needed to store bitsize bits. uint32_t bytesize; if (!file || !ret_hash){ return -1; } try { img.load(file); } catch (CImgIOException ex){ return -1; } const int blk_size = blk_size_x * blk_size_y; block = (uint8_t*)malloc(sizeof(uint8_t) * blk_size); if(!block) return -1; switch (img.spectrum()) { case 3: // from RGB img.RGBtoYCbCr().channel(0); break; default: *ret_hash = NULL; free(block); return -1; } img.resize(preset_size_x, preset_size_y); // ~step b ptrsrc = img.data(); // set pointer to beginning of pixel buffer if(method == 2) { pixcolstep /= 2; pixrowstep /= 2; number_of_blocks = ((preset_size_x / blk_size_x) * 2 - 1) * ((preset_size_y / blk_size_y) * 2 - 1); } else { number_of_blocks = preset_size_x / blk_size_x * preset_size_y / blk_size_y; } bitsize= number_of_blocks; bytesize = bitsize / 8; double *mean_vals = new double[number_of_blocks]; /* * pixel row < block < block row < image * * The pixel rows of a block are copied consecutively * into the block buffer (using memcpy). When a block is * finished, the next block in the block row is processed. * After finishing a block row, the processing of the next * block row is started. An image consists of an arbitrary * number of block rows. */ /* image (multiple rows of blocks) */ for(prow = 0;prow<=preset_size_y-blk_size_y;prow += pixrowstep) { /* block row */ for(pcol = 0;pcol<=preset_size_x-blk_size_x;pcol += pixcolstep) { // idx for array holding one block. int blockpos = 0; /* block */ // i is used to address the different // pixel rows of a block for(int i=0 ; i < blk_size_y; i++) { ptrsrc = img.data(pcol, prow + i); memcpy(block + blockpos, ptrsrc, blk_size_x); blockpos += blk_size_x; } mean_vals[blockidx] = CImg<uint8_t>(block,blk_size).mean(); blockidx++; } } /* calculate the median */ median = CImg<double>(mean_vals, number_of_blocks).median(); /* step e */ BinHash *hash = _ph_bmb_new(bytesize); if(!hash) { *ret_hash = NULL; return -1; } *ret_hash = hash; for(uint32_t i = 0; i < bitsize; i++) { if(mean_vals[i] < median) { hash->addbit(0); } else { hash->addbit(1); } } delete[] mean_vals; free(block); return 0; }
//' @export // [[Rcpp::export]] NumericVector RGBtoYCbCr(NumericVector im) { CImg<double> img = as<CImg<double> >(im); img.RGBtoYCbCr(); return wrap(img); }