/****************************************************************************** imgSeek :: C++ database implementation --------------------------------------- begin : Fri Jan 17 2003 email : nieder|at|mail.ru Copyright (C) 2003 Ricardo Niederberger Cabral 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ******************************************************************************/ /* STL Includes */ #include #include #include #include #include // NOTE: when running build-ext.sh (auto swig wrappers) this namespace line has to be commented using namespace std; /* imgSeek includes */ #include "haar.h" /* Database */ #include "imgdb.h" /* C Includes */ #include #include #include "EXTERN.h" #include "perl.h" void cleardb() { for (sigIterator it = sigs.begin(); it != sigs.end(); it++) { free((*it).second->sig1); free((*it).second->sig2); free((*it).second->sig3); free((*it).second->avgl); delete (*it).second; } for (int c = 0;c<3;c++) for (int pn=0;pn<2;pn++) for (int i = 0;i<16384;i++) { imgbuckets[c][pn][i].clear(); } } int addImage(const long int id, unsigned char* red, unsigned char* green, unsigned char* blue) { /* id is a unique image identifier filename is the image location thname is the thumbnail location for this image doThumb should be set to 1 if you want to save the thumbnail on thname Images with a dimension smaller than ignDim are ignored */ double* avgl = (double*)Perl_safesysmalloc(3*sizeof(double)); int* sig1; int* sig2; int* sig3; double* cdata1, * cdata2, * cdata3; int i; New(200, cdata1, 16384, double); New(200, cdata2, 16384, double); New(200, cdata3, 16384, double); New(200, sig1, 40, int); New(200, sig2, 40, int); New(200, sig3, 40, int); sigStruct* nsig = new sigStruct(); nsig->sig1 = sig1; nsig->sig2 = sig2; nsig->sig3 = sig3; nsig->avgl = avgl; nsig->id = id; transformChar(red, green, blue, cdata1,cdata2,cdata3); sigs[id] = nsig; calcHaar(cdata1,cdata2,cdata3,sig1,sig2,sig3,avgl); for (i = 0;i<40;i++) { // populate buckets if (sig1[i]>0) imgbuckets[0][0][sig1[i]].push_back(id); if (sig1[i]<0) imgbuckets[0][1][-sig1[i]].push_back(id); if (sig2[i]>0) imgbuckets[1][0][sig2[i]].push_back(id); if (sig2[i]<0) imgbuckets[1][1][-sig2[i]].push_back(id); if (sig3[i]>0) imgbuckets[2][0][sig3[i]].push_back(id); if (sig3[i]<0) imgbuckets[2][1][-sig3[i]].push_back(id); } free(cdata1); free(cdata2); free(cdata3); return 1; } /* Data: buckets[3][2][16835] sigs (hash) */ int loaddb(char* filename) { std::ifstream f(filename, ios::binary); if (!f.is_open()) return 0; int sz,coef,c,k; long int id; // read buckets for ( c = 0;c<3;c++) for (int pn=0;pn<2;pn++) for (int i = 0;i<16384;i++) { f.read ((char*)&(sz), sizeof(int) ); for ( k = 0;kid = id; sigs[id]->sig1 = (int*)(Perl_safesysmalloc(40*sizeof(int))); sigs[id]->sig2 = (int*)(Perl_safesysmalloc(40*sizeof(int))); sigs[id]->sig3 = (int*)(Perl_safesysmalloc(40*sizeof(int))); sigs[id]->avgl = (double*)Perl_safesysmalloc(3*sizeof(double)); // sig for ( c = 0;c<40;c++) { f.read ((char*)&(coef), sizeof( int) ); sigs[id]->sig1[c] = coef; f.read ((char*)&(coef), sizeof( int) ); sigs[id]->sig2[c] = coef; f.read ((char*)&(coef), sizeof( int) ); sigs[id]->sig3[c] = coef; } // avgl for ( c = 0;c<3;c++) { f.read ((char*)&(sigs[id]->avgl[c]), sizeof( double) ); } } f.close(); return 1; } int savedb(char* filename) { /* Serialization order: for each color {0,1,2}: for {positive,negative}: for each 128x128 coefficient {0-16384}: [int] bucket size (size of list of ids) for each id: [long int] image id [int] number of images (signatures) for each image: [long id] image id for each sig coef {0-39}: (the 40 greatest coefs) for each color {0,1,2}: [int] coef index (signed) for each color {0,1,2}: [double] average luminance [int] image height */ std::ofstream f(filename, ios::binary); if (!f.is_open()) return 0; int sz,c; long int id; // save buckets for ( c = 0;c<3;c++) for (int pn=0;pn<2;pn++) for (int i = 0;i<16384;i++) { sz = imgbuckets[c][pn][i].size(); f.write((char*)&(sz), sizeof(int) ); for (long_listIterator it = imgbuckets[c][pn][i].begin(); it != imgbuckets[c][pn][i].end(); it++) { f.write ((char*)&((*it)), sizeof(long int) ); } } // save sigs sz = sigs.size(); f.write ((char*)&(sz), sizeof(int) ); for (sigIterator it = sigs.begin(); it != sigs.end(); it++) { id = (*it).first; f.write ((char*)&(id), sizeof(long int)); // sigs for ( c = 0;c<40;c++) { f.write ((char*)&((*it).second->sig1[c]), sizeof( int)); f.write ((char*)&((*it).second->sig2[c]), sizeof( int)); f.write ((char*)&((*it).second->sig3[c]), sizeof( int)); } // avgl for ( c = 0;c<3;c++) f.write ((char*)&((*it).second->avgl[c]), sizeof(double)); } f.close(); return 1; } /* sig1,2,3 are int arrays of lenght 40 avgl is the average luminance numres is the max number of results scanned tells which set of weights to use */ void queryImgData(int* sig1,int* sig2,int* sig3,double * avgl,int numres,int scanned) { int idx,c; bool pn; int * sig[3] = {sig1,sig2,sig3}; int nres = numres+1; int i,j; if (!imgBin[0]) { for (i = 0;i<128;i++) for (j=0;j<128;j++) imgBin[i*128+j] = min(max(i,j),5); } for (sigIterator sit = sigs.begin(); sit!=sigs.end(); sit++) { //#TODO3: do I really need to score every single sig on db? (*sit).second->score = 0; for (c = 0; c<3; c++) { (*sit).second->score += weights[scanned][0][c]*fabs((*sit).second->avgl[c]-avgl[c]); } } for (int b = 0;b<40;b++) { // for every coef on a sig for ( c = 0;c<3;c++) { pn = 0; if (sig[c][b]>0) { pn = 0; idx = sig[c][b]; } else { pn = 1; idx = -sig[c][b]; } // update the score of every image which has this coef for (long_listIterator uit = imgbuckets[c][pn][idx].begin(); uit != imgbuckets[c][pn][idx].end(); uit++) { sigs[(*uit)]->score -= weights[scanned][imgBin[idx]][c]; } } } while(!pqResults.empty()) pqResults.pop(); // make sure pqResults is empty. TODO: any faster way to empty it ? didn't find any on STL refs. int cnt = 0; for (sigIterator it = sigs.begin(); it != sigs.end(); it++) { cnt++; pqResults.push(*(*it).second); if (cnt>nres) { pqResults.pop(); } } } void queryImgID(long int id,int numres) { if (!sigs.count(id)) { return; } queryImgData(sigs[id]->sig1,sigs[id]->sig2,sigs[id]->sig3,sigs[id]->avgl, numres, 0); }