#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <cv.h>
#include <highgui.h>

#define BACKGROUND 0
#define OBJECT 255
#define NCIERRE 4
#define NBORDE 1



int h_max=255;
int h_min=0;
int s_max=255;
int s_min=0;
int v_max=255;
int v_min=0;


void dilate( IplImage  **img, int num);	
void dilate_blackholes(	IplImage  **img, int num);
void erode(	IplImage  **img, int num);		
void cierre( IplImage  **img, int num);
void borde_a_fondo(IplImage  **img, int num);
void umbralizado_doble(IplImage ** img, int min, int max);

void cambiarS(int position){	
}


int main() {

	
	uchar *rgb_data;
	uchar *hsv_data;
	uchar *yCrCb_data;

	uchar *h_data;
	uchar *s_data;
	
	uchar *r_data;
	uchar *g_data;
	uchar *b_data;
	
	uchar *Cb_data;
	uchar *Cr_data;


	int height,width;
	int step,channels;		//frame variables					

	
	CvCapture* capture = cvCaptureFromCAM( CV_CAP_ANY );
	if( !capture ) {
		fprintf( stderr, "ERROR: capture is NULL \n" );
		getchar();
		return -1;
	}

	// Create a window in which the captured images will be presented
	cvNamedWindow( "ventana", CV_WINDOW_AUTOSIZE );
	cvNamedWindow( "H_Canny", CV_WINDOW_AUTOSIZE );
	cvNamedWindow( "S_Canny", CV_WINDOW_AUTOSIZE );
	cvNamedWindow( "V_Canny", CV_WINDOW_AUTOSIZE );
	cvCreateTrackbar("Hmax","H_Canny",&h_max,255, cambiarS);
	cvCreateTrackbar("Hmin","H_Canny",&h_min,255, cambiarS);
	
	cvCreateTrackbar("Smax","S_Canny",&s_max,255, cambiarS);
	cvCreateTrackbar("Smin","S_Canny",&s_min,255, cambiarS);

	cvCreateTrackbar("Vmax","V_Canny",&v_max,255, cambiarS);
	cvCreateTrackbar("Vmin","V_Canny",&v_min,255, cambiarS);
	


	/*cvNamedWindow( "RGB", CV_WINDOW_AUTOSIZE );	
	cvNamedWindow( "YCrCb", CV_WINDOW_AUTOSIZE );
	cvCreateTrackbar("Rmax","RGB",&r_max,255, cambiarS);
	cvCreateTrackbar("Rmin","RGB",&r_min,255, cambiarS);
	cvCreateTrackbar("Gmax","RGB",&g_max,255, cambiarS);
	cvCreateTrackbar("Gmin","RGB",&g_min,255, cambiarS);
	cvCreateTrackbar("Bmax","RGB",&b_max,255, cambiarS);
	cvCreateTrackbar("Bmin","RGB",&b_min,255, cambiarS);

	cvCreateTrackbar("Hmax","HSV",&h_max,255, cambiarS);
	cvCreateTrackbar("Hmin","HSV",&h_min,255, cambiarS);
	cvCreateTrackbar("Smax","HSV",&s_max,255, cambiarS);
	cvCreateTrackbar("Smin","HSV",&s_min,255, cambiarS);

	cvCreateTrackbar("Crmax","YCrCb",&Cr_max,255, cambiarS);
	cvCreateTrackbar("Crmin","YCrCb",&Cr_min,255, cambiarS);
	cvCreateTrackbar("Cbmax","YCrCb",&Cb_max,255, cambiarS);
	cvCreateTrackbar("Cbmin","YCrCb",&Cb_min,255, cambiarS);*/

	//cvNamedWindow( "back projection", CV_WINDOW_AUTOSIZE );

	//cvSetMouseCallback("ventana",(CvMouseCallback) captura_pos);
	IplImage* frame = cvQueryFrame( capture );
		
	// get the image data
	height    = frame->height;
	width     = frame->width;


	// Compute HSV image and separate into colors
	IplImage* hsv = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 3 );
	IplImage* hsv2 = cvCreateImage( cvGetSize( frame ), 8, 1 );
	IplImage* h = cvCreateImage( cvGetSize( frame ), 8, 1 );
	IplImage* s = cvCreateImage( cvGetSize( frame ), 8, 1 );
	IplImage* v = cvCreateImage( cvGetSize( frame ), 8, 1 );
	IplImage* h_out = cvCreateImage( cvGetSize( frame ), 8, 1 );
	IplImage* s_out = cvCreateImage( cvGetSize( frame ), 8, 1 );
	IplImage* v_out = cvCreateImage( cvGetSize( frame ), 8, 1 );
	cvCvtColor(frame,hsv,CV_RGB2HSV);
	cvSplit(hsv,h,s,v,0);
	
		
	//
	//// Compute RGB image and separate into colors
	//IplImage* rgb = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 3 );
	//IplImage* rgb2 = cvCreateImage( cvGetSize( frame ), 8, 1 );
	//IplImage* r = cvCreateImage( cvGetSize( frame ), 8, 1 );
	//IplImage* g = cvCreateImage( cvGetSize( frame ), 8, 1 );
	//IplImage* b = cvCreateImage( cvGetSize( frame ), 8, 1 );
	//cvSplit(frame,r,g,b,0);


	//// Compute YCrCb image and separate into colors
	//IplImage* yCrCb = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 3 );
	//IplImage* yCrCb2 = cvCreateImage( cvGetSize( frame ), 8, 1 );
	//IplImage* y = cvCreateImage( cvGetSize( frame ), 8, 1 );
	//IplImage* Cr = cvCreateImage( cvGetSize( frame ), 8, 1 );
	//IplImage* Cb = cvCreateImage( cvGetSize( frame ), 8, 1 );
	//cvCvtColor(frame,yCrCb,CV_RGB2YCrCb);
	//cvSplit(frame,y,Cr,Cb,0);



	//rgb_data      = (uchar *)rgb2->imageData;
	//r_data      = (uchar *)r->imageData;
	//g_data      = (uchar *)g->imageData;
	//b_data      = (uchar *)b->imageData;

	//hsv_data      = (uchar *)hsv2->imageData;
	//h_data      = (uchar *)h->imageData;
	//s_data      = (uchar *)s->imageData;

	//yCrCb_data      = (uchar *)yCrCb2->imageData;
	//Cr_data      = (uchar *)Cr->imageData;
	//Cb_data      = (uchar *)Cb->imageData;

	/*step	  = h->widthStep;
	channels  = h->nChannels;*/

	// Show the image captured from the camera in the window and repeat
	while( 1 ) {
		// Get one frame
		IplImage* frame = cvQueryFrame( capture );
		if( !frame ) {
			fprintf( stderr, "ERROR: frame is null...\n" );
			getchar();
			break;
		}


		cvCvtColor(frame,hsv,CV_RGB2HSV);
		cvSplit(hsv,h,s,v,0);
		cvCanny(h,h_out,h_min,h_max);
		cvCanny(s,s_out,s_min,s_max);
		cvCanny(v,v_out,v_min,v_max);

		cvShowImage("H_Canny",h_out);
		cvShowImage("S_Canny",s_out);
		cvShowImage("V_Canny",v_out);

		//cvCopy(frame,rgb);
		//cvSplit(rgb,r,g,b,0);
		//cvCvtColor(frame,hsv,CV_RGB2HSV);
		//cvSplit(frame,h,s,v,0);
		//cvCvtColor(frame,yCrCb,CV_RGB2YCrCb);
		//cvSplit(frame,y,Cr,Cb,0);

		//uchar suma;

		//for(int i=0;i<height;i++)
		//	for(int j=0;j<width;j++) {
		//		suma=r_data[i*step+j]+g_data[i*step+j]+b_data[i*step+j];
		//		if(suma>255)suma=255;
		//		if(suma!=0){
		//			r_data[i*step+j]=r_data[i*step+j]/suma;
		//			g_data[i*step+j]=g_data[i*step+j]/suma;
		//			b_data[i*step+j]=b_data[i*step+j]/suma;
		//		}
		//	}

		//umbralizado_doble(&r,r_min,r_max);
		//umbralizado_doble(&g,g_min,g_max);
		//umbralizado_doble(&b,b_min,b_max);
		//umbralizado_doble(&h,h_min,h_max);
		//umbralizado_doble(&s,s_min,s_max);
		//umbralizado_doble(&Cr,Cr_min,Cr_max);
		//umbralizado_doble(&Cb,Cb_min,Cb_max);
		//cvZero(rgb2);
		//cvZero(hsv2);
		//cvZero(yCrCb2);


		//for(int i=0;i<height;i++)
		//		for(int j=0;j<width;j++) {
		//				if(r_data[i*step+j]==0 || g_data[i*step+j]==0 || b_data[i*step+j]==0  ) 
		//					rgb_data[i*step+j]=0;
		//				else{
		//					rgb_data[i*step+j]=255;
		//				}


		//				if(h_data[i*step+j]==0 || s_data[i*step+j]==0 ) 
		//					hsv_data[i*step+j]=0;
		//				else{
		//					hsv_data[i*step+j]=255;
		//				}
		//				
		//				

		//				if(Cr_data[i*step+j]==0 || Cb_data[i*step+j]==0 ) 
		//					yCrCb_data[i*step+j]=0;
		//				else{
		//					yCrCb_data[i*step+j]=255;
		//				}
		//			}
		//
		////cvCvtColor( frame, hsv2, CV_BGR2HSV );
		//
		////IplImage* planes2[] = { h_plane2, s_plane2 };
		////cvCvtPixToPlane( hsv2, h_plane2, s_plane2, v_plane2, 0 );
		////cvCalcBackProject( planes2, back_img, hist );// Calculate back projection
		////cvThreshold(back_img,back_img2,150,0,CV_THRESH_TOZERO);
		////dilate(&back_img2,2);
		////erode(&back_img2,3);
		////dilate(&back_img2,3);


		//umbralizando_hsv(frame);
		
		cvShowImage("ventana",frame);
		/*cvShowImage("RGB",rgb2);
		cvShowImage("HSV",hsv2);
		cvShowImage("YCrCb",yCrCb2);*/
		//cvShowImage("back projection",back_img);
		// Do not release the frame!

		//If ESC key pressed, Key=0x10001B under OpenCV 0.9.7(linux version),
		//remove higher bits using AND operator
		if( (cvWaitKey(10) & 255) == 27 ) break;
	}


	// Release the capture device housekeeping
	cvReleaseCapture( &capture );

	cvDestroyWindow( "ventana" );












