void initialise_inpainting(nTupleVolume *imgVol, nTupleVolume *occVol, featurePyramid featuresVolPyramid,
				nTupleVolume *shiftVol, patchMatchParameterStruct *patchMatchParams)
{
	int iterNb=0;
	patchMatchParams->partialComparison = 1;
	bool initialisation = true;
	nTupleVolume *occVolIter;
	occVolIter = copy_image_nTuple(occVol);
	
	seed_random_numbers((double)3);
	
	nTupleVolume *structElErode = create_structuring_element("rectangle", 3, 3);
	nTupleVolume *structElDilate = create_structuring_element("rectangle", imgVol->patchSizeX, imgVol->patchSizeY);
	
	nTupleVolume *occVolDilate = imdilate(occVol, structElDilate);
	
	//extract features images from featuresVolPyramid (coarsest level)
	nTupleVolume *normGradXvol,*normGradYvol;
	
	if (featuresVolPyramid.nLevels >= 0)
	{
		normGradXvol = copy_image_nTuple((featuresVolPyramid.normGradX)[featuresVolPyramid.nLevels-1]);
		normGradYvol = copy_image_nTuple((featuresVolPyramid.normGradY)[featuresVolPyramid.nLevels-1]);
		//attach features to patchMatch parameters
		patchMatchParams->normGradX = normGradXvol;
		patchMatchParams->normGradY = normGradYvol;
	}
	
	while ( (occVolIter->sum_nTupleVolume()) >0)
	{
		nTupleVolume *occVolErode = imerode(occVolIter, structElErode);
		nTupleVolume *occVolPatchMatch = copy_image_nTuple(occVolDilate);
		
		/***************************/
		/*******   NNSEARCH   ******/
		/***************************/		
		//indicate which pixels can be used for comparing patches
		//but we are not allowed to point to in the patchMatch (we set these pixels to 2)
		for (int x=0; x<(occVolPatchMatch->xSize); x++)
			for (int y=0; y<(occVolPatchMatch->ySize); y++)
			{
				if ( (occVolDilate->get_image_value(x,y,0) - occVolIter->get_image_value(x,y,0)) == 1)
					occVolPatchMatch->set_image_value(x,y,0,(imageDataType)2);
			}
			
		//set first guess
		nTupleVolume *firstGuess = copy_image_nTuple(shiftVol);
		//carry out patchMatch
		patch_match_ANN(imgVol,imgVol,shiftVol,occVolPatchMatch,occVolDilate,patchMatchParams,firstGuess);
		/***************************/
		/****   RECONSTRUCTION   ***/
		/***************************/
		nTupleVolume *occVolReconstruct = copy_image_nTuple(occVolIter);
		//Indicate which pixels are on the current border, and need to be inpainted
		//Also, we indicate that the pixels inside the occlusion (and not on the border) are occluded (and
		//therefore not to be used for reconstruction) but should not
		//be inpainted at the current iteration. To indicate this
		//we set them to 2
		for (int x=0; x<(occVolPatchMatch->xSize); x++)
			for (int y=0; y<(occVolPatchMatch->ySize); y++)
			{
				imageDataType valueTemp = abs(occVolIter->get_image_value(x,y,0) - occVolErode->get_image_value(x,y,0));
				occVolReconstruct->set_image_value(x,y,0,valueTemp);
				if (occVolErode->get_image_value(x,y,0) == 1)
					occVolReconstruct->set_image_value(x,y,0,(imageDataType)2);
			}

		//call reconstruction function
		if (featuresVolPyramid.nLevels >= 0)
			reconstruct_image_and_features(imgVol, occVolReconstruct,
		    	normGradXvol, normGradYvol,
		    	shiftVol, SIGMA_COLOUR, AGGREGATED_PATCHES,initialisation);
		else
		{
			reconstruct_image(imgVol,occVolReconstruct,shiftVol,SIGMA_COLOUR,AGGREGATED_PATCHES,initialisation);
		}
		
		iterNb++;
		if (patchMatchParams->verboseMode == true)
			printf("\n Initialisation iteration number : %d \n",iterNb);
		delete(occVolPatchMatch);
		delete(occVolReconstruct);
		
		//copy the information from the eroded occlusion to the current occlusion (occVolIter)
		delete(occVolIter);
		occVolIter = copy_image_nTuple(occVolErode);
		delete(occVolErode);
	}
}
int main(int argc, char** argv)
{
        int i;
		int j;
		int Ymax = 235;
		int Ymin = 16;
		int row,col;
		int sum = 0;
		int id = 0;
		double temp;
		double Cx = 109.38;
		double Cy = 152.02;
		double theta = 2.53;
		double ecx = 1.60;
		double ecy = 2.41;
		double a = 25.39;
		double b = 14.03;
		double t;
		double lea = 0;
		imt_l* H;
		imt_l* y;
		imt_c* resultr;
		imt_c* resultg;
		imt_c* resultb;
		imt_c* bi_graph;
		imt_c* result;
		imt_c* h;

		linux_mem_init();
		
		
		rgb_mt_t* image = imread(argv[1]);
		if(image == NULL)
		{
			exit(2);
		}
		row = image->r->row;
		col = image->r->col;
		
		
		
		H =  create_zero_l(3,3);
		resultr = create_zero_c(row,col);
		resultg = create_zero_c(row,col);
		resultb = create_zero_c(row,col);
		y =  create_zero_l(row,col);
		
		
		medfilt2(image->r,resultr);
		move_c(resultr,image->r);
		medfilt2(image->g,resultg);
		move_c(resultg,image->g);
		medfilt2(image->b,resultb);
		move_c(resultb,image->b);
		
		imshow("blur.bmp",image);
		
		
		set_pixel_l(H,1,1,65.4810/255);
		set_pixel_l(H,1,2,128.5530/255);
		set_pixel_l(H,1,3,24.9660/255);
		set_pixel_l(H,2,1,-37.7970/255);
		set_pixel_l(H,2,2,-74.2030/255);
		set_pixel_l(H,2,3,112.0000/255);
		set_pixel_l(H,3,1,112.0000/255);
		set_pixel_l(H,3,2,-93.7860/255);
		set_pixel_l(H,3,3,-18.2140/255);
		
		for(i = 1;i <= row;i ++)
			for(j = 1;j <= col;j ++)
			{
				temp = get_pixel_l(H,1,1) * (double)get_pixel_c(image->r,i,j) + get_pixel_l(H,1,2) * (double)get_pixel_c(image->g,i,j) + get_pixel_l(H,1,3) * (double)get_pixel_c(image->b,i,j) + 16;
				set_pixel_c(resultr,i,j,(unsigned char)temp);
				temp = get_pixel_l(H,2,1) * (double)get_pixel_c(image->r,i,j) + get_pixel_l(H,2,2) * (double)get_pixel_c(image->g,i,j) + get_pixel_l(H,2,3) * (double)get_pixel_c(image->b,i,j) + 128;
				set_pixel_c(resultg,i,j,(unsigned char)temp);
				temp = get_pixel_l(H,3,1) * (double)get_pixel_c(image->r,i,j) + get_pixel_l(H,3,2) * (double)get_pixel_c(image->g,i,j) + get_pixel_l(H,3,3) * (double)get_pixel_c(image->b,i,j) + 128;
				set_pixel_c(resultb,i,j,(unsigned char)temp);
			}
		clear(H);		
		bi_graph = create_zero_c(row,col);
			
		for(i = 1;i <= row;i ++)
			for(j = 1;j <= col;j ++)
			{
				temp = cos(theta) * ((double)get_pixel_c(resultg,i,j) - Cx) + sin(theta) * ((double)get_pixel_c(resultb,i,j) - Cy);
				set_pixel_l(y,i,j,-sin(theta)*((double)get_pixel_c(resultg,i,j) - Cx) + cos(theta)*((double)get_pixel_c(resultb,i,j) - Cy));
				lea = (temp - ecx) * (temp - ecx) / (a * a) + (get_pixel_l(y,i,j) - ecy) * (get_pixel_l(y,i,j) - ecy) / b / b;
				if(lea < 1.0)
				{
					set_pixel_c(bi_graph,i,j,255);
				}
				if(get_pixel_c(resultr,i,j) <= 80)
				{
					set_pixel_c(bi_graph,i,j,0);
				}
			}
			
		clear(resultr);
		clear(resultg);
		clear(resultb);
		
		image->r = bi_graph;
		image->g = bi_graph;
		image->b = bi_graph;
		imshow("bigraph.bmp",image);
		
		h = create_zero_c(3,3);
		set_pixel_c(h,1,1,255);
		set_pixel_c(h,1,2,255);
		set_pixel_c(h,1,3,255);
		set_pixel_c(h,2,1,255);
		set_pixel_c(h,2,2,255);
		set_pixel_c(h,2,3,255);
		set_pixel_c(h,3,1,255);
		set_pixel_c(h,3,2,255);
		set_pixel_c(h,3,3,255);
		result = imrode(bi_graph,h);
		move_c(result,bi_graph);
		clear(result);
		clear(h);
		
		h = create_zero_c(12,12);
		for(i = 1;i <= 12;i ++)
			for(j = 1;j <= 12;j ++)
				set_pixel_c(h,i,j,255);
		result = imdilate(bi_graph,h);
		move_c(result,bi_graph);
		clear(result);
		clear(h);
		
		bwareaopen(bi_graph,row * col / 10);
		for(i = 1;i <= row;i ++)
		{
			for(j = 1;j <= col;j ++)
			{
				if(get_pixel_c(bi_graph,i,j) == 0)
					set_pixel_c(bi_graph,i,j,255);
				else
					set_pixel_c(bi_graph,i,j,0);
			}
		}
		bwareaopen(bi_graph,row * col / 10);
		for(i = 1;i <= row;i ++)
		{
			for(j = 1;j <= col;j ++)
			{
				if(get_pixel_c(bi_graph,i,j) == 0)
					set_pixel_c(bi_graph,i,j,255);
				else
					set_pixel_c(bi_graph,i,j,0);
			}		
		}
		
		result = focus(bi_graph);
		id = identifier(result);
		
		image->r = bi_graph;
		image->g = bi_graph;
		image->b = bi_graph;
		imshow("result.bmp",image);
		clear(bi_graph);
		
		image = imread(argv[1]);
		for(i = 1;i <= row;i ++)
			for(j = 1;j < col;j ++)
			{
				if(i <= l1 && i >= l0 && j <= n1 && j >= n0)
				{
					if(get_pixel_c(result,i - l0,j - n0) == 255)
					{
						sum ++;
						set_pixel_c(image->r,i,j,0);
						set_pixel_c(image->g,i,j,255);
						set_pixel_c(image->b,i,j,0);
					}
				}
				if(((j > n0 - 5 && j < n0 + 5) || (j < n1 + 5 && j > n1 - 5)) && ((i < l1 + 5 && i > l1 - 5) || (i > l0 - 5&& i < l0 + 5)))
				{
					set_pixel_c(image->r,i,j,255);
					set_pixel_c(image->g,i,j,0);
					set_pixel_c(image->b,i,j,0);
				}
			}
		imshow("focus.bmp",image);
		m_stat(); 
		characteristic();
		
		if(id == 0)
		{
			printf("Unknown\n");
		}
		else if(id == 1)
		{
			printf("Rock!\n");
		}
		else if(id == 2)
		{
			printf("Scissors!\n");
		}
		else if(id == 3)
		{
			printf("Paper!\n");
		}
        return 0;
}
nTupleVolume * inpaint_image( nTupleVolume *imgVolIn, nTupleVolume *occVolIn,
patchMatchParameterStruct *patchMatchParams, inpaintingParameterStruct *inpaintingParams)
{
	
	// ******************************************************************** //
	// **** AUTOMATICALLY DETERMINE NUMBER OF LEVELS, IF NOT SPECIFIED **** //
	// ******************************************************************** //
	if (inpaintingParams->nLevels == -1)
	{
		inpaintingParams->nLevels =
			determine_multiscale_level_number(occVolIn,imgVolIn->patchSizeX,imgVolIn->patchSizeY);
	}
	display_inpainting_parameters(inpaintingParams);
	display_patch_match_parameters(patchMatchParams);
	
	nTupleVolume *imgVolOut;

	// ************************** //
	// **** CREATE PYRDAMIDS **** //
	// ************************** //
	nTupleVolumePyramid imgVolPyramid = create_nTupleVolume_pyramid(imgVolIn, inpaintingParams->nLevels);
	nTupleVolumePyramid occVolPyramid = create_nTupleVolume_pyramid_binary(occVolIn, inpaintingParams->nLevels);
	featurePyramid featuresVolPyramid;
	if (inpaintingParams->useFeatures == true)
	{
		double t1 = clock();
		featuresVolPyramid = create_feature_pyramid(imgVolIn, occVolIn, inpaintingParams->nLevels);
		MY_PRINTF("\n\nFeatures calculation time: %f\n",((double)(clock()-t1)) / CLOCKS_PER_SEC);
	}
	else
	{
		featuresVolPyramid.normGradX = NULL;
        featuresVolPyramid.normGradY = NULL;
        featuresVolPyramid.nLevels = -1;
	}

	//create structuring element
	nTupleVolume *structElDilate = create_structuring_element("rectangle", imgVolIn->patchSizeX, imgVolIn->patchSizeY);
	
	//show_patch_match_parameters(patchMatchParams);
	
	// ****************************************** //
	// ************* START INPAINTING *********** //
	// ****************************************** //
	
	nTupleVolume *imgVol,*normGradXvol,*normGradYvol;
	nTupleVolume *shiftVol=NULL;
	for (int level=( (inpaintingParams->nLevels)-1); level>=0; level--)
	{
		printf("Current pyramid level : %d\n",level);
		nTupleVolume *imgVolPrevious,*occVol,*occVolDilate;

		if (patchMatchParams->maxShiftDistance != -1)		
			patchMatchParams->maxShiftDistance =
			(float)( (patchMatchParams->maxShiftDistance)/( pow((float)SUBSAMPLE_FACTOR,(float)level) ));
		
		imgVol = copy_image_nTuple(imgVolPyramid[level]);
		occVol = copy_image_nTuple(occVolPyramid[level]);
		//create dilated occlusion
		occVolDilate = imdilate(occVol, structElDilate);
		
		if (featuresVolPyramid.nLevels >= 0)
		{
			normGradXvol = copy_image_nTuple((featuresVolPyramid.normGradX)[level]);
			normGradYvol = copy_image_nTuple((featuresVolPyramid.normGradY)[level]);
			//attach features to patchMatch parameters
			patchMatchParams->normGradX = normGradXvol;
			patchMatchParams->normGradY = normGradYvol;
		}
					
		//initialise solution
		if (level == ((inpaintingParams->nLevels)-1))
		{
			shiftVol = new nTupleVolume(4,imgVol->xSize,imgVol->ySize,imgVol->patchSizeX,imgVol->patchSizeY,IMAGE_INDEXING);
			shiftVol->set_all_image_values(0);
			printf("\nInitialisation started\n\n\n");
			initialise_inpainting(imgVol,occVol,featuresVolPyramid,shiftVol,patchMatchParams);
			patchMatchParams->partialComparison = 0;
			printf("\nInitialisation finished\n\n\n");
			
			if (featuresVolPyramid.nLevels >= 0)	//retrieve features from the pointers in the patchMatch parameters
			{
				normGradXvol = patchMatchParams->normGradX;
				normGradYvol = patchMatchParams->normGradY;
			}
		}
		else	//reconstruct current solution
		{
			if (featuresVolPyramid.nLevels >= 0)
			{
				reconstruct_image_and_features(imgVol, occVol,
				normGradXvol, normGradYvol,
				shiftVol, SIGMA_COLOUR);
			}
			else
			{
				reconstruct_image(imgVol,occVol,shiftVol,SIGMA_COLOUR);
				//write_shift_map(shiftVol,fileOut);
			}
		}
		
		calclulate_patch_distances(imgVol,imgVol,shiftVol,occVolDilate,patchMatchParams);
		
		//iterate ANN search and reconstruction
		int iterationNb = 0;
		imageDataType residual = FLT_MAX;
		while( (residual > (inpaintingParams->residualThreshold) ) && (iterationNb < (inpaintingParams->maxIterations) ) )
		{
			//copy current imgVol
			imgVolPrevious = copy_image_nTuple(imgVol);
			patch_match_ANN(imgVol,imgVol,shiftVol,occVolDilate,occVolDilate,patchMatchParams);
			if (featuresVolPyramid.nLevels >= 0)
			{
				reconstruct_image_and_features(imgVol, occVol,
        			normGradXvol, normGradYvol,
        			shiftVol, SIGMA_COLOUR);
			}
			else
				reconstruct_image(imgVol,occVol,shiftVol,SIGMA_COLOUR);
			residual = calculate_residual(imgVol,imgVolPrevious,occVol);
			if (patchMatchParams->verboseMode == true)
				printf("Iteration number %d, residual = %f\n",iterationNb,residual);
			iterationNb++;
		}
		//upsample shift volume, if we are not on the finest level
		if (level >0)
		{	
			nTupleVolume * shiftVolTemp = up_sample_image(shiftVol, SUBSAMPLE_FACTOR,imgVolPyramid[level-1]);
			delete(shiftVol);
			shiftVol = copy_image_nTuple(shiftVolTemp);
			shiftVol->multiply((imageDataType)SUBSAMPLE_FACTOR);
			delete(shiftVolTemp);
		}
		else
		{
			reconstruct_image(imgVol,occVol,shiftVol,SIGMA_COLOUR,3);
			imgVolOut = new nTupleVolume(imgVol);
		}
		//destroy structures
		delete(imgVol);
		delete(imgVolPrevious);
		delete(occVol);
		delete(occVolDilate);
		if (featuresVolPyramid.nLevels >= 0)
		{
			delete normGradXvol;
			delete normGradYvol;
		}
	}
	
	// ************************** //
	// **** DELETE STRUCTURES *** //
	// ************************** //
	for (int i=0; i< (inpaintingParams->nLevels); i++)
	{
		delete(imgVolPyramid[i]);
		delete(occVolPyramid[i]);
	}
	delete(imgVolPyramid);
	delete(occVolPyramid);
	delete(shiftVol);
	delete_feature_pyramid(featuresVolPyramid);
	delete(patchMatchParams);
	
	printf("Inpainting finished !\n");

	return(imgVolOut);
}