/** * @file LFPatches.cpp * @brief simple patch based approach * @author Erik Rodner * @date 02/06/2008 */ #include #include #include #include #include "vislearning/features/localfeatures/LFPatches.h" #include "vislearning/features/localfeatures/IDRandomSampling.h" #include "vislearning/features/localfeatures/IDKLTSampling.h" #include "vislearning/features/localfeatures/IDSIFTSampling.h" #include "vislearning/image/ImagePyramid.h" using namespace OBJREC; using namespace std; using namespace NICE; void LFPatches::setDetector ( const int & _detectormode, const NICE::Config * conf) { if ( this->id != NULL ) { delete this->id; this->id = NULL; } if (_detectormode == 0) { this->id = new IDRandomSampling(conf, this->numPatches); } else if (_detectormode == 1) { this->id = new IDKLTSampling(conf, this->numPatches); } else if (_detectormode == 2) { this->id = new IDSIFTSampling(conf); } else { this->id = new IDRandomSampling(conf, this->numPatches); } } void LFPatches::setNormalization( const std::string & _normalization_s) { if (_normalization_s == "n01") normalization = NORMALIZE_N01; else if (_normalization_s == "stddev") normalization = NORMALIZE_STDDEV; else if (_normalization_s == "mean") normalization = NORMALIZE_MEAN; else if (_normalization_s == "none") normalization = NORMALIZE_NONE; else { fprintf(stderr, "LFPatches::LFPatches: unknown normalization method\n"); exit(-1); } } ///////////////////// ///////////////////// ///////////////////// // CONSTRUCTORS / DESTRUCTORS ///////////////////// ///////////////////// ///////////////// LFPatches::LFPatches() { this->numPatches = -1; this->xsize = 11; this->ysize = 11; this->maxLevels = 10; this->scaleSpacing = sqrt(sqrt(2)); this->detectormode = 0; this->id = NULL; std::string normalization_s = "n01"; this->setNormalization ( normalization_s ); //TODO initialization useful here? srand(time(NULL)); } LFPatches::LFPatches(const Config *conf, int _numPatches) : numPatches(_numPatches) { this->xsize = conf->gI("Patches", "xsize", 11); this->ysize = conf->gI("Patches", "ysize", 11); this->maxLevels = conf->gI("Patches", "levels", 10); this->scaleSpacing = conf->gD("Patches", "scale_spacing", sqrt(sqrt(2))); this->detectormode = conf->gI("Patches", "detector", 0); this->setDetector ( this->detectormode, conf ); std::string normalization_s = conf->gS("Patches", "normalization", "n01"); this->setNormalization ( normalization_s ); srand(time(NULL)); } LFPatches::~LFPatches() { if ( this->id != NULL ) { delete this->id; this->id = NULL; } } ///////////////////// ///////////////////// ///////////////////// // FEATURE STUFF ///////////////////// ///////////////////// ////////////////// int LFPatches::getDescSize() const { return xsize * ysize; } int LFPatches::extractFeatures(const NICE::Image & img, VVector & features, VVector & positions) const { ImagePyramid imp(img, maxLevels, scaleSpacing, xsize, ysize); //imp.show(); VVector positions_tmp; if(positions.size()<=0) { id->getRandomInterests(imp, positions_tmp,numPatches); } else { positions_tmp=positions; } correctPositions(imp, positions_tmp, positions); calcDescriptors(imp, positions, features); return features.size(); } void LFPatches::correctPositions(const ImagePyramid & imp, VVector & positions, VVector & positions_corrected) const { positions_corrected.clear(); int numlevels = imp.getNumLevels(); for (size_t i = 0; i < positions.size(); i++) { const NICE::Vector & position = positions[i]; if ((size_t) position[2] < numlevels) { const NICE::Image & img = imp.getLevel((size_t) position[2]); double xl, yl; imp.getLevelCoordinates(position[0], position[1], (size_t) position[2], xl, yl); int x = (int) xl; int y = (int) yl; x -= xsize / 2; y -= ysize / 2; if ((x >= 0) && (y >= 0) && (x <= img.width() - xsize) && (y <= img.height() - ysize)) { NICE::Vector position_new(3); imp.getOriginalCoordinates(x, y, (size_t) position[2], position_new[0], position_new[1]); position_new[2] = position[2]; positions_corrected.push_back(position_new); } } } } void LFPatches::calcDescriptors(const ImagePyramid & imp, VVector & positions, VVector & features) const { NICE::Vector desc(getDescSize()); for (VVector::iterator i = positions.begin(); i != positions.end();) { bool deletePosition = false; if (calcDescriptor(imp, *i, desc) < 0) { deletePosition = true; } else { features.push_back(desc); } if (deletePosition) { i = positions.erase(i); } else { i++; } } } int LFPatches::calcDescriptor(const ImagePyramid & imp, const NICE::Vector & position, NICE::Vector & desc) const { const NICE::Image & img = imp.getLevel((size_t) position[2]); double xl, yl; imp.getLevelCoordinates(position[0], position[1], (uint) position[2], xl, yl); int x = (int) xl; int y = (int) yl; if ((x < 0) || (y < 0) || (x > img.width() - xsize) || (y > img.height() - ysize)) { return -1; } double mean = 0.0; double stddev = 0.0; if (normalization != NORMALIZE_NONE) { // compute mean for (int yi = y; yi < y + ysize; yi++) for (int xi = x; xi < x + xsize; xi++) mean += img.getPixel(xi, yi); mean /= (xsize * ysize); if (normalization != NORMALIZE_MEAN) { // compute stddev stddev = 0.0; for (int yi = y; yi < y + ysize; yi++) for (int xi = x; xi < x + xsize; xi++) { double d = img.getPixel(xi, yi) - mean; stddev += d * d; } if (stddev < 10e-5) return -1; stddev /= xsize * ysize; stddev = sqrt(stddev); } } if (normalization == NORMALIZE_STDDEV) { // normalize pixel values int k = 0; for (int yi = y; yi < y + ysize; yi++) for (int xi = x; xi < x + xsize; xi++, k++) desc[k] = (img.getPixel(xi, yi) - mean) / stddev + mean; } else if (normalization == NORMALIZE_N01) { // normalize pixel values int k = 0; for (int yi = y; yi < y + ysize; yi++) for (int xi = x; xi < x + xsize; xi++, k++) desc[k] = (img.getPixel(xi, yi) - mean) / stddev; } else if (normalization == NORMALIZE_MEAN) { // normalize pixel values int k = 0; for (int yi = y; yi < y + ysize; yi++) for (int xi = x; xi < x + xsize; xi++, k++) desc[k] = (img.getPixel(xi, yi) - mean); } else { int k = 0; for (int yi = y; yi < y + ysize; yi++) for (int xi = x; xi < x + xsize; xi++, k++) desc[k] = img.getPixel(xi, yi); } return 0; } void LFPatches::visualizeFeatures(NICE::Image & mark, const VVector & positions, size_t color) const { for (size_t i = 0; i < positions.size(); i++) { const NICE::Vector & pos = positions[i]; double s = pow(scaleSpacing, pos[2]); int x = (int) (pos[0]); int y = (int) (pos[1]); int w = (int) (s * xsize); int h = (int) (s * ysize); RectangleT rect(Coord(x, y), Coord(x + w, y + w)); mark.draw(rect, (unsigned char) color); } } void LFPatches::visualize(NICE::Image & img, const NICE::Vector & feature) const { if (feature.size() != (size_t) xsize * ysize) { fprintf(stderr, "LFPatches::visualize implementation failure\n"); exit(-1); } img.resize(xsize, ysize); double max = -numeric_limits::max(); double min = numeric_limits::max(); int k = 0; for (k = 0; k < xsize * ysize; k++) { if (feature[k] > max) max = feature[k]; if (feature[k] < min) min = feature[k]; } k = 0; for (int y = 0; y < ysize; y++) for (int x = 0; x < xsize; x++, k++) { double val = ((feature[k] - min) * 255 / (max - min)); img.setPixel(x, y, (int) val); } } ///////////////////// INTERFACE PERSISTENT ///////////////////// // interface specific methods for store and restore ///////////////////// INTERFACE PERSISTENT ///////////////////// void LFPatches::restore ( std::istream & is, int format ) { fthrow ( Exception, "LFPatches::restore not implemented yet." ); //TODO } void LFPatches::store ( std::ostream & os, int format ) const { fthrow ( Exception, "LFPatches::store not implemented yet." ); //TODO } void LFPatches::clear () { if ( this->id != NULL ) { delete this->id; this->id = NULL; } }