InputImageType::Pointer getEmpty(int s1,int s2, int s3)
{
	InputImageType::Pointer p = InputImageType::New();
	InputImageType::SizeType size;
	InputImageType::IndexType index;
	InputImageType::RegionType region;
	size[0] = s1; size[1] = s2; size[2] = s3;
	index.Fill(0);
	region.SetSize(size);
	region.SetIndex(index);
	p->SetRegions(region);
	p->Allocate();
	return p;
}
void unmixMPIInternal(InputImageType::Pointer im [4],InputImageType::Pointer om[4], InputImageType::Pointer assignment[4])
{
	printf("Performing unmixing ...\n");
	InputImageType::SizeType size = im[0]->GetLargestPossibleRegion().GetSize();


	IteratorType iterator[4];
	IteratorType assigniter[4];

	InputImageType::SizeType radius;
	radius[0]=1;
	radius[1]=1;
	radius[2]=1;

	InputImageType::SizeType imagesize = im[0]->GetLargestPossibleRegion().GetSize();
	InputImageType::IndexType imageindex;
	imageindex.Fill(0);
	InputImageType::RegionType region;
	region.SetSize(imagesize);
	region.SetIndex(imageindex);


	for(int counter=0; counter<4; counter++)
	{
		printf("\tPerforming median filtering on channel %d ...",counter+1);
		om[counter]=im[counter];
		assignment[counter]=InputImageType::New();
		assignment[counter]->SetRegions(region);
		assignment[counter]->Allocate();
		assigniter[counter]=IteratorType(assignment[counter],assignment[counter]->GetLargestPossibleRegion());
		assigniter[counter].GoToBegin();
		iterator[counter]=IteratorType(om[counter],om[counter]->GetLargestPossibleRegion());
		iterator[counter].GoToBegin();
		printf(" Done %d.\n",counter+1);
	}

	//int total_voxels = size[0]*size[1]*size[2];
	int num_processed = 0;
	printf("\tComputing maximum among channels ... ");
	for(;!iterator[0].IsAtEnd();)
	{
		num_processed++;
		/*
		if(num_processed % 100 ==0)
		printf("Processed %0.2lf%% voxels\r",100.0/total_voxels*num_processed);
		*/
		//		if(100.0/total_voxels*num_processed> 100)
		//			break;
		double max = -1;
		int maxpos = -1;
		for(int co = 0; co < 4; co++)
		{
			unsigned char temp = iterator[co].Value();
			if(max < temp)
			{
				max = temp;
				maxpos = co;
			}
		}
		for(int co = 0; co < 4; co++)
		{
			if(maxpos != co)
			{
				iterator[co].Set(0);
				assigniter[co].Set(0);
			}
			else
			{
				assigniter[co].Set(255);
			}
		}
		for(int co = 0; co<4; co++)
		{
			++iterator[co];
			++assigniter[co];
		}
	}
	printf(" Done.\n");
}
void unmix_median(InputImageType::Pointer im[],InputImageType::Pointer om[],int n)
{
	printf("Unnmixing %d channels ...\n",n);
	InputImageType::SizeType size = im[0]->GetLargestPossibleRegion().GetSize();

	printf("I'm here\n");
	MedianFilterType::Pointer filt[15];
	IteratorType iterator[15];
	//IteratorType assigniter[15];

	InputImageType::SizeType radius;
	radius[0]=1;
	radius[1]=1;
	radius[2]=1;

	InputImageType::SizeType imagesize = im[0]->GetLargestPossibleRegion().GetSize();
	InputImageType::IndexType imageindex;
	imageindex.Fill(0);
	InputImageType::RegionType region;
	region.SetSize(imagesize);
	region.SetIndex(imageindex);

	double max_values[15];
	for(int counter=0; counter<n; counter++)
	{
		printf("\tPerforming median filtering on channel %d ...",counter+1);
		filt[counter]=MedianFilterType::New();
		filt[counter]->SetRadius(radius);
		filt[counter]->SetInput(im[counter]);
		filt[counter]->Update();
		om[counter]=filt[counter]->GetOutput();
		iterator[counter]=IteratorType(om[counter],om[counter]->GetLargestPossibleRegion());
		iterator[counter].GoToBegin();
		max_values[counter]=-1;
		printf(" Done %d.\n",counter+1);
		for(;!iterator[counter].IsAtEnd();++iterator[counter])
		{
			if(max_values[counter]<iterator[counter].Value())
				max_values[counter] = iterator[counter].Value();

		}
		//	printf("Max%d = %lf\n",counter,max_values[counter]);
		iterator[counter].GoToBegin();
	}

	//int total_voxels = size[0]*size[1]*size[2];
	int num_processed = 0;
	printf("\tComputing maximum among channels ... ");
	for(;!iterator[0].IsAtEnd();)
	{
		num_processed++;
		/*
		if(num_processed % 100 ==0)
		printf("Processed %0.2lf%% voxels\r",100.0/total_voxels*num_processed);
		*/
		//		if(100.0/total_voxels*num_processed> 100)
		//			break;
		double max = -1;
		int maxpos = -1;
		for(int co = 0; co < n; co++)
		{
			double temp = iterator[co].Value();///max_values[co];
			if(max < temp)
			{
				max = temp;
				maxpos = co;
			}
		}
		for(int co = 0; co < n; co++)
		{
			if(maxpos != co)
			{
				iterator[co].Set(0);
			}
		}
		for(int co = 0; co<n; co++)
		{
			++iterator[co];

		}
	}
	printf(" Done.\n");
}
void get_tiles(InputImageType::RegionType inputr, int tilesizex, int tilesizey, int tilesizez, int borderx, int bordery, int borderz, std::vector<InputImageType::RegionType> &in1, std::vector<InputImageType::RegionType> &in2, std::vector<InputImageType::RegionType> &out1, std::vector<InputImageType::RegionType> &out2)
{
	
	int xsize = inputr.GetSize()[0];
	int ysize = inputr.GetSize()[1];
	int zsize = inputr.GetSize()[2];

	int kx = 0;int ky = 0;int kz = 0;

	kx = xsize /(tilesizex-borderx);
	ky = ysize /(tilesizey-bordery);
	kz = zsize /(tilesizez-borderz);

	int remx = xsize % (tilesizex-borderx);
	int remy = ysize % (tilesizey-bordery);
	int remz = zsize % (tilesizez-borderz);

	if ( remx > 0 )
		kx ++;
	if ( remy > 0 )
		ky ++;
	if ( remz > 0 )
		kz ++;

	for(int xco = 0; xco < kx; xco++)
	{
		for(int yco = 0; yco < ky; yco++)
		{
			for(int zco = 0; zco < kz; zco++)
			{
				InputImageType::SizeType imsize = inputr.GetSize();
				InputImageType::IndexType index;
				InputImageType::SizeType size;


				index.Fill(0);
				size[0] = MIN((xco)*(tilesizex-borderx)+tilesizex-1,imsize[0]-1) -  xco * (tilesizex-borderx) +1;
				size[1] = MIN((yco)*(tilesizey-bordery)+tilesizey-1,imsize[1]-1) -  yco * (tilesizey-bordery) +1;
				size[2] = MIN((zco)*(tilesizez-borderz)+tilesizez-1,imsize[2]-1) -  zco * (tilesizez-borderz) +1;

				InputImageType::RegionType region;
				region.SetIndex(index);
				region.SetSize(size);
				in2.push_back(region);

				InputImageType::RegionType region1;
				index[0] = xco *(tilesizex-borderx);
				index[1] = yco *(tilesizey-bordery);
				index[2] = zco *(tilesizez-borderz);
				region1.SetIndex(index);
				region1.SetSize(size);
				in1.push_back(region1);


				if(xco != 0)
				{
					size[0] = size[0] - borderx/2;
					index[0] = borderx/2;
				}
				if(xco != kx-1)
				{
					size[0] = size[0] - borderx/2;
				}

				if(yco != 0)
				{
					size[1] = size[1] - bordery/2;
					index[1] = bordery/2;
				}
				if(yco != ky-1)
				{
					size[1] = size[1] - bordery/2;
				}

				if(zco != 0)
				{
					size[2] = size[2] - borderz/2;
					index[2] = borderz/2;
				}
				if(zco != kz-1)
				{
					size[2] = size[2] - borderz/2;
				}
				region.SetIndex(index);
				region.SetSize(size);

				out2.push_back(region);

				if(xco!=0)
				{
					index[0] = xco *(tilesizex-borderx)+borderx/2;
				}
				if(yco!=0)
				{
					index[1] = yco *(tilesizey-bordery)+bordery/2;
				}
				if(zco!=0)
				{
					index[2] = zco *(tilesizez-borderz)+borderz/2;
				}
				region1.SetIndex(index);
				region1.SetSize(size);
				out1.push_back(region1);
			}
		}
	}
}
vtkSmartPointer<vtkPolyData> getVTKPolyDataPrecise(LabelImageType::Pointer label)
{
	LabelIteratorType liter = LabelIteratorType(label,label->GetLargestPossibleRegion());
	liter.GoToBegin();

	//find the maximum number of cells
	unsigned short max1 = 0;
	for(liter.GoToBegin();!liter.IsAtEnd();++liter)
		max1 = MAX(max1,liter.Get());

	//find all the cubes in which cells lie
	cubecoord* carray = new cubecoord[max1+1];
	for(int counter=0; counter<=max1; counter++)
	{
		carray[counter].sx=60000; carray[counter].sy=60000;carray[counter].sz=60000;
		carray[counter].ex=0;carray[counter].ey=0;carray[counter].ez=0;
	}

	typedef itk::ImageRegionConstIteratorWithIndex<LabelImageType> ConstLabelIteratorWithIndex;
	ConstLabelIteratorWithIndex cliter = ConstLabelIteratorWithIndex(label,label->GetLargestPossibleRegion());
	InputImageType::IndexType index;
	for(cliter.GoToBegin();!cliter.IsAtEnd();++cliter)
	{
		int cur = cliter.Get();
		if(cur!=0)
		{
			index = cliter.GetIndex();
			carray[cur].sx= MIN(index[0],carray[cur].sx);
			carray[cur].sy= MIN(index[1],carray[cur].sy);
			carray[cur].sz= MIN(index[2],carray[cur].sz);
			carray[cur].ex= MAX(index[0],carray[cur].ex);
			carray[cur].ey= MAX(index[1],carray[cur].ey);
			carray[cur].ez= MAX(index[2],carray[cur].ez);
		}
	}

	//find the largest image size we need
	unsigned short wx=0,wy=0,wz=0;
	for(int counter=1; counter<=max1; counter++)
	{
		wx = MAX(carray[counter].ex-carray[counter].sx+1,wx);
		wy = MAX(carray[counter].ey-carray[counter].sy+1,wy);
		wz = MAX(carray[counter].ez-carray[counter].sz+1,wz);
	}
	// accommodate padding
	wx = wx+2;wy = wy +2; wz = wz+2;
	printf("wx wy wz %u %u %u\n",wx,wy,wz);
	// create a tiny image of maximum size


	//appendfilter->UserManagedInputsOn();
	//appendfilter->SetNumberOfInputs(max1);
	vtkSmartPointer<vtkAppendPolyData> appendfilter = vtkSmartPointer<vtkAppendPolyData>::New();

/**************/
			ExportFilterType::Pointer itkexporter = ExportFilterType::New();
			
			vtkSmartPointer<vtkImageImport> vtkimporter = vtkSmartPointer<vtkImageImport>::New();
			ConnectPipelines(itkexporter,(vtkImageImport *)vtkimporter);
			vtkSmartPointer<vtkMarchingCubes> contourf = vtkSmartPointer<vtkMarchingCubes>::New();
			contourf->SetInputData(vtkimporter->GetOutput());
			contourf->SetValue(0,127);
			contourf->ComputeNormalsOff();
			contourf->ComputeScalarsOff();
			contourf->ComputeGradientsOff();
			vtkSmartPointer<vtkSmoothPolyDataFilter> smoothf = vtkSmartPointer<vtkSmoothPolyDataFilter>::New();
			smoothf->SetInputData(contourf->GetOutput());
			smoothf->SetRelaxationFactor(0.3);
			smoothf->SetNumberOfIterations(20);

			vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
			transform->PostMultiply();
	
			transform->Identity();
			vtkSmartPointer<vtkTransformPolyDataFilter> tf = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
			tf->SetTransform(transform);
			tf->SetInputData(smoothf->GetOutput());
		
/******************/



InputImageType::Pointer t = getEmpty(wx,wy,wz);
	for(int counter=1; counter<=max1; counter++)
	{

		
			
			//printf("Maximum tiny image size I need is [%d %d %d]\n",wx,wy,wz);

			if(carray[counter].sx > 59999)
				continue;
			printf("Working..\n");
	//		scanf("%*d");
			InputImageType::SizeType size;
			InputImageType::RegionType region;
			index.Fill(1);

			region.SetIndex(index);
			region.SetSize(size);


			LabelImageType::SizeType lsize;
			LabelImageType::IndexType lindex;
			LabelImageType::RegionType lregion;

			itkexporter->SetInput(t);

			
			
		

			t->FillBuffer(0);
			lsize[0] = carray[counter].ex-carray[counter].sx+1;
			lsize[1] = carray[counter].ey-carray[counter].sy+1;
			lsize[2] = carray[counter].ez-carray[counter].sz+1;

			lindex[0] = carray[counter].sx;
			lindex[1] = carray[counter].sy;
			lindex[2] = carray[counter].sz;

			lregion.SetIndex(lindex);
			lregion.SetSize(lsize);
			LabelIteratorType localiter = LabelIteratorType(label,lregion);

			size = lsize;
			region.SetSize(size);
			IteratorType iter = IteratorType(t,region);
			for(localiter.GoToBegin(),iter.GoToBegin();!localiter.IsAtEnd();++localiter,++iter)
			{
				if(localiter.Get()==counter)
				{
					iter.Set(255);
				}
			}
			t->Modified();
			vtkimporter->Modified();

			transform->Identity();	
			transform->Translate(carray[counter].sx-1,carray[counter].sy-1,carray[counter].sz-1);
			tf->SetTransform(transform);
			tf->Update();
		vtkSmartPointer<vtkPolyData> pol=vtkSmartPointer<vtkPolyData>::New();
		pol->DeepCopy(tf->GetOutput());
	//	tf->GetOutput()->Print(std::cout);
		
		appendfilter->AddInputData(pol);
		//appendfilter->Update();
	
		//appendfilter->SetInputByNumber(counter-1,tf->GetOutput());
	//	appendfilter->Update();
	//	appendfilter->GetOutput()->Print(std::cout);
		//if(counter>500)
		//	break;
		printf("Completed %d/%d\r",counter,max1);
	//	scanf("%*d");
	}

	appendfilter->Update();
	vtkSmartPointer<vtkDecimatePro> decimate = vtkSmartPointer<vtkDecimatePro>::New();
	decimate->SetInputData(appendfilter->GetOutput());
	decimate->SetTargetReduction(0.1);
	//decimate->SetNumberOfDivisions(32,32,32);
	printf("Decimating the contours...");
	decimate->Update();
	printf("Done\n");
	printf("Smoothing the contours after decimation...");
	vtkSmartPointer<vtkSmoothPolyDataFilter> smoothfinal = vtkSmartPointer<vtkSmoothPolyDataFilter>::New();
	smoothfinal->SetRelaxationFactor(0.2);
	smoothfinal->SetInputData(decimate->GetOutput());
	smoothfinal->SetNumberOfIterations(0);
	smoothfinal->Update();
	printf("Done\n");
	delete [] carray;
	vtkSmartPointer<vtkPolyData> out = smoothfinal->GetOutput();
	return out;
}
InputImageType::Pointer Curvelet::RunOnInputImage(InputImageType::Pointer InputImage)
{
	//InputImage = NewInputImage;
	slices = InputImage->GetLargestPossibleRegion().GetSize()[2];
	InputImageType::Pointer outputim = InputImageType::New();
	outputim->SetRegions(InputImage->GetLargestPossibleRegion());
	outputim->Allocate();
	FloatImageType::Pointer cosim = FloatImageType::New();
	cosim->SetRegions(InputImage->GetLargestPossibleRegion());
	cosim->Allocate();
	FloatImageType::Pointer sinim = FloatImageType::New();
	sinim->SetRegions(InputImage->GetLargestPossibleRegion());
	sinim->Allocate();

	if(outputim->GetBufferPointer() == NULL || cosim->GetBufferPointer() == NULL || sinim->GetBufferPointer() == NULL)
	{
		printf("Couldnt' allocate memory - 3.. going to crash now\n");
	}
	int max_dim = tile_size;


	int xsize = InputImage->GetLargestPossibleRegion().GetSize()[0];
	int ysize = InputImage->GetLargestPossibleRegion().GetSize()[1];

	int kx = 0;int ky = 0;


	kx = xsize /(max_dim-this->border);
	ky = ysize /(max_dim-this->border);

	int remx = xsize % (max_dim-this->border);
	int remy = ysize % (max_dim-this->border);

	if ( remx > 0 )
		kx ++;
	if ( remy > 0 )
		ky ++;

	for(int xco = 0; xco < kx; xco++)
	{
		for(int yco = 0; yco < ky; yco++)
		{

			InputImageType::SizeType imsize = InputImage->GetLargestPossibleRegion().GetSize();
			InputImageType::IndexType index;
			InputImageType::SizeType size;
			InputImageType::RegionType region;

			index.Fill(0);
			size[0] =  MIN((xco)*(max_dim-this->border)+max_dim-1,imsize[0]-1) -  xco * (max_dim-this->border) +1;
			size[1] =  MIN((yco)*(max_dim-this->border)+max_dim-1,imsize[1]-1) -  yco * (max_dim-this->border) +1;
			size[2] = imsize[2];

			InputImageType::Pointer imtile = InputImageType::New();
			region.SetIndex(index);
			region.SetSize(size);
			imtile->SetRegions(region);
			imtile->Allocate();
			if(imtile->GetBufferPointer()==NULL)
				printf("Couldn't allocate memory - 4 .. going to crash now\n");
			InputImageType::RegionType region1;
			index[0] = xco *(max_dim-this->border);
			index[1] = yco *(max_dim-this->border);
			index[2] = 0;
			region1.SetIndex(index);
			region1.SetSize(size);

			typedef itk::ImageRegionIterator<InputImageType> IteratorType;
			IteratorType iter1(InputImage,region1);
			IteratorType iter2(imtile,region);


			//printf("xco = %d yco = %d :\n",xco,yco);
			region1.Print(std::cout);
			region.Print(std::cout);

			iter1.GoToBegin();
			iter2.GoToBegin();
			for(;!iter1.IsAtEnd();++iter1,++iter2)
			{
				iter2.Set(iter1.Get());
			}


			InputImageType::Pointer outputtile = InputImageType::New();
			outputtile->SetRegions(imtile->GetLargestPossibleRegion());
			outputtile->Allocate();
			FloatImageType::Pointer cosimtile = FloatImageType::New();
			cosimtile->SetRegions(imtile->GetLargestPossibleRegion());
			cosimtile->Allocate();
			FloatImageType::Pointer sinimtile = FloatImageType::New();
			sinimtile->SetRegions(imtile->GetLargestPossibleRegion());
			sinimtile->Allocate();
			if(outputtile->GetBufferPointer() == NULL || cosimtile->GetBufferPointer()==NULL || sinimtile->GetBufferPointer() == NULL )
			{
				printf("Couldn't allocate memory - 5 .. going to crash now ..\n");
			}

			{
#pragma omp parallel for shared(cosimtile,imtile,sinimtile,outputtile)  num_threads(numt)
				for(int counter = 0; counter < slices; counter++)
				{
					//printf("Counter = %d\n",counter);
					Input2DImageType::Pointer im2d = getSlice(imtile,counter);
					Input2DImageType::Pointer om2d;
					Float2DImageType::Pointer cosim2d,sinim2d;
					//call single slice 2-d curvelets function
					getCurveletsForOneSlice(im2d,om2d,cosim2d,sinim2d);
					copyslice<InputPixelType>(om2d,outputtile,counter);
					copyslice<float>(cosim2d,cosimtile,counter);
					copyslice<float>(sinim2d,sinimtile,counter);
				}
			}
			
			//printf("copying the tile\n");
			if(xco != 0)
			{
				size[0] = size[0] - border/2;
				index[0] = border/2;
			}
			if(xco != kx-1)
			{
				size[0] = size[0] - border/2;
			}

			if(yco != 0)
			{
				size[1] = size[1] - border/2;
				index[1] = border/2;
			}
			if(yco != ky-1)
			{
				size[1] = size[1] - border/2;
			}
			size[2] = slices;
			index[2] = 0;


			region.SetIndex(index);
			region.SetSize(size);
			
			if(xco!=0)
			{
				index[0] = xco *(max_dim-border)+border/2;
			}
			if(yco!=0)
			{
				index[1] = yco *(max_dim-border)+border/2;
			}
			
			
			index[2] = 0;
			region1.SetSize(size);
			region1.SetIndex(index);

			iter1 = IteratorType(outputim,region1);
			iter2 = IteratorType(outputtile,region);
			typedef itk::ImageRegionIterator<FloatImageType> FIteratorType;
			FIteratorType iter3(cosim,region1);
			FIteratorType iter4(cosimtile,region);
			FIteratorType iter5(sinim,region1);
			FIteratorType iter6(sinimtile, region);

			iter1.GoToBegin();iter2.GoToBegin();
			iter3.GoToBegin();iter4.GoToBegin();
			iter5.GoToBegin();iter6.GoToBegin();

			for(;!iter1.IsAtEnd();++iter1,++iter2,++iter3,++iter4,++iter5,++iter6)
			{
				iter1.Set(iter2.Get());
				iter3.Set(iter4.Get());
				iter5.Set(iter6.Get());
			}
			//printf("Done with copying the tile to full image\n");
		}
	}
	return outputim;
}
void unmix_threshold(InputImageType::Pointer im[],InputImageType::Pointer om[],int n,int GFP_channel,int AF_channel, int thresh)
{
	printf("Unnmixing %d channels ...\n",n);
	InputImageType::SizeType size = im[0]->GetLargestPossibleRegion().GetSize();

	printf("I'm here\n");
	MedianFilterType::Pointer filt[15];
	IteratorType iterator[15];
	//IteratorType assigniter[15];

	InputImageType::SizeType radius;
	radius[0]=1;
	radius[1]=1;
	radius[2]=1;

	InputImageType::SizeType imagesize = im[0]->GetLargestPossibleRegion().GetSize();
	InputImageType::IndexType imageindex;
	imageindex.Fill(0);
	InputImageType::RegionType region;
	region.SetSize(imagesize);
	region.SetIndex(imageindex);

	double max_values[15];
	for(int counter=0; counter<n; counter++)
	{
		printf("\tPerforming median filtering on channel %d ...",counter+1);
		filt[counter]=MedianFilterType::New();
		filt[counter]->SetRadius(radius);
		filt[counter]->SetInput(im[counter]);
		filt[counter]->Update();
		om[counter]=filt[counter]->GetOutput();
		iterator[counter]=IteratorType(om[counter],om[counter]->GetLargestPossibleRegion());
		iterator[counter].GoToBegin();
		max_values[counter]=-1;
		printf(" Done %d.\n",counter+1);
		for(;!iterator[counter].IsAtEnd();++iterator[counter])
		{
			if(max_values[counter]<iterator[counter].Value())
				max_values[counter] = iterator[counter].Value();

		}
		//	printf("Max%d = %lf\n",counter,max_values[counter]);
		iterator[counter].GoToBegin();
	}
	
	printf("Binarizing the Autofluoroscence Channel\n");
	ThresholdFilterType::Pointer tfilter = ThresholdFilterType::New();
	tfilter->SetInput(om[AF_channel]);
	tfilter->SetLowerThreshold(thresh);
	tfilter->SetUpperThreshold(255);
	tfilter->SetInsideValue(255);
	tfilter->SetOutsideValue(0);
	om[AF_channel] = tfilter->GetOutput();
	tfilter->Update();
	
	//int total_voxels = size[0]*size[1]*size[2];
	int num_processed = 0;
	
	//Removing Small components
	om[AF_channel] = getLargeComponents(om[AF_channel],thresh);

	printf("\tComputing foreground in AF channel ... ");
	for(;!iterator[0].IsAtEnd();)
	{
		num_processed++;
		unsigned char temp = iterator[2].Value();///max_values[co];
		if(temp > 0)
			{
				iterator[GFP_channel].Set(0);
				//iterator[0].Set(0);
			}
		
		for(int co = 0; co<n; co++)
		{
			++iterator[co];

		}
	}
	printf(" Done.\n");
}