예제 #1
0
void WholeCellSeg::BinarizationForRealBounds(){
	if( !nuc_im_set || !cyt_im_set ){
		std::cerr<<"Complete segmenting nuclei and set input imge before starting segmentation\n";
		return;
	}

	itk::SizeValueType size1=cyt_im_inp->GetLargestPossibleRegion().GetSize()[0];
	itk::SizeValueType size2=cyt_im_inp->GetLargestPossibleRegion().GetSize()[1];

	if( ( size1 != nuclab_inp->GetLargestPossibleRegion().GetSize()[0] ) ||
      	    ( size2 != nuclab_inp->GetLargestPossibleRegion().GetSize()[1] ) )
	{
		std::cerr<<"The input images must be of the same size\n";
		return;
	}

	typedef unsigned short int UShortPixelType;

	typedef itk::ImageRegionIteratorWithIndex< UShortImageType > IteratorType;
	typedef itk::ImageRegionConstIterator< UShortImageType > ConstIteratorType;

	typedef itk::Statistics::ScalarImageToHistogramGenerator< IntImageType > ScalarImageToHistogramGeneratorType;
	typedef ScalarImageToHistogramGeneratorType::HistogramType HistogramType;
	typedef itk::OtsuMultipleThresholdsCalculator< HistogramType > CalculatorType;
	typedef itk::RescaleIntensityImageFilter< UShortImageType, IntImageType > RescaleUsIntType;
	typedef itk::RescaleIntensityImageFilter< UShortImageType, UShortImageType > RescaleUsUsType;
	typedef itk::BinaryThresholdImageFilter< IntImageType, UShortImageType >  ThreshFilterType;
	typedef itk::BinaryThresholdImageFilter< UShortImageType, UShortImageType >  ThresholdFilterType;
	typedef itk::OrImageFilter< UShortImageType, UShortImageType, UShortImageType > OrFilterType;
 	typedef itk::BinaryBallStructuringElement< UShortPixelType, 2 > StructuringElementType;
	typedef itk::BinaryErodeImageFilter< UShortImageType, UShortImageType, StructuringElementType > ErodeFilterType;
	typedef itk::BinaryDilateImageFilter< UShortImageType, UShortImageType, StructuringElementType > DilateFilterType;

	unsigned char *in_Image;
	itk::SizeValueType ind=0;

//Call Yousef's binarization method if the number of bin levels is < 2
	if( num_levels < 2 ){
		bin_Image = (unsigned short *) malloc (size1*size2*sizeof(unsigned short));
		for(itk::SizeValueType j=0; j<size2; ++j)
			for(itk::SizeValueType i=0; i<size1; ++i)
				BIN_Image(i,j)=255;
		in_Image = (unsigned char *) malloc (size1*size2);
		if( ( in_Image == NULL ) || ( bin_Image == NULL ) ){
			std::cerr << "Memory allocation for binarization of image failed\n";
			return;
		}

		RescaleUsUsType::Pointer rescaleususfilter = RescaleUsUsType::New();
		rescaleususfilter->SetInput( cyt_im_inp );
		rescaleususfilter->SetOutputMaximum( itk::NumericTraits<unsigned char>::max() );
		rescaleususfilter->SetOutputMinimum( 0 );
		rescaleususfilter->Update();
		UShortImageType::Pointer resc_cyt_im = UShortImageType::New();
		resc_cyt_im = rescaleususfilter->GetOutput();
		ConstIteratorType pix_buf1( resc_cyt_im, resc_cyt_im->GetRequestedRegion() );
		for ( pix_buf1.GoToBegin(); !pix_buf1.IsAtEnd(); ++pix_buf1, ++ind )
		in_Image[ind]=(unsigned char)(pix_buf1.Get());

		int ok = 0;
		ok = Cell_Binarization_2D(in_Image,bin_Image, size1, size2, shift_bin);
		free( in_Image );

		if( !ok ){
			std::cerr<<"Binarization Failed\n";
			return;
		}

//copy the output binary image into the ITK image
		intermediate_bin_im_out = UShortImageType::New();
		UShortImageType::PointType origin;
		origin[0] = 0;
		origin[1] = 0;
		intermediate_bin_im_out->SetOrigin( origin );

		UShortImageType::IndexType start;
		start[0] = 0;  // first index on X
		start[1] = 0;  // first index on Y
		UShortImageType::SizeType  size;
		size[0] = size1;  // size along X
		size[1] = size2;  // size along Y

		UShortImageType::RegionType region;
		region.SetSize( size );
		region.SetIndex( start );

		intermediate_bin_im_out->SetRegions( region );
		intermediate_bin_im_out->Allocate();
		intermediate_bin_im_out->FillBuffer(0);
		intermediate_bin_im_out->Update();

		itk::SizeValueType dum,dum1;
		dum = 0;
		dum1 = USHRT_MAX;

		//unsigned int asd,asd1; asd=0; asd1=0;
		IteratorType iterator ( intermediate_bin_im_out, intermediate_bin_im_out->GetRequestedRegion() );
		for(itk::SizeValueType i=0; i < (size1*size2); ++i){
			if( bin_Image[i] )
			iterator.Set( dum1 );
			else
			iterator.Set( dum );
			++iterator;
		}
	}
//Call multi level binarization method if the number of bin levels is >= 2
	else{
		RescaleUsIntType::Pointer rescaleusintfilter = RescaleUsIntType::New();
		ScalarImageToHistogramGeneratorType::Pointer scalarImageToHistogramGenerator = ScalarImageToHistogramGeneratorType::New();
		rescaleusintfilter->SetInput( cyt_im_inp );
		rescaleusintfilter->SetOutputMaximum( itk::NumericTraits<unsigned short>::max() );
		rescaleusintfilter->SetOutputMinimum( 0 );
		rescaleusintfilter->Update();

		ThreshFilterType::Pointer threshfilter = ThreshFilterType::New();
		CalculatorType::Pointer calculator = CalculatorType::New();
		scalarImageToHistogramGenerator->SetNumberOfBins( 255 );
		calculator->SetNumberOfThresholds( num_levels );
		threshfilter->SetOutsideValue( (int)0 );
		threshfilter->SetInsideValue( (int)USHRT_MAX );
		scalarImageToHistogramGenerator->SetInput( rescaleusintfilter->GetOutput() );
		scalarImageToHistogramGenerator->Compute();
		calculator->SetInputHistogram( scalarImageToHistogramGenerator->GetOutput() );
		threshfilter->SetInput( rescaleusintfilter->GetOutput() );
		calculator->Update();
		const CalculatorType::OutputType &thresholdVector = calculator->GetOutput();
		CalculatorType::OutputType::const_iterator itNum = thresholdVector.begin();
		int lowerThreshold,upperThreshold;

		for( int i=0; i<(num_levels-num_levels_incl); ++i ) ++itNum;
		lowerThreshold = static_cast<unsigned short>(*itNum);
		upperThreshold = itk::NumericTraits<unsigned short>::max();

		threshfilter->SetLowerThreshold( lowerThreshold );
		threshfilter->SetUpperThreshold( upperThreshold );
		threshfilter->Update();

		intermediate_bin_im_out = UShortImageType::New();
		intermediate_bin_im_out = threshfilter->GetOutput();
	}

//Fill holes left by the nuclei
	ThresholdFilterType::Pointer binarythreshfilter = ThresholdFilterType::New();
	binarythreshfilter->SetInsideValue( USHRT_MAX );
	binarythreshfilter->SetOutsideValue( 0 );
	binarythreshfilter->SetLowerThreshold( 1 );
	binarythreshfilter->SetUpperThreshold( USHRT_MAX );
	binarythreshfilter->SetInput( nuclab_inp );
	OrFilterType::Pointer orfilter = OrFilterType::New();
	orfilter->SetInput1( binarythreshfilter->GetOutput() );
	orfilter->SetInput2( intermediate_bin_im_out );
//dialate and erode
	ErodeFilterType::Pointer  binaryErode  = ErodeFilterType::New();
	DilateFilterType::Pointer binaryDilate = DilateFilterType::New();
	StructuringElementType  structuringElement;
	structuringElement.SetRadius( 3 );  // 3x3 structuring element
	structuringElement.CreateStructuringElement();
	binaryErode->SetKernel( structuringElement );
	binaryErode->SetErodeValue( USHRT_MAX );
	binaryDilate->SetDilateValue( USHRT_MAX );
	binaryDilate->SetKernel( structuringElement );
	binaryErode->SetInput( binaryDilate->GetOutput() );
	binaryDilate->SetInput( orfilter->GetOutput() );
//erode and dialate
	ErodeFilterType::Pointer  binaryErode1  = ErodeFilterType::New();
	DilateFilterType::Pointer binaryDilate1 = DilateFilterType::New();
	binaryErode1->SetKernel(  structuringElement );
	binaryErode1->SetErodeValue( USHRT_MAX );
	binaryDilate1->SetDilateValue( USHRT_MAX );
	binaryDilate1->SetKernel( structuringElement );
	binaryErode1->SetInput( binaryErode->GetOutput() );
	binaryDilate1->SetInput( binaryErode1->GetOutput() );
	binaryDilate1->Update();
//Get pointer to the final binary image and return it to calling function
	UShortImageType::Pointer image_bin = UShortImageType::New();
	image_bin = binaryDilate1->GetOutput();
	bin_im_out = image_bin;
	bin_done = 1;

//Update bin array
	ind=0;
	if( draw_real_bounds ){
		ConstIteratorType pix_buf3( bin_im_out, bin_im_out->GetRequestedRegion() );
		for ( pix_buf3.GoToBegin(); !pix_buf3.IsAtEnd(); ++pix_buf3, ++ind )
		bin_Image[ind]=(pix_buf3.Get());
	}else
		free( bin_Image );
/*
	typedef itk::ImageFileWriter< UShortImageType > WriterType;
	WriterType::Pointer writer = WriterType::New();
	writer->SetFileName( "bin_info.tif" );
	writer->SetInput( bin_im_out );//RescaleIntIO1--finalO/P
	writer->Update();
*/
	return;
}
예제 #2
0
std::vector<float> compute_ec_features( USImageType::Pointer input_image,  USImageType::Pointer inp_labeled, int number_of_rois, unsigned short thresh, int surr_dist, int inside_dist ){

	std::vector< float > qfied_num;
	std::vector< USImageType::PixelType > labelsList;
	std::vector< double > quantified_numbers_cell;

	typedef itk::ExtractImageFilter< USImageType, UShortImageType > LabelExtractType;
	typedef itk::ImageRegionConstIterator< UShortImageType > ConstIteratorType;
	typedef itk::ImageRegionIteratorWithIndex< USImageType > IteratorType;
	typedef itk::SignedDanielssonDistanceMapImageFilter<FloatImageType, FloatImageType > DTFilter;
	typedef itk::ImageRegionIteratorWithIndex< FloatImageType > IteratorTypeFloat;
	typedef itk::LabelGeometryImageFilter< USImageType > GeometryFilterType;
	typedef GeometryFilterType::LabelIndicesType labelindicestype;

	itk::SizeValueType sz_x, sz_y, sz_z;
	sz_x = input_image->GetLargestPossibleRegion().GetSize()[0];
	sz_y = input_image->GetLargestPossibleRegion().GetSize()[1];
	sz_z = input_image->GetLargestPossibleRegion().GetSize()[2];

	if( sz_x==1 || sz_y==1 || sz_z==1 ){
		LabelExtractType::Pointer deFilter = LabelExtractType::New();
		USImageType::RegionType dRegion = inp_labeled->GetLargestPossibleRegion();
		dRegion.SetSize(2,0);
		deFilter->SetExtractionRegion(dRegion);
		deFilter->SetInput( inp_labeled );
		deFilter->SetDirectionCollapseToIdentity();
		try{
			deFilter->Update();
		}
		catch( itk::ExceptionObject & excep ){
			std::cerr << "Exception caught !" << std::endl;
			std::cerr << excep << std::endl;
		}
		//Dialate input first
		WholeCellSeg *dialate_filter = new WholeCellSeg;
		dialate_filter->set_nuc_img( deFilter->GetOutput() );
		dialate_filter->set_radius( surr_dist );
		dialate_filter->RunSegmentation();
		UShortImageType::Pointer input_lab = dialate_filter->getSegPointer();

		USImageType::Pointer input_labeled = USImageType::New();
		USImageType::PointType origint;
		origint[0] = 0;
		origint[1] = 0;
		origint[2] = 0;
		input_labeled->SetOrigin( origint );
		USImageType::IndexType startt;
		startt[0] = 0;  // first index on X
		startt[1] = 0;  // first index on Y
		startt[2] = 0;  // first index on Z
		USImageType::SizeType  sizet;
		sizet[0] = inp_labeled->GetLargestPossibleRegion().GetSize()[0];  // size along X
		sizet[1] = inp_labeled->GetLargestPossibleRegion().GetSize()[1];  // size along Y
		sizet[2] = inp_labeled->GetLargestPossibleRegion().GetSize()[2];  // size along Z
		USImageType::RegionType regiont;
		regiont.SetSize( sizet );
		regiont.SetIndex( startt );
		input_labeled->SetRegions( regiont );
		input_labeled->Allocate();
		input_labeled->FillBuffer(0);
		input_labeled->Update();

		ConstIteratorType pix_buf1( input_lab, input_lab->GetRequestedRegion() );
		IteratorType iterator2 ( input_labeled, input_labeled->GetRequestedRegion() );
		iterator2.GoToBegin();
		for ( pix_buf1.GoToBegin(); !pix_buf1.IsAtEnd(); ++pix_buf1 ){
			iterator2.Set( pix_buf1.Get() );
			++iterator2;
		}

		std::vector< float > quantified_numbers;

		typedef itk::LabelGeometryImageFilter< USImageType > GeometryFilterType;
		typedef GeometryFilterType::LabelIndicesType labelindicestype;

		GeometryFilterType::Pointer geomfilt1 = GeometryFilterType::New();

		geomfilt1->SetInput( input_labeled );
		geomfilt1->SetCalculatePixelIndices( true );
		geomfilt1->Update();
		labelsList = geomfilt1->GetLabels();

		bool zp=false;
		for( USImageType::PixelType i=0; i < labelsList.size(); ++i ){
			if( labelsList[i] == 0 ){ zp=true; continue; }
			std::vector<float> quantified_numbers_cell;
			for( unsigned j=0; j<number_of_rois; ++j ) quantified_numbers_cell.push_back((float)0.0);
			double centroid_x = geomfilt1->GetCentroid(labelsList[i])[0];
			double centroid_y = geomfilt1->GetCentroid(labelsList[i])[1];
			labelindicestype indices1;
			indices1 = geomfilt1->GetPixelIndices(labelsList[i]);
			for( labelindicestype::iterator itPixind = indices1.begin(); itPixind!=indices1.end(); ++itPixind ){
				IteratorType iterator1 ( input_image, input_image->GetRequestedRegion() );
				iterator1.SetIndex( *itPixind );
				if( iterator1.Get() < thresh )
					continue;
				double x = iterator1.GetIndex()[0];
				double y = iterator1.GetIndex()[1];
				double angle = atan2((centroid_y-y),fabs(centroid_x-x));
				if( (centroid_x-x)>0 )
					angle += M_PI_2;
				else
					angle = M_PI+M_PI-(angle+M_PI_2);
				angle = ((number_of_rois-1)*angle)/(2*M_PI);
				double angle_fraction[1];
				unsigned angular_index;
				if( modf( angle, angle_fraction ) > 0.5 )
					angular_index = ceil( angle );
				else
					angular_index = floor( angle );
				
				quantified_numbers_cell[angular_index] += iterator1.Get();
			}
			for( unsigned j=0; j<number_of_rois; ++j ) quantified_numbers.push_back(quantified_numbers_cell[j]);
		}
		unsigned qnum_sz = zp? (labelsList.size()-1) : (labelsList.size());
		for( unsigned i=0; i<qnum_sz; ++i ){
			unsigned counter=0;
			for( unsigned j=0; j<number_of_rois; ++j ){
				if( quantified_numbers[(i*number_of_rois+j)] > (255.0*surr_dist) )
					++counter;
			}
			qfied_num.push_back(counter);
		}
	}
	else{
		GeometryFilterType::Pointer geomfilt1 = GeometryFilterType::New();
		geomfilt1->SetInput( inp_labeled );
		geomfilt1->SetCalculatePixelIndices( true );
		geomfilt1->Update();
		labelsList = geomfilt1->GetLabels();
		std::cout<<std::endl<<"The size is: "<<labelsList.size();
		if( labelsList.size() == 1 )
		{
			qfied_num.clear();
			return qfied_num;
		}
		bool zp=false; USPixelType zero;
		//Check if the background is also included
		for( USPixelType i=0; i<labelsList.size(); ++i ) if( labelsList[i] == 0 ){ zp=true; zero = i; }

		USImageType::SizeType  sizee;
		sizee[0] = inp_labeled->GetLargestPossibleRegion().GetSize()[0];  // size along X
		sizee[1] = inp_labeled->GetLargestPossibleRegion().GetSize()[1];  // size along Y
		sizee[2] = inp_labeled->GetLargestPossibleRegion().GetSize()[2];  // size along Z

		itk::SizeValueType roi_list_size = zp ?
					((itk::SizeValueType)number_of_rois*(labelsList.size()-1)*2) : 
					((itk::SizeValueType)number_of_rois*labelsList.size()*2);
		std::vector<double> quantified_numbers_cell((roi_list_size),0.0
			);
		std::cout<<"Bounding boxes computed"<<std::endl;

#ifdef _OPENMP
itk::MultiThreader::SetGlobalDefaultNumberOfThreads(1);
#pragma omp parallel for
#if _OPENMP < 200805L
		for( int i=0; i<labelsList.size(); ++i )
#else
		for( USImageType::PixelType i=0; i<labelsList.size(); ++i )
#endif
#else
		for( USImageType::PixelType i=0; i<labelsList.size(); ++i )
#endif
		{
			itk::SizeValueType ind;
			if( zp && (zero==i) ) continue;
			if( zp && (i>zero)  ) ind = i-1;
			else ind = i;
			//Get label indices
			labelindicestype indices1;
			double centroid_x,centroid_y,centroid_z;
			GeometryFilterType::BoundingBoxType boundbox;
			#pragma omp critical
			{
				indices1 = geomfilt1->GetPixelIndices(labelsList[i]);
				//Get Centroid
				centroid_x = geomfilt1->GetCentroid(labelsList[i])[0];
				centroid_y = geomfilt1->GetCentroid(labelsList[i])[1];
				centroid_z = geomfilt1->GetCentroid(labelsList[i])[2];
				//Create an image with bounding box + 2 * outside distance + 2
				//and get distance map for the label
				boundbox = geomfilt1->GetBoundingBox(labelsList[i]);
			}
			//Create vnl array 3xN( label indicies )
			vnl_matrix<double> B(3,indices1.size());

			FloatImageType::Pointer inp_lab = FloatImageType::New();
			FloatImageType::PointType origint; origint[0] = 0; origint[1] = 0; origint[2] = 0;
			inp_lab->SetOrigin( origint );
			FloatImageType::IndexType startt;
			startt[0] = 0;  // first index on X
			startt[1] = 0;  // first index on Y
			startt[2] = 0;  // first index on Z
			FloatImageType::SizeType  sizet;
			sizet[0] = boundbox[1]-boundbox[0]+2*surr_dist+2;  // size along X
			sizet[1] = boundbox[3]-boundbox[2]+2*surr_dist+2;  // size along Y
			sizet[2] = boundbox[5]-boundbox[4]+2*surr_dist+2;  // size along Z
			FloatImageType::RegionType regiont;
			regiont.SetSize( sizet );
			regiont.SetIndex( startt );
			inp_lab->SetRegions( regiont );
			inp_lab->Allocate();
			inp_lab->FillBuffer(0.0);
			inp_lab->Update();
			IteratorTypeFloat iterator444 ( inp_lab, inp_lab->GetRequestedRegion() );

			//Populate matrix with deviations from the centroid for principal axes and
			//at the same time set up distance-transform computation
			itk::SizeValueType ind1=0;
			for( labelindicestype::iterator itPixind = indices1.begin(); itPixind!=indices1.end(); ++itPixind ){
				IteratorType iterator3( input_image, input_image->GetRequestedRegion() );
				iterator3.SetIndex( *itPixind );
				B(0,(ind1)) = iterator3.GetIndex()[0]-centroid_x;
				B(1,(ind1)) = iterator3.GetIndex()[1]-centroid_y;
				B(2,(ind1)) = iterator3.GetIndex()[2]-centroid_z;
				FloatImageType::IndexType cur_in;
				cur_in[0] = iterator3.GetIndex()[0]-boundbox[0]+1+surr_dist;
				cur_in[1] = iterator3.GetIndex()[1]-boundbox[2]+1+surr_dist;
				cur_in[2] = iterator3.GetIndex()[2]-boundbox[4]+1+surr_dist;
				iterator444.SetIndex( cur_in );
				iterator444.Set( 255.0 );
				++ind1;
			}

			//Compute distance transform for the current object
			DTFilter::Pointer dt_obj= DTFilter::New() ;
			dt_obj->SetInput( inp_lab );
			dt_obj->SquaredDistanceOff();
			dt_obj->InsideIsPositiveOff();
			try{
				dt_obj->Update() ;
			} catch( itk::ExceptionObject & err ){
				std::cerr << "Error in Distance Transform: " << err << std::endl;
			}
			FloatImageType::Pointer dist_im = dt_obj->GetOutput();

			//Use KLT to compute pricipal axes
			vnl_matrix<double> B_transp((int)indices1.size(),3);
			B_transp = B.transpose();
			vnl_matrix<double>  COV(3,3);
			COV = B * B_transp;
			double norm = 1.0/(double)indices1.size();
			COV = COV * norm;
			//Eigen decomposition
			vnl_real_eigensystem Eyegun( COV );
			vnl_matrix<vcl_complex<double> > EVals = Eyegun.D;
			double Eval1 = vnl_real(EVals)(0,0); double Eval2 = vnl_real(EVals)(1,1); double Eval3 = vnl_real(EVals)(2,2);
			vnl_double_3x3 EVectMat = Eyegun.Vreal;
			double V1[3],V2[3],EP_norm[3];
			if( Eval1 >= Eval3 && Eval2 >= Eval3 ){
				if( Eval1 >= Eval2 ){
					V1[0] = EVectMat(0,0); V1[1] = EVectMat(1,0); V1[2] = EVectMat(2,0);
					V2[0] = EVectMat(0,1); V2[1] = EVectMat(1,1); V2[2] = EVectMat(2,1);
				} else {
					V2[0] = EVectMat(0,0); V2[1] = EVectMat(1,0); V2[2] = EVectMat(2,0);
					V1[0] = EVectMat(0,1); V1[1] = EVectMat(1,1); V1[2] = EVectMat(2,1);
				}
			} else if( Eval1 >= Eval2 && Eval3 >= Eval2 ) {
				if( Eval1 >= Eval3 ){
					V1[0] = EVectMat(0,0); V1[1] = EVectMat(1,0); V1[2] = EVectMat(2,0);
					V2[0] = EVectMat(0,2); V2[1] = EVectMat(1,2); V2[2] = EVectMat(2,2);
				} else {
					V2[0] = EVectMat(0,0); V2[1] = EVectMat(1,0); V2[2] = EVectMat(2,0);
					V1[0] = EVectMat(0,2); V1[1] = EVectMat(1,2); V1[2] = EVectMat(2,2);
				}
			} else {
				if( Eval2 >= Eval3 ){
					V1[0] = EVectMat(0,1); V1[1] = EVectMat(1,1); V1[2] = EVectMat(2,1);
					V2[0] = EVectMat(0,2); V2[1] = EVectMat(1,2); V2[2] = EVectMat(2,2);
				} else {
					V2[0] = EVectMat(0,1); V2[1] = EVectMat(1,1); V2[2] = EVectMat(2,1);
					V1[0] = EVectMat(0,2); V1[1] = EVectMat(1,2); V1[2] = EVectMat(2,2);
				}
			}
			double n_sum = sqrt( V1[0]*V1[0]+V1[1]*V1[1]+V1[2]*V1[2] );
			V1[0] /= n_sum; V1[1] /= n_sum; V1[2] /= n_sum;
			n_sum = sqrt( V2[0]*V2[0]+V2[1]*V2[1]+V2[2]*V2[2] );
			V2[0] /= n_sum; V2[1] /= n_sum; V2[2] /= n_sum;
			//Get the normal to the plane formed by the biggest two EVs
			EP_norm[0] = V1[1]*V2[2]-V1[2]*V2[1];
			EP_norm[1] = V1[2]*V2[0]-V1[0]*V2[2];
			EP_norm[2] = V1[0]*V2[1]-V1[1]*V2[0];
			//Reassign V2 so that it is orthogonal to both EP_norm and V1
			V2[0] = V1[1]*EP_norm[2]-V1[2]*EP_norm[1];
			V2[1] = V1[2]*EP_norm[0]-V1[0]*EP_norm[2];
			V2[2] = V1[0]*EP_norm[1]-V1[1]*EP_norm[0];
			//Now we have the point normal form; EP_norm is the normal and
			//centroid_x, centroid_y, centroid_z is the point
			//The equation to the plane is EP_norm[0](x-centroid_x)+EP_norm[1](y-centroid_y)+EP_norm[2](z-centroid_z)=0
			double dee = (centroid_x*EP_norm[0]+centroid_y*EP_norm[1]+centroid_z*EP_norm[2])*(-1.00);

			//Iterate through and assign values to each region
			typedef itk::ImageRegionConstIterator< FloatImageType > ConstIteratorTypeFloat;
			ConstIteratorTypeFloat pix_buf2( dist_im, dist_im->GetRequestedRegion() );
			IteratorType iterator44( input_image, input_image->GetRequestedRegion() );

			for ( pix_buf2.GoToBegin(); !pix_buf2.IsAtEnd(); ++pix_buf2 ){
				//Use pixels that are only within the defined radius from the nucleus
				double current_distance = pix_buf2.Get();
				if( (current_distance <= (double)surr_dist) && (current_distance>=(-1*inside_dist)) ){
					USImageType::IndexType cur_in;//,cur_in_cpy;
					double n_vec[3];
					cur_in[0] = pix_buf2.GetIndex()[0]+boundbox[0]-1-surr_dist;
					cur_in[1] = pix_buf2.GetIndex()[1]+boundbox[2]-1-surr_dist;
					cur_in[2] = pix_buf2.GetIndex()[2]+boundbox[4]-1-surr_dist;
					//cur_in_cpy[0] = cur_in[0]; cur_in_cpy[1] = cur_in[1]; cur_in_cpy[2] = cur_in[2];
					if( cur_in[0] < 0 || cur_in[1] < 0 || cur_in[2] < 0 ) continue;
					if( cur_in[0] >= sizee[0] || cur_in[1] >= sizee[1] || cur_in[2] >= sizee[2] ) continue;
					iterator44.SetIndex( cur_in );
					USImageType::PixelType pixel_intensity;
					pixel_intensity = iterator44.Get();
					if( pixel_intensity < thresh ) continue;

					//The projection of the point on the plane formed by the fist two major axes
					double xxx, yyy, zzz;
					xxx = cur_in[0] - EP_norm[0]*((EP_norm[0]*cur_in[0]+EP_norm[1]*cur_in[1]+EP_norm[2]*cur_in[2]+dee)
									/(EP_norm[0]*EP_norm[0]+EP_norm[1]*EP_norm[1]+EP_norm[2]*EP_norm[2]));
					yyy = cur_in[1] - EP_norm[1]*((EP_norm[0]*cur_in[0]+EP_norm[1]*cur_in[1]+EP_norm[2]*cur_in[2]+dee)
									/(EP_norm[0]*EP_norm[0]+EP_norm[1]*EP_norm[1]+EP_norm[2]*EP_norm[2]));
					zzz = cur_in[2] - EP_norm[2]*((EP_norm[0]*cur_in[0]+EP_norm[1]*cur_in[1]+EP_norm[2]*cur_in[2]+dee)
									/(EP_norm[0]*EP_norm[0]+EP_norm[1]*EP_norm[1]+EP_norm[2]*EP_norm[2]));
					//The vector from the centroid to the projected point
					n_vec[0] = centroid_x-xxx;
					n_vec[1] = centroid_y-yyy;
					n_vec[2] = centroid_z-zzz;
					n_sum = sqrt( n_vec[0]*n_vec[0] + n_vec[1]*n_vec[1] + n_vec[2]*n_vec[2] );
					n_vec[0] /= n_sum; n_vec[1] /= n_sum; n_vec[2] /= n_sum;
					//n_vec is the normalized vect in the direction of the projected point
					//V1 is the largest eigenvector
					//Get the dot and cross product between the two
					double doooot, crooos,fin_est_angle;
					doooot = n_vec[0]*V1[0]+n_vec[1]*V1[1]+n_vec[2]*V1[2];
					crooos = n_vec[0]*V2[0]+n_vec[1]*V2[1]+n_vec[2]*V2[2];

					fin_est_angle = atan2( crooos, doooot );
					USPixelType bin_num;
					//Compute bin num
					if( fin_est_angle<0 )
						fin_est_angle += (2*M_PI);
					bin_num = floor(fin_est_angle*number_of_rois/(2*M_PI));

					//Check which side of the plane the point lies on
					double v_norm = (cur_in[0]-centroid_x)*(cur_in[0]-centroid_x)
									+(cur_in[1]-centroid_y)*(cur_in[1]-centroid_y)
									+(cur_in[2]-centroid_z)*(cur_in[2]-centroid_z);
					v_norm = sqrt( v_norm );
					double doot   = (cur_in[0]-centroid_x)*EP_norm[0]/v_norm + (cur_in[1]-centroid_y)*EP_norm[1]/v_norm + (cur_in[2]-centroid_z)*EP_norm[2]/v_norm;

					if( doot<0 )
						bin_num += number_of_rois;
					quantified_numbers_cell.at((ind*(2*number_of_rois)+bin_num)) += pixel_intensity;
				}
			}
		}
		number_of_rois = number_of_rois*2;
		if( labelsList.size() == 1 )
		{
			qfied_num.clear();
			return qfied_num;
		}
		std::vector<double> quantified_numbers_cell_cpy(roi_list_size);
		std::copy(quantified_numbers_cell.begin(), quantified_numbers_cell.end(), quantified_numbers_cell_cpy.begin() );
		//Run k-means
		//Most of the code is adapted from mul/mbl/mbl_k_means.cxx
		std::sort(quantified_numbers_cell.begin(), quantified_numbers_cell.end());
	
		bool skipKmeans;
		double Positive_thresh;
		if( quantified_numbers_cell.at(0) == quantified_numbers_cell.at(quantified_numbers_cell.size()-1) )
			skipKmeans = true;

		if( !skipKmeans ){
			std::cout<<"Starting k-means\n";
			std::cout<<"First:"<<quantified_numbers_cell.at(0)<<" Last:"<<quantified_numbers_cell.at(quantified_numbers_cell.size()-1)<<std::endl;
			unsigned k = 2;
			//Vectors and matrices for k-means
			std::vector< USImageType::PixelType > partition( roi_list_size, 0 );
			std::vector< double > sums   ( k, 0.0 );
			std::vector< double > centers( k, 0.0 );
			std::vector< USImageType::PixelType > nNearest( k, 0 );

			//Use the elements that are evenly spaced to get the intial centers
			for( unsigned i=0; i<k; ++i ){
				double index = ((double)(i)*roi_list_size)/(k+1);
				centers.at(i) = quantified_numbers_cell.at((itk::SizeValueType)index);
				bool duplicated;
				std::cout<<"Initializing centers\n"<<std::flush;
				if(i){
					if( centers.at((i-1)) == centers.at(i) ){
						duplicated = true;
						itk::SizeValueType ind=i+1;
						while( centers.at((i-1))==quantified_numbers_cell.at(ind) )
							++ind;
						centers.at(i) = quantified_numbers_cell.at(ind);
						sums.at(i)    = quantified_numbers_cell.at(ind);
					}
				}
				if(!duplicated)
					sums.at(i) = quantified_numbers_cell.at((i+1)/(k+1));
				++nNearest[i];
			}

			bool changed = true;
			std::cout<<"Waiting for kmeans to converge\n"<<std::flush;
			while(changed){
				changed = false;
				for(itk::SizeValueType i=0; i<roi_list_size; ++i){
					unsigned bestCentre = 0;
					double bestDist = fabs((centers.at(0)-quantified_numbers_cell.at(i)));
					for(unsigned j=1; j<k; ++j){
						double dist = fabs((centers.at(j)-quantified_numbers_cell.at(i)));
						if( dist < bestDist ){
							bestDist = dist; bestCentre = j;
						}
					}
					sums[bestCentre] += quantified_numbers_cell.at(i);
					++ nNearest[bestCentre];
					if( bestCentre != partition.at(i) ){
						changed = true;
						partition.at(i) = bestCentre;
					}
				}
				for( unsigned j=0; j<k; ++j) centers.at(j)  = sums.at(j)/nNearest.at(j);
				for( unsigned j=0; j<k; ++j) sums.at(j)     = 0;
				for( unsigned j=0; j<k; ++j) nNearest.at(j) = 0;
			}
			for( unsigned i=0; i<k; ++i )
				std::cout<<"Center "<<i<<" "<<centers.at(i)<<"\n";

			Positive_thresh = ((centers.at(0)+centers.at(1))/2) < (255.0*thresh)?
						 ((centers.at(0)+centers.at(1))/2) : (255.0*thresh); //Arbitrary upper thresh
		}
		else
			Positive_thresh = 255.0*thresh;

		std::cout<<"Positive_thresh "<<Positive_thresh<<"\n";

		std::cout<<"Done k-means\n";
		itk::SizeValueType ind = 0;
		for( USPixelType i=0; i<labelsList.size(); ++i ){
			if( zp && (zero==i) ) continue;
			int num_positive_rois = 0;
			for( unsigned j=0; j<number_of_rois; ++j ){
				itk::SizeValueType index_of_roi = ind*number_of_rois+j;
				if( quantified_numbers_cell_cpy.at(index_of_roi)>Positive_thresh )
					++num_positive_rois;
			}
			qfied_num.push_back(num_positive_rois);
			++ind;
		}
	}
	std::cout<<"Done surroundedness\n"<<std::flush;
	return qfied_num;
}