示例#1
0
void run_teste_integral_2(){
    std::string crop_image = Config::PROJECT_PATH + "/dataset/24x24/Instancia_Sun_300_400/training_images/non_faces/group_0/crop/1403571922.05/crop_399.pgm";
    std::string full_image = Config::PROJECT_PATH + "/dataset/24x24/Instancia_Sun_nocrop/training_images/non_faces/SUN2012/16155.pgm";

    IntegralImage ii1(crop_image);
    teste_integral_2(ii1);

    ulong*** data;
    int crop_start_index = 10;
    int ncrops = 1;
    int maxCrops = 10;
    int crop_width = 24;
    int crop_height = 24;
    int shift_step = 24;

    Point img_size;
    int last_crop;
    int random_hop = 23;

    ulong** img_data;
    getImageCrops(&data,&img_data,&img_size,full_image.c_str(),&crop_start_index,ncrops,maxCrops,crop_width,crop_height,shift_step,random_hop,checkData,NULL);
    
    Point p;
    p.x = 24;
    p.y = 24;

    IntegralImage ii2(data[0],p,true);
    teste_integral_2(ii2);    
}
示例#2
0
// Calculates the array of values used as the integral image, lest values need calculation.
void JCHaarFinder::generateIIArray() {
    // if true, the gnerated II array will be printed to a file after calculation
    bool takeSnapshot = false;

    int width = curImage->getWidth(),
        height = curImage->getHeight();
    
    if (_iiArray == NULL) {
        free(_iiArray);
    }
    
    _iiArray = (int*) malloc(width * height * sizeof(int));
    _ii2Array = (int*) malloc(width * height * sizeof(int));

    for (int i = 0; i<width*height; i++) {
        _iiArray[i] = 0;
        _ii2Array[i] = 0;
    }

    for (int row=0; row < height; row++) {
        int rowsum = 0;
        int rowsum2 = 0;
        
        /* The strategy here is to keep a sum of the current row that is calculated.
         * The values of the fields in the rows are continuously added to the rowsum
         * variable, and the columns are taken care of by looking earlier in the array
         * as we're building it (we look in the previous row at the same column). This
         * eventually yields the integral image.
         * 
         * Also, we keep an integral image over all the squares of the pixel values. This
         * is used for the standard deviations in the normalization stage when the feature
         * sums are compared to their thresholds.
         */
        
        for(int col=0; col < width; col++) {
            rowsum += i(col, row);
            rowsum2 += i(col, row)*i(col, row);
            
            if (row > 0) {
                
                _iiArray[row*width + col] = rowsum + ii(col, row-1);
                _ii2Array[row*width + col] = rowsum2 + ii2(col, row-1);
            } else {
                _iiArray[row*width + col] = rowsum;
                _ii2Array[row*width + col] = rowsum2;
            }
        }
    }
    
    // Debug functionality that writes out the integral images in CSV structures.
    if (takeSnapshot) {
        ofFile iiFile;
        ofFile ii2File;
        iiFile.open(ofToDataPath("ii.csv"), ofFile::WriteOnly, false);
        ii2File.open(ofToDataPath("ii2.csv"), ofFile::WriteOnly, false);
        
        for (int row= 0; row<height; row++) {
            for (int col = 0; col<width; col++) {
                iiFile << ofToString(ii(col, row)) + ";";
                ii2File << ofToString(ii2(col, row)) + ";";
            }
            
            iiFile << endl;
            ii2File << endl;
        }
        
        iiFile.close();       
    }
}
示例#3
0
// Returns a vector of rectangles that pass the requirements for faces.
vector<ofxCvBlob> JCHaarFinder::getRectsFromImage(ofImage* inputImage) {
    curImage = inputImage;
    
    float scale = 1;
    float scaleMultiplier = 1.25;
    blobs.clear();
    
    generateIIArray();

    /*
     * Strategy: Loop through the image such that a window moves over the
     * picture, checking stages. Once the window has moved through the image
     * scale it a bit up, and re-run the algorithm. 
     *
     * The values to be for'ed over are nested as follows:
     *
     * the scale of the cascade window
     * window's position on y axis
     * window's position on x axis
     * stages of the cascade
     * features of the stage
     * rectangles of the feature
     * 
     * Since we don't support larger trees than the ones which only have a
     * root node, we can ignore traversing trees and just consider a list
     * of rectangles for any one feature.
     */
        
    // This implementation keeps enlarging the window until it is bigger than the picture.
    for (scale = 1; scale*casc.height <= curImage->getHeight() || scale*casc.width <= curImage->getWidth(); scale *= scaleMultiplier) {
        
        int window_area = scale*casc.height * scale*casc.width;
        
        // Keep moving the window down as long as its offset and its height are within the image. Likewise to the left
        // As an experiment, we're shifting the window in chunks equal to about a tenth of the current window height and width, respectively.
        for (int offsetY = 0; (offsetY+scale*casc.height) < curImage->getHeight(); offsetY += (int) ((scale*casc.height)/10)  ) {
            for (int offsetX = 0; (offsetX + scale*casc.width) < curImage->getWidth(); offsetX += (int) ((scale*casc.width)/10)) {
                bool passed = true;
                
                // *** LOOPING OVER STAGES
                for (int curStageIdx = 0; curStageIdx < casc.stages.size(); curStageIdx++) {
                    if (passed == false) break;
                    
                    stage* s = &casc.stages.at(curStageIdx);
                    float stage_sum = 0.0;
                    
                    // *** LOOPING OVER FEATURES
                    for (int featureIdx = 0; featureIdx < s->features.size(); featureIdx++) {
                        feature* f = & (s->features.at(featureIdx));
                        
                        float feature_sum = 0.0;
                        
                        // These coordinates are for the sliding window
                        int px1 = offsetX,
                            py1 = offsetY,
                            px2 = offsetX + scale*casc.width,
                            py2 = offsetY + scale*casc.height;
                        
                        float mean   = ((float) (ii(px2, py2)  + ii(px1, py1)  - ii(px1, py2)  - ii(px2, py1)))  / window_area;
                        float stddev = sqrt((ii2(px2, py2) + ii2(px1, py1) - ii2(px1, py2) - ii2(px2, py1)) / window_area - mean*mean);

                        // *** LOOPING OVER RECTANGLES
                        for (int rectangleIdx = 0; rectangleIdx < f->rectangles.size(); rectangleIdx++) {
                            featureRect* r = & ( f->rectangles.at(rectangleIdx));
                            
                            // These coordinates are for the rectangles inside the sliding window. The coordinates 
                            // are absolute; i.e. they share the same origin as the coordinates of the window.
                            int x1 = offsetX + (r->rectangle.x * scale),
                                y1 = offsetY + (r->rectangle.y * scale),
                                x2 = x1      +  r->rectangle.width * scale,
                                y2 = y1      +  r->rectangle.height * scale;
                            
                            int thisRect = (ii(x2, y2) + ii(x1, y1) - ii(x1, y2) - ii(x2, y1)) * r->weight;
                            
                            feature_sum += thisRect;
                        }
                        
                        // Determine in which direction the cascade should "fall". If the feature sum is less than
                        // its threshold, fall left, otherwise right.
                        // http://stackoverflow.com/questions/978742/what-do-the-left-and-right-values-mean-in-the-haar-cascade-xml-files
                        if (feature_sum/window_area < f->threshold*stddev) {
                            stage_sum += f->leftVal;
                        } else {
                            stage_sum += f->rightVal;
                        }                        
                    }
                    
                    // The stage is passed if its sum is above its threshold.
                    passed = (stage_sum > s->threshold);
                }
            
                // passed will be true iff all stages passed; if so, we detected a face.
                if (passed) {
                    ofLog(OF_LOG_NOTICE, "detected face (maybe)!");
                    blobs.push_back(makeBlob(offsetX, offsetY, scale*casc.width, scale*casc.height));
                }
            }
        }
    }
    
    return blobs;
}