MASH logo
Login | Register

cdubout/haar

User avatar

Core team

Author:
cdubout
Upload date:
April 20, 2010, 8:18 p.m.
Status:
Enabled
Summary:
Haar transform heuristic. Computes the 2D haar transform of the region of interest (all levels).
Description:

Pads the ROI with zeros so that the size is a power of two.

Evaluation:
Configuration Training error ( sd ) Test error ( sd )
adaboost-caltech 70.25% (2.0372) 75.35% (1.4975)
perceptron-mnist 8.44% (0.3484) 11.76% (0.1084)
/** Author: Charles Dubout (charles.dubout@idiap.ch)
 *
 *  Haar transform heuristic. Compute the 2D haar transform of the region of
 *  interest (all levels), padding the ROI with zeros so that the size is a
 *  power of two.
 */

#include <mash/heuristic.h>

#include <cmath>
#include <vector>

using namespace Mash;

//------------------------------------------------------------------------------
/// The 'Haar' heuristic class
//------------------------------------------------------------------------------
class HaarHeuristic: public Heuristic {
    //_____ Implementation of Heuristic __________
public:
    virtual unsigned int dim();
    virtual void prepareForCoordinates();
    virtual scalar_t computeFeature(unsigned int feature_index);

private:
    // Compute the 1D haar transform
    static void haar1(scalar_t* features, unsigned int w);

    // Compute the 2D haar transform
    static void haar2(scalar_t* features, unsigned int w);

    // Round up to the next highest power of 2
    static unsigned int roundUp(unsigned int x);

    // The transformed version of the region of interest
    std::vector<scalar_t> features_;
};

//------------------------------------------------------------------------------
/// Creation function of the heuristic
//------------------------------------------------------------------------------
extern "C" Heuristic* new_heuristic() {
    return new HaarHeuristic();
}

/************************* IMPLEMENTATION OF Heuristic ************************/

unsigned int HaarHeuristic::dim() {
    // We have has many features than pixels in the region of interest (rounded
    // to the next highest power of 2)
    unsigned int roi_size = roi_extent * 2 + 1;
    unsigned int extended_size = roundUp(roi_size);
    return extended_size * extended_size;
}

void HaarHeuristic::prepareForCoordinates() {
    // Compute the coordinates of the top-left pixel of the region of interest
    unsigned int x0 = coordinates.x - roi_extent;
    unsigned int y0 = coordinates.y - roi_extent;

    // Compute the size of the region of interest
    unsigned int roi_size = roi_extent * 2 + 1;
    unsigned int extended_size = roundUp(roi_size);

    // Get the pixels values of the region of interest
    byte_t** pLines = image->grayLines();

    // Resize the features to the correct dimension
    features_.clear();
    features_.resize(dim());

    // Fill the feature image
    for(unsigned int y = 0; y < roi_size; ++y) {
        for(unsigned int x = 0; x < roi_size; ++x) {
            features_[y * extended_size + x] = pLines[y][x];
        }
    }

    haar2(&features_[0], extended_size);
}

scalar_t HaarHeuristic::computeFeature(unsigned int feature_index) {
    return features_[feature_index];
}

// Compute the 1D haar transform
void HaarHeuristic::haar1(scalar_t* features, unsigned int w) {
    const scalar_t invSqrt2 = 0.707106781187;

    std::vector<scalar_t> temp(w);

    for(unsigned int i = 0; i < (w / 2); ++i) {
        temp[i] = (features[2 * i] + features[2 * i + 1]) * invSqrt2;
        temp[i + (w / 2)] = (features[2 * i] - features[2 * i + 1]) * invSqrt2;
    }

    for(unsigned int i = 0; i < w; ++i) {
        features[i] = temp[i];
    }
}

// Compute the 2D haar transform
void HaarHeuristic::haar2(scalar_t* features, unsigned int w) {
    std::vector<scalar_t> temp(w);

    unsigned int z = w;

    while(z > 1) {
        // Do 1D haar transforms along the rows
        for(unsigned int i = 0; i < z; ++i) {
            haar1(features + i * w, z);
        }

        // Do 1D haar transforms along the columns
        for(unsigned int i = 0; i < z; ++i) {
            for(unsigned int j = 0; j < w; ++j) {
                temp[j] = features[i + j * w];
            }

            haar1(&temp[0], z);

            for(unsigned int j = 0; j < w; ++j) {
                features[i + j * w] = temp[j];
            }
        }

        z >>= 1;
    }
}

// Round up to the next highest power of 2
unsigned int HaarHeuristic::roundUp(unsigned int x) {
    // Assume x is 32-bits
    --x;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    return ++x;
}