/*
	// Set up images
	IplImage* img2 = cvLoadImage("probado1.bmp");
	IplImage* img = cvLoadImage("mano2.bmp");
	IplImage* back_img = cvCreateImage( cvGetSize( img ), IPL_DEPTH_8U, 1 );
	IplImage* back_img2 = cvCreateImage( cvGetSize( img ), IPL_DEPTH_8U, 1 );

	// Compute HSV image and separate into colors
	IplImage* hsv = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 3 );
	cvCvtColor( img, hsv, CV_BGR2HSV );

	IplImage* h_plane = cvCreateImage( cvGetSize( img ), 8, 1 );
	IplImage* s_plane = cvCreateImage( cvGetSize( img ), 8, 1 );
	IplImage* v_plane = cvCreateImage( cvGetSize( img ), 8, 1 );
	IplImage* planes[] = { h_plane, s_plane };
	cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 );

	// Compute HSV image and separate into colors
	IplImage* hsv2 = cvCreateImage( cvGetSize(img2), IPL_DEPTH_8U, 3 );
	cvCvtColor( img2, hsv2, CV_BGR2HSV );
	IplImage* h_plane2 = cvCreateImage( cvGetSize( img2 ), 8, 1 );
	IplImage* s_plane2 = cvCreateImage( cvGetSize( img2 ), 8, 1 );
	IplImage* v_plane2 = cvCreateImage( cvGetSize( img2 ), 8, 1 );
	IplImage* planes2[] = { h_plane2, s_plane2 };
	cvCvtPixToPlane( hsv2, h_plane2, s_plane2, v_plane2, 0 );

	// Build and fill the histogram
	int h_bins = 30, s_bins = 32;
	CvHistogram* hist;
	{
		int hist_size[] = { h_bins, s_bins };
		float h_ranges[] = { 0, 180 };
		float s_ranges[] = { 0, 255 };
		float* ranges[] = { h_ranges, s_ranges };
		hist = cvCreateHist( 2, hist_size, CV_HIST_ARRAY, ranges, 1 );
	}
	cvCalcHist( planes, hist, 0, 0 ); // Compute histogram
	cvNormalizeHist( hist, 20*255 ); // Normalize it

	cvCalcBackProject( planes2, back_img, hist );// Calculate back projection
	cvNormalizeHist( hist, 1.0 ); // Normalize it
	cvThreshold(back_img,back_img2,150,0,CV_THRESH_TOZERO);
	dilate(&back_img2,2);
	erode(&back_img2,3);
	dilate(&back_img2,3);


	
	// Create an image to visualize the histogram
	int scale = 10;
	IplImage* hist_img = cvCreateImage( cvSize( h_bins * scale, s_bins * scale ), 8, 3 );
	cvZero ( hist_img );

	// populate the visualization
	float max_value = 0;
	cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 );

	for( int h = 0; h < h_bins; h++ ){
		for( int s = 0; s < s_bins; s++ ){
			float bin_val = cvQueryHistValue_2D( hist, h, s );
			int intensity = cvRound( bin_val * 255 / max_value );
			cvRectangle( hist_img, cvPoint( h*scale, s*scale ),
						cvPoint( (h+1)*scale - 1, (s+1)*scale - 1 ),
						CV_RGB( intensity, intensity, intensity ),
						CV_FILLED );
		}
	}

	// Show original
	cvNamedWindow( "Source", 1) ;
	cvShowImage( "Source", img2 );

	// Show back projection
	cvNamedWindow( "Back Projection", 1) ;
	cvShowImage( "Back Projection", back_img2 );

	// Show histogram equalized
	cvNamedWindow( "H-S Histogram", 1) ;
	cvShowImage( "H-S Histogram", hist_img );

	cvWaitKey(0);

	cvReleaseImage( &img );
	cvReleaseImage( &back_img );
	cvReleaseImage( &hist_img );

	return 0;*/
}



