void
PeriodicPredictor::calculate_autocorrelation(std::vector<double> *container) {
  std::vector<double> samples_copy;
  std::deque<double>::iterator it;

  for (it = this->samples.begin(); it != this->samples.end(); it++) {
    samples_copy.push_back(*it);
  }

  for (int32_t offset = 0; offset <= this->sample_size/2; offset++) {
    std::vector<double> container1(samples_copy.begin(),
                                   samples_copy.end() - offset);
    std::vector<double> container2(samples_copy.begin() + offset,
                                   samples_copy.end());

    double variance1 = calculate_variance(container1);
    double variance2 = calculate_variance(container2);
    double covariance = calculate_covariance(container1, container2);
    double correlation = (variance1 == 0 || variance2 == 0) ?
                         1.0 : covariance/(variance1*variance2);
    container->push_back(correlation);
  }
}
vector<Mat_<double> > FernCascade::Train(const vector<Mat_<uchar> >& images,
                                    const vector<Mat_<double> >& current_shapes,
                                    const vector<Mat_<double> >& ground_truth_shapes,
                                    const vector<BoundingBox> & bounding_box,
                                    const Mat_<double>& mean_shape,
                                    int second_level_num,
                                    int candidate_pixel_num,
                                    int fern_pixel_num){
    Mat_<double> candidate_pixel_locations(candidate_pixel_num,2);
    Mat_<int> nearest_landmark_index(candidate_pixel_num,1);
    vector<Mat_<double> > regression_targets;
    RNG random_generator(getTickCount());
    second_level_num_ = second_level_num;
    
    // calculate regression targets: the difference between ground truth shapes and current shapes
    // candidate_pixel_locations: the locations of candidate pixels, indexed relative to its nearest landmark on mean shape 
    regression_targets.resize(current_shapes.size()); 
    for(int i = 0;i < current_shapes.size();i++){
        regression_targets[i] = ProjectShape(ground_truth_shapes[i],bounding_box[i]) 
                                - ProjectShape(current_shapes[i],bounding_box[i]);
        Mat_<double> rotation;
        double scale;
        SimilarityTransform(mean_shape,ProjectShape(current_shapes[i],bounding_box[i]),rotation,scale);
        transpose(rotation,rotation);

        regression_targets[i] = scale * regression_targets[i] * rotation;
    }

    
    // get candidate pixel locations, please refer to 'shape-indexed features'
    for(int i = 0;i < candidate_pixel_num;i++){
        double x = random_generator.uniform(-1.0,1.0);
        double y = random_generator.uniform(-1.0,1.0);
        if(x*x + y*y > 1.0){
            i--;
            continue;
        }
        // find nearest landmark index
        double min_dist = 1e10;
        int min_index = 0;
        for(int j = 0;j < mean_shape.rows;j++){
            double temp = pow(mean_shape(j,0)-x,2.0) + pow(mean_shape(j,1)-y,2.0);
            if(temp < min_dist){
                min_dist = temp;
                min_index = j;
            }
        }
        candidate_pixel_locations(i,0) = x - mean_shape(min_index,0);
        candidate_pixel_locations(i,1) = y - mean_shape(min_index,1);
        nearest_landmark_index(i) = min_index;   
    }

    // get densities of candidate pixels for each image
    // for densities: each row is the pixel densities at each candidate pixels for an image 
    // Mat_<double> densities(images.size(), candidate_pixel_num);
    vector<vector<double> > densities;
    densities.resize(candidate_pixel_num);
    for(int i = 0;i < images.size();i++){
        Mat_<double> rotation;
        double scale;
        Mat_<double> temp = ProjectShape(current_shapes[i],bounding_box[i]);
        SimilarityTransform(temp,mean_shape,rotation,scale);
        for(int j = 0;j < candidate_pixel_num;j++){
            double project_x = rotation(0,0) * candidate_pixel_locations(j,0) + rotation(0,1) * candidate_pixel_locations(j,1);
            double project_y = rotation(1,0) * candidate_pixel_locations(j,0) + rotation(1,1) * candidate_pixel_locations(j,1);
            project_x = scale * project_x * bounding_box[i].width / 2.0;
            project_y = scale * project_y * bounding_box[i].height / 2.0;
            int index = nearest_landmark_index(j);
            int real_x = project_x + current_shapes[i](index,0);
            int real_y = project_y + current_shapes[i](index,1); 
            real_x = std::max(0.0,std::min((double)real_x,images[i].cols-1.0));
            real_y = std::max(0.0,std::min((double)real_y,images[i].rows-1.0));
            densities[j].push_back((int)images[i](real_y,real_x));
        }
    }
        
    // calculate the covariance between densities at each candidate pixels 
    Mat_<double> covariance(candidate_pixel_num,candidate_pixel_num);
    Mat_<double> mean;
    for(int i = 0;i < candidate_pixel_num;i++){
        for(int j = i;j< candidate_pixel_num;j++){
            double correlation_result = calculate_covariance(densities[i],densities[j]);
            covariance(i,j) = correlation_result;
            covariance(j,i) = correlation_result;
        }
    } 


    // train ferns
    vector<Mat_<double> > prediction;
    prediction.resize(regression_targets.size());
    for(int i = 0;i < regression_targets.size();i++){
        prediction[i] = Mat::zeros(mean_shape.rows,2,CV_64FC1); 
    } 
    ferns_.resize(second_level_num);
    for(int i = 0;i < second_level_num;i++){
        cout<<"Training ferns: "<<i+1<<" out of "<<second_level_num<<endl;
        vector<Mat_<double> > temp = ferns_[i].Train(densities,covariance,candidate_pixel_locations,nearest_landmark_index,regression_targets,fern_pixel_num);     
        // update regression targets
        for(int j = 0;j < temp.size();j++){
            prediction[j] = prediction[j] + temp[j];
            regression_targets[j] = regression_targets[j] - temp[j];
        }  
    }
    
    for(int i = 0;i < prediction.size();i++){
        Mat_<double> rotation;
        double scale;
        SimilarityTransform(ProjectShape(current_shapes[i],bounding_box[i]),mean_shape,rotation,scale);
        transpose(rotation,rotation);
        prediction[i] = scale * prediction[i] * rotation; 
    } 
    return prediction;    
}
Beispiel #3
0
/**
 * Train a fern cascade.
 * @param images training images in gray scale
 * @param normalize_matrix similarity matrix
 * @param target_shapes target shapes of each face image
 * @param mean_shape mean shape
 * @param second_level_num level number for second level regression 
 * @param current_shapes current shapes of training images
 * @param pixel_pair_num number of pair of pixels to be selected
 * @param normalized_targets (target - current) * normalize_matrix
 */
