Commit 288a87a6 authored by Andrey Filippov's avatar Andrey Filippov

debugging initial pattern detection

parent 0414c82c
...@@ -131,7 +131,8 @@ public class LensAdjustment { ...@@ -131,7 +131,8 @@ public class LensAdjustment {
imp_eq, // image to process imp_eq, // image to process
threadsMax, threadsMax,
updateStatus, updateStatus,
debug_level);// debug level used inside loops debug_level,// debug level used inside loops
debug_level); // global debug level ?
if (debug_level>1) System.out.println("distortions() finished at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)); if (debug_level>1) System.out.println("distortions() finished at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
matchSimulatedPattern.recalculateWaveVectors ( matchSimulatedPattern.recalculateWaveVectors (
......
...@@ -27,6 +27,8 @@ import java.awt.Rectangle; ...@@ -27,6 +27,8 @@ import java.awt.Rectangle;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
...@@ -34,7 +36,6 @@ import javax.swing.SwingUtilities; ...@@ -34,7 +36,6 @@ import javax.swing.SwingUtilities;
import Jama.LUDecomposition; import Jama.LUDecomposition;
import Jama.Matrix; // Download here: http://math.nist.gov/javanumerics/jama/ import Jama.Matrix; // Download here: http://math.nist.gov/javanumerics/jama/
import ij.IJ; import ij.IJ;
import ij.ImagePlus; import ij.ImagePlus;
import ij.ImageStack; import ij.ImageStack;
...@@ -2976,7 +2977,8 @@ public class MatchSimulatedPattern { ...@@ -2976,7 +2977,8 @@ public class MatchSimulatedPattern {
final ImagePlus imp, // image to process final ImagePlus imp, // image to process
final int threadsMax, final int threadsMax,
final boolean updateStatus, final boolean updateStatus,
final int debug_level){// debug level used inside loops final int debug_level, // debug level used inside loops
final int global_debug_level){
// moved to caller // moved to caller
// this.PATTERN_GRID=null; // this.PATTERN_GRID=null;
// invalidateCalibration(); // invalidateCalibration();
...@@ -3050,6 +3052,13 @@ public class MatchSimulatedPattern { ...@@ -3050,6 +3052,13 @@ public class MatchSimulatedPattern {
int [] iUV= new int [2]; int [] iUV= new int [2];
final boolean updating=(PATTERN_GRID!=null); final boolean updating=(PATTERN_GRID!=null);
final boolean useFocusMask=updating && (focusMask!=null); // do not expand wave beyound 1 grid step from needed image regions final boolean useFocusMask=updating && (focusMask!=null); // do not expand wave beyound 1 grid step from needed image regions
// double [][][] nodes=null;
Queue<GridNode> nodeQueue = new ConcurrentLinkedQueue<GridNode>();
boolean fromVeryBeginning=true;
for (int i=3;i<triedIndices.length;i++) if (triedIndices[i]){ // do not count forst three
fromVeryBeginning=false;
break;
}
if (!updating) { if (!updating) {
double [] point = new double[2]; double [] point = new double[2];
int tryHor=0,tryVert=0; int tryHor=0,tryVert=0;
...@@ -3067,7 +3076,8 @@ public class MatchSimulatedPattern { ...@@ -3067,7 +3076,8 @@ public class MatchSimulatedPattern {
int nbv,nbh,nh,nv,nb; int nbv,nbh,nh,nv,nb;
if (debugLevel>1) System.out.println("selection.x="+selection.x+" selection.y="+selection.y+" selection.width="+selection.width+" selection.height="+selection.height); if (debugLevel>1) System.out.println("selection.x="+selection.x+" selection.y="+selection.y+" selection.width="+selection.width+" selection.height="+selection.height);
if (debugLevel>1) System.out.println("numTries="+numTries+" tryHor="+tryHor+" tryVert="+tryVert); if (debugLevel>1) System.out.println("numTries="+numTries+" tryHor="+tryHor+" tryVert="+tryVert);
double [][] node=null; // double [][] node=null;
// double [][][] nodes=null;
boolean oldMode=false; //true; // false; boolean oldMode=false; //true; // false;
/* /*
if (startScanIndex[0]==0) startScanIndex[0]=3; if (startScanIndex[0]==0) startScanIndex[0]=3;
...@@ -3080,6 +3090,8 @@ public class MatchSimulatedPattern { ...@@ -3080,6 +3090,8 @@ public class MatchSimulatedPattern {
if (oldMode) { // old (single-threaded) mode if (oldMode) { // old (single-threaded) mode
// for (int n=startScanIndex[0];n<numTries;n++) { // for (int n=startScanIndex[0];n<numTries;n++) {
// final boolean [] triedIndices, // final boolean [] triedIndices,
// nodes = new double [1][][];
// nodes[0]=null;
for (int startScanIndex=3;startScanIndex<=numTries;startScanIndex++) if (!triedIndices[startScanIndex]){ for (int startScanIndex=3;startScanIndex<=numTries;startScanIndex++) if (!triedIndices[startScanIndex]){
if (startScanIndex==numTries){ if (startScanIndex==numTries){
...@@ -3110,7 +3122,7 @@ public class MatchSimulatedPattern { ...@@ -3110,7 +3122,7 @@ public class MatchSimulatedPattern {
if (debugLevel>2) System.out.println("trying xc="+point[0]+", yc="+point[1]+"(nv="+nv+", nh="+nh+")"); if (debugLevel>2) System.out.println("trying xc="+point[0]+", yc="+point[1]+"(nv="+nv+", nh="+nh+")");
// System.out.println("### trying xc="+point[0]+", yc="+point[1]+"(nv="+nv+", nh="+nh+")"); // System.out.println("### trying xc="+point[0]+", yc="+point[1]+"(nv="+nv+", nh="+nh+")");
if ((debugLevel>2) && (startScanIndex==3)) debugLevel=3; // show debug images for the first point only if ((debugLevel>2) && (startScanIndex==3)) debugLevel=3; // show debug images for the first point only
node=tryPattern ( double [][] node=tryPattern (
point, // xy to try point, // xy to try
thisDistortionParameters, //no control of the displacement thisDistortionParameters, //no control of the displacement
patternDetectParameters, patternDetectParameters,
...@@ -3129,6 +3141,7 @@ public class MatchSimulatedPattern { ...@@ -3129,6 +3141,7 @@ public class MatchSimulatedPattern {
); );
debugLevel=was_debug_level; debugLevel=was_debug_level;
if ((node!=null) && (node[0]!=null)) { if ((node!=null) && (node[0]!=null)) {
nodeQueue.add(new GridNode(node));
break; break;
} }
} }
...@@ -3140,7 +3153,7 @@ public class MatchSimulatedPattern { ...@@ -3140,7 +3153,7 @@ public class MatchSimulatedPattern {
if (debugLevel>1) System.out.println("distortions(): startScanIndex="+startScanIndex); if (debugLevel>1) System.out.println("distortions(): startScanIndex="+startScanIndex);
if (startScanIndex<numTries) { if (startScanIndex<numTries) {
node = findPatternCandidate( nodeQueue = findPatternCandidates(
triedIndices, triedIndices,
startScanIndex, // [0] will be updated startScanIndex, // [0] will be updated
tryHor, tryHor,
...@@ -3165,9 +3178,12 @@ public class MatchSimulatedPattern { ...@@ -3165,9 +3178,12 @@ public class MatchSimulatedPattern {
updateStatus, updateStatus,
this.debugLevel this.debugLevel
); );
if (node==null){ if (nodeQueue.isEmpty()) { // nodes==null){
if (debugLevel>1) System.out.println("All start points tried"); if (debugLevel>1) System.out.println("All start points tried");
triedIndices[numTries]=true; // all tried triedIndices[numTries]=true; // all tried
} else {
// if (debugLevel>1) System.out.println("Found "+nodes.length+" candidates");
if (debugLevel>1) System.out.println("Found "+nodeQueue.size()+" candidates");
} }
} else { } else {
if (debugLevel>1) System.out.println("All start points tried before - should not get here"); if (debugLevel>1) System.out.println("All start points tried before - should not get here");
...@@ -3175,29 +3191,18 @@ public class MatchSimulatedPattern { ...@@ -3175,29 +3191,18 @@ public class MatchSimulatedPattern {
} }
} }
// if (startScanIndex[0]>=numTries) startScanIndex[0]=-1; // all indices used // if (startScanIndex[0]>=numTries) startScanIndex[0]=-1; // all indices used
if ((node==null) || (node[0]==null)) { // if ((nodes==null) || (nodes[0]==null) || (nodes[0][0]==null)) {
if ((nodeQueue.isEmpty()) || (nodeQueue.peek().getNode()[0]==null)) {
if (debugLevel>1) System.out.println("*** Pattern not found"); if (debugLevel>1) System.out.println("*** Pattern not found");
this.PATTERN_GRID=null; this.PATTERN_GRID=null;
return 0; return 0;
} }
double [] centerXY=node[0]; if (debugLevel>1) {
/* TODO null pointrer in next line - DONE?*/ System.out.println("*** distortions: got "+nodeQueue.size()+" candidates");
if (debugLevel>1) System.out.println("*** distortions: Center x="+IJ.d2s(centerXY[0],3)+" y="+ IJ.d2s(centerXY[1],3)); // System.out.println("*** distortions: Center x="+IJ.d2s(centerXY[0],3)+" y="+ IJ.d2s(centerXY[1],3));
}
debugLevel=debug_level;
// Reset pattern grid debugLevel=debug_level; // ????
this.PATTERN_GRID=setPatternGridArray(distortionParameters.gridSize); // global to be used with threads?
setPatternGridCell(
this.PATTERN_GRID,
centerUV,
centerXY, // contrast OK?
node[1],
node[2]);
putInWaveList(waveFrontList, centerUV, 0);
// Mark initial point as debug one (seems to be largest correction later
// patternDetectParameters.debugX=centerXY[0];
// patternDetectParameters.debugY=centerXY[1];
// System.out.println(">>>>>> Set debugX="+patternDetectParameters.debugX + " debugY="+patternDetectParameters.debugY);
} else { // create initial wave from the border nodes of existent grid } else { // create initial wave from the border nodes of existent grid
// start with clearing all invalid nodes // start with clearing all invalid nodes
...@@ -3222,404 +3227,493 @@ public class MatchSimulatedPattern { ...@@ -3222,404 +3227,493 @@ public class MatchSimulatedPattern {
putInWaveList(waveFrontList, iUV, 0); putInWaveList(waveFrontList, iUV, 0);
} }
} }
double [][] node={null};
nodeQueue.add(new GridNode(node)); // will not be used, any element
} }
int numDefinedCells=0;
for (GridNode gn:nodeQueue){
if (!updating){
double [][] node=gn.getNode();
double [] centerXY=node[0];
if (debugLevel>1) {
System.out.println("*** distortions: Center x="+IJ.d2s(centerXY[0],3)+" y="+ IJ.d2s(centerXY[1],3));
}
debugLevel=debug_level;
// Reset pattern grid
this.PATTERN_GRID=setPatternGridArray(distortionParameters.gridSize); // global to be used with threads?
setPatternGridCell(
this.PATTERN_GRID,
centerUV,
centerXY, // contrast OK?
node[1],
node[2]);
waveFrontList.clear();
putInWaveList(waveFrontList, centerUV, 0);
}
// Each layer processing may be multi-threaded, they join before going to the next layer // Each layer processing may be multi-threaded, they join before going to the next layer
// When looking for the next cells, the position is estimated knowing the neighbor that has wave vectors defined // When looking for the next cells, the position is estimated knowing the neighbor that has wave vectors defined
// after the layer pass is over, the wave vectors are calculated from the distances to neighbors (one or both vectors may have // after the layer pass is over, the wave vectors are calculated from the distances to neighbors (one or both vectors may have
// to use those from the neighbor? // to use those from the neighbor?
if (debugLevel>1) System.out.println("-->centerUV= "+centerUV[0]+", "+centerUV[1]+", 0"); if (debugLevel>1) System.out.println("-->centerUV= "+centerUV[0]+", "+centerUV[1]+", 0");
int [] uvdir; // (u,v,direction} int [] uvdir; // (u,v,direction}
int layer=0; int layer=0;
int dir; int dir;
// int [] iUV0= new int [2]; // int [] iUV0= new int [2];
// double [][] uv12t=new double[2][2]; // double [][] uv12t=new double[2][2];
// double [][] xy12t=new double[2][2]; // double [][] xy12t=new double[2][2];
// double [][][] cells =new double [3][][]; //0 - this cell, 1 - parent, 2 - other non co-linear // double [][][] cells =new double [3][][]; //0 - this cell, 1 - parent, 2 - other non co-linear
double [][][] neibors=new double [8][][]; // uv and xy vectors to 8 neibors (some may be null double [][][] neibors=new double [8][][]; // uv and xy vectors to 8 neibors (some may be null
double [][] thisCell; double [][] thisCell;
double [][] otherCell; double [][] otherCell;
final int debugThreshold=2; final int debugThreshold=2;
final double [][] extrapolationWeights=generateWeights ( final double [][] extrapolationWeights=generateWeights (
distortionParameters.correlationWeightSigma, distortionParameters.correlationWeightSigma,
distortionParameters.correlationRadiusScale); // if 0 - use sigma as radius, inside - 1.0, outside 0.0. If >0 - size of array n*sigma distortionParameters.correlationRadiusScale); // if 0 - use sigma as radius, inside - 1.0, outside 0.0. If >0 - size of array n*sigma
int umax,vmax,vmin,umin; int umax,vmax,vmin,umin;
final AtomicInteger addedCells = new AtomicInteger(0); // cells added at cleanup stage final AtomicInteger addedCells = new AtomicInteger(0); // cells added at cleanup stage
final AtomicBoolean cleanup=new AtomicBoolean(false); // after the wave dies, it will be restored for all cells with defined neigbors to try again. maybe - try w/o therads? final AtomicBoolean cleanup=new AtomicBoolean(false); // after the wave dies, it will be restored for all cells with defined neigbors to try again. maybe - try w/o therads?
final AtomicInteger debugCellSet= new AtomicInteger(0); // cells added at cleanup stage final AtomicInteger debugCellSet= new AtomicInteger(0); // cells added at cleanup stage
// special case (most common, actually) when initial wave has 1 node. Remove it after processing // special case (most common, actually) when initial wave has 1 node. Remove it after processing
ArrayList<Integer> initialWave=new ArrayList<Integer>(); ArrayList<Integer> initialWave=new ArrayList<Integer>();
for (Integer I:waveFrontList) initialWave.add(I); for (Integer I:waveFrontList) initialWave.add(I);
while (waveFrontList.size()>0) {
while (waveFrontList.size()>0) { // process current list, add new wave layer (moving in one of the 4 directions)
// process current list, add new wave layer (moving in one of the 4 directions) // proceed until the entry is undefined on the grid (or list is empty
// proceed until the entry is undefined on the grid (or list is empty while (waveFrontList.size()>0) { // will normally break out of the cycle
while (waveFrontList.size()>0) { // will normally break out of the cycle uvdir= getWaveList (waveFrontList,0);
uvdir= getWaveList (waveFrontList,0); if (this.debugLevel>1) System.out.println("<--uvdir= "+uvdir[0]+", "+uvdir[1]+", "+uvdir[2]);
if (this.debugLevel>1) System.out.println("<--uvdir= "+uvdir[0]+", "+uvdir[1]+", "+uvdir[2]); if (this.PATTERN_GRID[uvdir[1]][uvdir[0]]==null) break; // finished adding new layer
if (this.PATTERN_GRID[uvdir[1]][uvdir[0]]==null) break; // finished adding new layer if (!isCellDefined(this.PATTERN_GRID,uvdir)) break; // finished adding new layer, hit one of the newely added
if (!isCellDefined(this.PATTERN_GRID,uvdir)) break; // finished adding new layer, hit one of the newely added boolean hasNeededNeighbor=true;
boolean hasNeededNeighbor=true; if (useFocusMask) {
if (useFocusMask) { int ix=(int) Math.round(this.PATTERN_GRID[uvdir[1]][uvdir[0]][0][0]);
int ix=(int) Math.round(this.PATTERN_GRID[uvdir[1]][uvdir[0]][0][0]); int iy=(int) Math.round(this.PATTERN_GRID[uvdir[1]][uvdir[0]][0][1]);
int iy=(int) Math.round(this.PATTERN_GRID[uvdir[1]][uvdir[0]][0][1]); int indx=iy*getImageWidth()+ix;
int indx=iy*getImageWidth()+ix; if ((indx<0) || (indx>focusMask.length)){
if ((indx<0) || (indx>focusMask.length)){ System.out.println("distortions(): this.PATTERN_GRID["+uvdir[1]+"]["+uvdir[0]+"][0][0]="+this.PATTERN_GRID[uvdir[1]][uvdir[0]][0][0]);
System.out.println("distortions(): this.PATTERN_GRID["+uvdir[1]+"]["+uvdir[0]+"][0][0]="+this.PATTERN_GRID[uvdir[1]][uvdir[0]][0][0]); System.out.println("distortions(): this.PATTERN_GRID["+uvdir[1]+"]["+uvdir[0]+"][0][1]="+this.PATTERN_GRID[uvdir[1]][uvdir[0]][0][1]);
System.out.println("distortions(): this.PATTERN_GRID["+uvdir[1]+"]["+uvdir[0]+"][0][1]="+this.PATTERN_GRID[uvdir[1]][uvdir[0]][0][1]); System.out.println("distortions(): ix="+ix);
System.out.println("distortions(): ix="+ix); System.out.println("distortions(): iy="+iy);
System.out.println("distortions(): iy="+iy); System.out.println("distortions(): focusMask.length="+focusMask.length);
System.out.println("distortions(): focusMask.length="+focusMask.length); }
// TODO: find how it could get negative coordinates
if ((ix<0) || (iy<0) || (ix>=distortionParameters.gridSize) || (iy>=distortionParameters.gridSize)) hasNeededNeighbor=false; //???
else hasNeededNeighbor=focusMask[iy*getImageWidth()+ix]; //* OOB -1624 java.lang.ArrayIndexOutOfBoundsException: -1624, at MatchSimulatedPattern.distortions(MatchSimulatedPattern.java:3063), at LensAdjustment.updateFocusGrid(LensAdjustment.java:121), at Aberration_Calibration.measurePSFMetrics(Aberration_Calibration.java:5994)
} }
// TODO: find how it could get negative coordinates for (dir=0;dir<directionsUV.length;dir++) {
if ((ix<0) || (iy<0) || (ix>=distortionParameters.gridSize) || (iy>=distortionParameters.gridSize)) hasNeededNeighbor=false; //??? iUV[0]=uvdir[0]+directionsUV[dir][0];
else hasNeededNeighbor=focusMask[iy*getImageWidth()+ix]; //* OOB -1624 java.lang.ArrayIndexOutOfBoundsException: -1624, at MatchSimulatedPattern.distortions(MatchSimulatedPattern.java:3063), at LensAdjustment.updateFocusGrid(LensAdjustment.java:121), at Aberration_Calibration.measurePSFMetrics(Aberration_Calibration.java:5994) iUV[1]=uvdir[1]+directionsUV[dir][1];
}
for (dir=0;dir<directionsUV.length;dir++) { if ((iUV[0]<0) || (iUV[1]<0) ||
iUV[0]=uvdir[0]+directionsUV[dir][0]; (iUV[0]>=distortionParameters.gridSize) || (iUV[1]>=distortionParameters.gridSize)) continue; // don't fit into UV grid
iUV[1]=uvdir[1]+directionsUV[dir][1]; if (!isCellNew(PATTERN_GRID,iUV)) continue; // already processed
// add uv and dir to the list
if ((iUV[0]<0) || (iUV[1]<0) || // public boolean [] focusMask=null; // array matching image pixels, used with focusing (false outside sample areas)
(iUV[0]>=distortionParameters.gridSize) || (iUV[1]>=distortionParameters.gridSize)) continue; // don't fit into UV grid // New: if it is updating the grid and focusMask is defined - do not go more than 1 step away from the needed image area
if (!isCellNew(PATTERN_GRID,iUV)) continue; // already processed if (hasNeededNeighbor) {
// add uv and dir to the list putInWaveList (waveFrontList, iUV, (dir+(directionsUV.length/2))%directionsUV.length); // opposite direction
// public boolean [] focusMask=null; // array matching image pixels, used with focusing (false outside sample areas) initPatternGridCell(PATTERN_GRID, iUV);
// New: if it is updating the grid and focusMask is defined - do not go more than 1 step away from the needed image area if (debugLevel>1) System.out.println("-->iUV= "+iUV[0]+", "+iUV[1]+", "+((dir+(directionsUV.length/2))%directionsUV.length));
if (hasNeededNeighbor) { }
putInWaveList (waveFrontList, iUV, (dir+(directionsUV.length/2))%directionsUV.length); // opposite direction
initPatternGridCell(PATTERN_GRID, iUV);
if (debugLevel>1) System.out.println("-->iUV= "+iUV[0]+", "+iUV[1]+", "+((dir+(directionsUV.length/2))%directionsUV.length));
} }
waveFrontList.remove(0); // remove first element from the list
if (debugLevel>1) System.out.println("xx> remove(0), (waveFrontList.size()="+(waveFrontList.size()));
} }
waveFrontList.remove(0); // remove first element from the list if (waveFrontList.size()==0) break; // not really needed?
if (debugLevel>1) System.out.println("xx> remove(0), (waveFrontList.size()="+(waveFrontList.size())); layer++;
} if (updateStatus) IJ.showStatus("Correlating patterns, layer "+layer+(cleanup.get()?"(cleanup)":"")+", length "+waveFrontList.size());
if (waveFrontList.size()==0) break; // not really needed? if (debugLevel>1) System.out.println("Correlating patterns, layer "+layer+", length "+waveFrontList.size());
layer++; // starting layer
if (updateStatus) IJ.showStatus("Correlating patterns, layer "+layer+(cleanup.get()?"(cleanup)":"")+", length "+waveFrontList.size()); cellNum.set(0);
if (debugLevel>1) System.out.println("Correlating patterns, layer "+layer+", length "+waveFrontList.size()); for (int ithread = 0; ithread < threads.length; ithread++) {
// starting layer threads[ithread] = new Thread() {
cellNum.set(0); public void run() {
for (int ithread = 0; ithread < threads.length; ithread++) { SimulationPattern simulationPattern= new SimulationPattern(bPattern);
threads[ithread] = new Thread() { MatchSimulatedPattern matchSimulatedPatternCorr=new MatchSimulatedPattern(distortionParameters.correlationSize);
public void run() { DoubleFHT fht_instance =new DoubleFHT(); // provide DoubleFHT instance to save on initializations (or null)
SimulationPattern simulationPattern= new SimulationPattern(bPattern); String dbgStr="";
MatchSimulatedPattern matchSimulatedPatternCorr=new MatchSimulatedPattern(distortionParameters.correlationSize); for (int ncell=cellNum.getAndIncrement(); ncell<waveFrontList.size();ncell=cellNum.getAndIncrement()){
DoubleFHT fht_instance =new DoubleFHT(); // provide DoubleFHT instance to save on initializations (or null) int [] iUVdir=getWaveList (waveFrontList,ncell);
String dbgStr=""; if (debugLevel>debugThreshold) {
for (int ncell=cellNum.getAndIncrement(); ncell<waveFrontList.size();ncell=cellNum.getAndIncrement()){ dbgStr="";
int [] iUVdir=getWaveList (waveFrontList,ncell); dbgStr+="<--iUVdir= "+iUVdir[0]+", "+iUVdir[1]+", "+iUVdir[2];
if (debugLevel>debugThreshold) {
dbgStr="";
dbgStr+="<--iUVdir= "+iUVdir[0]+", "+iUVdir[1]+", "+iUVdir[2];
}
int [] iUVRef=new int[2];
iUVRef[0]=iUVdir[0]+directionsUV[iUVdir[2]][0];
iUVRef[1]=iUVdir[1]+directionsUV[iUVdir[2]][1];
double [][] refCell=PATTERN_GRID[iUVRef[1]][iUVRef[0]]; // should never be null as it is an old one
if (refCell==null){
System.out.println("refCell==null");
continue;
}
//found reference cell, calculate x/y, make sure it is inside the selection w/o borders
double [][] wv=new double [2][];
wv[0]=refCell[1];
wv[1]=refCell[2];
double [][]uv2xy=matrix2x2_invert(wv);
double [] dUV = new double [2];
dUV[0]=0.5*(iUVdir[0]-iUVRef[0]);
dUV[1]=0.5*(iUVdir[1]-iUVRef[1]);
double []dXY=matrix2x2_mul(uv2xy,dUV);
double [] expectedXY=matrix2x2_add(refCell[0],dXY);
// Try new extrapolation, debug print both
//extrapolationWeights
double [][] estimatedCell=estimateCell(
PATTERN_GRID,
iUVdir,
extrapolationWeights, // quadrant of sample weights
true, // useContrast
!distortionParameters.useQuadratic, // use linear approximation (instead of quadratic)
1.0E-10, // thershold ratio of matrix determinant to norm for linear approximation (det too low - fail)
1.0E-20 // thershold ratio of matrix determinant to norm for quadratic approximation (det too low - fail)
);
double [][] simulPars=null;
if (debugLevel>debugThreshold) {
dbgStr+=" ExpectedXY(old)= "+IJ.d2s(expectedXY[0],3)+" / "+IJ.d2s(expectedXY[1],3)+", "+
" vw00="+IJ.d2s(wv[0][0],5)+" vw01="+IJ.d2s(wv[0][1],5)+
" vw10="+IJ.d2s(wv[1][0],5)+" vw11="+IJ.d2s(wv[1][1],5);
if (estimatedCell==null) {
dbgStr+=" -- ExpectedXY(new)= ***** NULL **** ";
} else {
dbgStr+=" -- ExpectedXY(new)= "+IJ.d2s(estimatedCell[0][0],3)+" / "+IJ.d2s(estimatedCell[0][1],3)+", "+
" vw00="+IJ.d2s(estimatedCell[1][0],5)+" vw01="+IJ.d2s(estimatedCell[1][1],5)+
" vw10="+IJ.d2s(estimatedCell[2][0],5)+" vw11="+IJ.d2s(estimatedCell[2][1],5);
} }
int [] iUVRef=new int[2];
iUVRef[0]=iUVdir[0]+directionsUV[iUVdir[2]][0];
} iUVRef[1]=iUVdir[1]+directionsUV[iUVdir[2]][1];
if (estimatedCell!=null) {
expectedXY=estimatedCell[0]; double [][] refCell=PATTERN_GRID[iUVRef[1]][iUVRef[0]]; // should never be null as it is an old one
wv[0]=estimatedCell[1]; if (refCell==null){
wv[1]=estimatedCell[2]; System.out.println("**** refCell==null - what does it mean?****");
continue;
simulPars=getSimulationParametersFromGrid( }
//found reference cell, calculate x/y, make sure it is inside the selection w/o borders
double [][] wv=new double [2][];
wv[0]=refCell[1];
wv[1]=refCell[2];
double [][]uv2xy=matrix2x2_invert(wv);
double [] dUV = new double [2];
dUV[0]=0.5*(iUVdir[0]-iUVRef[0]);
dUV[1]=0.5*(iUVdir[1]-iUVRef[1]);
double []dXY=matrix2x2_mul(uv2xy,dUV);
double [] expectedXY=matrix2x2_add(refCell[0],dXY);
// Try new extrapolation, debug print both
//extrapolationWeights
double [][] estimatedCell=estimateCell(
PATTERN_GRID, PATTERN_GRID,
iUVdir, // U,V of the center point (for which the simulation pattern should be built iUVdir,
expectedXY, // x,y of the center point (or null to use grid)
extrapolationWeights, // quadrant of sample weights extrapolationWeights, // quadrant of sample weights
true, // useContrast
!distortionParameters.useQuadratic, // use linear approximation (instead of quadratic) !distortionParameters.useQuadratic, // use linear approximation (instead of quadratic)
1.0E-10, // thershold ratio of matrix determinant to norm for linear approximation (det too low - fail) 1.0E-10, // thershold ratio of matrix determinant to norm for linear approximation (det too low - fail)
1.0E-20 // thershold ratio of matrix determinant to norm for quadratic approximation (det too low - fail) 1.0E-20 // thershold ratio of matrix determinant to norm for quadratic approximation (det too low - fail)
); );
double [][] simulPars=null;
if (debugLevel>debugThreshold) { if (debugLevel>debugThreshold) {
dbgStr+=" {"+IJ.d2s(simulPars[0][0],5)+"/"+IJ.d2s(simulPars[0][1],5)+"/"+IJ.d2s(simulPars[0][2],5); dbgStr+=" ExpectedXY(old)= "+IJ.d2s(expectedXY[0],3)+" / "+IJ.d2s(expectedXY[1],3)+", "+
if (simulPars[0].length>3) dbgStr+="/"+IJ.d2s(simulPars[0][3],7)+"/"+IJ.d2s(simulPars[0][4],7)+"/"+IJ.d2s(simulPars[0][5],7)+"}"; " vw00="+IJ.d2s(wv[0][0],5)+" vw01="+IJ.d2s(wv[0][1],5)+
dbgStr+=" {"+IJ.d2s(simulPars[1][0],5)+"/"+IJ.d2s(simulPars[1][1],5)+"/"+IJ.d2s(simulPars[1][2],5); " vw10="+IJ.d2s(wv[1][0],5)+" vw11="+IJ.d2s(wv[1][1],5);
if (simulPars[1].length>3) dbgStr+="/"+IJ.d2s(simulPars[1][3],7)+"/"+IJ.d2s(simulPars[1][4],7)+"/"+IJ.d2s(simulPars[1][5],7)+"}"; if (estimatedCell==null) {
} dbgStr+=" -- ExpectedXY(new)= ***** NULL **** ";
} } else {
if (!selection.contains((int) Math.round(expectedXY[0]),(int) Math.round(expectedXY[1]))) { // just the center point dbgStr+=" -- ExpectedXY(new)= "+IJ.d2s(estimatedCell[0][0],3)+" / "+IJ.d2s(estimatedCell[0][1],3)+", "+
invalidatePatternGridCell( " vw00="+IJ.d2s(estimatedCell[1][0],5)+" vw01="+IJ.d2s(estimatedCell[1][1],5)+
PATTERN_GRID, " vw10="+IJ.d2s(estimatedCell[2][0],5)+" vw11="+IJ.d2s(estimatedCell[2][1],5);
iUVdir); }
if (debugLevel>debugThreshold) {
dbgStr+=" -- not in selection ";
System.out.println(dbgStr);
} }
continue; // the correlation selection does not fit into WOI selection if (estimatedCell!=null) {
} expectedXY=estimatedCell[0];
//Proceed with correlation wv[0]=estimatedCell[1];
//TODO: add contrast verification ? Maximal distance from expected? (return null if failed) wv[1]=estimatedCell[2];
double [] centerXY=correctedPatternCrossLocation(
expectedXY, // initial coordinates of the pattern cross point simulPars=getSimulationParametersFromGrid(
wv[0][0], PATTERN_GRID,
wv[0][1], iUVdir, // U,V of the center point (for which the simulation pattern should be built
wv[1][0], expectedXY, // x,y of the center point (or null to use grid)
wv[1][1], extrapolationWeights, // quadrant of sample weights
simulPars, !distortionParameters.useQuadratic, // use linear approximation (instead of quadratic)
imp, // image data (Bayer mosaic) 1.0E-10, // thershold ratio of matrix determinant to norm for linear approximation (det too low - fail)
distortionParameters, // 1.0E-20 // thershold ratio of matrix determinant to norm for quadratic approximation (det too low - fail)
patternDetectParameters, );
matchSimulatedPatternCorr, // correlationSize if (debugLevel>debugThreshold) {
thisSimulParameters, dbgStr+=" {"+IJ.d2s(simulPars[0][0],5)+"/"+IJ.d2s(simulPars[0][1],5)+"/"+IJ.d2s(simulPars[0][2],5);
equalizeGreens, if (simulPars[0].length>3) dbgStr+="/"+IJ.d2s(simulPars[0][3],7)+"/"+IJ.d2s(simulPars[0][4],7)+"/"+IJ.d2s(simulPars[0][5],7)+"}";
windowFunctionCorr, dbgStr+=" {"+IJ.d2s(simulPars[1][0],5)+"/"+IJ.d2s(simulPars[1][1],5)+"/"+IJ.d2s(simulPars[1][2],5);
windowFunctionCorr2, if (simulPars[1].length>3) dbgStr+="/"+IJ.d2s(simulPars[1][3],7)+"/"+IJ.d2s(simulPars[1][4],7)+"/"+IJ.d2s(simulPars[1][5],7)+"}";
windowFunctionCorr4, }
simulationPattern, }
((iUVdir[0]^iUVdir[1])&1)!=0, // if true - invert pattern if (!selection.contains((int) Math.round(expectedXY[0]),(int) Math.round(expectedXY[1]))) { // just the center point
fht_instance, invalidatePatternGridCell(
distortionParameters.fastCorrelationOnFirstPass, PATTERN_GRID,
locsNeib, iUVdir);
debugLevel); if (debugLevel>debugThreshold) {
// System.out.println("*+*debugLevel="+debugLevel); dbgStr+=" -- not in selection ";
if (centerXY==null){ System.out.println(dbgStr);
invalidatePatternGridCell( }
continue; // the correlation selection does not fit into WOI selection
}
//Proceed with correlation
//TODO: add contrast verification ? Maximal distance from expected? (return null if failed)
double [] centerXY=correctedPatternCrossLocation(
expectedXY, // initial coordinates of the pattern cross point
wv[0][0],
wv[0][1],
wv[1][0],
wv[1][1],
simulPars,
imp, // image data (Bayer mosaic)
distortionParameters, //
patternDetectParameters,
matchSimulatedPatternCorr, // correlationSize
thisSimulParameters,
equalizeGreens,
windowFunctionCorr,
windowFunctionCorr2,
windowFunctionCorr4,
simulationPattern,
((iUVdir[0]^iUVdir[1])&1)!=0, // if true - invert pattern
fht_instance,
distortionParameters.fastCorrelationOnFirstPass,
locsNeib,
debugLevel);
// System.out.println("*+*debugLevel="+debugLevel);
if (centerXY==null){
invalidatePatternGridCell(
PATTERN_GRID,
iUVdir);
if (debugLevel>debugThreshold) {
dbgStr+=" -- FAILED";
System.out.println(dbgStr);
}
continue; // failed to find pattern in the cell TODO: implement
}
if (debugCellSet.getAndIncrement()==0){ // First cell
if (passNumber==1) {
debugUV[0]=iUVdir[0];
debugUV[1]=iUVdir[1];
if (debugLevel>debugThreshold) System.out.println("debugUV[] set to {"+debugUV[0]+","+debugUV[1]+"}");
passNumber=2; // global passNumber
}
}
//Found new cell, save info and increment counter
setPatternGridCell(
PATTERN_GRID, PATTERN_GRID,
iUVdir); iUVdir,
centerXY,
// specify wave vectors from the parent cell, will recalculate (if possible)
wv[0], //null, // double [] wv1,
wv[1]); //null); // double [] wv2);
if (cleanup.get()) addedCells.getAndIncrement();
if (debugLevel>debugThreshold) { if (debugLevel>debugThreshold) {
dbgStr+=" -- FAILED"; dbgStr+="==>added"+iUVdir[0]+"/"+iUVdir[1]+", dir"+iUVdir[2];
System.out.println(dbgStr); System.out.println(dbgStr);
} }
continue; // failed to find pattern in the cell TODO: implement
} }
if (debugCellSet.getAndIncrement()==0){ // First cell }
if (passNumber==1) { };
debugUV[0]=iUVdir[0]; }
debugUV[1]=iUVdir[1]; startAndJoin(threads);
if (debugLevel>debugThreshold) System.out.println("debugUV[] set to {"+debugUV[0]+","+debugUV[1]+"}"); // remove invalid cells from the list
passNumber=2; // global passNumber for (int i=waveFrontList.size()-1;i>=0;i--) {
} if (!isCellValid(PATTERN_GRID,getWaveList (waveFrontList,i))) {
// Make that cell "new", so it will be tried again, until wave will not touch it. So when more neigbors will be defined, previously failed
// cell will be retried
clearPatternGridCell(PATTERN_GRID,getWaveList (waveFrontList,i));
waveFrontList.remove(i);
if (debugLevel>1) System.out.println("XXX->clear invalid ("+i+")");
}
}
//If anything was added during the layer - calculate and fill in wave vectors here (they are set to the same as in the parent cell)
// this code is not needed now, the wave vectors are recalculated from x/y locations, the stored ones are not used
if (waveFrontList.size()>0) {
for (int listIndex=0;listIndex<waveFrontList.size();listIndex++) {
uvdir= getWaveList (waveFrontList,listIndex);
if (debugLevel>1) System.out.println("<---= uvdir= "+uvdir[0]+", "+uvdir[1]+", "+uvdir[2]);
thisCell=PATTERN_GRID[uvdir[1]][uvdir[0]];
neibBits=0;
for (dir=0;dir<directionsUV8.length;dir++) {
neibors[dir]=null;
iUV[0]=uvdir[0]+directionsUV8[dir][0];
iUV[1]=uvdir[1]+directionsUV8[dir][1];
if ((iUV[0]<0) || (iUV[1]<0) ||
(iUV[0]>=distortionParameters.gridSize) || (iUV[1]>=distortionParameters.gridSize)) continue; // don't fit into UV grid
if (isCellValid(PATTERN_GRID,iUV)) {
neibors[dir]= new double [2][2];
otherCell=PATTERN_GRID[iUV[1]][iUV[0]];
neibors[dir][0][0]=0.5*directionsUV8[dir][0]; // u
neibors[dir][0][1]=0.5*directionsUV8[dir][1]; // v
neibors[dir][1][0]=otherCell[0][0]-thisCell[0][0]; // x
neibors[dir][1][1]=otherCell[0][1]-thisCell[0][1]; // y
neibBits |= directionsBits8[dir];
} }
//Found new cell, save info and increment counter }
int i=Integer.bitCount(neibBits);
if (debugLevel>1) System.out.println("neibBits="+neibBits+", number of bits= "+i);
if (i>1) {
double[][] wv= waveVectorsFromNeib(neibors);
setPatternGridCell( setPatternGridCell(
PATTERN_GRID, PATTERN_GRID,
iUVdir, uvdir,
centerXY, null, // XY already set
// specify wave vectors from the parent cell, will recalculate (if possible) wv[0],
wv[0], //null, // double [] wv1, wv[1]);
wv[1]); //null); // double [] wv2);
if (cleanup.get()) addedCells.getAndIncrement(); if (debugLevel>1) System.out.println("==+> number of bits:"+i+
if (debugLevel>debugThreshold) { " vw00="+IJ.d2s(wv[0][0],5)+" vw01="+IJ.d2s(wv[0][1],5)+
dbgStr+="==>added"+iUVdir[0]+"/"+iUVdir[1]+", dir"+iUVdir[2]; " vw10="+IJ.d2s(wv[1][0],5)+" vw11="+IJ.d2s(wv[1][1],5));
System.out.println(dbgStr); // wv= WaveVectorsFromNeib(neibors);
} //
// vectors: [num_vector][0][0] - U
// [num_vector][0][1] - V
// [num_vector][1][0] - X
// [num_vector][1][1] - Y
// [num_vector] == null - skip
//
}
}
} else if (!cleanup.get() || (addedCells.get()>0)) { // create list of the defined cells on the border
cleanup.set(true);
if ((debugLevel>1) && !cleanup.get()) System.out.println("Added "+addedCells.get()+" during border cleanup");
addedCells.set(0);
umax=0;
vmax=0;
vmin=PATTERN_GRID.length;
umin=PATTERN_GRID[0].length;
for (int i=0;i<PATTERN_GRID.length;i++) for (int j=0;j<PATTERN_GRID[i].length;j++) {
if ((PATTERN_GRID[i][j]!=null) && (PATTERN_GRID[i][j][0]!=null)) {
if (vmin > i) vmin = i;
if (vmax < i) vmax = i;
if (umin > j) umin = j;
if (umax < j) umax = j;
} }
} }
}; int [] uvNew=new int [2];
} for (uvNew[1]=vmin;uvNew[1]<=vmax;uvNew[1]++) for (uvNew[0]=umin;uvNew[0]<=umax;uvNew[0]++) if (isCellDefined(PATTERN_GRID,uvNew)){
startAndJoin(threads); for (dir=0;dir<directionsUV.length;dir++) {
// remove invalid cells from the list iUV[0]=uvNew[0]+directionsUV[dir][0];
for (int i=waveFrontList.size()-1;i>=0;i--) { iUV[1]=uvNew[1]+directionsUV[dir][1];
if (!isCellValid(PATTERN_GRID,getWaveList (waveFrontList,i))) { if (!isCellDefined(PATTERN_GRID,iUV)){
// Make that cell "new", so it will be tried again, until wave will not touch it. So when more neigbors will be defined, previously failed putInWaveList (waveFrontList, uvNew, dir); // direction does not matter here
// cell will be retried break;
clearPatternGridCell(PATTERN_GRID,getWaveList (waveFrontList,i)); }
waveFrontList.remove(i);
if (debugLevel>1) System.out.println("XXX->clear invalid ("+i+")");
}
}
//If anything was added during the layer - calculate and fill in wave vectors here (they are set to the same as in the parent cell)
// this code is not needed now, the wave vectors are recalculated from x/y locations, the stored ones are not used
if (waveFrontList.size()>0) {
for (int listIndex=0;listIndex<waveFrontList.size();listIndex++) {
uvdir= getWaveList (waveFrontList,listIndex);
if (debugLevel>1) System.out.println("<---= uvdir= "+uvdir[0]+", "+uvdir[1]+", "+uvdir[2]);
thisCell=PATTERN_GRID[uvdir[1]][uvdir[0]];
neibBits=0;
for (dir=0;dir<directionsUV8.length;dir++) {
neibors[dir]=null;
iUV[0]=uvdir[0]+directionsUV8[dir][0];
iUV[1]=uvdir[1]+directionsUV8[dir][1];
if ((iUV[0]<0) || (iUV[1]<0) ||
(iUV[0]>=distortionParameters.gridSize) || (iUV[1]>=distortionParameters.gridSize)) continue; // don't fit into UV grid
if (isCellValid(PATTERN_GRID,iUV)) {
neibors[dir]= new double [2][2];
otherCell=PATTERN_GRID[iUV[1]][iUV[0]];
neibors[dir][0][0]=0.5*directionsUV8[dir][0]; // u
neibors[dir][0][1]=0.5*directionsUV8[dir][1]; // v
neibors[dir][1][0]=otherCell[0][0]-thisCell[0][0]; // x
neibors[dir][1][1]=otherCell[0][1]-thisCell[0][1]; // y
neibBits |= directionsBits8[dir];
} }
} }
int i=Integer.bitCount(neibBits); if (debugLevel>1) System.out.println("***** Starting cleanup, wave length="+waveFrontList.size());
if (debugLevel>1) System.out.println("neibBits="+neibBits+", number of bits= "+i); }
if (i>1) { // end of layer
double[][] wv= waveVectorsFromNeib(neibors); if (initialWave!=null){ // just after the first layer (usually one cell) - delete it and add next time - otherwise first one needs large correction
setPatternGridCell( if (debugLevel>0) System.out.println("Removing "+initialWave.size()+" initial wave cells");
PATTERN_GRID, while (initialWave.size()>0){
uvdir, uvdir= getWaveList (initialWave,0);
null, // XY already set clearPatternGridCell(PATTERN_GRID, uvdir);
wv[0], initialWave.remove(0);
wv[1]);
if (debugLevel>1) System.out.println("==+> number of bits:"+i+
" vw00="+IJ.d2s(wv[0][0],5)+" vw01="+IJ.d2s(wv[0][1],5)+
" vw10="+IJ.d2s(wv[1][0],5)+" vw11="+IJ.d2s(wv[1][1],5));
// wv= WaveVectorsFromNeib(neibors);
//
// vectors: [num_vector][0][0] - U
// [num_vector][0][1] - V
// [num_vector][1][0] - X
// [num_vector][1][1] - Y
// [num_vector] == null - skip
//
} }
initialWave=null;
}
}//while (waveFrontList.size()>0)
debugLevel=was_debug_level;
/*
if (updating){
return PATTERN_GRID; // no need to crop the array, it should not change
}
*/
umax=0;
vmax=0;
vmin=PATTERN_GRID.length;
umin=PATTERN_GRID[0].length;
numDefinedCells=0;
for (int i=0;i<PATTERN_GRID.length;i++) for (int j=0;j<PATTERN_GRID[i].length;j++) {
if ((PATTERN_GRID[i][j]!=null) && (PATTERN_GRID[i][j][0]!=null)) {
if (vmin > i) vmin = i;
if (vmax < i) vmax = i;
if (umin > j) umin = j;
if (umax < j) umax = j;
numDefinedCells++;
}
}
// if (updating){
// return numDefinedCells; // no need to crop the array, it should not change
// }
if (!updating){
if (vmin>vmax){
this.PATTERN_GRID=null;
continue; // try next in queue if available
// return 0; // null; // nothing found
} }
} else if (!cleanup.get() || (addedCells.get()>0)) { // create list of the defined cells on the border // Add extra margins for future extrapolation
cleanup.set(true); int extra=distortionParameters.numberExtrapolated -((distortionParameters.removeLast)?1:0);
if ((debugLevel>1) && !cleanup.get()) System.out.println("Added "+addedCells.get()+" during border cleanup"); vmin-=extra;
addedCells.set(0); if (vmin<0) vmin=0;
umax=0; umin-=extra;
vmax=0; if (umin<0) umin=0;
vmin=PATTERN_GRID.length; vmax+=extra;
umin=PATTERN_GRID[0].length; if (vmax>=PATTERN_GRID.length) vmax=PATTERN_GRID.length-1;
for (int i=0;i<PATTERN_GRID.length;i++) for (int j=0;j<PATTERN_GRID[i].length;j++) { umax+=extra;
if (umax>=PATTERN_GRID[0].length) umax=PATTERN_GRID[0].length-1;
// make sure the odd/even uv does not change (and so the cross phases defined by U & V)
vmin &= ~1;
umin &= ~1;
// make width/height even (not needed)
umax |=1;
vmax |=1;
// remove margins
double [][][][] result = new double [vmax-vmin+1][umax-umin+1][][];
for (int i=vmin;i<=vmax;i++) for (int j=umin;j<=umax;j++) {
if ((PATTERN_GRID[i][j]!=null) && (PATTERN_GRID[i][j][0]!=null)) { if ((PATTERN_GRID[i][j]!=null) && (PATTERN_GRID[i][j][0]!=null)) {
if (vmin > i) vmin = i; result[i-vmin][j-umin]=PATTERN_GRID[i][j];
if (vmax < i) vmax = i; } else result[i-vmin][j-umin]=null;
if (umin > j) umin = j; }
if (umax < j) umax = j; this.debugUV[0]-=umin;
this.debugUV[1]-=umin;
if (debugLevel>2) System.out.println("debugUV[] updated to {"+this.debugUV[0]+","+this.debugUV[1]+"}");
if (debugLevel>1) System.out.println("Total number of defined cells="+numDefinedCells);
this.PATTERN_GRID=result;
}
// more tests here (moved from the caller) that result is good
double averageGridPeriod=Double.NaN;
if (this.PATTERN_GRID!=null) averageGridPeriod=averageGridPeriod(this.PATTERN_GRID);
if (debugLevel>0){
System.out.println("Pattern period="+averageGridPeriod+
" limits are set to :"+patternDetectParameters.minGridPeriod+","+patternDetectParameters.maxGridPeriod);
}
if (!Double.isNaN(averageGridPeriod)) {
if (!Double.isNaN(patternDetectParameters.minGridPeriod) &&
(patternDetectParameters.minGridPeriod>0.0) &&
(averageGridPeriod<patternDetectParameters.minGridPeriod)){
if (debugLevel>0){
System.out.println("Pattern is too small, period="+averageGridPeriod+
" minimal="+patternDetectParameters.minGridPeriod);
} }
continue; // bad grid
} }
int [] uvNew=new int [2]; if (!Double.isNaN(patternDetectParameters.maxGridPeriod) &&
for (uvNew[1]=vmin;uvNew[1]<=vmax;uvNew[1]++) for (uvNew[0]=umin;uvNew[0]<=umax;uvNew[0]++) if (isCellDefined(PATTERN_GRID,uvNew)){ (patternDetectParameters.maxGridPeriod>0.0) &&
for (dir=0;dir<directionsUV.length;dir++) { (averageGridPeriod>patternDetectParameters.maxGridPeriod)){
iUV[0]=uvNew[0]+directionsUV[dir][0]; if (debugLevel>0){
iUV[1]=uvNew[1]+directionsUV[dir][1]; System.out.println("Pattern is too large, period="+averageGridPeriod+
if (!isCellDefined(PATTERN_GRID,iUV)){ " maximal="+patternDetectParameters.maxGridPeriod);
putInWaveList (waveFrontList, uvNew, dir); // direction does not matter here
break;
}
} }
continue; // bad grid
} }
if (debugLevel>1) System.out.println("***** Starting cleanup, wave length="+waveFrontList.size());
} }
// end of layer if (
if (initialWave!=null){ // just after the first layer (usually one cell) - delete it and add next time - otherwise first one needs large correction (distortionParameters.minimalPatternCluster<=0) || // minimal cluster size is disabled
if (debugLevel>0) System.out.println("Removing "+initialWave.size()+" initial wave cells"); (distortionParameters.scaleMinimalInitialContrast<=0) || // minimal cluster size is disabled
while (initialWave.size()>0){ ((numDefinedCells==0) && fromVeryBeginning)|| // no cells detected at all, starting from the very beginning
uvdir= getWaveList (initialWave,0); (numDefinedCells>=distortionParameters.minimalPatternCluster) // detected enough cells
clearPatternGridCell(PATTERN_GRID, uvdir); ) {
initialWave.remove(0); return numDefinedCells;
}
initialWave=null;
} }
if (roi!=null){ // don't use this feature with ROI as it can be small
}//while (waveFrontList.size()>0) if (global_debug_level>0) System.out.println("Initial pattern cluster is small ("+numDefinedCells+"), but ROI is set - no retries");
debugLevel=was_debug_level; {
/* return numDefinedCells;
if (updating){ }
return PATTERN_GRID; // no need to crop the array, it should not change
}
*/
umax=0;
vmax=0;
vmin=PATTERN_GRID.length;
umin=PATTERN_GRID[0].length;
int numDefinedCells=0;
for (int i=0;i<PATTERN_GRID.length;i++) for (int j=0;j<PATTERN_GRID[i].length;j++) {
if ((PATTERN_GRID[i][j]!=null) && (PATTERN_GRID[i][j][0]!=null)) {
if (vmin > i) vmin = i;
if (vmax < i) vmax = i;
if (umin > j) umin = j;
if (umax < j) umax = j;
numDefinedCells++;
} }
} } // next node in queue
// failed to find - deal in the caller
if (updating){ /*
return numDefinedCells; // no need to crop the array, it should not change boolean someLeft=false;
int startScanIndex=0;
for (startScanIndex=3;startScanIndex<triedIndices.length;startScanIndex++) if (!triedIndices[startScanIndex]){
someLeft=true;
break;
} }
if (vmin>vmax){ if (someLeft) {
this.PATTERN_GRID=null; if (global_debug_level>0){
return 0; // null; // nothing found System.out.println("Initial pattern cluster is too small ("+numDefinedCells+
} "), continuing scanning from index "+startScanIndex);
// Add extra margins for future extrapolation }
int extra=distortionParameters.numberExtrapolated -((distortionParameters.removeLast)?1:0); } else {
vmin-=extra; // startScanIndex[0]=0;
if (vmin<0) vmin=0; System.out.println("Last pattern cluster was too small, adjusting the minimal contrast from "+
umin-=extra; IJ.d2s(distortionParameters.correlationMinInitialContrast,3)+
if (umin<0) umin=0; " to "+IJ.d2s(distortionParameters.correlationMinInitialContrast*distortionParameters.scaleMinimalInitialContrast,3));
vmax+=extra; distortionParameters.correlationMinInitialContrast*=distortionParameters.scaleMinimalInitialContrast;
if (vmax>=PATTERN_GRID.length) vmax=PATTERN_GRID.length-1; for (int i=0;i<triedIndices.length;i++) triedIndices[i]=(i<3); // mark first 3 as if they are already used
umax+=extra; fromVeryBeginning=true;
if (umax>=PATTERN_GRID[0].length) umax=PATTERN_GRID[0].length-1;
// make sure the odd/even uv does not change (and so the cross phases defined by U & V)
vmin &= ~1;
umin &= ~1;
// make width/height even (not needed)
umax |=1;
vmax |=1;
// remove margins
double [][][][] result = new double [vmax-vmin+1][umax-umin+1][][];
for (int i=vmin;i<=vmax;i++) for (int j=umin;j<=umax;j++) {
if ((PATTERN_GRID[i][j]!=null) && (PATTERN_GRID[i][j][0]!=null)) {
result[i-vmin][j-umin]=PATTERN_GRID[i][j];
} else result[i-vmin][j-umin]=null;
} }
this.debugUV[0]-=umin; */
this.debugUV[1]-=umin; return 0; // none
if (debugLevel>2) System.out.println("debugUV[] updated to {"+this.debugUV[0]+","+this.debugUV[1]+"}");
if (debugLevel>1) System.out.println("Total number of defined cells="+numDefinedCells);
this.PATTERN_GRID=result;
return numDefinedCells; //result;
} }
private double [][] findPatternCandidate( public double [][] findPatternCandidate_old(
// final int [] startScanIndex, // [0] will be updated // final int [] startScanIndex, // [0] will be updated
final boolean [] triedIndices, // which indices are already tried final boolean [] triedIndices, // which indices are already tried
final int startScanIndex, final int startScanIndex,
...@@ -3730,6 +3824,117 @@ public class MatchSimulatedPattern { ...@@ -3730,6 +3824,117 @@ public class MatchSimulatedPattern {
// if (nodeRef[0]==null) startScanIndex[0]=numTries; // all used // if (nodeRef[0]==null) startScanIndex[0]=numTries; // all used
return nodeRef[0]; return nodeRef[0];
} }
class GridNode {
double [][] node;
public GridNode(double [][] node){
this.node=node;
}
public double [][] getNode(){
return this.node;
}
}
// private double [][][] findPatternCandidates(
private Queue<GridNode> findPatternCandidates(
// final int [] startScanIndex, // [0] will be updated
final boolean [] triedIndices, // which indices are already tried
final int startScanIndex,
final int tryHor,
final int tryVert,
// final int numTries,
final Rectangle selection,
final DistortionParameters distortionParameters, //
final MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
final SimulationPattern.SimulParameters thisSimulParameters,
final MatchSimulatedPattern matchSimulatedPattern,
final MatchSimulatedPattern matchSimulatedPatternCorr,
final SimulationPattern simulationPattern,
final boolean equalizeGreens,
final ImagePlus imp, // image to process
final double [] bPattern,
final double [] windowFunction,
final double [] windowFunctionCorr,
final double [] windowFunctionCorr2,
final double [] windowFunctionCorr4,
final double[][] locsNeib, // which neibors to try (here - just the center)
final int threadsMax,
final boolean updateStatus,
final int debugLevel
){
final Thread[] threads = newThreadArray(threadsMax);
final AtomicInteger seqNumber = new AtomicInteger(startScanIndex);
// final AtomicBoolean nodeSet=new AtomicBoolean(false);
// final double [][][] nodeRef= new double[1][][];
// nodeRef[0]=null;
final Queue<GridNode> nodeQueue = new ConcurrentLinkedQueue<GridNode>();
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
int nbh, nbv, nh, nv, nb;
double [] point = new double[2];
for (int n=seqNumber.getAndIncrement(); n<(triedIndices.length-1); n=seqNumber.getAndIncrement()) if (!triedIndices[n]){
if (!nodeQueue.isEmpty()) break; // already set at least one element
nbh=tryHor-1;
nbv=tryVert-1;
nh=0;
nv=0;
nb=0;
while (nb<(tryHor+tryVert)) {
if (nbh>=0) {
if ((n & (1<<nb))!=0) nh |= 1<<nbh;
nbh--;
nb++;
}
if (nbv>=0) {
if ((n & (1<<nb))!=0) nv |= 1<<nbv;
nbv--;
nb++;
}
}
if (debugLevel>2) System.out.println("Searching, n="+n+", nv="+nv+", nh="+nh+", nb="+nb );
if ((nv>0) && (nh>0)) {
point[0]=(selection.x+nh*selection.width/(1<<tryHor)) & ~1;
point[1]=(selection.y+nv*selection.height/(1<<tryVert)) & ~1;
if (debugLevel>2) System.out.println("trying xc="+point[0]+", yc="+point[1]+"(nv="+nv+", nh="+nh+")");
// if ((debugLevel>2) && (n==3)) debugLevel=3; // show debug images for the first point
double [][] node=tryPattern (
point, // xy to try
distortionParameters, //no control of the displacement
patternDetectParameters,
thisSimulParameters,
matchSimulatedPattern,
matchSimulatedPatternCorr,
simulationPattern,
equalizeGreens,
imp, // image to process
bPattern,
windowFunction,
windowFunctionCorr,
windowFunctionCorr2,
windowFunctionCorr4,
locsNeib // which neibors to try (here - just the center)
);
if ((node!=null) && (node[0]!=null)) {
nodeQueue.add(new GridNode(node));
if (debugLevel>1) System.out.println("probing "+n);
}
}
triedIndices[n]=true; // regardless - good or bad
}
}
};
}
startAndJoin(threads);
// if (nodeQueue.isEmpty()) return null;
return nodeQueue; // never null, may be empty
// double [][][] nodes = new double [nodeQueue.size()][][];
// for (int i=0;i<nodes.length;i++) nodes[i]=nodeQueue.poll().getNode();
// return nodes;
}
/* ================================================================*/ /* ================================================================*/
public void scaleContrast(double scale){ public void scaleContrast(double scale){
...@@ -5270,8 +5475,18 @@ public class MatchSimulatedPattern { ...@@ -5270,8 +5475,18 @@ public class MatchSimulatedPattern {
imp, imp,
threadsMax, threadsMax,
updateStatus, updateStatus,
debug_level); // debug level debug_level,
global_debug_level); // debug level
if (global_debug_level>1) System.out.println("Pattern correlation done at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)); if (global_debug_level>1) System.out.println("Pattern correlation done at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
if (patternCells>0) {
foundGoodCluster=true;
break; // new distortions() code - returns non-zero only if passed other tests
}
if (fromVeryBeginning){
if (global_debug_level>1) System.out.println("--- Nothing found at all ---");
break; // or maybe - still try to adjust threshold?
}
/*
double averageGridPeriod=Double.NaN; double averageGridPeriod=Double.NaN;
if (this.PATTERN_GRID!=null) averageGridPeriod=averageGridPeriod(this.PATTERN_GRID); if (this.PATTERN_GRID!=null) averageGridPeriod=averageGridPeriod(this.PATTERN_GRID);
if (global_debug_level>0){ if (global_debug_level>0){
...@@ -5337,7 +5552,36 @@ public class MatchSimulatedPattern { ...@@ -5337,7 +5552,36 @@ public class MatchSimulatedPattern {
} }
// distortionParameters.correlationMinInitialContrast*=distortionParameters.scaleMinimalInitialContrast; // distortionParameters.correlationMinInitialContrast*=distortionParameters.scaleMinimalInitialContrast;
// } // }
*/
boolean someLeft=false;
int startScanIndex=0;
for (startScanIndex=3;startScanIndex<triedIndices.length;startScanIndex++) if (!triedIndices[startScanIndex]){
someLeft=true;
break;
}
if (someLeft) {
// if (!triedIndices[triedIndices.length-1]) {
if (global_debug_level>0){
// int startScanIndex=3;
// for (;(startScanIndex<triedIndices.length) && triedIndices[startScanIndex];startScanIndex++); // skip tried indices
System.out.println("Initial pattern cluster is too small ("+patternCells+
"), continuing scanning from index "+startScanIndex);
}
} else {
// startScanIndex[0]=0;
System.out.println("Last pattern cluster was too small, adjusting the minimal contrast from "+
IJ.d2s(distortionParameters.correlationMinInitialContrast,3)+
" to "+IJ.d2s(distortionParameters.correlationMinInitialContrast*distortionParameters.scaleMinimalInitialContrast,3));
distortionParameters.correlationMinInitialContrast*=distortionParameters.scaleMinimalInitialContrast;
for (int i=0;i<triedIndices.length;i++) triedIndices[i]=(i<3); // mark first 3 as if they are already used
fromVeryBeginning=true;
}
} }
// restore initial distortionParameters.correlationMinInitialContrast // restore initial distortionParameters.correlationMinInitialContrast
distortionParameters.correlationMinInitialContrast=savedCorrelationMinInitialContrast; distortionParameters.correlationMinInitialContrast=savedCorrelationMinInitialContrast;
if (!foundGoodCluster){ if (!foundGoodCluster){
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment