src/main/java/sc/fiji/pQCT/selectroi/RoiSelector.java
private Vector<Object> traceGradient(final double[] scaledImage,
		final byte[] result, final double threshold, int i, int j)
	{
		double[] sobel = ScaledImageData.sobel(scaledImage,width,height);	//Get the gradient image for tracing
		
	
		/*
		//Considered using a multiplication of the gradient and the image, tunred out not to be a good idea
		double[] toTrace = new double[scaledImage.length];	//Combine gradient and intensity information to stay on gray scale if gradient disappears?
		for (int ii = 0;ii<toTrace.length;++ii){
			toTrace[ii] = scaledImage[ii]*sobel[ii];
		}
		*/
		
		final ArrayList<Integer> iit = new ArrayList<Integer>();
		final ArrayList<Integer> jiit = new ArrayList<Integer>();
		iit.add(i);
		jiit.add(j);
		// begin by advancing right. Positive angles rotate the direction clockwise.
		double direction = 0;
		final int initI;
		final int initJ;
		initI = i;
		initJ = j;
		double[] weights = new double[]{0.2,0.8,1.0,1,0.8,0.5,0.1};	//Weight the counter clockwise tracking more heavily
		double[] directions = new double[]{-Math.PI*3d / 4d,  -Math.PI*2d / 4d, -Math.PI*1d / 4d, 0d ,
											Math.PI*1d / 4d, Math.PI*2d / 4d, Math.PI*3d / 4d};

		double[] values = new double[directions.length];
		double[] bmds = new double[directions.length];
		
		while (true) {
			int counter = 0;
			
			
			
			//Get the values of the pixels in the direction of travel
			int[][] toCheck = new int[][]{
											{(int) Math.round(Math.cos(direction+directions[0])),(int) Math.round(Math.sin(direction+directions[0]))},	
											{(int) Math.round(Math.cos(direction+directions[1])),(int) Math.round(Math.sin(direction+directions[1]))},	
											{(int) Math.round(Math.cos(direction+directions[2])),(int) Math.round(Math.sin(direction+directions[2]))},	
											{(int) Math.round(Math.cos(direction+directions[3])),(int) Math.round(Math.sin(direction+directions[3]))},	
											{(int) Math.round(Math.cos(direction+directions[4])),(int) Math.round(Math.sin(direction+directions[4]))},	
											{(int) Math.round(Math.cos(direction+directions[5])),(int) Math.round(Math.sin(direction+directions[5]))},	
											{(int) Math.round(Math.cos(direction+directions[6])),(int) Math.round(Math.sin(direction+directions[6]))}	
											};
											
			// Look for valid boundary pixel. If one is found, ignore the rest
			boolean routeFound = false;
			int selectInd = 0;
			for (int t = 0; t<toCheck.length;++t){
				
				
				//values[t] = i+toCheck[t][0] < width & i+toCheck[t][0] > -1 &
				//			j+toCheck[t][1] < height & j+toCheck[t][1] > -1 ? toTrace[i+toCheck[t][0]+(j+toCheck[t][1])*width]*weights[t] : 0;
							
				values[t] = i+toCheck[t][0] < width & i+toCheck[t][0] > -1 &
							j+toCheck[t][1] < height & j+toCheck[t][1] > -1 ? sobel[i+toCheck[t][0]+(j+toCheck[t][1])*width]*weights[t] : 0;
				/*
				//Debugging, not needed for purely gradient-based tracing
				bmds[t] = i+toCheck[t][0] < width & i+toCheck[t][0] > -1 &
							j+toCheck[t][1] < height & j+toCheck[t][1] > -1 ? scaledImage[i+toCheck[t][0]+(j+toCheck[t][1])*width] : 0;
				
				if (t > 0){
					if (bmds[t-1] < threshold & bmds[t] >= threshold){
						//Matching pixel found, keep going along the edge
						selectInd = t;
						routeFound = true;
						IJ.log(String.format("RouteFound I %d J %d goto %d",i,j,selectInd));
						break;
					}
					
					
				}
				*/
							
			}
			
			if (!routeFound){
				//IJ.log("ROUTE NOT FOUND???");
				selectInd = maxIndex(values);	//Always in use with gradient tracing
			}
			direction +=directions[selectInd];
			i += (int) Math.round(Math.cos(direction));
			j += (int) Math.round(Math.sin(direction));
			if ((i == initI && j == initJ) || counter > 7 | result[i + j * width] == 1 || result[i + j *
					width] > 3)
			{
				for (int ii = 0; ii < result.length; ++ii) {
					if (result[ii] > 1) {
						result[ii] = 1;
					}
				}
				final Vector<Object> returnVector = new Vector<>();
				returnVector.add(result);
				returnVector.add(iit);
				returnVector.add(jiit);
				return returnVector;
			}
			else {
				if (result[i + j * width] == 0) {
					result[i + j * width] = 2;
				}
				else if (result[i + j * width] != 1) {
					result[i + j * width]++;
				}
				iit.add(i);
				jiit.add(j);

			}
		}
		
		
	}
/* Gradient tracing 
		trace edge by advancing according to the previous direction
		progress into the weighted local maximum, counter clockwise direction is weighted
		@i = column
		@j = row
	*/
Gradient tracing
trace edge by advancing according to the previous direction
progress into the weighted local maximum, counter clockwise direction is weighted
Gradient tracing trace edge by advancing according to the previous direction progress into the weighted local maximum counter clockwise direction is weighted
private Vector<Object> traceGradient(final double[] scaledImage,
		final byte[] result, final double threshold, int i, int j)
	{
		double[] sobel = ScaledImageData.sobel(scaledImage,width,height);	
		/*
		//Considered using a multiplication of the gradient and the image, tunred out not to be a good idea
		double[] toTrace = new double[scaledImage.length];	//Combine gradient and intensity information to stay on gray scale if gradient disappears?
		for (int ii = 0;ii<toTrace.length;++ii){
			toTrace[ii] = scaledImage[ii]*sobel[ii];
		}
		*/
		final ArrayList<Integer> iit = new ArrayList<Integer>();
		final ArrayList<Integer> jiit = new ArrayList<Integer>();
		iit.add(i);
		jiit.add(j);
		double direction = 0;
		final int initI;
		final int initJ;
		initI = i;
		initJ = j;
		double[] weights = new double[]{0.2,0.8,1.0,1,0.8,0.5,0.1};	
		double[] directions = new double[]{-Math.PI*3d / 4d,  -Math.PI*2d / 4d, -Math.PI*1d / 4d, 0d ,
											Math.PI*1d / 4d, Math.PI*2d / 4d, Math.PI*3d / 4d};
		double[] values = new double[directions.length];
		double[] bmds = new double[directions.length];
		while (true) {
			int counter = 0;
			int[][] toCheck = new int[][]{
											{(int) Math.round(Math.cos(direction+directions[0])),(int) Math.round(Math.sin(direction+directions[0]))},	
											{(int) Math.round(Math.cos(direction+directions[1])),(int) Math.round(Math.sin(direction+directions[1]))},	
											{(int) Math.round(Math.cos(direction+directions[2])),(int) Math.round(Math.sin(direction+directions[2]))},	
											{(int) Math.round(Math.cos(direction+directions[3])),(int) Math.round(Math.sin(direction+directions[3]))},	
											{(int) Math.round(Math.cos(direction+directions[4])),(int) Math.round(Math.sin(direction+directions[4]))},	
											{(int) Math.round(Math.cos(direction+directions[5])),(int) Math.round(Math.sin(direction+directions[5]))},	
											{(int) Math.round(Math.cos(direction+directions[6])),(int) Math.round(Math.sin(direction+directions[6]))}	
											};
			boolean routeFound = false;
			int selectInd = 0;
			for (int t = 0; t<toCheck.length;++t){
				values[t] = i+toCheck[t][0] < width & i+toCheck[t][0] > -1 &
							j+toCheck[t][1] < height & j+toCheck[t][1] > -1 ? sobel[i+toCheck[t][0]+(j+toCheck[t][1])*width]*weights[t] : 0;
				/*
				//Debugging, not needed for purely gradient-based tracing
				bmds[t] = i+toCheck[t][0] < width & i+toCheck[t][0] > -1 &
							j+toCheck[t][1] < height & j+toCheck[t][1] > -1 ? scaledImage[i+toCheck[t][0]+(j+toCheck[t][1])*width] : 0;
				if (t > 0){
					if (bmds[t-1] < threshold & bmds[t] >= threshold){
						//Matching pixel found, keep going along the edge
						selectInd = t;
						routeFound = true;
						IJ.log(String.format("RouteFound I %d J %d goto %d",i,j,selectInd));
						break;
					}
				}
				*/
			}
			if (!routeFound){
				selectInd = maxIndex(values);	
			}
			direction +=directions[selectInd];
			i += (int) Math.round(Math.cos(direction));
			j += (int) Math.round(Math.sin(direction));
			if ((i == initI && j == initJ) || counter > 7 | result[i + j * width] == 1 || result[i + j *
					width] > 3)
			{
				for (int ii = 0; ii < result.length; ++ii) {
					if (result[ii] > 1) {
						result[ii] = 1;
					}
				}
				final Vector<Object> returnVector = new Vector<>();
				returnVector.add(result);
				returnVector.add(iit);
				returnVector.add(jiit);
				return returnVector;
			}
			else {
				if (result[i + j * width] == 0) {
					result[i + j * width] = 2;
				}
				else if (result[i + j * width] != 1) {
					result[i + j * width]++;
				}
				iit.add(i);
				jiit.add(j);
			}
		}
	}