void FernCascade::train(const vector<Mat_<uchar> >& images,
        const vector<Mat_<double> >& target_shapes,
        int second_level_num,
        vector<Mat_<double> >& current_shapes,
        int pixel_pair_num,
        vector<Mat_<double> >& normalized_targets,
        int pixel_pair_in_fern,
        const Mat_<double>& mean_shape,
        const vector<Bbox>& target_bounding_box){

    second_level_num_ = second_level_num;
	// coordinates of selected pixels
    Mat_<double> pixel_coordinates(pixel_pair_num,2);
	Mat_<int> nearest_keypoint_index(pixel_pair_num,1);
    RNG random_generator(getTickCount());
    int landmark_num = current_shapes[0].rows;
    int training_num = images.size();
    int image_width = images[0].cols;
    int image_height = images[0].rows;

    /* vector<Mat_<double> > normalized_curr_shape;  */
    // get bounding box of target shapes
   
    vector<Mat_<double> > normalized_shapes;
    /* vector<Mat_<double> > normalized_ground_truth; */


    normalized_shapes = project_shape(current_shapes,target_bounding_box);
    /* normalized_ground_truth = project_shape(target_shapes,target_bounding_box); */
    
    /*
    vector<SimilarityTransform> curr_to_mean_shape;
    vector<SimilarityTransform> ground_to_mean_shape;
    
    curr_to_mean_shape = get_similarity_transform(mean_shape,normalized_shapes);
    ground_to_mean_shape = get_similarity_transform(mean_shape,normalized_ground_truth);
     
    vector<Mat_<double> > curr_project_to_mean;
    vector<Mat_<double> > ground_project_to_mean;
    
    for(int i = 0;i < current_shapes.size();i++){
    ipd// get normalized_targets 
        Mat_<double> temp = curr_to_mean_shape[i].apply_similarity_transform(normalized_shapes[i]);
        curr_project_to_mean.push_back(temp.clone());

        temp = ground_to_mean_shape[i].apply_similarity_transform(normalized_ground_truth[i]);
        ground_to_mean_shape.push_back(temp.clone()); 
    }i
    */


    // calculate normalized targets
    normalized_targets = inverse_shape(current_shapes,target_bounding_box);
    normalized_targets = compose_shape(normalized_targets,target_shapes,target_bounding_box); 
    
    for(int i = 0;i < normalized_targets.size();i++){
        Mat_<double> rotation;
        Mat_<double> translation;
        double scale;
        translate_scale_rotate(mean_shape,normalized_shapes[i],translation,scale,rotation);
        transpose(rotation,rotation);
        normalized_targets[i] = scale * normalized_targets[i] * rotation;
    } 

    
    // normalized_targets.clear();
    // for(int i = 0;i < curr_project_to_mean.size();i++){
        // normalized_targets.push_back(ground_project_to_mean[i] - curr_project_to_mean[i]);
    // }

    // generate feature pixel location 
    for(int i = 0;i < pixel_pair_num;i++){
        double x = random_generator.uniform(-1.0,1.0);
        double y = random_generator.uniform(-1.0,1.0);

        if(x*x + y*y > 1){
            i--;
            continue;
        }
        
        // get its nearest landmark
        double min_dist = 1e10;
        int min_index = 0;
        for(int j = 0;j < landmark_num;j++){
            double temp = pow(mean_shape(j,0) - x,2.0) + pow(mean_shape(j,1) - y,2.0);
            if(temp < min_dist){
                min_dist = temp;
                min_index = j;
            } 
        } 
        nearest_keypoint_index(i) = min_index;
        pixel_coordinates(i,0) = x - mean_shape(min_index,0);
        pixel_coordinates(i,1) = y - mean_shape(min_index,1);
    }

    // get feature pixel location for each image
    // for pixel_density, each vector in it stores the pixel value for each image on the corresponding pixel locations
    vector<vector<double> > pixel_density;
    pixel_density.resize(pixel_pair_num);
    for(int i = 0;i < normalized_shapes.size();i++){
        // similarity transform from normalized_shapes to mean shape     
        Mat_<double> rotation(2,2);
        Mat_<double> translation(landmark_num,2);
        double scale = 0;

        translate_scale_rotate(normalized_shapes[i],mean_shape,translation,scale,rotation); 
       
        for(int j = 0;j < pixel_pair_num;j++){
            double x = pixel_coordinates(j,0);
            double y = pixel_coordinates(j,1);
            double project_x = rotation(0,0) * x + rotation(0,1) * y;
            double project_y = rotation(1,0) * x + rotation(1,1) * y;
            project_x = project_x * scale;
            project_y = project_y * scale;
            
            // resize according to bounding_box
            project_x = project_x * target_bounding_box[i].width/2.0;
            project_y = project_y * target_bounding_box[i].height/2.0; 
            
            int index = nearest_keypoint_index(j); 
            int real_x = project_x + current_shapes[i](index,0);
            int real_y = project_y + current_shapes[i](index,1);
            
             
            if(real_x < 0){
                real_x = 0;
            } 
            if(real_y < 0){
                real_y = 0;
            }
            if(real_x > images[i].cols-1){
                real_x = images[i].cols-1;
            }
            if(real_y > images[i].rows - 1){
                real_y = images[i].rows - 1;
            }
            pixel_density[j].push_back(int(images[i](real_y,real_x)));    
        }
    }

   	// calculate the correlation between pixels 
    Mat_<double> correlation(pixel_pair_num,pixel_pair_num);
    for(int i = 0;i < pixel_pair_num;i++){
        for(int j = i;j< pixel_pair_num;j++){
            double correlation_result = calculate_covariance(pixel_density[i],pixel_density[j]);
            correlation(i,j) = correlation_result;
            correlation(j,i) = correlation_result;
        }
    }
	// train ferns
    primary_fern_.resize(second_level_num);

    // predications for each shape 
    vector<Mat_<double> > prediction;
    prediction.resize(current_shapes.size());
    for(int i = 0;i < current_shapes.size();i++){
        prediction[i] = Mat::zeros(landmark_num,2,CV_64FC1);
    }
    
    for(int i = 0;i < second_level_num;i++){
		cout<<"Training fern "<<i<<endl;
        primary_fern_[i].train(pixel_density,correlation,pixel_coordinates,nearest_keypoint_index, current_shapes,pixel_pair_in_fern,normalized_targets,
                prediction); 
    }
    for(int i = 0;i < prediction.size();i++){
        Mat_<double> rotation;
        Mat_<double> translation;
        double scale;
        translate_scale_rotate(normalized_shapes[i],mean_shape,translation,scale,rotation);
        transpose(rotation,rotation);
        prediction[i] = scale * prediction[i] * rotation; 
    }
    current_shapes = compose_shape(prediction, current_shapes, target_bounding_box); 
    current_shapes = reproject_shape(current_shapes, target_bounding_box);
   
    /* Mat_<uchar> test_image_1 = images[10].clone(); */
    // for(int i = 0;i < landmark_num;i++){
        // circle(test_image_1,Point2d(current_shapes[10](i,0),current_shapes[10](i,1)),3,Scalar(255,0,0),-1,8,0);
    // }
    // imshow("result",test_image_1);
    /* waitKey(0);  */

}