
#include <cv.h>
#include <highgui.h>
#include <iostream>

/*
	Program to calculate the mean and variance using the histogram extracted
	from a section of an image.
	@author: Gavin Page, gsp8334@cs.rit.edu
	@date: 29 November 2005
*/
int main( int argc, char** argv ) {
	int hist_size = 255; //The number of the bins in the histogram
	float range_0[]={0,256}; //The range of values for the 0th dimension
	float* ranges[] = { range_0 };// The range of values for the 1st dimension 
	int i, bin_w; //indeces
	float max_value = 0, min_value = 0; //max and min value of the histogram
	int min_idx = 0, max_idx = 0; //max and min index corresponding to max and min value
	double mean = 0, variance = 0; //variable to hold mean and variance

	char* imageName = "Critters_00005.JPG"; //the name of the image being loaded

	//Load the image and make sure that it loads correctly
	IplImage* im = cvLoadImage(imageName, -1);
	if( im == 0 ) {
		//Drop out if the image isn't found
		std::cerr << "Failed to load: " << imageName << std::endl;
		return 1;
	}

	//Create a single planed image of the same size as the original
	IplImage* grayImage = cvCreateImage(cvSize(im->width,im->height), 
			IPL_DEPTH_8U, 1);

	//convert the original image to gray
	cvCvtColor(im, grayImage, CV_BGR2GRAY);

	//create a rectangular area to evaluate
	CvRect rect = cvRect(0, 0, 500, 600 );

	//apply the rectangle to the image and establish a region of interest
	cvSetImageROI(grayImage, rect);

	//create an image to hold the histogram
	IplImage* histImage = cvCreateImage(cvSize(320,200), 8, 1);
	//create a histogram to store the information from the image
	CvHistogram* hist = 
		cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1);
	//calculate the histogram and apply to hist
	cvCalcHist( &grayImage, hist, 0, NULL );

	//grab the min and max values and their indeces
	cvGetMinMaxHistValue( hist, &min_value, &max_value, &min_idx, &max_idx);
	//scale the bin values so that they will fit in the image representation
	cvScale( hist->bins, hist->bins, ((double)histImage->height)/max_value, 0 );

	//set all histogram values to 255
	cvSet( histImage, cvScalarAll(255), 0 );
	//create a factor for scaling along the width
	bin_w = cvRound((double)histImage->width/hist_size);
	for( i = 0; i < hist_size; i++ ) {
		//draw the histogram data onto the histogram image
		cvRectangle( histImage, cvPoint(i*bin_w, histImage->height),
			cvPoint((i+1)*bin_w, 
			histImage->height - cvRound(cvGetReal1D(hist->bins,i))),
			cvScalarAll(0), -1, 8, 0 );

		//get the value at the current histogram bucket
		float* bins = cvGetHistValue_1D(hist,i);
		//increment the mean value
		mean += bins[0];
		//std::cout<< bins[0] << " " << bins[1] << std::endl;
	}
	//finish mean calculation
	mean /= hist_size;

	//go back through now that mean has been calculated in order to calculate variance
	for( i = 0; i < hist_size; i++ ) {
		float* bins = cvGetHistValue_1D(hist,i);
		variance += pow((bins[0] - mean),2);
	}

	//finish variance calculation
	variance /= hist_size;


	std::cout << "Histogram Mean: " << mean << std::endl;
	std::cout << "Variance: " << variance << std::endl;
	std::cout << "Standard Deviation: " << sqrt(variance) << std::endl;


	//display the 3 images
	cvNamedWindow("Original", 0);
	cvShowImage("Original", im );

	cvNamedWindow("Gray", 0);
	cvShowImage("Gray", grayImage );

	cvNamedWindow("Histogram", 0);
	cvShowImage("Histogram", histImage );

	//hold the images until a key is pressed
	cvWaitKey(0);

	//clean up images
	cvReleaseImage(&histImage);
	cvReleaseImage(&grayImage);
	cvReleaseImage(&im);

	//remove windows
	cvDestroyWindow("Original");
	cvDestroyWindow("Gray");
	cvDestroyWindow("Histogram");

	return 0;

}