private Vector < Object > traceGradient ( final double [ ] scaledImage , final byte [ ] result , final double threshold , int i , int j ) { double [ ] sobel = ScaledImageData . sobel ( scaledImage , width , height ) ; /*
		//Considered using a multiplication of the gradient and the image, tunred out not to be a good idea
		double[] toTrace = new double[scaledImage.length];	//Combine gradient and intensity information to stay on gray scale if gradient disappears?
		for (int ii = 0;ii<toTrace.length;++ii){
			toTrace[ii] = scaledImage[ii]*sobel[ii];
		}
		*/ final ArrayList < Integer > iit = new ArrayList < Integer > ( ) ; final ArrayList < Integer > jiit = new ArrayList < Integer > ( ) ; iit . add ( i ) ; jiit . add ( j ) ; double direction = 0 ; final int initI ; final int initJ ; initI = i ; initJ = j ; double [ ] weights = new double [ ] { 0.2 , 0.8 , 1.0 , 1 , 0.8 , 0.5 , 0.1 } ; double [ ] directions = new double [ ] { - Math . PI * 3d / 4d , - Math . PI * 2d / 4d , - Math . PI * 1d / 4d , 0d , Math . PI * 1d / 4d , Math . PI * 2d / 4d , Math . PI * 3d / 4d } ; double [ ] values = new double [ directions . length ] ; double [ ] bmds = new double [ directions . length ] ; while ( true ) { int counter = 0 ; int [ ] [ ] toCheck = new int [ ] [ ] { { ( int ) Math . round ( Math . cos ( direction + directions [ 0 ] ) ) , ( int ) Math . round ( Math . sin ( direction + directions [ 0 ] ) ) } , { ( int ) Math . round ( Math . cos ( direction + directions [ 1 ] ) ) , ( int ) Math . round ( Math . sin ( direction + directions [ 1 ] ) ) } , { ( int ) Math . round ( Math . cos ( direction + directions [ 2 ] ) ) , ( int ) Math . round ( Math . sin ( direction + directions [ 2 ] ) ) } , { ( int ) Math . round ( Math . cos ( direction + directions [ 3 ] ) ) , ( int ) Math . round ( Math . sin ( direction + directions [ 3 ] ) ) } , { ( int ) Math . round ( Math . cos ( direction + directions [ 4 ] ) ) , ( int ) Math . round ( Math . sin ( direction + directions [ 4 ] ) ) } , { ( int ) Math . round ( Math . cos ( direction + directions [ 5 ] ) ) , ( int ) Math . round ( Math . sin ( direction + directions [ 5 ] ) ) } , { ( int ) Math . round ( Math . cos ( direction + directions [ 6 ] ) ) , ( int ) Math . round ( Math . sin ( direction + directions [ 6 ] ) ) } } ; boolean routeFound = false ; int selectInd = 0 ; for ( int t = 0 ; t < toCheck . length ; ++ t ) { values [ t ] = i + toCheck [ t ] [ 0 ] < width & i + toCheck [ t ] [ 0 ] > - 1 & j + toCheck [ t ] [ 1 ] < height & j + toCheck [ t ] [ 1 ] > - 1 ? sobel [ i + toCheck [ t ] [ 0 ] + ( j + toCheck [ t ] [ 1 ] ) * width ] * weights [ t ] : 0 ; /*
				//Debugging, not needed for purely gradient-based tracing
				bmds[t] = i+toCheck[t][0] < width & i+toCheck[t][0] > -1 &
							j+toCheck[t][1] < height & j+toCheck[t][1] > -1 ? scaledImage[i+toCheck[t][0]+(j+toCheck[t][1])*width] : 0;
				
				if (t > 0){
					if (bmds[t-1] < threshold & bmds[t] >= threshold){
						//Matching pixel found, keep going along the edge
						selectInd = t;
						routeFound = true;
						IJ.log(String.format("RouteFound I %d J %d goto %d",i,j,selectInd));
						break;
					}
					
					
				}
				*/ } if ( ! routeFound ) { selectInd = maxIndex ( values ) ; } direction += directions [ selectInd ] ; i += ( int ) Math . round ( Math . cos ( direction ) ) ; j += ( int ) Math . round ( Math . sin ( direction ) ) ; if ( ( i == initI && j == initJ ) || counter > 7 | result [ i + j * width ] == 1 || result [ i + j * width ] > 3 ) { for ( int ii = 0 ; ii < result . length ; ++ ii ) { if ( result [ ii ] > 1 ) { result [ ii ] = 1 ; } } final Vector < Object > returnVector = new Vector < > ( ) ; returnVector . add ( result ) ; returnVector . add ( iit ) ; returnVector . add ( jiit ) ; return returnVector ; } else { if ( result [ i + j * width ] == 0 ) { result [ i + j * width ] = 2 ; } else if ( result [ i + j * width ] != 1 ) { result [ i + j * width ] ++ ; } iit . add ( i ) ; jiit . add ( j ) ; } } }
Gradient tracing
trace edge by advancing according to the previous direction
progress into the weighted local maximum, counter clockwise direction is weighted
Gradient tracing trace edge by advancing according to the previous direction progress into the weighted local maximum counter clockwise direction is weighted
//Get the gradient image for tracing // begin by advancing right. Positive angles rotate the direction clockwise. //Weight the counter clockwise tracking more heavily //Get the values of the pixels in the direction of travel // Look for valid boundary pixel. If one is found, ignore the rest //values[t] = i+toCheck[t][0] < width & i+toCheck[t][0] > -1 & //			j+toCheck[t][1] < height & j+toCheck[t][1] > -1 ? toTrace[i+toCheck[t][0]+(j+toCheck[t][1])*width]*weights[t] : 0; //IJ.log("ROUTE NOT FOUND???"); //Always in use with gradient tracing