void dilate(	IplImage  **img, int num)
{
	int      i, j,k;
	int height,width,step,chan;
	uchar *data,*data_tmp;
	IplImage *tmp;

	height	= (*img)->height;
	width		= (*img)->width;
	step      = (*img)->widthStep;
	chan		= (*img)->nChannels;
	data      = (uchar *)(*img)->imageData;

	for (int n =0; n<num; n++){
		tmp = cvCloneImage((*img));
		data_tmp      = (uchar *)tmp->imageData;

		for(i=1;i<height-1;i++)
			for(j=1;j<width-1;j++) 
				for(k=0;k<chan;k++)
					if(data[i*step+j*chan+k]==BACKGROUND &&
						( 
						data_tmp[(i-1)*step+(j-1)*chan+k]==OBJECT ||
						data_tmp[(i-1)*step+(j)*chan+k]==OBJECT ||
						data_tmp[(i-1)*step+(j+1)*chan+k]==OBJECT ||
						data_tmp[(i)*step+(j-1)*chan+k]==OBJECT ||
						data_tmp[(i)*step+(j+1)*chan+k]==OBJECT ||
						data_tmp[(i+1)*step+(j-1)*chan+k]==OBJECT ||
						data_tmp[(i+1)*step+(j)*chan+k]==OBJECT ||
						data_tmp[(i+1)*step+(j+1)*chan+k]==OBJECT 
						)
						)data[i*step+j*chan+k]=OBJECT;

		cvReleaseImage(&tmp);
	}
} 
void dilate_blackholes(	IplImage  **img, int num)
{
	int      i, j,k;
	int height,width,step,chan;
	uchar *data,*data_tmp;
	IplImage *tmp;

	height	= (*img)->height;
	width		= (*img)->width;
	step      = (*img)->widthStep;
	chan		= (*img)->nChannels;
	data      = (uchar *)(*img)->imageData;

	for (int n =0; n<num; n++){
		tmp = cvCloneImage((*img));
		data_tmp      = (uchar *)tmp->imageData;

		for(i=3;i<height-3;i++)
			for(j=3;j<width-3;j++) 
				for(k=0;k<chan;k++)
					if(data[i*step+j*chan+k]==BACKGROUND &&
						( 
							(data_tmp[(i-1)*step+(j-1)*chan+k]==OBJECT &&
							data_tmp[(i-1)*step+(j)*chan+k]==OBJECT &&
							data_tmp[(i-1)*step+(j+1)*chan+k]==OBJECT )
							&&
							(data_tmp[(i)*step+(j-1)*chan+k]==OBJECT ||
							data_tmp[(i)*step+(j+1)*chan+k]==OBJECT )
						)
					)
					data[i*step+j*chan+k]=OBJECT;

		cvReleaseImage(&tmp);
	}
} 


void erode(	IplImage  **img, int num)
{
	int      i, j,k;
	int height,width,step,chan;
	uchar *data,*data_tmp;
	IplImage *tmp;

	height	= (*img)->height;
	width		= (*img)->width;
	step      = (*img)->widthStep;
	chan		= (*img)->nChannels;
	data      = (uchar *)(*img)->imageData;

	for (int n =0; n<num; n++){
		tmp = cvCloneImage((*img));
		data_tmp      = (uchar *)tmp->imageData;

		for(i=1;i<height-1;i++)
			for(j=1;j<width-1;j++) 
				for(k=0;k<chan;k++)
					if(data[i*step+j*chan+k]==OBJECT &&
						( 
						data_tmp[(i-1)*step+(j-1)*chan+k]==BACKGROUND ||
						data_tmp[(i-1)*step+(j)*chan+k]==BACKGROUND ||
						data_tmp[(i-1)*step+(j+1)*chan+k]==BACKGROUND ||
						data_tmp[(i)*step+(j-1)*chan+k]==BACKGROUND ||
						data_tmp[(i)*step+(j+1)*chan+k]==BACKGROUND ||
						data_tmp[(i+1)*step+(j-1)*chan+k]==BACKGROUND ||
						data_tmp[(i+1)*step+(j)*chan+k]==BACKGROUND ||
						data_tmp[(i+1)*step+(j+1)*chan+k]==BACKGROUND 
						)
						)data[i*step+j*chan+k]=BACKGROUND;

		cvReleaseImage(&tmp);
	}
} 

void cierre (IplImage  **img, int num){
	erode(img,num);
	dilate(img,num+1);
	erode(img,1);
}

void borde_a_fondo(IplImage  **img, int num){
	int      i, j,k;
	int height,width,step,chan;
	uchar *data;

	height	= (*img)->height;
	width		= (*img)->width;
	step      = (*img)->widthStep;
	chan		= (*img)->nChannels;
	data      = (uchar *)(*img)->imageData;

	for(j=0;j<width;j++) 
		for(k=0;k<chan;k++){
			data[0+j*chan+k]=BACKGROUND;
			data[(height-1)*step+j*chan+k]=BACKGROUND;
		}
	for(i=0;i<height;i++) 
		for(k=0;k<chan;k++){
			data[i*step+k]=BACKGROUND;
			data[i*step+(width-1)*chan+k]=BACKGROUND;
		}

}
void umbralizado_doble(IplImage ** img, int min, int max){

	int i,j,k;
	int height,width,step,channels;
	uchar *data;

	// get the image data
	height    = (*img)->height;
	width     = (*img)->width;
	step      = (*img)->widthStep;
	channels  = (*img)->nChannels;
	data      = (uchar *)(*img)->imageData;

	

	for(i=1;i<height-1;i++)
		for(j=1;j<width-1;j++) 
			for(k=0;k<channels;k++){
				if(  (data[i*step+j*channels+k] > max) || ( data[i*step+j*channels+k] ) < min )
					data[i*step+j*channels+k] = BACKGROUND;
				//else data[i*step+j*channels+k] = OBJECT;
			}
}