SuperTiles.java 388 KB
Newer Older
1
package com.elphel.imagej.tileprocessor;
2 3 4 5 6 7 8
/**
 **
 ** SuperTiles - Process tiles resulted from quad image sets
 **
 ** Copyright (C) 2017 Elphel, Inc.
 **
 ** -----------------------------------------------------------------------------**
9
 **
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 **  SuperTiles.java is free software: you can redistribute it and/or modify
 **  it under the terms of the GNU General Public License as published by
 **  the Free Software Foundation, either version 3 of the License, or
 **  (at your option) any later version.
 **
 **  This program is distributed in the hope that it will be useful,
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 **  GNU General Public License for more details.
 **
 **  You should have received a copy of the GNU General Public License
 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ** -----------------------------------------------------------------------------**
 **
 */
25
import java.util.ArrayList;
Andrey Filippov's avatar
Andrey Filippov committed
26 27
import java.util.Collections;
import java.util.Comparator;
28 29
import java.util.HashMap;
import java.util.HashSet;
30
import java.util.concurrent.atomic.AtomicInteger;
31

Andrey Filippov's avatar
Andrey Filippov committed
32
import com.elphel.imagej.common.DoubleGaussianBlur;
33
import com.elphel.imagej.common.ShowDoubleFloatArrays;
Andrey Filippov's avatar
Andrey Filippov committed
34

35
public class SuperTiles{
36
	public TileProcessor tileProcessor;
Andrey Filippov's avatar
Andrey Filippov committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
	double      step_far;
	double      step_near;
	double      step_threshold_far;    // relative to min_disparity
	double      step_threshold_near;   // relative to min_disparity
	double      bin_far;               // bin value (before rounding) matching  (min_disparity + step_threshold_far)
	double      bin_near;              // bin value (before rounding) matching  (min_disparity + step_threshold_near)
	double      min_disparity;
	double      max_disparity;
	double      stBlurSigma;
	int         numBins;
	double []   bin_centers;
	double [][] disparityHistograms = null;
	double []   stStrength =          null; // per super-tile correlation strength
	double [][][] maxMinMax = null;
	double []   bgDisparity = null;
	double []   bgStrength = null;
53
	int         measSel = 1; // bitmask of the selected measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
54

55
	boolean     smplMode        = true;   // Use sample mode (false - regular tile mode)
56 57 58 59

	/*
	double      strength_floor;
	double      strength_pow;
60 61 62
	int         smplSide        = 2;      // Sample size (side of a square)
	int         smplNum         = 3;      // Number after removing worst
	double      smplRms         = 0.1;    // Maximal RMS of the remaining tiles in a sample
63
	boolean     smplWnd         = false;  // final boolean    smplWnd,  // use window functions for the samples
64 65 66 67 68 69 70
	double      max_abs_tilt  = 2.0; // Maximal absolute tilt in pixels/tile
	double      max_rel_tilt  = 0.2; // Maximal relative tilt in pixels/tile/disparity
	double      damp_tilt  =    0.001; // Damp tilt to handle insufficient  (co-linear)data
	double      min_tilt_disp = 4.0; // Disparity switch between filtering modes - near objects use tilts, far - use max disparity
	double      transition    = 1.0; // Mode transition range (between tilted and maximal disparity)
	int         far_mode  =     1;   // Far objects filtering mode (0 - off, 1 - power of disparity)
	double      far_power =     1.0; // Raise disparity to this power before averaging for far objects
71 72
*/
	MeasuredLayersFilterParameters mlfp = new MeasuredLayersFilterParameters();     // filter parameters
Andrey Filippov's avatar
Andrey Filippov committed
73
	MeasuredLayers measuredLayers = null;
74

Andrey Filippov's avatar
Andrey Filippov committed
75 76 77 78
	CLTPass3d cltPass3d;
	TilePlanes.PlaneData [][] planes =  null;
	TilePlanes.PlaneData [][] planes_mod = null;
	double [][][] fuse_coeff = null; // coefficients to fuse planes in neighbor supertiles
Andrey Filippov's avatar
Andrey Filippov committed
79

Andrey Filippov's avatar
Andrey Filippov committed
80 81
	int [][]    shell_map = null;   // per supertile, per disparity plane - shell index + 1 (0 - none)
	double [][] surfaces;  // per shell, per tile (linescan order) disparity value or NaN in missing supertiles
82 83 84

	TileSurface tileSurface = null;

Andrey Filippov's avatar
Andrey Filippov committed
85

86 87 88 89 90
	/**
	 * currently lowest plane for each includes all tiles, so do not use it. May change in the future
	 * @param np total number of planes in a supertile
	 * @return lowest plane to iterate through
	 */
91 92

	static int LOWEST_PLANE(int np){ //
93 94
		return (np >1) ? 1 : 0;
	}
Andrey Filippov's avatar
Andrey Filippov committed
95 96 97 98 99 100 101 102

	public SuperTiles(
			CLTPass3d cltPass3d,
			double                  step_near,
			double                  step_far,
			double                  step_threshold,
			double                  min_disparity,
			double                  max_disparity,
103

104
			double                  stBlurSigma,
105
			boolean                 smplMode, //        = true;   // Use sample mode (false - regular tile mode)
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
			MeasuredLayersFilterParameters  mlfp,

//			double                  strength_floor,
//			double                  strength_pow,
//			boolean                 smplMode, //        = true;   // Use sample mode (false - regular tile mode)
//			int                     smplSide, //        = 2;      // Sample size (side of a square)
//			int                     smplNum, //         = 3;      // Number after removing worst
//			double                  smplRms, //         = 0.1;    // Maximal RMS of the remaining tiles in a sample
//			boolean                 smplWnd,  // use window functions for the samples

//  			double     max_abs_tilt,  //  2.0;   // pix per tile
//			double     max_rel_tilt,  //  0.2;   // (pix / disparity) per tile
//			double     damp_tilt,     //  0.001; // Damp tilt to handle insufficient  (co-linear)data
//			double     min_tilt_disp, //  4.0;   // Disparity switch between filtering modes - near objects use tilts, far - use max disparity
//			double     transition,    //  1.0;   // Mode transition range (between tilted and maximal disparity)
//			int        far_mode,      //  1;     // Far objects filtering mode (0 - off, 1 - power of disparity)
//			double     far_power,     //  3.0;   // Raise disparity to this power before averaging for far objects
123 124
//			boolean    null_if_none,

125
			int                     measSel)
Andrey Filippov's avatar
Andrey Filippov committed
126 127 128 129 130 131 132 133 134
	{
		this.cltPass3d =           cltPass3d;
		this.tileProcessor =       cltPass3d.getTileProcessor();
		this.step_near =           step_near;
		this.step_far =            step_far;
		this.step_threshold_far = step_threshold;
		this.min_disparity =  min_disparity;
		this.max_disparity =  max_disparity;
		this.stBlurSigma =    stBlurSigma;
135
		this.smplMode        = smplMode;   // Use sample mode (false - regular tile mode)
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
		this.mlfp = mlfp.clone();

//		this.strength_floor = strength_floor;
//		this.strength_pow =   strength_pow;
//		this.smplSide        = smplSide;   // Sample size (side of a square)
//		this.smplNum         = smplNum;    // Number after removing worst
//		this.smplRms         = smplRms;    // Maximal RMS of the remaining tiles in a sample
//		this.max_abs_tilt =  max_abs_tilt;
//		this.max_rel_tilt =  max_rel_tilt;
//		this.damp_tilt =     damp_tilt;
//		this.min_tilt_disp = min_tilt_disp;
//		this.transition =    transition;
//		this.far_mode =      far_mode;
//		this.far_power =     far_power;
//		this.smplWnd         = smplWnd;    // Use window functions for the samples
151 152


153
		this.measSel =        measSel;
Andrey Filippov's avatar
Andrey Filippov committed
154
		this.step_threshold_near = this.step_threshold_far * step_near / this.step_far ;
155
		this.bin_far =             this.step_threshold_far / this.step_far;
Andrey Filippov's avatar
Andrey Filippov committed
156 157 158 159 160 161
		this.bin_near =            this.step_threshold_far / this.step_far * (Math.log(this.step_near/this.step_far) + 1);
		int bin_max = disparityToBin(max_disparity);
		numBins = bin_max + 1;
		bin_centers = new double [numBins];
		int bin = 0;
		for (bin = 0; bin < numBins; bin ++){
162
			bin_centers[bin] = binToDisparity(bin);
Andrey Filippov's avatar
Andrey Filippov committed
163
		}
Andrey Filippov's avatar
Andrey Filippov committed
164 165
//		initFuseCoeff(0.5, true); // true);
		initFuseCoeff(0.5, false); // true);
166 167

// Set up MeasuredLayers
Andrey Filippov's avatar
Andrey Filippov committed
168 169 170 171 172 173 174 175
		measuredLayers = new MeasuredLayers(
				4, // combo, quad, hor, vert
				tileProcessor.getTilesX(),
				tileProcessor.getTilesY(),
				tileProcessor.getSuperTileSize());
// MeasuredLayer.setLayer(int, double[], double[], boolean[])
		measuredLayers.setLayer( // combo disparity
				0,                                // int       num_layer,
176
				cltPass3d.getDisparity(0),        // double [] disparity,
Andrey Filippov's avatar
Andrey Filippov committed
177 178 179 180
				cltPass3d.getStrength(),          // double [] strength,
				cltPass3d.getSelected());         // boolean [] selection) // may be null
		measuredLayers.setLayer(                  // quad disparity
				1,                                // int       num_layer,
181
				cltPass3d.getDisparity(1),        // double [] disparity,
Andrey Filippov's avatar
Andrey Filippov committed
182 183 184 185
				cltPass3d.getOriginalStrength(),  // double [] strength,
				cltPass3d.getSelected());         // boolean [] selection) // may be null
		measuredLayers.setLayer(                  // hor disparity
				2,                                // int       num_layer,
186
				cltPass3d.getDisparity(2),        // double [] disparity,
Andrey Filippov's avatar
Andrey Filippov committed
187 188 189 190
				cltPass3d.getHorStrength(),       // double [] strength,
				cltPass3d.getSelected());         // boolean [] selection) // may be null
		measuredLayers.setLayer(                  // vert disparity
				3,                                // int       num_layer,
191
				cltPass3d.getDisparity(3),        // double [] disparity,
Andrey Filippov's avatar
Andrey Filippov committed
192 193
				cltPass3d.getVertStrength(),      // double [] strength,
				cltPass3d.getSelected());         // boolean [] selection) // may be null
194

195
		getDisparityHistograms(
196 197
				null,       // double  []   world_plane, // tilt equi-disparity planes to match real world planes (usually horizontal (or null)
				null,       // boolean [][] tile_sel, // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all
198
				smplMode,   // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
199 200 201 202 203 204 205 206 207 208 209 210 211
				mlfp,
//				smplSide,   // final int        smplSide, //        = 2;      // Sample size (side of a square)
//				smplNum,    // final int        smplNum,  //         = 3;      // Number after removing worst
//				smplRms,    // final double     smplRms,  //         = 0.1;    // Maximal RMS of the remaining tiles in a sample
//				smplWnd,    // final boolean    smplWnd,  // use window functions for the samples

//				max_abs_tilt,  // 2.0; // Maximal absolute tilt in pixels/tile
//				max_rel_tilt,  // 0.2; // Maximal relative tilt in pixels/tile/disparity
//				damp_tilt,     //    0.001; // Damp tilt to handle insufficient  (co-linear)data
//				min_tilt_disp, // 4.0; // Disparity switch between filtering modes - near objects use tilts, far - use max disparity
//				transition,    // 1.0; // Mode transition range (between tilted and maximal disparity)
//				far_mode,      //     1;   // Far objects filtering mode (0 - off, 1 - power of disparity)
//				far_power,     //    1.0; // Raise disparity to this power before averaging for far objects
212

213 214
				measSel);   // calculate and blur supertiles (for all, not just selected?)
		if (tileProcessor.globalDebugLevel > 0){
215 216 217 218 219 220 221 222 223
			System.out.println("SuperTiles(): min_disparity = "+min_disparity+", max_disparity="+max_disparity);
			System.out.println("SuperTiles(): step_far = "+step_far+", step_near="+step_near);
			System.out.println("SuperTiles(): numBins = "+numBins+", bin_far="+bin_far+", bin_near = "+bin_near);
			System.out.println("SuperTiles(): step_threshold_far = "+step_threshold_far+", step_threshold_near="+step_threshold_near);
			for (int i = 0; i<numBins; i++){
				System.out.println(i+": "+bin_centers[i]+", "+disparityToBin(bin_centers[i]));
			}
			//
		}
224 225 226 227 228 229 230
		if (tileProcessor.globalDebugLevel > 0){
			String [] titles = {"d0","s0","d1","s1","d2","s2","d3","s3"};
			double [][] dbg_img = new double [titles.length][];
			for (int i = 0; i < measuredLayers.getNumLayers(); i++){
				dbg_img[2 * i] =     measuredLayers.getDisparity(i);
				dbg_img[2 * i + 1] = measuredLayers.getStrength(i);
			}
231
			ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays();
232
			sdfa_instance.showArrays(dbg_img,  tileProcessor.getTilesX(), tileProcessor.getTilesY(), true, "measuredLayers",titles);
Andrey Filippov's avatar
Andrey Filippov committed
233
		}
Andrey Filippov's avatar
Andrey Filippov committed
234
	}
235 236 237
	public TileProcessor getTileProcessor(){
		return  tileProcessor;
	}
238

239 240 241 242
	public void setTileSurface( TileSurface tileSurface)
	{
		this.tileSurface = tileSurface;
	}
243 244 245 246 247 248 249 250 251
	public void setTileSurface(
			GeometryCorrection   geometryCorrection)
	{
		this.tileSurface = new TileSurface(
				tileProcessor.getTileSize(),      // int tileSize,
				tileProcessor.getSuperTileSize(), // int superTileSize,
				tileProcessor.getTilesX(),        // int tilesX,
				tileProcessor.getTilesY(),        // int tilesY,
				geometryCorrection,               // GeometryCorrection geometryCorrection,
252
				tileProcessor.threadsMax);        // int threadsMax);
253 254
	}

255

256 257 258 259
	public TileSurface getTileSurface()
	{
		return tileSurface;
	}
260

Andrey Filippov's avatar
Andrey Filippov committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
	public void initFuseCoeff(
			double scale_diag,
			boolean debug)
	{
		final int superTileSize = tileProcessor.getSuperTileSize();

		fuse_coeff = new double [8][2][superTileSize * superTileSize];
		double [] sin2orthotab = new double [2* superTileSize];
		for (int i = 0; i < 2 * superTileSize; i++){
			sin2orthotab[i] = 0.5 * (1.0 - Math.cos(Math.PI*(i + 0.5)/superTileSize));
		}
		double [] sin2diagtab = new double [4* superTileSize];
		for (int i = 0; i < 4 * superTileSize; i++){
			sin2diagtab[i] = 0.5 * (1.0 - Math.cos(Math.PI*i/(2 * superTileSize)));
		}
		//  ortho neighbors N, E, S, W
		for (int y = 0; y < superTileSize /2 ; y++){
			for (int x = 0; x < superTileSize; x++){
				int [] indx = {
						y * superTileSize +                       x,
						x * superTileSize +                       (superTileSize - y - 1),
						(superTileSize - y - 1) * superTileSize + (superTileSize - x - 1),
						(superTileSize - x - 1) * superTileSize + y,
				};
				for (int dir = 0; dir <4; dir++){
286 287
					fuse_coeff[2*dir][0][indx[dir]] = sin2orthotab[x + superTileSize/2] * sin2orthotab[y + superTileSize / 2];
					fuse_coeff[2*dir][1][indx[dir]] = sin2orthotab[x + superTileSize/2] * sin2orthotab[y + 3 * superTileSize / 2];
Andrey Filippov's avatar
Andrey Filippov committed
288
				}
289
			}
Andrey Filippov's avatar
Andrey Filippov committed
290 291 292 293 294 295 296 297 298 299 300 301 302 303
		}
		// Diagonal: NE, SE, SW, NW
		for (int y = 0; y < superTileSize ; y++){
			for (int x = y; x < superTileSize; x++){
				int [] indx = {
						y * superTileSize +                       x,
						x * superTileSize +                       (superTileSize - y - 1),
						(superTileSize - y - 1) * superTileSize + (superTileSize - x - 1),
						(superTileSize - x - 1) * superTileSize + y,
				};

				for (int dir = 0; dir <4; dir++){
					fuse_coeff[2*dir + 1][0][indx[dir]] = scale_diag *
							sin2diagtab[x + y + superTileSize + 1] *
304
							sin2diagtab[ x - y + 2* superTileSize];
Andrey Filippov's avatar
Andrey Filippov committed
305 306
					fuse_coeff[2*dir + 1][1][indx[dir]] = scale_diag *
							sin2diagtab[x + y + superTileSize + 1] *
307
							sin2diagtab[ x - y];
Andrey Filippov's avatar
Andrey Filippov committed
308
				}
309
			}
Andrey Filippov's avatar
Andrey Filippov committed
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
		}
		if (debug) {
			String [] titles = {
					"N_this",  "N-other",
					"NE_this", "NE-other",
					"E_this",  "E-other",
					"SE_this", "SE-other",
					"S_this",  "S-other",
					"SW_this", "SW-other",
					"W_this",  "W-other",
					"NW_this", "NW-other"};
			double [][] dbg_img = {
					fuse_coeff[0][0],fuse_coeff[0][1],
					fuse_coeff[1][0],fuse_coeff[1][1],
					fuse_coeff[2][0],fuse_coeff[2][1],
					fuse_coeff[3][0],fuse_coeff[3][1],
					fuse_coeff[4][0],fuse_coeff[4][1],
					fuse_coeff[5][0],fuse_coeff[5][1],
					fuse_coeff[6][0],fuse_coeff[6][1],
					fuse_coeff[7][0],fuse_coeff[7][1]};
330
			ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays(); // just for debugging?
Andrey Filippov's avatar
Andrey Filippov committed
331 332 333
			sdfa_instance.showArrays(dbg_img, superTileSize, superTileSize, true, "fuse_coeff",titles);
		}
	}
Andrey Filippov's avatar
Andrey Filippov committed
334

Andrey Filippov's avatar
Andrey Filippov committed
335 336 337 338 339 340
	public double [] getFuseThis(int dir){
		return fuse_coeff[dir][0];
	}
	public double [] getFuseOther(int dir){
		return fuse_coeff[dir][1];
	}
Andrey Filippov's avatar
Andrey Filippov committed
341

Andrey Filippov's avatar
Andrey Filippov committed
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
	public void setShellMap(int [][] shells){
		shell_map = shells;
	}

	public int [][] getShellMap(){
		return shell_map;
	}

	public void setSurfaces(double [][] surfaces){
		this.surfaces = surfaces;
	}

	public double [][] getSurfaces(){
		return surfaces;
	}

	public int disparityToBin(double disparity){ // not filtered
		double x = disparity - min_disparity;
		int bin;
		if (x < step_threshold_far){
			bin = (int) Math.round(x/step_far);
		} else if (x < step_threshold_near){
			bin = (int) Math.round(step_threshold_far / step_far * (Math.log(x / step_threshold_far) + 1));
		} else  {
			bin = (int) Math.round(bin_near + (x - step_threshold_near) / step_near);
		}
		//				if (bin < 0) bin = 0;
		//				else if (bin >= numBins) bin = numBins - 1;
		return bin;
	}

	public double binToDisparity(double bin){
		double d;
		if (bin < bin_far ) {
			d = bin * step_far;
		} else if (bin < bin_near){
			d =  step_threshold_far * Math.exp(bin * step_far / step_threshold_far - 1.0);
		} else {
380
			d = step_threshold_near + (bin - bin_near) * step_near;
Andrey Filippov's avatar
Andrey Filippov committed
381
		}
382
		return min_disparity + d;
Andrey Filippov's avatar
Andrey Filippov committed
383 384 385 386
	}

	public TilePlanes.PlaneData [][] getPlanes()
	{
387
		return planes;
Andrey Filippov's avatar
Andrey Filippov committed
388 389 390 391
	}

	public TilePlanes.PlaneData [][] getPlanesMod()
	{
392
		return planes_mod;
Andrey Filippov's avatar
Andrey Filippov committed
393 394 395 396
	}

	public void resetPlanesMod()
	{
397
		planes_mod = null;
Andrey Filippov's avatar
Andrey Filippov committed
398 399 400 401 402 403 404 405 406 407 408 409
	}

	private double [][] getLapWeights(){
		final int superTileSize = tileProcessor.superTileSize;
		final double [][] lapWeight = new double [2 * superTileSize][2 * superTileSize];
		final double [] lapWeight1d = new double [superTileSize];
		final int superTileSize2 = 2 * superTileSize;
		for (int i = 0; i < superTileSize; i++){
			lapWeight1d[i] = 0.5*(1.0 - Math.cos((i + 0.5)* Math.PI/superTileSize));
		}
		for (int i = 0; i < superTileSize; i++){
			for (int j = 0; j < superTileSize; j++){
410
				lapWeight[i]                     [                     j] = lapWeight1d[i]*lapWeight1d[j];
Andrey Filippov's avatar
Andrey Filippov committed
411
				lapWeight[superTileSize2 - 1 - i][                     j] = lapWeight[i][j];
412 413
				lapWeight[i]                     [superTileSize2 - 1 - j] = lapWeight[i][j];
				lapWeight[superTileSize2 - 1 - i][superTileSize2 - 1 - j] = lapWeight[i][j];
414
			}
Andrey Filippov's avatar
Andrey Filippov committed
415 416 417 418 419
		}
		double s = 0.0;
		for (int i = 0; i < superTileSize2; i++){
			for (int j = 0; j < superTileSize2; j++){
				s+=lapWeight[i][j];
420
			}
Andrey Filippov's avatar
Andrey Filippov committed
421 422 423 424
		}
		System.out.println("getLapWeights: sum = "+s);
		return lapWeight;
	}
425

426 427 428 429
	public void resetDisparityHistograms()
	{
		this.disparityHistograms = null;
	}
430

431 432 433 434 435
	public void setBlurSigma(double blurSigma) // resets histograms, as it needs re-calculating
	{
		this.stBlurSigma =         blurSigma;
		this.disparityHistograms = null;
	}
436

437
	public double [][] getDisparityHistograms(
438 439 440
			final double [][][][] disparity_strength, // pre-calculated disparity/strength [per super-tile][per-measurement layer][2][tiles] or null
			final boolean [][]    tile_sel, // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all
			final boolean         smplMode, //        = true;   // Use sample mode (false - regular tile mode)
441 442 443 444 445 446 447 448 449 450 451 452 453 454

			final MeasuredLayersFilterParameters mlfp,
//			final int             smplSide, //        = 2;      // Sample size (side of a square)
//			final int             smplNum,  //         = 3;      // Number after removing worst
//			final double          smplRms,  //         = 0.1;    // Maximal RMS of the remaining tiles in a sample
//			final boolean         smplWnd, //

//			final double          max_abs_tilt,  //  2.0;   // pix per tile
//			final double          max_rel_tilt,  //  0.2;   // (pix / disparity) per tile
//			final double          damp_tilt,     //  0.001; // Damp tilt to handle insufficient  (co-linear)data
//			final double          min_tilt_disp, //  4.0;   // Disparity switch between filtering modes - near objects use tilts, far - use max disparity
//			final double          transition,    //  1.0;   // Mode transition range (between tilted and maximal disparity)
//			final int             far_mode,      //  1;     // Far objects filtering mode (0 - off, 1 - power of disparity)
//			final double          far_power,     //  3.0;   // Raise disparity to this power before averaging for far objects
455

456
			final int             measSel)  //
457
	{
458
		if (disparity_strength != null) {
459
			System.out.println("getDisparityHistograms() with non-null disparity_strength");
460
		}
461 462
		if ((this.disparityHistograms != null) &&
				(smplMode == this.smplMode) &&
463 464 465 466 467 468 469 470 471 472 473 474
				(mlfp.equals(this.mlfp)) &&
//				(smplSide == this.smplSide) &&
//				(smplNum  == this.smplNum) &&
//				(smplRms  == this.smplRms) &&

//				(max_abs_tilt  == this.max_abs_tilt) &&
//				(max_rel_tilt  == this.max_rel_tilt) &&
//				(damp_tilt  == this.damp_tilt) &&
//				(min_tilt_disp  == this.min_tilt_disp) &&
//				(transition  == this.transition) &&
//				(far_mode  == this.far_mode) &&
//				(far_power  == this.far_power) &&
475 476 477
				(measSel  == this.measSel)){
				return this.disparityHistograms;
		}
478
		this.smplMode =      smplMode;   // Use sample mode (false - regular tile mode)
479 480 481 482 483 484 485 486 487 488 489 490
		this.mlfp = mlfp.clone();
//		this.smplSide =      smplSide;   // Sample size (side of a square)
//		this.smplNum  =      smplNum;    // Number after removing worst
//		this.smplRms  =      smplRms;    // Maximal RMS of the remaining tiles in a sample

//		this.max_abs_tilt =  max_abs_tilt;
//		this.max_rel_tilt =  max_rel_tilt;
//		this.damp_tilt =     damp_tilt;
//		this.min_tilt_disp = min_tilt_disp;
//		this.transition =    transition;
//		this.far_mode =      far_mode;
//		this.far_power =     far_power;
491 492 493

		this.measSel  =      measSel;

494 495
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
496
		final int superTileSize = tileProcessor.getSuperTileSize();
497
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
498
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
499 500
		final int nStiles = stilesX * stilesY;
		final double [][] dispHist =     new double [nStiles][]; // now it will be sparse
501 502 503
		final double []   strengthHist = new double [nStiles];
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
504
//		final TilePlanes tpl = new TilePlanes(tileProcessor.getTileSize(),superTileSize);
505

506 507
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
508
				@Override
509
				public void run() {
510

511
					for (int nsTile = ai.getAndIncrement(); nsTile < nStiles; nsTile = ai.getAndIncrement()) {
512
						int stileY = nsTile / stilesX;
513
						int stileX = nsTile % stilesX;
514 515
						double sw = 0.0; // sum weights
						double [] hist = new double [numBins];
516
						//						double [][][] disp_strength = new double [measuredLayers.getNumLayers()][][] ;
517
						for (int nl = 0; nl < measuredLayers.getNumLayers(); nl ++) {
518
							if (((measSel & (1 << nl)) != 0) && ((tile_sel == null) || ((tile_sel[nl] != null)))) {
519
								double [][] disp_strength;
520 521
								if (disparity_strength == null) {
									if (smplMode) {
Andrey Filippov's avatar
Andrey Filippov committed
522
										disp_strength =  measuredLayers.getDisparityStrengthMLTilted(
523 524 525 526 527
												nl,             // int num_layer,
												stileX,         // int stX,
												stileY,         // int stY,
												(((tile_sel == null) || (tile_sel[nl].length == 0))? null:tile_sel[nl]), // boolean [] sel_in,
												//											null,           // boolean [] sel_in,
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
												mlfp,
//												strength_floor, // double strength_floor,
//												strength_pow,   // double strength_pow,
//												smplSide,       // int        smplSide, // = 2;   // Sample size (side of a square)
//												smplNum,        //int        smplNum,   // = 3;   // Number after removing worst (should be >1)
//												smplRms,        //double     smplRms,   // = 0.1; // Maximal RMS of the remaining tiles in a sample
//												smplWnd,


//												max_abs_tilt,   //  = 2.0; // Maximal absolute tilt in pixels/tile
//												max_rel_tilt,   //  = 0.2; // Maximal relative tilt in pixels/tile/disparity
//												damp_tilt,      //  =    0.001; // Damp tilt to handle insufficient  (co-linear)data
//												min_tilt_disp,  // = 4.0; // Disparity switch between filtering modes - near objects use tilts, far - use max disparity
//												transition,     //    = 1.0; // Mode transition range (between tilted and maximal disparity)
//												far_mode,       //  =     1;   // Far objects filtering mode (0 - off, 1 - power of disparity)
//												far_power,      // =     1.0; // Raise disparity to this power before averaging for far objects
544

545 546
												true,          // boolean null_if_none);
												-1); // int debugLevel
547
									} else {
Andrey Filippov's avatar
Andrey Filippov committed
548
										disp_strength =  measuredLayers.getDisparityStrengthML(
549 550 551 552 553
												nl,             // int num_layer,
												stileX,         // int stX,
												stileY,         // int stY,
												(((tile_sel == null) || (tile_sel[nl].length == 0))? null:tile_sel[nl]), // boolean [] sel_in,
												//											null,           // boolean [] sel_in,
554 555
												mlfp.strength_floor, // double strength_floor,
												mlfp.strength_pow,   // double strength_pow,
556 557
												true);          // boolean null_if_none);
									}
558
								} else {
559
									disp_strength =  (disparity_strength[nsTile] != null) ? disparity_strength[nsTile][nl] : null;
560
								}
561 562
								if (disp_strength != null) {
									for (int indx = 0; indx < disp_strength[1].length; indx++) {
563
										double w = disp_strength[1][indx];
564
										if ( w > 0.0){
565
											double d = disp_strength[0][indx];
566 567 568 569 570 571 572 573 574 575 576 577 578
											int bin = disparityToBin(d);
											if ((bin >= 0) && (bin < numBins)){ // maybe collect below min and above max somewhere?
												hist[bin] += w; // +1]
												sw +=w;
											}
										}
									}
								}
							}
						}
						strengthHist[nsTile] = sw / superTileSize / superTileSize; // average strength per tile in the super-tile
						if (sw > 0){
							for (int i = 0; i<numBins; i++){
579
								hist[i] /= sw;
580 581 582 583 584 585 586 587
							}
							dispHist[nsTile] = hist;
						} else {
							dispHist[nsTile] = null;
						}
					}
				}
			};
588
		}
589 590 591 592 593 594 595 596
		ImageDtt.startAndJoin(threads);
		this.disparityHistograms = dispHist;
		this.stStrength =          strengthHist;
		if (this.stBlurSigma > 0.0) {
			blurDisparityHistogram(0); // debugLevel);
		}
		return this.disparityHistograms; // dispHist;
	}
597 598 599 600




Andrey Filippov's avatar
Andrey Filippov committed
601 602 603 604 605 606 607 608 609 610 611 612 613

	public void blurDisparityHistogram( // in-place
			final int  debugLevel)
	{

		final double [][] dispHist = this.disparityHistograms;
		final double      sigma =    this.stBlurSigma;
		final int sTiles = dispHist.length;
		//				final int numBins = dispHist[0].length;
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
614
				@Override
Andrey Filippov's avatar
Andrey Filippov committed
615 616 617 618 619 620 621 622 623
				public void run() {
					DoubleGaussianBlur gb=new DoubleGaussianBlur();
					for (int nsTile = ai.getAndIncrement(); nsTile < sTiles; nsTile = ai.getAndIncrement()) {
						if (dispHist[nsTile] != null) {
							gb.blur1Direction(dispHist[nsTile], numBins, 1, sigma, 0.01,true);
						}
					}
				}
			};
624
		}
Andrey Filippov's avatar
Andrey Filippov committed
625 626 627 628
		ImageDtt.startAndJoin(threads);
	}
	// returns odd-length array of max/min (x, strength) pairs

629 630 631 632
	public double [][][] getMaxMinMax(
			final double [][][][] disparity_strength, // pre-calculated disparity/strength [per super-tile][per-measurement layer][2][tiles] or null
			final boolean [][] tile_sel // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all
			){
Andrey Filippov's avatar
Andrey Filippov committed
633
		// first find all integer maximums, and if the top is flat - use the middle. If not flat - use 2-nd degree polynomial
634
		if (disparityHistograms == null) getDisparityHistograms(
635
//				world_plane, // double  []   world_plane, // tilt equi-disparity planes to match real world planes (usually horizontal (or null)
636
				disparity_strength, // pre-calculated disparity/strength [per super-tile][per-measurement layer][2][tiles] or null
637
				tile_sel,   // boolean [][] tile_sel, // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all
638
				this.smplMode,   // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
639 640 641 642 643 644 645 646 647 648 649 650 651
				this.mlfp,
//				this.smplSide,   // final int        smplSide, //        = 2;      // Sample size (side of a square)
//				this.smplNum,    // final int        smplNum,  //         = 3;      // Number after removing worst
//				this.smplRms,    // final double     smplRms,  //         = 0.1;    // Maximal RMS of the remaining tiles in a sample
//				this.smplWnd,    // final boolean    smplWnd,  // use window functions for the samples

//				this.max_abs_tilt,  // 2.0; // Maximal absolute tilt in pixels/tile
//				this.max_rel_tilt,  // 0.2; // Maximal relative tilt in pixels/tile/disparity
//				this.damp_tilt,     //    0.001; // Damp tilt to handle insufficient  (co-linear)data
//				this.min_tilt_disp, // 4.0; // Disparity switch between filtering modes - near objects use tilts, far - use max disparity
//				this.transition,    // 1.0; // Mode transition range (between tilted and maximal disparity)
//				this.far_mode,      //     1;   // Far objects filtering mode (0 - off, 1 - power of disparity)
//				this.far_power,     //    1.0; // Raise disparity to this power before averaging for far objects
652

653
				this.measSel);
Andrey Filippov's avatar
Andrey Filippov committed
654 655 656 657 658 659
		final int globalDebugLevel = tileProcessor.globalDebugLevel;
		maxMinMax = new double [disparityHistograms.length][][];
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
660
				@Override
Andrey Filippov's avatar
Andrey Filippov committed
661
				public void run() {
662
//					DoubleGaussianBlur gb=new DoubleGaussianBlur();
Andrey Filippov's avatar
Andrey Filippov committed
663 664 665 666 667
					for (int nsTile = ai.getAndIncrement(); nsTile < maxMinMax.length; nsTile = ai.getAndIncrement()) {
						if (disparityHistograms[nsTile] != null) {
							double [] dh = disparityHistograms[nsTile];
							double [][] mmm = new double [numBins][2]; // will definitely be shorter
							int numMax = 0;
668
							int lo = 0;
Andrey Filippov's avatar
Andrey Filippov committed
669
							int hi = 1;
670 671 672
//							if ((globalDebugLevel > -1 ) && (nsTile == 795)) {
//								System.out.println("getMaxMinMax(): nsTile="+nsTile);
//							}
Andrey Filippov's avatar
Andrey Filippov committed
673 674 675 676 677
							while (hi < numBins) {
								// looking for next max
								while ((hi < numBins) && (dh[hi] >= dh[hi - 1])) hi++; // flat or higher - continue
								if (hi == numBins){ // last
									if (dh[hi - 1] == dh[lo]) break; // no maximums till the very end
678 679
									if (dh[hi - 1] > dh[hi-2]) {//  and is higher than previous
										mmm[numMax * 2][0] = hi - 1;
Andrey Filippov's avatar
Andrey Filippov committed
680 681 682
									} else { // flat top, but higher than [lo]
										int i = hi - 3;
										while (dh[i] == dh[hi - 1]) i --;
683
										mmm[numMax * 2][0] = 0.5 * (hi + i); // middle
684
									}
Andrey Filippov's avatar
Andrey Filippov committed
685 686 687 688 689 690 691 692 693 694
									mmm[numMax * 2][1] = dh[hi - 1];
									numMax++;
									break;
								} else { // d[hi] < d[hi-1] // can be 2-nd after higher first, has sharp max at hi-1, have flat max (including from start)
									if ((dh[hi - 1] == dh[lo]) || (dh[hi - 1] == dh[hi-2])){ // just a second with higher 1-st, or a flat initial top
										// flat top
										while (dh[lo] < dh[hi - 1]) lo++;
										mmm[numMax * 2][0] = 0.5 *(hi - 1 + lo);
										mmm[numMax * 2][1] = dh[hi - 1];
									} else { // normal max, use parabola for approximation and max
695
										double a = 0.5*(dh[hi] -2*dh[hi-1] + dh[hi-2]);
Andrey Filippov's avatar
Andrey Filippov committed
696 697 698 699 700 701 702 703 704 705 706 707 708
										double b = 0.5*(dh[hi] - dh[hi-2]);
										double dx =  - b/(2*a);
										// protect agains very low a,b
										if (dx > 1.0){
											dx = 1.0;
											mmm[numMax * 2][1] = dh[hi];
											System.out.println("Max: insufficient precision, dx = "+dx+" > 1.0");
										} else if (dx < -1.0){
											dx = -1.0;
											mmm[numMax * 2][1] = dh[hi - 2];
											System.out.println("Max: insufficient precision, dx = "+dx+" < -1.0");
										} else {
											mmm[numMax * 2][1] = dh[hi-1] - b*b / (4*a);
709
										}
Andrey Filippov's avatar
Andrey Filippov committed
710
										mmm[numMax * 2][0] = (hi -1) + dx;
711
									}
Andrey Filippov's avatar
Andrey Filippov committed
712 713 714 715 716 717 718 719 720 721 722 723
									lo = hi-1;
									numMax++;
								}
								// look for next minimum after maximum
								while ((hi < numBins) && (dh[hi] <= dh[hi - 1])) hi++; // flat or lower - continue
								if (hi == numBins){ // last
									break;// do not need to register minimum after maximum
								} else if (dh[hi - 1] == dh[hi-2]) { // flat top
									while (dh[lo] > dh[hi - 1]) lo++;
									mmm[numMax * 2 - 1][0] = 0.5 *(hi - 1 + lo);
									mmm[numMax * 2 - 1][1] = dh[hi - 1];
								} else { // normal min - use parabola
724 725
									double a = 0.5*(dh[hi] -2*dh[hi-1] + dh[hi-2]);
									double b = 0.5*(dh[hi] - dh[hi-2]);
Andrey Filippov's avatar
Andrey Filippov committed
726
									double dx =  - b/(2*a);
727
									// protect against very low a,b
Andrey Filippov's avatar
Andrey Filippov committed
728 729 730 731 732 733 734 735
									if (dx > 1.0){
										dx = 1.0;
										mmm[numMax * 2 - 1][1] = dh[hi];
										System.out.println("Min: insufficient precision, dx = "+dx+" > 1.0");
									} else if (dx < -1.0){
										dx = -1.0;
										mmm[numMax * 2 - 1][1] = dh[hi - 2];
										System.out.println("Min: insufficient precision, dx = "+dx+" < -1.0");
736
									} else {
Andrey Filippov's avatar
Andrey Filippov committed
737
										mmm[numMax * 2 -1][1] = dh[hi-1] - b*b / (4*a);
738
									}
Andrey Filippov's avatar
Andrey Filippov committed
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
									mmm[numMax * 2 - 1][0] = (hi -1) + dx;
									lo = hi -1;
								}
							}
							if (numMax > 0) {
								maxMinMax[nsTile] = new double[numMax * 2 - 1][2];
								for (int i = 0; i < maxMinMax[nsTile].length; i++){
									maxMinMax[nsTile][i][0] = binToDisparity(mmm[i][0]); // convert to actual disparity !
									maxMinMax[nsTile][i][1] = mmm[i][1] * stStrength[nsTile];
								}
								if (globalDebugLevel > 0 ) { //************
									System.out.println(nsTile+": "+dh[0]+" "+dh[1]+" "+dh[2]+" "+dh[3]+" "+dh[4]+" "+
											dh[5]+" "+dh[6]+" "+dh[7]+" "+dh[8]+" "+dh[9]+ " "+dh[10]+" "+dh[11]+" "+dh[12]+" "+dh[13]+" "+dh[14]+" "+
											dh[15]+" "+dh[16]+" "+dh[17]+" "+dh[18]+" "+dh[19]+ " "+dh[20]);
									String dbg_str = ""+nsTile+": ";
									for (int i = 0; i < maxMinMax[nsTile].length; i++){
										dbg_str += " "+maxMinMax[nsTile][i][0]+":"+maxMinMax[nsTile][i][1];
									}
									System.out.println(dbg_str);
758
								}
Andrey Filippov's avatar
Andrey Filippov committed
759 760
							} else {
								maxMinMax[nsTile] = null;
761
							}
Andrey Filippov's avatar
Andrey Filippov committed
762 763 764

						} else {
							maxMinMax[nsTile] = null;
765
						}
Andrey Filippov's avatar
Andrey Filippov committed
766 767 768
					}
				}
			};
769
		}
Andrey Filippov's avatar
Andrey Filippov committed
770 771 772
		ImageDtt.startAndJoin(threads);
		return maxMinMax;
	}
773

Andrey Filippov's avatar
Andrey Filippov committed
774 775 776 777

	public int showDisparityHistogramWidth()
	{
		final int superTileSize = tileProcessor.superTileSize;
778
		int sTilesX = (tileProcessor.getTilesX() + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
779 780 781
		return sTilesX * (numBins + 1) + 1;
	}
	public double [] showDisparityHistogram()
782
	{
783 784
		if (disparityHistograms == null){
			getDisparityHistograms(
785 786
					null, // double  []   world_plane, // tilt equi-disparity planes to match real world planes (usually horizontal (or null)
					null,   // boolean [][] tile_sel, // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all
787
					this.smplMode,   // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
788 789 790 791 792 793 794 795 796 797 798 799 800 801
					this.mlfp,

//					this.smplSide,   // final int        smplSide, //        = 2;      // Sample size (side of a square)
//					this.smplNum,    // final int        smplNum,  //         = 3;      // Number after removing worst
//					this.smplRms,    // final double     smplRms,  //         = 0.1;    // Maximal RMS of the remaining tiles in a sample
//					this.smplWnd,    // final boolean         smplWnd, //

//					this.max_abs_tilt,  // 2.0; // Maximal absolute tilt in pixels/tile
//					this.max_rel_tilt,  // 0.2; // Maximal relative tilt in pixels/tile/disparity
//					this.damp_tilt,     //    0.001; // Damp tilt to handle insufficient  (co-linear)data
//					this.min_tilt_disp, // 4.0; // Disparity switch between filtering modes - near objects use tilts, far - use max disparity
//					this.transition,    // 1.0; // Mode transition range (between tilted and maximal disparity)
//					this.far_mode,      //     1;   // Far objects filtering mode (0 - off, 1 - power of disparity)
//					this.far_power,     //    1.0; // Raise disparity to this power before averaging for far objects
802

803
					this.measSel);   // calculate and blur with the current settings, specified at instantiation
804 805
		}
		return showDisparityHistogram(disparityHistograms);
806
	}
807

808

809
	public double [] showDisparityHistogram(
810 811 812
//			double  []   world_plane, // tilt equi-disparity planes to match real world planes (usually horizontal (or null)
			final double [][][][] disparity_strength, // pre-calculated disparity/strength [per super-tile][per-measurement layer][2][tiles] or null
			boolean [][] tile_sel, // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all
813
			boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
814 815 816 817 818 819 820 821 822 823 824 825 826
			MeasuredLayersFilterParameters mlfp, // parameters
//			int        smplSide, //        = 2;      // Sample size (side of a square)
//			int        smplNum,  //         = 3;      // Number after removing worst
//			double     smplRms,  //         = 0.1;    // Maximal RMS of the remaining tiles in a sample
//			boolean    smplWnd, //

//  			double     max_abs_tilt,  //  2.0;   // pix per tile
//			double     max_rel_tilt,  //  0.2;   // (pix / disparity) per tile
//			double     damp_tilt,     //  0.001; // Damp tilt to handle insufficient  (co-linear)data
//			double     min_tilt_disp, //  4.0;   // Disparity switch between filtering modes - near objects use tilts, far - use max disparity
//			double     transition,    //  1.0;   // Mode transition range (between tilted and maximal disparity)
//			int        far_mode,      //  1;     // Far objects filtering mode (0 - off, 1 - power of disparity)
//			double     far_power,     //  3.0;   // Raise disparity to this power before averaging for far objects
827

828
			int        measSel) // bitmask of the selected measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
Andrey Filippov's avatar
Andrey Filippov committed
829
	{
830
		getDisparityHistograms( // will recalculate if does not exist or some parameters changed
831
//				world_plane, // double  []   world_plane, // tilt equi-disparity planes to match real world planes (usually horizo
832 833
				disparity_strength, // pre-calculated disparity/strength [per super-tile][per-measurement layer][2][tiles] or nullntal (or null)
				tile_sel,   // boolean [][] tile_sel, // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all
834
				smplMode,   // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
835 836 837 838 839 840 841 842 843 844 845 846 847
				mlfp,
//				smplSide,   // final int        smplSide, //        = 2;      // Sample size (side of a square)
//				smplNum,    // final int        smplNum,  //         = 3;      // Number after removing worst
//				smplRms,    // final double     smplRms,  //         = 0.1;    // Maximal RMS of the remaining tiles in a sample
//				smplWnd,    // final boolean         smplWnd, //

//				max_abs_tilt,  // 2.0; // Maximal absolute tilt in pixels/tile
//				max_rel_tilt,  // 0.2; // Maximal relative tilt in pixels/tile/disparity
//				damp_tilt,     //    0.001; // Damp tilt to handle insufficient  (co-linear)data
//				min_tilt_disp, // 4.0; // Disparity switch between filtering modes - near objects use tilts, far - use max disparity
//				transition,    // 1.0; // Mode transition range (between tilted and maximal disparity)
//				far_mode,      //     1;   // Far objects filtering mode (0 - off, 1 - power of disparity)
//				far_power,     //    1.0; // Raise disparity to this power before averaging for far objects
848

849
				measSel); // calculate and blur with the current settings, specified at instantiation
Andrey Filippov's avatar
Andrey Filippov committed
850 851 852 853 854 855 856
		return showDisparityHistogram(disparityHistograms);
	}

	public double [] showDisparityHistogram(final double [][] dispHist){
		final int superTileSize = tileProcessor.superTileSize;
		int         sTileHeight0 = 0; // vertical pixels for each  histogram (excluding borders). if <= 0 make square cells
		final double [] strengthHist = stStrength;
857
		final int sTilesX = (tileProcessor.getTilesX() + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
858 859 860 861

		final int sTiles = dispHist.length;
		final int sTilesY = sTiles / sTilesX;
		//				final int numBins = dispHist[0].length; // [0] - weight
862
		final int sTileHeight = (sTileHeight0 > 0)? sTileHeight0 : numBins;
Andrey Filippov's avatar
Andrey Filippov committed
863 864 865 866 867 868 869 870 871 872 873

		final double [] maxHist = new double [sTiles];
		final int width = sTilesX * (numBins + 1) + 1;
		final int height = sTilesY * (sTileHeight + 1) +1;
		double [] rslt = new double [width*height];
		double maxW = 0.0; // use for borders between cells
		for (int i = 0; i < sTiles; i++){
			if (maxW < strengthHist[i]) maxW = strengthHist[i];
			if (dispHist[i] != null) {
				for (int j = 0; j< numBins; j++){
					if (!Double.isNaN( dispHist[i][j]) && (maxHist[i] < dispHist[i][j])) maxHist[i] = dispHist[i][j];
874 875
				}
			}
Andrey Filippov's avatar
Andrey Filippov committed
876 877
		}
		for (int nsTile = 0; nsTile < sTiles; nsTile++){
878 879
			int stileY = nsTile / sTilesX;
			int stileX = nsTile % sTilesX;
Andrey Filippov's avatar
Andrey Filippov committed
880 881
			int x0 = stileX * (numBins + 1);
			int y0 = stileY * (numBins + 1);
882
			int indx0 = x0 + y0*width;
Andrey Filippov's avatar
Andrey Filippov committed
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901

			// draw rectangular frame - horisontal dotted lines
			for (int j = 0; j < numBins + 2; j+=2) {
				rslt [indx0 + j] =                            maxW;
				rslt [indx0 + (sTileHeight + 1) * width+ j] = maxW;
			}
			// vertical dotted lines
			for (int j = 0; j < sTileHeight + 2; j+=2) {
				rslt [indx0 + j * width] =                    maxW;
				rslt [indx0 + (numBins + 1)+  j * width] =    maxW;
			}
			// draw normalized histograms, using overall weight as intensity
			if (dispHist[nsTile] != null) {
				for (int bin = 0; bin <numBins; bin ++){
					int h = (int) (sTileHeight * dispHist[nsTile][bin] / maxHist[nsTile]);
					int x = bin + 1;
					for (int j = 0; j <= h;  j++) {
						int y =  sTileHeight + 1 - j;
						rslt [indx0 + y * width + x] =           strengthHist[nsTile];
902 903
					}
				}
Andrey Filippov's avatar
Andrey Filippov committed
904 905 906 907
			}
		}
		return rslt;
	}
908

Andrey Filippov's avatar
Andrey Filippov committed
909
	public double [] showMaxMinMax(){
910 911 912 913 914 915 916
			return showMaxMinMax( // calculate and blur with the current settings, specified at instantiation
					null,
					null);
	}
	public double [] showMaxMinMax(
//			double  []   world_plane, // tilt equi-disparity planes to match real world planes (usually horizontal (or null)
			double [][][][] disparity_strength, // pre-calculated disparity/strength [per super-tile][per-measurement layer][2][tiles] or null
917

918 919
			boolean [][] tile_sel // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all
		){
920
		if (maxMinMax == null){
921 922 923 924
			getMaxMinMax( // calculate and blur with the current settings, specified at instantiation
//					world_plane, // tilt equi-disparity planes to match real world planes (usually horizontal (or null)
					disparity_strength, // pre-calculated disparity/strength [per super-tile][per-measurement layer][2][tiles] or null
					tile_sel); // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all
925

Andrey Filippov's avatar
Andrey Filippov committed
926 927 928 929 930
		}
		final int superTileSize = tileProcessor.superTileSize;

		int         sTileHeight0 = 0; // vertical pixels for each  histogram (excluding borders). if <= 0 make square cells
		final double [] strengthHist = stStrength;
931
		final int sTilesX = (tileProcessor.getTilesX() + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
932 933 934 935 936

		//				final int sTiles = disparityHistograms.length;
		final int sTiles = maxMinMax.length;
		final int sTilesY = sTiles / sTilesX;
		//				final int numBins = dispHist[0].length; // [0] - weight
937
		final int sTileHeight = (sTileHeight0 > 0)? sTileHeight0 : numBins;
Andrey Filippov's avatar
Andrey Filippov committed
938 939 940 941 942 943 944 945 946 947 948 949 950 951

		final double [] maxHist = new double [sTiles];
		final int width = sTilesX * (numBins + 1) + 1;
		final int height = sTilesY * (sTileHeight + 1) +1;
		final boolean [] isMax = new boolean [numBins];
		final boolean [] isMin = new boolean [numBins];

		double [] rslt = new double [width*height];
		double maxW = 0.0; // use for borders between cells
		for (int i = 0; i < sTiles; i++){
			if (maxW < strengthHist[i]) maxW = strengthHist[i];
			if (disparityHistograms[i] != null) {
				for (int j = 0; j< numBins; j++){
					if (!Double.isNaN( disparityHistograms[i][j]) && (maxHist[i] < disparityHistograms[i][j])) maxHist[i] = disparityHistograms[i][j];
952 953
				}
			}
Andrey Filippov's avatar
Andrey Filippov committed
954 955
		}
		for (int nsTile = 0; nsTile < sTiles; nsTile++){
956 957 958
//			if (nsTile == 795){
//				System.out.println("showMaxMinMax(), nsTile="+nsTile);
//			}
959 960
			int stileY = nsTile / sTilesX;
			int stileX = nsTile % sTilesX;
Andrey Filippov's avatar
Andrey Filippov committed
961 962
			int x0 = stileX * (numBins + 1);
			int y0 = stileY * (numBins + 1);
963
			int indx0 = x0 + y0*width;
Andrey Filippov's avatar
Andrey Filippov committed
964

965
			// draw rectangular frame - horizontal dotted lines
Andrey Filippov's avatar
Andrey Filippov committed
966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981
			for (int j = 0; j < numBins + 2; j+=2) {
				rslt [indx0 + j] =                            maxW;
				rslt [indx0 + (sTileHeight + 1) * width+ j] = maxW;
			}
			// vertical dotted lines
			for (int j = 0; j < sTileHeight + 2; j+=2) {
				rslt [indx0 + j * width] =                    maxW;
				rslt [indx0 + (numBins + 1)+  j * width] =    maxW;
			}
			// draw normalized histograms, using overall weight as intensity
			if ((disparityHistograms[nsTile] != null) && (maxMinMax[nsTile] != null)) {
				for (int bin = 0; bin <numBins; bin ++){
					isMax[bin] = false;
					isMin[bin] = false;
				}
				for (int i = 0; i <maxMinMax[nsTile].length; i++){
982 983
//					int imm = (int) Math.round(maxMinMax[nsTile][i][0]);
					int imm = disparityToBin(maxMinMax[nsTile][i][0]);
Andrey Filippov's avatar
Andrey Filippov committed
984 985 986 987
					if      (imm <0 )        imm = 0;
					else if (imm >= numBins) imm = numBins - 1;
					if ((i & 1) == 0) isMax[imm] = true;
					else              isMin[imm] = true;
988
				}
Andrey Filippov's avatar
Andrey Filippov committed
989 990 991 992 993 994 995 996 997 998 999

				for (int bin = 0; bin <numBins; bin ++){
					int h = (int) (sTileHeight * disparityHistograms[nsTile][bin] / maxHist[nsTile]);
					int x = bin + 1;
					int jMin = isMin[bin] ? h : 0;
					int jMax = isMax[bin] ? h : sTileHeight;

					if (isMax[bin] || isMin[bin]) {
						for (int j = jMin; j <= jMax;  j++) {
							int y =  sTileHeight + 1 - j;
							rslt [indx0 + y * width + x] = strengthHist[nsTile];
1000 1001 1002
						}
					}
				}
Andrey Filippov's avatar
Andrey Filippov committed
1003 1004 1005 1006 1007 1008 1009
			}
		}
		return rslt;
	}

	// updates bgDisparity, bgStrength
	public double [][] getBgDispStrength(
1010
			final double minBgDisparity,
Andrey Filippov's avatar
Andrey Filippov committed
1011 1012
			final double minBgFract)
	{
1013
////		final double step_disparity = step_near; // TODO: implement
Andrey Filippov's avatar
Andrey Filippov committed
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025


		if (maxMinMax == null) return null;
		final int superTileSize = tileProcessor.superTileSize;
		final int globalDebugLevel = tileProcessor.globalDebugLevel;
		final int sTiles = maxMinMax.length;
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		bgDisparity = new double[sTiles];
		bgStrength =  new double[sTiles];
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
1026
				@Override
Andrey Filippov's avatar
Andrey Filippov committed
1027 1028 1029 1030
				public void run() {
					for (int nsTile = ai.getAndIncrement(); nsTile < sTiles; nsTile = ai.getAndIncrement()) {
						if (nsTile == 49) { // 414){ // 331){
							System.out.println("getBgDispStrength(); nsTIle="+nsTile);
1031
						}
Andrey Filippov's avatar
Andrey Filippov committed
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
						double [][] mmm = maxMinMax[nsTile];
						bgDisparity[nsTile] = Double.NaN;
						bgStrength[nsTile] =  0.0;
						if (mmm != null){
							int maxNum = 0;
							int numMax = (maxMinMax[nsTile].length + 1) / 2;
							double selStrenth = 0.0;
							int startIndex = 0;
							for (maxNum = 0; maxNum < numMax; maxNum++){
								if (mmm[2 * maxNum][0] >= minBgDisparity){
									if (selStrenth == 0.0) startIndex = maxNum; // will keep first non-zero maximum number
1043
									selStrenth += mmm[2 * maxNum][1];
1044 1045
								}
							}
Andrey Filippov's avatar
Andrey Filippov committed
1046 1047 1048 1049 1050 1051
							if (selStrenth > 0.0){
								selStrenth *= minBgFract;
								double accumStrength = 0.0;
								for (maxNum = startIndex; maxNum < numMax; maxNum++){
									accumStrength += mmm[2 * maxNum][1];
									if (accumStrength >= selStrenth){
1052
										break;
1053
									}
Andrey Filippov's avatar
Andrey Filippov committed
1054 1055
								}
								if (maxNum >= numMax){
1056
									maxNum = numMax - 1; // probably just wrong fraction (>1.0)
Andrey Filippov's avatar
Andrey Filippov committed
1057 1058 1059 1060 1061 1062
								}
								// if unlikely there are several maximums before minBgFract - use the strongest
								int maxIndex = startIndex;
								if (startIndex < maxNum){
									for (startIndex++; startIndex < numMax ;startIndex++){
										if (mmm[2 * startIndex][1] > mmm[2 * maxIndex][1]) maxIndex = startIndex;
1063 1064
									}
								}
Andrey Filippov's avatar
Andrey Filippov committed
1065 1066 1067 1068
								//maxIndex is what we need. Which strength to use - individual or accumulated? Use individual.
								///										bgDisparity[nsTile] = min_disparity + mmm[2 * maxIndex][0] * step_disparity;
								bgDisparity[nsTile] = binToDisparity (mmm[2 * maxIndex][0]);
								bgStrength[nsTile] =  mmm[2 * maxIndex][1];
1069 1070
							}
						}
Andrey Filippov's avatar
Andrey Filippov committed
1071
					}
1072
				}
Andrey Filippov's avatar
Andrey Filippov committed
1073
			};
1074
		}
Andrey Filippov's avatar
Andrey Filippov committed
1075 1076 1077
		ImageDtt.startAndJoin(threads);
		final double [][] bgDispStrength = {bgDisparity, bgStrength};
		if (globalDebugLevel > 0) {
1078
			ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays(); // just for debugging?
1079
			final int stilesX = (tileProcessor.getTilesX() + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
			final int stilesY = (tileProcessor.getTilesY()  + superTileSize -1)/superTileSize;
			sdfa_instance.showArrays(bgDispStrength, stilesX, stilesY, true, "bgDispStrength");
		}
		return bgDispStrength;
	}

	// from per-super-tile disparity/strength interpolate per-tile disparity/strength using same sine-based window
	public double [][] getBgTileDispStrength()
	{
		if ((this.bgDisparity == null) || (this.bgStrength == null)) return null;
		final int tilesX = tileProcessor.getTilesX();
		final int tilesY = tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.superTileSize;
1093
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
1094
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
1095
		final int nStiles = stilesX * stilesY;
Andrey Filippov's avatar
Andrey Filippov committed
1096 1097 1098 1099 1100 1101 1102 1103 1104
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		final int superTileSize2 = 2 * superTileSize;
		final double [][] lapWeight = getLapWeights();
		final double [] tileDisparity = new double [tilesY * tilesX]; // assuming all 0.0
		final double [] tileStrength =  new double [tilesY * tilesX]; // assuming all 0.0

		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
1105
				@Override
Andrey Filippov's avatar
Andrey Filippov committed
1106 1107
				public void run() {
					for (int nsTile = ai.getAndIncrement(); nsTile < nStiles; nsTile = ai.getAndIncrement()) {
1108 1109
						int stileY = nsTile / stilesX;
						int stileX = nsTile % stilesX;
Andrey Filippov's avatar
Andrey Filippov committed
1110 1111 1112 1113
						int tY0 = stileY * superTileSize;
						int tX0 = stileX * superTileSize;
						double [][] lapWeight_dbg = lapWeight;
						if (nsTile ==  414) { //317) { // 755){
1114
							System.out.println("getBgTileDispStrength(x): stileY="+stileY+", stileX="+stileX+" lapWeight_dbg.length="+lapWeight_dbg.length);
Andrey Filippov's avatar
Andrey Filippov committed
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
						}
						for (int tY = 0; tY < superTileSize; tY++){
							int tileY = tY0 +tY;
							if (tileY < tilesY) {
								for (int tX = 0; tX < superTileSize; tX++){
									int tileX = tX0 +tX;
									if (tileX < tilesX) {
										int tIndex =  tileY * tilesX + tileX;
										// iterate for +/- 1 supterile around current, acummulate disparity/strength
										double sd = 0.0, sw = 0.0;
										for (int stDY = -1; stDY <=1; stDY ++){
											int stY =  stileY + stDY;
											int dtY =tY + superTileSize/2 -superTileSize * stDY;
											if ((stY >= 0) && (stY < stilesY) && (dtY >= 0) && (dtY < superTileSize2)){
												for (int stDX = -1; stDX <=1; stDX ++){
													int stX =  stileX + stDX;
													int dtX =tX + superTileSize/2 -superTileSize * stDX;
													if ((stX >= 0) && (stX < stilesX) && (dtX >= 0) && (dtX < superTileSize2)){
														int stIndex = stY * stilesX + stX;
														double w = bgStrength[stIndex] * lapWeight[dtY][dtX];
														if (nsTile ==  415) {
															System.out.println("tX="+tX+", tY="+tY+", tileX="+tileX+", tileY="+tileY+" stDX="+stDX+" stDY="+stDY+
																	", bgStrength["+stIndex+"] = "+bgStrength[stIndex]+
																	", lapWeight["+dtY+"]["+dtX+"]="+lapWeight[dtY][dtX]+" stY="+stY+" stX="+stX+" w="+w);
1139
														}
Andrey Filippov's avatar
Andrey Filippov committed
1140
														sw += w;
1141
														if (w >0.0) sd += w * bgDisparity[stIndex]; // so NaN will be OK
1142 1143 1144 1145
													}
												}
											}
										}
Andrey Filippov's avatar
Andrey Filippov committed
1146 1147 1148 1149 1150 1151 1152 1153
										tileStrength[tIndex] = sw;
										if (sw > 0.0) {
											tileDisparity[tIndex] = sd/sw;
										} else {
											tileDisparity[tIndex] = Double.NaN;
										}
										if (nsTile ==  415) {
											System.out.println("sw= "+sw+", sd="+sd);
1154
										}
1155
									}
Andrey Filippov's avatar
Andrey Filippov committed
1156
								}
1157
							}
1158
						}
Andrey Filippov's avatar
Andrey Filippov committed
1159 1160 1161
					}
				}
			};
1162
		}
Andrey Filippov's avatar
Andrey Filippov committed
1163 1164 1165 1166
		ImageDtt.startAndJoin(threads);
		final double [][] bgTileDispStrength = {tileDisparity, tileStrength};
		return bgTileDispStrength;
	}
1167

Andrey Filippov's avatar
Andrey Filippov committed
1168

Andrey Filippov's avatar
Andrey Filippov committed
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
	public double corrMaxEigen(
			double maxEigen,
			double dispNorm,
			TilePlanes.PlaneData pd)
	{
		return corrMaxEigen(
				maxEigen,
				dispNorm,
				pd.getZxy()[0]);
	}
Andrey Filippov's avatar
Andrey Filippov committed
1179

Andrey Filippov's avatar
Andrey Filippov committed
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
	public double corrMaxEigen(
			double maxEigen,
			double dispNorm,
			double disparity)
	{
		double corrV = maxEigen;
		if ((dispNorm > 0.0) && (disparity > dispNorm)) {
			//					double dd = (dispNorm + z0)/ dispNorm; // > 1
			double dd = disparity/ dispNorm; // > 1
			corrV *= dd * dd; // > original
		}
		return corrV;

	}

1195 1196 1197 1198 1199 1200
	public int [][] getTransMatrix(
			boolean [][][] selections ) // for each plane should have the same non-null ml
	{
		int num_ml = measuredLayers.getNumLayers();
		int num_p = selections.length;
		int superTileSize = tileProcessor.getSuperTileSize();
1201
		int st2 = 2 * superTileSize;
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
		int [][] trans_mat = new int [num_p][num_p];
		for (int ml = 0; ml < num_ml; ml++) if (selections[0][ml] != null){
			for (int y = 0; y < st2; y++){
				for (int x = 0; x < (st2 - 1); x++){
					int indx1 = y * st2 + x;
					int indx2 = y * st2 + x + 1;
					for (int np1 = 0; np1 < num_p; np1++){
						for (int np2 = 0; np2 < num_p; np2++){
							if (selections[np1][ml][indx1] && selections[np2][ml][indx2]){
								trans_mat[np1][np2]++;
							}
						}
					}
				}
			}
			for (int x = 0; x < st2; x++){
				for (int y = 0; y < (st2 - 1); y++){
					int indx1 = y * st2 + x;
					int indx2 = y * st2 + x + st2;
					for (int np1 = 0; np1 < num_p; np1++){
						for (int np2 = 0; np2 < num_p; np2++){
							if (selections[np1][ml][indx1] && selections[np2][ml][indx2]){
								trans_mat[np1][np2]++;
							}
						}
					}
				}
			}
		}
		return trans_mat;
	}
1233

1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
	public double [][] getTransRel(
			int [][] trans_matrix)
	{
		double [][] trans_rel = new double [trans_matrix.length][trans_matrix.length];
		for (int i = 0; i < trans_matrix.length; i++){
			for (int j = 0; j < trans_matrix[i].length; j++){
				if ((trans_matrix[i][i] + trans_matrix[j][j]) > 0){
					trans_rel[i][j] = (trans_matrix[i][j] + trans_matrix[j][i]);
					trans_rel[i][j] /= (trans_matrix[i][i] + trans_matrix[j][j]);
				}
			}
		}
		return trans_rel;
	}
1248

1249 1250 1251
	public String [] showSupertileSeparationTitles(
			double [][][]  disp_strength,
			boolean [][][] selections)
1252 1253 1254
	{
		return 	showSupertileSeparationTitles(disp_strength, selections, null);
	}
1255

1256
	public double [][] showSupertileSeparation(
1257
			boolean        useWorld,
1258 1259 1260
			double [][][]  disp_strength,
			boolean [][][] selections)
	{
1261
		return 	showSupertileSeparation(useWorld, disp_strength, selections, null);
1262 1263 1264 1265 1266 1267
	}

	public String [] showSupertileSeparationTitles(
			double [][][]  disp_strength,
			boolean [][][] selections,
			TilePlanes.PlaneData [] planes)
1268 1269
	{
		int num_ml = disp_strength.length;
1270
		int num_p  = (selections == null) ? 0: selections.length;
1271
		int num_pm = num_ml * num_p;
1272
		int num_pd = (planes != null) ? (planes.length - LOWEST_PLANE(planes.length)) : 0;
1273
		String [] titles = new String [num_pm + 3 * num_ml + 8 * num_pd];
1274 1275 1276 1277 1278 1279
		for (int np = 0; np < num_p; np++){
			for (int ml = 0; ml < num_ml; ml++){
				titles [np * num_ml + ml] = "p"+np+"_l"+ml;
			}
		}
		for (int ml = 0; ml < num_ml; ml++){
1280 1281 1282
			titles [num_pm + 0 * num_ml + ml] = "disp_"+ml;
			titles [num_pm + 1 * num_ml + ml] = "strn_"+ml;
			titles [num_pm + 2 * num_ml + ml] = "sel_"+ml;
1283
		}
1284 1285 1286 1287
		for (int npd = 0; npd < num_pd; npd++){
			titles [num_pm + 3 * num_ml + 0 * num_pd + npd] = "pd_"+npd;
			titles [num_pm + 3 * num_ml + 1 * num_pd + npd] = "pdm_"+npd;
			titles [num_pm + 3 * num_ml + 2 * num_pd + npd] = "pdd_"+npd;
1288 1289 1290 1291 1292
			titles [num_pm + 3 * num_ml + 3 * num_pd + npd] = "pwd_"+npd;
			titles [num_pm + 3 * num_ml + 4 * num_pd + npd] = "pds_"+npd;
			titles [num_pm + 3 * num_ml + 5 * num_pd + npd] = "pws_"+npd;
			titles [num_pm + 3 * num_ml + 6 * num_pd + npd] = "-pdd_"+npd;
			titles [num_pm + 3 * num_ml + 7 * num_pd + npd] = "-pwd_"+npd;
1293
		}
1294

1295
	// TilePlanes.PlaneData
1296 1297
		return titles;
	}
1298 1299

	public double [][] showSupertileSeparation(
1300
			boolean useWorld,
1301
			double [][][]  disp_strength,
1302 1303 1304
			boolean [][][] selections,
			TilePlanes.PlaneData [] planes
			)
1305 1306 1307
	{
		int superTileSize = tileProcessor.getSuperTileSize();
		int num_ml = disp_strength.length;
1308
		int num_p  = (selections == null) ? 0: selections.length;
1309
		int num_pm = num_ml * num_p;
1310
		int num_pd = (planes != null) ? (planes.length - LOWEST_PLANE(planes.length)) : 0;
1311
		final double [][] lapWeight = getLapWeights();
1312
		double [][] data = new double [num_pm + 3 * num_ml + 8 * num_pd ][]; // 4* superTileSize*superTileSize];
1313 1314
		for (int np = 0; np < num_p; np++) if (selections [np] != null){
			for (int ml = 0; ml < num_ml; ml++) if ((disp_strength[ml]!=null) && (selections[np][ml] != null)){
1315
				int nd = np * num_ml + ml;
1316 1317 1318
				data[nd] = new double[4 * superTileSize * superTileSize];
				for (int i = 0; i < data[nd].length; i++){
					if (selections[np][ml][i] && (disp_strength[ml][1][i] > 0.0)){
1319
						data[nd][i] = disp_strength[ml][0][i];
1320
					} else {
1321
						data[nd][i] = Double.NaN;
1322 1323 1324 1325 1326
					}
				}
			}
		}
		for (int ml = 0; ml < num_ml; ml++) if (disp_strength[ml]!=null){
1327 1328
			int nd = num_pm + 2 * num_ml + ml;

1329
			data [nd] = new double [4* superTileSize*superTileSize];
1330
			int [] multi_sel = new int [4* superTileSize*superTileSize];
1331
			for (int i = 0; i < data[nd].length; i++){
1332
				data [nd][i] = Double.NaN;
Andrey Filippov's avatar
Andrey Filippov committed
1333
				for (int np = 0; np < num_p; np++) if ((selections [np] != null) && (selections [np][ml] != null) && selections [np][ml][i]){
1334 1335
//					data [nd][i] = np + 1;
					multi_sel[i] |= (1 << np);
1336
					data [nd][i] = multi_sel[i];
1337
//					break;
1338 1339
				}
			}
1340
			data [num_pm + 0 * num_ml + ml] = disp_strength[ml][0];
1341 1342 1343 1344 1345 1346 1347
			data [num_pm + 1 * num_ml + ml] = disp_strength[ml][1].clone();
			// undo lapweight to show
			for (int sty = 0; sty < 2 * superTileSize; sty++){
				for (int stx = 0; stx < 2 * superTileSize; stx++){
					data [num_pm + 1 * num_ml + ml][stx + 2 * superTileSize * sty] /= lapWeight[sty][stx];
				}
			}
1348

1349
		}
1350
		for (int npd = 0; npd < num_pd; npd++) if (planes[npd +LOWEST_PLANE(planes.length)] != null){
1351 1352 1353 1354 1355 1356 1357
/*			double [][] ellipsoids = planes[npd +LOWEST_PLANE(planes.length)].getDoublePlaneDisparityStrength(
					useWorld,
					null, // double [] window,
					true, // boolean   use_sel,
					true, // boolean   divide_by_area,
					1.5, // double   scale_projection,
					1); // int       debugLevel) */
1358
			double [][] ellipsoids = planes[npd +LOWEST_PLANE(planes.length)].getDoublePlaneDisparityStrength(
1359
					useWorld,
1360
					null, // double [] window,
1361
					-1, //
1362 1363 1364 1365 1366 1367 1368
					true, // boolean   use_sel,
					true, // boolean   divide_by_area,
					1.5, // double   scale_projection,
					0.0, // double    fraction_uni,
					1); // int       debugLevel)
			double [][] ellipsoidsW = planes[npd +LOWEST_PLANE(planes.length)].getDoublePlaneWorldDisparityStrength(
					null, // double [] window,
1369
					-1, //
1370
					true, // boolean   use_sel,
1371
					true, // boolean   divide_by_area,
1372
					1.5, // double   scale_projection,
1373
					0.0, // double    fraction_uni,
1374
					1); // int       debugLevel)
1375 1376 1377
			data [num_pm + 3 * num_ml + 0 * num_pd + npd] = planes[npd +LOWEST_PLANE(planes.length)].getDoublePlaneDisparity(
					useWorld,
					false);
1378

1379
			boolean [][] msel = planes[npd +LOWEST_PLANE(planes.length)].getMeasSelection();
1380
			int ntiles = data [num_pm + 3 * num_ml + 0 * num_pd + npd].length;
1381 1382 1383 1384 1385 1386
			data [num_pm + 3 * num_ml + 1 * num_pd + npd] = new double [ntiles];
			for (int i = 0; i < ntiles; i++) {
				data [num_pm + 3 * num_ml + 1 * num_pd + npd][i] = Double.NaN;
				for (int ml = 0; ml < num_ml; ml++) if ((disp_strength[ml]!=null) && (msel[ml] != null)){
					if (msel[ml][i] && (disp_strength[ml][1][i] > 0.0)){
						data [num_pm + 3 * num_ml + 1 * num_pd + npd][i] = data [num_pm + 3 * num_ml + 0 * num_pd + npd][i];
1387 1388 1389
					}
				}
			}
1390 1391 1392 1393 1394 1395 1396
			if (ellipsoids != null) {
				data [num_pm + 3 * num_ml + 2 * num_pd + npd] = ellipsoids[0];
				data [num_pm + 3 * num_ml + 4 * num_pd + npd] = ellipsoids[1];
				data [num_pm + 3 * num_ml + 6 * num_pd + npd] = new double[ntiles];
				for (int i = 0; i < ntiles; i++) {
					for (int ml = 0; ml < num_ml; ml++) if ((disp_strength[ml]!=null) && (msel[ml] != null)){
						if (msel[ml][i] && (disp_strength[ml][1][i] > 0.0)){
1397
							data [num_pm + 3 * num_ml + 6 * num_pd + npd][i] = disp_strength[ml][0][i] - ellipsoids[0][i];
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
						} else {
							data [num_pm + 3 * num_ml + 6 * num_pd + npd][i] = Double.NaN;
						}
						break;
					}
				}
			}
			if (ellipsoidsW != null) {
				data [num_pm + 3 * num_ml + 3 * num_pd + npd] = ellipsoidsW[0];
				data [num_pm + 3 * num_ml + 5 * num_pd + npd] = ellipsoidsW[1];
				data [num_pm + 3 * num_ml + 7 * num_pd + npd] = new double[ntiles];
				for (int i = 0; i < ntiles; i++) {
					for (int ml = 0; ml < num_ml; ml++) if ((disp_strength[ml]!=null) && (msel[ml] != null)){
						if (msel[ml][i] && (disp_strength[ml][1][i] > 0.0)){
1412
							data [num_pm + 3 * num_ml + 7 * num_pd + npd][i] = disp_strength[ml][0][i] - ellipsoidsW[0][i];
1413 1414 1415 1416 1417 1418 1419 1420 1421 1422
						} else {
							data [num_pm + 3 * num_ml + 7 * num_pd + npd][i] = Double.NaN;
						}
						break;
					}
				}
			}
		}
		return data;
	}
1423

1424 1425 1426 1427 1428
	public String [] showSupertileWorldTitles(
			double [][][]  disp_strength,
			boolean [][][] selections,
			TilePlanes.PlaneData [] planes)
	{
1429
//		int num_p  = selections.length;
1430
		int num_pd = (planes != null) ? (planes.length - LOWEST_PLANE(planes.length)) : 0;
1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
		String [] titles = new String [9 * num_pd];
		for (int npd = 0; npd < num_pd; npd++){
			titles [0 * num_pd + npd] = "tile_x_"+npd;
			titles [1 * num_pd + npd] = "tile_y_"+npd;
			titles [2 * num_pd + npd] = "tile_z_"+npd;
			titles [3 * num_pd + npd] = "plane_x_"+npd;
			titles [4 * num_pd + npd] = "plane_y_"+npd;
			titles [5 * num_pd + npd] = "plane_z_"+npd;
			titles [6 * num_pd + npd] = "diff_x_"+npd;
			titles [7 * num_pd + npd] = "diff_y_"+npd;
			titles [8 * num_pd + npd] = "diff_z_"+npd;
		}

1444
	// TilePlanes.PlaneData
1445 1446
		return titles;
	}
1447
/*
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
	public double [][] showSupertileWorld(
			double [][][]  disp_strength,
			boolean [][][] selections,
			TilePlanes.PlaneData [] planes
			)
	{
		int superTileSize = tileProcessor.getSuperTileSize();
		int num_ml = disp_strength.length;
		int num_p  = (selections == null) ? 0: selections.length;
		int num_pm = num_ml * num_p;
		int num_pd = (planes != null) ? (planes.length - LOWEST_PLANE(planes.length)) : 0;
		int ml = 0;
		for (ml = 0; ml < num_ml; ml++) if (disp_strength[ml]!=null){
			break;
		}
		double [][] data = new double [num_pd][];
		for (int npd = 0; npd < num_pd; npd++) if (planes[npd +LOWEST_PLANE(planes.length)] != null){
			double [][] ellipsoids = planes[npd +LOWEST_PLANE(planes.length)].getDoublePlaneDisparityStrength(
					useWorld,
					null, // double [] window,
1468
					-1, //
1469 1470 1471 1472 1473 1474 1475
					true, // boolean   use_sel,
					true, // boolean   divide_by_area,
					1.5, // double   scale_projection,
					0.0, // double    fraction_uni,
					1); // int       debugLevel)
			double [][] ellipsoidsW = planes[npd +LOWEST_PLANE(planes.length)].getDoublePlaneWorldDisparityStrength(
					null, // double [] window,
1476
					-1, //
1477 1478 1479 1480 1481
					true, // boolean   use_sel,
					true, // boolean   divide_by_area,
					1.5, // double   scale_projection,
					0.0, // double    fraction_uni,
					1); // int       debugLevel)
1482 1483 1484
			data [num_pm + 3 * num_ml + 0 * num_pd + npd] = planes[npd +LOWEST_PLANE(planes.length)].getDoublePlaneDisparity(
					useWorld,
					false);
1485

1486
			boolean [][] msel = planes[npd +LOWEST_PLANE(planes.length)].getMeasSelection();
1487
			int ntiles = data [num_pm + 3 * num_ml + 0 * num_pd + npd].length;
1488 1489 1490 1491 1492 1493
			data [num_pm + 3 * num_ml + 1 * num_pd + npd] = new double [ntiles];
			for (int i = 0; i < ntiles; i++) {
				data [num_pm + 3 * num_ml + 1 * num_pd + npd][i] = Double.NaN;
				for (int ml = 0; ml < num_ml; ml++) if ((disp_strength[ml]!=null) && (msel[ml] != null)){
					if (msel[ml][i] && (disp_strength[ml][1][i] > 0.0)){
						data [num_pm + 3 * num_ml + 1 * num_pd + npd][i] = data [num_pm + 3 * num_ml + 0 * num_pd + npd][i];
1494 1495 1496
					}
				}
			}
1497 1498 1499 1500 1501 1502 1503
			if (ellipsoids != null) {
				data [num_pm + 3 * num_ml + 2 * num_pd + npd] = ellipsoids[0];
				data [num_pm + 3 * num_ml + 4 * num_pd + npd] = ellipsoids[1];
				data [num_pm + 3 * num_ml + 6 * num_pd + npd] = new double[ntiles];
				for (int i = 0; i < ntiles; i++) {
					for (int ml = 0; ml < num_ml; ml++) if ((disp_strength[ml]!=null) && (msel[ml] != null)){
						if (msel[ml][i] && (disp_strength[ml][1][i] > 0.0)){
1504
							data [num_pm + 3 * num_ml + 6 * num_pd + npd][i] = disp_strength[ml][0][i] - ellipsoids[0][i];
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
						} else {
							data [num_pm + 3 * num_ml + 6 * num_pd + npd][i] = Double.NaN;
						}
						break;
					}
				}
			}
			if (ellipsoidsW != null) {
				data [num_pm + 3 * num_ml + 3 * num_pd + npd] = ellipsoidsW[0];
				data [num_pm + 3 * num_ml + 5 * num_pd + npd] = ellipsoidsW[1];
				data [num_pm + 3 * num_ml + 7 * num_pd + npd] = new double[ntiles];
				for (int i = 0; i < ntiles; i++) {
					for (int ml = 0; ml < num_ml; ml++) if ((disp_strength[ml]!=null) && (msel[ml] != null)){
						if (msel[ml][i] && (disp_strength[ml][1][i] > 0.0)){
1519
							data [num_pm + 3 * num_ml + 7 * num_pd + npd][i] = disp_strength[ml][0][i] - ellipsoidsW[0][i];
1520 1521 1522 1523 1524 1525 1526
						} else {
							data [num_pm + 3 * num_ml + 7 * num_pd + npd][i] = Double.NaN;
						}
						break;
					}
				}
			}
1527
		}
1528 1529
		return data;
	}
1530 1531 1532 1533 1534 1535
*/





1536 1537
	// calculate "tilted" disparity, so planes parallel to the same world plane would have the same disparity
	// also produces non-tilted, if world_plane_norm == null
1538
	// Protecting from behind the horizon - set strength of all tiles in the negative disparity area to 0
Andrey Filippov's avatar
Andrey Filippov committed
1539 1540
	public double [][][][] getPlaneDispStrengthsST(
			final double []  world_plane_norm, // real world normal vector to a suggested plane family (0,1,0) for horizontal planes, (0,0,1) const disparity, null - floating
1541 1542 1543 1544 1545
			final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
			final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
			final GeometryCorrection geometryCorrection,
			final boolean    correct_distortions,
			final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
1546
			final MeasuredLayersFilterParameters mlfp,
1547 1548 1549 1550
			final int        debugLevel,
			final int        dbg_X,
			final int        dbg_Y)
	{
Andrey Filippov's avatar
Andrey Filippov committed
1551 1552
		final boolean const_disparity = (world_plane_norm != null) && (world_plane_norm[0] == 0.0)  && (world_plane_norm[1] == 0.0);
		final boolean floating =  (world_plane_norm == null);
1553 1554 1555 1556 1557
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		final int tileSize =      tileProcessor.getTileSize();

1558
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
1559
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
1560
		final int nStiles = stilesX * stilesY;
1561 1562
//		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final Thread[] threads = ImageDtt.newThreadArray((debugLevel > 1)? 1 : tileProcessor.threadsMax);
1563

1564 1565 1566 1567 1568
		final AtomicInteger ai = new AtomicInteger(0);
		final int debug_stile = (debugLevel > -1)? (dbg_Y * stilesX + dbg_X):-1;
		// TODO: Remove when promoting PlaneData
		final TilePlanes tpl = new TilePlanes(tileSize,superTileSize, geometryCorrection);
		final double [][][][] plane_disp_strength = new double [nStiles][][][];
1569 1570
		// DEBUG feature:
		final double [][] zero_tilts = {{0.0,0.0}}; // set to null for float
1571 1572 1573
		if (debugLevel > -1) {
			System.out.println("getPlaneDispStrengthsST(x): debugLevel == "+debugLevel);
		}
1574 1575
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
1576
				@Override
1577
				public void run() {
1578
					double [][][] plane_tilts = null; // used only for world_plane_norm != null
1579
					// to get tile disparities needed to calculate tilts
1580
					for (int nsTile = ai.getAndIncrement(); nsTile < nStiles; nsTile = ai.getAndIncrement()) {
1581
                        int dl = ((debugLevel > 1) && (nsTile == debug_stile)) ? 3: debugLevel;
1582
						if (dl > 2){
1583 1584
							System.out.println("getPlaneDispStrengths(): nsTile="+nsTile);
						}
1585
						int stileY = nsTile / stilesX;
1586 1587 1588 1589
						int stileX = nsTile % stilesX;
						int [] sTiles = {stileX, stileY};
						// first make a plane from all tiles
						TilePlanes.PlaneData pd0 = tpl.new  PlaneData (
1590
								sTiles, // int [] sTileXY,
1591 1592 1593 1594 1595 1596
								tileSize, // int tileSize,
								geometryCorrection, // GeometryCorrection   geometryCorrection,
								correct_distortions,
								measuredLayers,     // MeasuredLayers measuredLayers,
								plPreferDisparity);   // boolean preferDisparity)

Andrey Filippov's avatar
Andrey Filippov committed
1597 1598
//						if (smplMode && (world_plane_norm != null)) {
						if (smplMode && !floating) {
1599 1600
							plane_tilts = new double [measuredLayers.getNumLayers()][][];
							for (int ml = 0; ml < plane_tilts.length; ml++) if ((stMeasSel & ( 1 << ml)) != 0){
Andrey Filippov's avatar
Andrey Filippov committed
1601 1602 1603 1604 1605 1606 1607
								plane_tilts[ml] = 	zero_tilts;
								if (!const_disparity) {
									double [][] tile_disp_strengths = measuredLayers.getDisparityStrengthML(
											ml,             // int num_layer,
											stileX,         // int stX,
											stileY,         // int stY,
											null,           // boolean [] sel_in,
1608 1609
											mlfp.strength_floor, // double strength_floor,
											mlfp.strength_pow,   // double strength_pow,
Andrey Filippov's avatar
Andrey Filippov committed
1610 1611
											true);          // boolean null_if_none);
									// if failed - keep constant disparity (plane_tilts[ml] = 	zero_tilts)
1612

Andrey Filippov's avatar
Andrey Filippov committed
1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631
									if (tile_disp_strengths != null){
										plane_tilts[ml] = pd0.getDisparityTilts(
												world_plane_norm,     // double []     world_normal_xyz,
												tile_disp_strengths,  // double [][]   tile_disp_strengths,
												debugLevel);         // int           debugLevel);
										if(dl > 2){
											if (plane_tilts[ml] != null){
												for (int k = 0; k < 2; k++) {
													System.out.println((k > 0) ? "tilt Y, pix/tile" : "tilt X, pix/tile");
													for (int i = 0; i < 2 * superTileSize; i++){
														System.out.print(i+",");
														for (int j = 0; j < 2 * superTileSize; j++){
															int it = j + 2 * superTileSize * i;
															if (plane_tilts[ml][it] !=null){
																System.out.print(String.format("%f7.4", plane_tilts[ml][it][k]));
															}
															if (j < (2 * superTileSize - 1)){
																System.out.print(", ");
															}
1632
														}
Andrey Filippov's avatar
Andrey Filippov committed
1633
														System.out.println();
1634 1635 1636 1637 1638 1639 1640 1641
													}
													System.out.println();
												}
											}
										}
									}
								}
							}
1642
						}
1643 1644

						plane_disp_strength[nsTile] = new double[measuredLayers.getNumLayers()][][];
1645

1646
						for (int ml = 0; ml < plane_disp_strength[nsTile].length; ml++) if ((stMeasSel & ( 1 << ml)) != 0){
1647
							// TODO": apply tilt before/with getDisparityStrength()
1648
							if (smplMode) {
Andrey Filippov's avatar
Andrey Filippov committed
1649
								plane_disp_strength[nsTile][ml] =  measuredLayers.getDisparityStrengthMLTilted(
1650 1651 1652 1653
										ml,             // int num_layer,
										stileX,         // int stX,
										stileY,         // int stY,
										null,           // boolean [] sel_in,
1654
										(floating? null: plane_tilts[ml]),      // double []  tiltXY, // null - free with limit on both absolute (2.0?) and relative (0.2) values
1655
										mlfp,
1656
										true,           // boolean null_if_none);
1657
										dl);
1658
							} else {
Andrey Filippov's avatar
Andrey Filippov committed
1659
								plane_disp_strength[nsTile][ml] =  measuredLayers.getDisparityStrengthML(
1660 1661 1662 1663
										ml,             // int num_layer,
										stileX,         // int stX,
										stileY,         // int stY,
										null,           // boolean [] sel_in,
1664 1665
										mlfp.strength_floor, // double strength_floor,
										mlfp.strength_pow,   // double strength_pow,
1666 1667 1668
										true);          // boolean null_if_none);
							}
						}
1669 1670 1671 1672
						if (world_plane_norm != null) {
							// find average disparity for the supertile (improve?)
							double sd = 0.0, sw = 0.0;
							for (int ml = 0; ml < plane_disp_strength[nsTile].length; ml++) if ((stMeasSel & ( 1 << ml)) != 0){
1673 1674 1675 1676 1677 1678 1679
								if ((plane_disp_strength[nsTile] !=null) && (plane_disp_strength[nsTile][ml] !=null)  && (plane_disp_strength[nsTile][ml][1] !=null)) {
									for (int i = 0; i < plane_disp_strength[nsTile][ml][1].length; i++){
										double w = plane_disp_strength[nsTile][ml][1][i];
										double d = plane_disp_strength[nsTile][ml][0][i];
										sd += w * d;
										sw += w;
									}
1680 1681 1682 1683 1684 1685
								}
							}
							if (sw > 0) {
								if (dl > 0) {
									System.out.println("Plane tilted disparity for stileX = "+stileX+" stileY="+stileY+", average disparity "+(sd/sw));
								}
1686
								if (dl>2) {
1687 1688
									String [] dbg_titles = showSupertileSeparationTitles( plane_disp_strength[nsTile], null);
									double [][] dbg_img = showSupertileSeparation(false, plane_disp_strength[nsTile], null); // plane_sels);
1689
									ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays();
1690 1691 1692 1693
									sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2* superTileSize, true, "plane_separation_original_disp"+nsTile,dbg_titles);
									dbg_img = showSupertileSeparation(true, plane_disp_strength[nsTile], null); // plane_sels);
									sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2* superTileSize, true, "plane_separation_original_world"+nsTile,dbg_titles);
								}
1694 1695 1696 1697
								plane_disp_strength[nsTile] = pd0.getDisparityToPlane(
										world_plane_norm, // double []     world_normal_xyz,
										sd / sw, // average disparity // double        disp_center,
										null, // boolean [][]  tile_sel, // null - do not use, {} use all (will be modified)
1698
										plane_disp_strength[nsTile], // double [][][] disp_str, // calculate just once if null
1699
										dl); // 1); // int           debugLevel);
1700
								if (dl>2) {
1701
									String [] dbg_titles = showSupertileSeparationTitles( plane_disp_strength[nsTile], null);
1702
									double [][] dbg_img = showSupertileSeparation(false, plane_disp_strength[nsTile], null); // plane_sels);
1703
									ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays();
1704 1705 1706
									sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2* superTileSize, true, "plane_separation_disp"+nsTile,dbg_titles);
									dbg_img = showSupertileSeparation(true, plane_disp_strength[nsTile], null); // plane_sels);
									sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2* superTileSize, true, "plane_separation_world"+nsTile,dbg_titles);
1707 1708 1709 1710 1711 1712 1713 1714
								}
							} else {
								plane_disp_strength[nsTile] = null;
							}
						}
					}
				}
			};
1715
		}
1716 1717 1718 1719
		ImageDtt.startAndJoin(threads);
		return plane_disp_strength;
	}

1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
	public boolean [][][][] dispClusterizeHighest(
			final double [][][][] disparity_strengths, // either normal or tilted disparity/strengths
			final boolean [][][] selected,   // tiles OK to be assigned [supertile][measurement layer] [tile index] or null (or null or per-measurement layer)
			final boolean [][][] prohibited, // already assigned tiles [supertile][measurement layer] [tile index] or null
			final boolean        search_min,
			final int            stMeasSel,  //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
			final double         plDispNorm,         // to increase weight of nearer planes
			final double         sigma,
			final double         disp_arange,
			final double         disp_rrange,
			final double         tolerance_above,
			final double         tolerance_below,
			final int            plMinPoints, //          =     5;  // Minimal number of points for plane detection
			final String         suffix,
			final int            debugLevel,
			final int            dbg_X,
			final int            dbg_Y)
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		final int stSize2 =       2 * superTileSize;
		final int stLen2 =        stSize2 * stSize2;


		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		final int nStiles = stilesX * stilesY;
		final Thread[] threads = ImageDtt.newThreadArray((debugLevel > 1)? 1 :tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		this.planes = new TilePlanes.PlaneData[nStiles][];
		final int debug_stile = (debugLevel > -1)? (dbg_Y * stilesX + dbg_X):-1;
//		final boolean [][][] enabled = (selected == null) ? (new boolean [nStiles][][]) : selected;

		final boolean [][][][] plane_selections = new boolean [nStiles][][][]; // [supertile] [ plane number] [measurement layer] [tile index]
		class Selections2{
			boolean [][] sel;
			Selections2(boolean [][] sel) {
				this.sel = sel;
			}
			boolean [][] getSel(){
				return this.sel;
			}
		}
//		final double max_diff2 = Double.isNaN(max_diff)? Double.NaN: (max_diff*max_diff);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				@Override
				public void run() {
					for (int nsTile = ai.getAndIncrement(); nsTile < nStiles; nsTile = ai.getAndIncrement()) {
						if (disparity_strengths[nsTile] != null){
                            int dl = ((debugLevel > 0) && (nsTile == debug_stile)) ? (debugLevel + 2) : debugLevel;
							if (dl > 2){
								System.out.println("dispClusterizeHighest(): nsTile="+nsTile);
							}
//							int stileY = nsTile / stilesX;
//							int stileX = nsTile % stilesX;
							double[][][] disp_strength = new double[measuredLayers.getNumLayers()][][];
							for (int ml = 0; ml < disp_strength.length; ml++) if ((stMeasSel & ( 1 << ml)) != 0){
								disp_strength[ml] = disparity_strengths[nsTile][ml]; // will we change it  - no, no need to clone
							}
							boolean [][] enabled = (selected == null) ? (new boolean [disp_strength.length][]) : selected[nsTile];
							for (int ml = 0; ml < disp_strength.length; ml++) if (disp_strength[ml] != null) {
								if (selected != null) {
									enabled[ml] = selected[nsTile][ml].clone();
								}else {
									enabled[ml] = new boolean [stLen2];
									for (int i = 0; i < stLen2; i++) {
										enabled[ml][i] = true;
									}
								}
								if ((prohibited != null) && (prohibited[nsTile] != null) && (prohibited[nsTile][ml] != null)) {
									for (int i = 0; i < stLen2; i++) {
										enabled[ml][i] &= !prohibited[nsTile][ml][i];
									}
								}
							}
							ArrayList<Selections2> sel_list = new ArrayList<Selections2>();
							for (int ntry = 0; ntry < 20; ntry++) {
								boolean [][] new_sel = getHighestPlaneSelection(
										enabled,         //boolean  [][]  enabled, // will not be modified
										disp_strength,   // double [][][]  disp_str,
										//FIXME: use this argument
										search_min, // boolean        search_min,
										2,     // int            grow,
										sigma,           // double         sigma,
										disp_arange,     // double         disp_arange,
										disp_rrange,     // double         disp_rrange,
										tolerance_above, // double         tolerance_above,
										tolerance_below, // double         tolerance_below,
										dl);             // int debugLevel)
								int num_tiles = 0;
								for (int ml = 0; ml < enabled.length; ml++) if (new_sel[ml] != null) {
									for (int i = 0; i < new_sel[ml].length; i++) {
										if (new_sel[ml][i]) {
											num_tiles++;
											enabled[ml][i]=false;
										}
									}
								}
								if (num_tiles < plMinPoints) {
									break;
								}
								sel_list.add(new Selections2(new_sel));
							}
1825 1826 1827 1828 1829 1830
							if (sel_list.isEmpty()) {
								if (dl > 2){
									System.out.println("dispClusterizeHighest(): nsTile="+nsTile+": nothing found");
								}
								continue;
							}
1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866
							plane_selections[nsTile] = new boolean [sel_list.size()][][]; //plane_sels;
							for (int np = 0; np < plane_selections[nsTile].length; np++) {
								plane_selections[nsTile][np] = sel_list.get(np).getSel();
							}
							if (dl > 2){
								System.out.println("dispClusterizeHighest(): nsTile="+nsTile);
								double [][]  dbg_img = new double [plane_selections[nsTile].length + 2][];
								String []  dbg_titles = new String [plane_selections[nsTile].length + 2];
								for (int ml = 0; ml < disp_strength.length; ml++) if (disp_strength[ml] != null){
									dbg_img[0] =                disp_strength[ml][0];
									dbg_img[dbg_img.length-1] = disp_strength[ml][1];
									break;
								}
								dbg_titles[0] =                "disparity";
								dbg_titles[dbg_img.length-1] = "strength";
								for (int np = 0; np < plane_selections[nsTile].length; np++) {
									double plane_strength = getSelectionStrength(
											true, // mod_strength, // boolean mod_strength,
											plDispNorm,          // double plDispNorm,
											plane_selections[nsTile][np], // boolean [][] sels,
											disp_strength); // double [][][] ds);
									dbg_titles[1 + np] = ""+plane_strength;
									dbg_img[1 + np] = new double [stLen2];
									for (int i = 0; i < stLen2; i++) {
										boolean has_tile = false;
										for (int ml = 0; ml < plane_selections[nsTile][np].length; ml++) if (plane_selections[nsTile][np][ml] != null){
											if (plane_selections[nsTile][np][ml][i]) {
												dbg_img[1 + np][i] +=  disp_strength[ml][0][i];
												has_tile = true;
											}
											if (!has_tile) {
												dbg_img[1 + np][i] = Double.NaN;
											}
										}
									}
								}
1867
								(new ShowDoubleFloatArrays()).showArrays(dbg_img, stSize2, stSize2, true,
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131
										"sel-"+nsTile+"-"+suffix,dbg_titles);
							}

						}
					}
				}
			};
		}
		ImageDtt.startAndJoin(threads);
		return plane_selections;
	}


	public boolean [][] getHighestPlaneSelection(
			boolean  [][]  enabled_ml, // will not be modified
			double [][][]  disp_str,
			boolean        search_min,
			int            grow,
			double         sigma,
			double         disp_arange,
			double         disp_rrange,
			double         tolerance_above,
			double         tolerance_below,
			int debugLevel){
		final int min_en_neib = 4;
		final boolean [][] plane_selection = new boolean[disp_str.length][];
		final double min_weight = 1.0E-20;
		final int stSize2 = 2 * tileProcessor.getSuperTileSize();
		final int stLen2 = stSize2 * stSize2;
		DoubleGaussianBlur gb=new DoubleGaussianBlur();
		TileNeibs tileNeibs = new TileNeibs(stSize2, stSize2);
		int expand = (grow + 1) & (~1);
		for (int ml = 0; ml < disp_str.length; ml++) if (disp_str[ml] != null) {
			double [] disparity =   disp_str[ml][0].clone();
			double [] strength =    disp_str[ml][1].clone();
			boolean [] enabled = enabled_ml[ml].clone();
			for (int i = 0; i < stLen2; i++) {
				if ((strength [i] > 0.0) && enabled[i]) {
					if (min_en_neib > 0) {
						int nn = 0;
						for (int dir = 0; dir < 8; dir++) {
							int i1 = tileNeibs.getNeibIndex(i, dir);
							if ((i1 >=0) && enabled_ml[ml][i1]) {
								nn++;
							}
						}
						if (nn < min_en_neib) {
							enabled[i] = false;
							strength[i] = 0.0;
							disparity[i] = 0.0;
						}
					}
					disparity[i] *= strength[i];
				} else {
					strength[i] = 0.0;
					disparity[i] = 0.0;
				}
			}
			gb.blurDouble(disparity,   stSize2, stSize2, sigma, sigma, 0.01);
			gb.blurDouble(strength,    stSize2, stSize2, sigma, sigma, 0.01);
			// TODO: handle large gaps with two sigmas?
			for (int i = 0; i < stLen2; i++) {
				if (strength [i] > min_weight) {
					disparity[i] /= strength [i];
				} else {
					strength [i] = 0.0;
					disparity[i] = 0.0;
				}
			}
			if (debugLevel > 2){
				System.out.println("getHighestPlaneSelection() debugLevel="+debugLevel);
			}
			boolean [] best_sel = null;
			double best_weight = 0.0;
			int best_height = 0;
//			int best_bottom;
			int bottom = stSize2 - 1;
			for (; bottom >= (best_height - 1); bottom --) {
				double line_max_max = 0.0, line_min_max= 0.0;
				int [] tops = new int [stSize2];
				int [][] line_se = new int [stSize2][2];
				int top;
				double disp_range = disp_arange;
				for (top = bottom; top >= 0; top--) {
					// find argmax for the top line;
					tops[top] = -1; //top *  stSize2;
					for (int ix = 0; ix < stSize2; ix++) {
						int indx = top *  stSize2 + ix;
						if (search_min) {
							if ((strength[indx] > 0.0) && ((tops[top] < 0) || (disparity[indx] < disparity[tops[top]]))){
								tops[top] = indx;
							}
						} else {
							if ((strength[indx] > 0.0) && ((tops[top] < 0) || (disparity[indx] > disparity[tops[top]]))){
								tops[top] = indx;
							}
						}
					}
					if (tops[top] > 0) {
						if (line_max_max == 0.0) {
							line_max_max = disparity[tops[top]]; // for search_min it will be line_max_min
							line_min_max = disparity[tops[top]]; // for search_min it will be line_min_min
							disp_range = disp_arange + 0.5 *(line_max_max + line_min_max) * disp_rrange;
						} else {
							if (disparity[tops[top]] > line_max_max) {
								if (disparity[tops[top]] > (line_min_max + disp_range)) {
									break; // difference more than allowed range
								}
								line_max_max = disparity[tops[top]];
								disp_range = disp_arange + 0.5 *(line_max_max + line_min_max) * disp_rrange;
							} else if (disparity[tops[top]] < line_min_max) {
								if (disparity[tops[top]] < (line_max_max - disp_range)) {
									break; // difference more than allowed range
								}
								line_min_max = disparity[tops[top]];
								disp_range = disp_arange + 0.5 *(line_max_max + line_min_max) * disp_rrange;
							}
						}
					} else { // no valid cells in a line (too far from enabled)
						break;
					}
				}
				if ((bottom - top) < (best_height - 2 - expand)) { //
					continue; // no sense even to try
				}
				disp_range = disp_arange + 0.5 *(line_max_max + line_min_max) * disp_rrange;
				double min_disp = line_max_max - disp_range; // used when looking for maximums
				double max_disp = line_min_max + disp_range; // used when looking for minimums
				// for each line set start and end, verify lines overlap
				int line = bottom;
				for (; line > top; line --) {
					// do not check first in the row
					for (line_se[line][0] = tops[line] ; line_se[line][0] >  stSize2 * line; line_se[line][0]--) {
						if (search_min) {
							if ((strength[line_se[line][0]] > 0.0) && (disparity[line_se[line][0]] > max_disp)) {
								//line_se[line][0]++; allow one extra
								break;
							}
						} else {
							if ((strength[line_se[line][0]] > 0.0) && (disparity[line_se[line][0]] < min_disp)) {
								//line_se[line][0]++; allow one extra
								break;
							}
						}
					}
					// do not check last in the row
					for (line_se[line][1] = tops[line] ; line_se[line][1] <  (stSize2 * (line + 1) -1); line_se[line][1]++) {
						if (search_min) {
							if ((strength[line_se[line][1]] > 0.0) && (disparity[line_se[line][1]] > max_disp)) {
								//line_se[line][1]--;
								break;
							}
						} else {
							if ((strength[line_se[line][1]] > 0.0) && (disparity[line_se[line][1]] < min_disp)) {
								//line_se[line][1]--;
								break;
							}
						}
					}
					// verify the lines overlap with previous
					if ((line < bottom) && (
							(line_se[line][0] >= (line_se[line + 1][1] - stSize2)) ||
							(line_se[line][1] <= (line_se[line + 1][0] - stSize2)))) {
						break;
					}
				}

				// now line - first invalid line
				// calculate actual selection and weight
				// duplicate first and last line to mitigate Gaussian blur - there may be some FG tiles cut off
				int bottom_ext = bottom;
				if (bottom_ext < (stSize2 - 1)) {
					bottom_ext++;
					line_se[bottom_ext][0] = line_se[bottom][0] + stSize2;
					line_se[bottom_ext][1] = line_se[bottom][1] + stSize2;
				}
				if ((line >= 0) && (line < (stSize2 - 1))) {
					line_se[line][0] = line_se[line + 1][0] - stSize2 ;
					line_se[line][1] = line_se[line + 1][1] - stSize2 ;
					line--;
				}

				if ((bottom_ext - line) < (best_height - expand)) {
					continue; // no sense even to try
				}

				boolean [] this_sel = new boolean [stLen2];
				double sw = 0.0;
				double min_tile_disp = search_min ? (line_min_max - tolerance_below): (min_disp - tolerance_below);
				double max_tile_disp = search_min ? (max_disp + tolerance_above) :    (line_max_max + tolerance_above);
				int first = -1, last = -1;

				for (int i = bottom_ext; i > line; i--) {
					for (int j = line_se[i][0]; j <= line_se[i][1]; j++) {
						if (  enabled[j] &&
								(disp_str[ml][1][j] > 0.0) &&
								(disp_str[ml][0][j] >= min_tile_disp) &&
								(disp_str[ml][0][j] <= max_tile_disp)) {
							sw += disp_str[ml][1][j];
							this_sel[j] = true;
							if (last < 0) last = i;
							first = i;
						}
					}
				}
				int sel_height = last - first + 1;
				if (sel_height < (best_height - expand)) {
					continue;
				}
				if (expand > 0) {
					boolean [] prohibit = new boolean [enabled.length];
					for (int i = 0; i < prohibit.length; i++) {
						prohibit[i] = !enabled[i];
					}
					boolean [] exp_sel = this_sel.clone();
					tileNeibs.growSelection(
							grow,
							exp_sel,
							prohibit);
					int i0 = -1, i1 = -1;
					for (int i = 0; i < stLen2; i++) if (exp_sel[i]){
						if (!this_sel[i]) {
							if ((disp_str[ml][1][i] > 0.0) &&
							(disp_str[ml][0][i] >= min_tile_disp) &&
							(disp_str[ml][0][i] <= max_tile_disp)) {
								this_sel[i] = true;
							}
						}
						if (this_sel[i]) {
							sw += disp_str[ml][1][i];
							if (i0 < 0) i0 = i;
							i1 = i;
						}
					}
					first = i0 / stSize2;
					last =  i1 / stSize2;
					sel_height = last - first + 1;
					if (sel_height < (best_height - expand)) {
						continue;
					}
				}
				if ((sel_height > best_height) ||
						(sw > best_weight)) {
					best_sel = this_sel;
					best_weight = sw;
					best_height = sel_height;
				}
			} // bottom
			plane_selection[ml] = best_sel;
			// add debug image here
			if ((debugLevel > 2) && (best_sel != null)) {
				double [] disp_sel = disp_str[ml][0].clone();
				for (int i = 0; i < plane_selection[ml].length; i++) {
					if (!plane_selection[ml][i]) {
						disp_sel[i] = Double.NaN;
					}
				}
				String [] dbg_titles = {"disp_blur","disp_sel","disp","str_blur","str"};
				double [][] dbg_img =
					{   disparity,
						disp_sel,
						disp_str[ml][0],
						strength,
						disp_str[ml][1]};
2132
				(new ShowDoubleFloatArrays()).showArrays(dbg_img, stSize2, stSize2, true, "disp_blured",dbg_titles);
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142
				System.out.println("getHighestPlaneSelection() done");
			}

		} // ml
		return plane_selection;
	}




2143 2144 2145 2146
	// use histogram data (min/max/strength) assign tiles to clusters
	// returns [supertile] [ plane number] [measurement layer] [tile index]
	public boolean [][][][] dispClusterize(
			final double [][][][] disparity_strengths, // either normal or tilted disparity/strengths
2147
			final double [][][] hist_max_min_max, // histogram data: per tile array of odd number of disparity/strengths pairs, starting with first maximum
2148 2149 2150
			final boolean [][][] selected,   // tiles OK to be assigned [supertile][measurement layer] [tile index] or null (or null or per-measurement layer)
			final boolean [][][] prohibited, // already assigned tiles [supertile][measurement layer] [tile index] or null
			final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
2151
			// TODO: Scale max_diff, smallDiff for large disparities
2152 2153 2154 2155
			final double     max_diff,  // maximal disparity difference (to assign to a cluster (of Double.NaN)
			final int        plMinPoints, //          =     5;  // Minimal number of points for plane detection
			final double     smallDiff,  //       = 0.4;   // Consider merging initial planes if disparity difference below
			final double     highMix,    //stHighMix         = 0.4;   // Consider merging initial planes if jumps between ratio above
2156 2157
			final boolean    norm_max_diff,   // scale  max_diff for large (> dispNorm) average disparities
			final boolean    norm_small_diff, // scale  max_diff for large (> dispNorm) average disparities
2158
			final double     dispNorm,
2159 2160 2161 2162 2163 2164 2165 2166
			final int        debugLevel,
			final int        dbg_X,
			final int        dbg_Y)
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();

2167
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
2168
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
2169
		final int nStiles = stilesX * stilesY;
2170
//		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
2171
		final Thread[] threads = ImageDtt.newThreadArray((debugLevel > 1)? 1 :tileProcessor.threadsMax);
2172 2173 2174
		final AtomicInteger ai = new AtomicInteger(0);
		this.planes = new TilePlanes.PlaneData[nStiles][];
		final int debug_stile = (debugLevel > -1)? (dbg_Y * stilesX + dbg_X):-1;
2175

2176 2177 2178 2179
		final boolean [][][][] plane_selections = new boolean [nStiles][][][]; // [supertile] [ plane number] [measurement layer] [tile index]
		final double max_diff2 = Double.isNaN(max_diff)? Double.NaN: (max_diff*max_diff);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
2180
				@Override
2181 2182
				public void run() {
					for (int nsTile = ai.getAndIncrement(); nsTile < nStiles; nsTile = ai.getAndIncrement()) {
2183
						if (disparity_strengths[nsTile] != null){
2184 2185
                            int dl = ((debugLevel > 1) && (nsTile == debug_stile)) ? 3: debugLevel;
							if (dl > 1){
2186
								System.out.println("dispClusterize(): nsTile="+nsTile);
2187
							}
2188
							int stileY = nsTile / stilesX;
2189
							int stileX = nsTile % stilesX;
2190
//							int dl =  (nsTile == debug_stile) ? 3 : 0;
2191 2192 2193 2194

							double[][][] disp_strength = new double[measuredLayers.getNumLayers()][][];

							for (int ml = 0; ml < disp_strength.length; ml++) if ((stMeasSel & ( 1 << ml)) != 0){
2195
								disp_strength[ml] = disparity_strengths[nsTile][ml]; // will we change it  - no, no need to clone
2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223
							}

							if (hist_max_min_max[nsTile] == null){
								continue;
							}
							double [][] max_only = new double [(hist_max_min_max[nsTile].length + 1)/2][2];
							for (int i = 0; i < max_only.length; i++){
								max_only[i] = hist_max_min_max[nsTile][2 * i];
							}
							boolean [][][] plane_sels = null;
							int num_ml = disp_strength.length;
							int num_tiles = 4 * superTileSize * superTileSize;
							int [] num_sel;
							boolean [][] tile_en = new boolean [num_ml][];
							for (int ml = 0; ml < num_ml; ml++) if (
									(disp_strength[ml] != null) &&
									((stMeasSel & ( 1 << ml)) != 0) &&
									((selected == null) || ((selected[nsTile] != null) && (selected[nsTile][ml] != null)))
									) {
								tile_en[ml] = new boolean [num_tiles];
								// apply all restrictions here
								for (int i = 0; i < num_tiles; i++){
									if (    (disp_strength[ml][1][i] > 0.0) &&
											((selected == null) || (selected[nsTile][ml].length == 0) || selected[nsTile][ml][i]) &&
											((prohibited == null) || (prohibited[nsTile] == null) || (prohibited[nsTile][ml] == null) || !prohibited[nsTile][ml][i])
											) {
										tile_en[ml][i] = true;
									}
2224 2225
								}
							}
2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241

							for (int iter = 0; iter < 2; iter ++){
								int num_p  = max_only.length;
								plane_sels = new boolean[num_p][num_ml][];
								num_sel = new int [num_p];
								for (int np = 0; np < num_p; np++) {
									for (int ml = 0; ml < num_ml; ml++) if (
											(disp_strength[ml] != null) &&
											((stMeasSel & ( 1 << ml)) != 0) &&
											((selected == null) || ((selected[nsTile] != null) && (selected[nsTile][ml] != null)))
											) {
										plane_sels[np][ml] = new boolean[num_tiles];
									}
								}
								// compare closest to be able to use tilted planes later
								for (int ml = 0; ml < num_ml; ml++) if (tile_en[ml] != null) {
Andrey Filippov's avatar
Andrey Filippov committed
2242
									if ( dl >2) {
2243 2244 2245 2246 2247 2248 2249
										System.out.println("dispClusterize(), nsTile="+nsTile+", tile_en["+ml+"] + iter = "+iter);
										for (int i = 0; i < 2 * superTileSize; i ++){
											for (int j = 0; j < 2 * superTileSize; j ++){
												int indx = 2 * superTileSize * i + j;
												System.out.print(tile_en[ml][indx]?" +":" .");
											}
											System.out.println();
2250 2251
										}
									}
2252 2253 2254 2255 2256
									for (int indx = 0; indx < num_tiles; indx++) if (tile_en[ml][indx]){
										int best_plane = -1;
										double best_d2 = Double.NaN;
										for (int np = 0; np < num_p; np++) {
											double d2 = max_only[np][0] - disp_strength[ml][0][indx];
2257 2258 2259 2260 2261 2262 2263
											// add disp_norm correction here? Yes!
											if (norm_max_diff) {
												double d_avg = 0.5 * (max_only[np][0] + disp_strength[ml][0][indx]);
												if (d_avg > dispNorm){
													d2 *= dispNorm / d_avg;
												}
											}
2264 2265 2266 2267 2268 2269 2270 2271 2272 2273
											d2 *= d2;
											if (!(d2 >= best_d2)){
												best_d2 = d2;
												best_plane = np;
											}
										}
										if (best_plane >= 0){ // compare to max diff here too
											if  (!(best_d2 > max_diff2)) { // works if max_diff2 is Double.NaN
												plane_sels[best_plane][ml][indx] = true; // so far exclusive
											}
2274 2275
										}
									}
Andrey Filippov's avatar
Andrey Filippov committed
2276
									if ( dl > 2) {
2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292
										System.out.println("dispClusterize(), nsTile="+nsTile+", plane_sels[?]["+ml+"] ,iter = "+iter);
										for (int i = 0; i < 2 * superTileSize; i ++){
											for (int j = 0; j < 2 * superTileSize; j ++){
												int indx = 2 * superTileSize * i + j;
												label1: {
													for (int np = 0; np < num_p; np++) {
														if (plane_sels[np][ml][indx]) {
															System.out.print(" " +np);
															break label1;
														}
													}
													System.out.print(" .");
												}
											}
											System.out.println();
										}
2293
									}
2294
								} //for (int ml = 0; ml < num_ml; ml++) if (tile_en[ml] != null) {
2295 2296 2297 2298 2299 2300 2301 2302 2303 2304
								// recalculate average disparities for each plane and show number of tiles in each in debug mode
								for (int np = 0; np < num_p; np++) {
									double sd = 0.0, sw = 0.0;
									for (int ml = 0; ml < num_ml; ml++) if (disp_strength[ml] != null) {
										for (int indx = 0; indx < num_tiles; indx++) if (plane_sels[np][ml][indx]){
											double w = disp_strength[ml][1][indx];
											sd += w * disp_strength[ml][0][indx];
											sw += w;
											num_sel[np]++;
										}
2305
									}
2306 2307
									if (sw > 0) {
										sd /= sw;
2308
									}
Andrey Filippov's avatar
Andrey Filippov committed
2309
									if (dl > 2) {
2310 2311
										System.out.println("plane num_sel["+np+"] = "+num_sel[np]+" disp "+max_only[np][0]+"->"+sd+
												", weight "+max_only[np][1]+"->"+sw);
2312
									}
2313 2314
									max_only[np][0] = sd;
									max_only[np][1] = sw;
2315
								}
2316 2317 2318 2319 2320
								// calculate transitions matrix (to find candidates for merge
								int [][]    trans_mat =  getTransMatrix(plane_sels);
								double [][] rel_trans =  getTransRel(trans_mat);


2321
								if (dl > 1) {
2322 2323 2324 2325 2326
									System.out.println("trans_mat = ");
									for (int i = 0; i < trans_mat.length; i++){
										System.out.print(i+": ");
										for (int j = 0; j < trans_mat[i].length; j++){
											System.out.print(trans_mat[i][j]+" ");
2327
										}
2328
										System.out.println();
2329
									}
2330 2331 2332 2333 2334 2335 2336 2337 2338
									System.out.println("rel_trans = ");
									for (int i = 0; i < rel_trans.length; i++){
										System.out.print(i+": ");
										for (int j = 0; j < rel_trans[i].length; j++){
											System.out.print(rel_trans[i][j]+" ");
										}
										System.out.println();
									}
								}
2339
								if ((iter > 0 ) && (num_p > 1)){ // remove /join bad
2340 2341 2342 2343
									int windx = 0;
									int remove_indx = -1;
									for (int i = 1; i < num_p; i++)	if (num_sel[i] < num_sel[windx]) windx = i;
									if (num_sel[windx] < plMinPoints) {
2344
										if ((debugLevel > 2) || (dl > 2)){
2345
											System.out.println ("dispClusterize(): stileX = "+stileX+" stileY="+stileY+
2346
													": removing plane "+windx+" with "+num_sel[windx]+" tiles ( <"+plMinPoints+")");
2347 2348 2349
										}
										remove_indx = windx;
									}
2350 2351
									if (remove_indx < 0) {
										// find candidates for merge
2352
										windx = -1;
2353
										for (int i = 0; i < (num_p - 1); i++)	{
2354 2355 2356 2357 2358 2359 2360
											double diff_disp = max_only[i+1][0] - max_only[i][0];
											if (norm_small_diff) {
												double d_avg = 0.5 * (max_only[i+1][0] + max_only[i][0]);
												if (d_avg > dispNorm){
													diff_disp *= dispNorm / d_avg;
												}
											}
2361

2362
											if ((diff_disp < smallDiff) &&  // close enough to consider merging
2363 2364 2365 2366 2367
													(rel_trans[i][i+1] > highMix)) {
												if ((windx < 0) || (rel_trans[i][i+1] > rel_trans[windx][windx+1])) windx = i;
											}
										}
										if (windx >=0 ) {
2368
											if ((debugLevel > 2) || (dl > 2)) {
2369 2370 2371 2372 2373 2374
												System.out.println ("dispClusterize(): stileX = "+stileX+" stileY="+stileY+
														": merging plane "+windx+" with " + (windx + 1)+": "+
														num_sel[windx] + " and "+num_sel[windx+1]+" tiles, "+
														" rel_trans="+rel_trans[windx][windx + 1]+ " ( > " + highMix+"),"+
														" diff="+ (max_only[windx + 1][0]- max_only[windx][0]) + " ( < " + smallDiff+" ),"+
														" disp1 = "+max_only[windx][0]+" disp2 = "+max_only[windx + 1][0]);
2375
											}
2376 2377 2378 2379
											double sum_w = max_only[windx][1] + max_only[windx + 1][1];
											max_only[windx+1][0] = (max_only[windx][0]*max_only[windx][1] +  max_only[windx+1][0]*max_only[windx+1][1]) / sum_w;
											max_only[windx+1][1] = sum_w;
											remove_indx = windx;
2380 2381
										}
									}
2382 2383 2384 2385 2386
									if (remove_indx >= 0){
										double [][] max_only_copy = max_only.clone();
										for (int i = 0; i < max_only.length; i++) max_only_copy[i] = max_only[i];
										max_only = new double [max_only.length - 1][];
										int indx = 0;
2387
										for (int i = 0; i < max_only_copy.length; i++) if (i != remove_indx) max_only[indx++] =max_only_copy[i];
2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406
										iter = 0;
										continue; // restart from 0

									}

									// Show other candidates for merge
									if ((debugLevel > 2) || (dl > 0)){
										double max_sep = 0.2;
										if (iter  > 0) {
											for (int i = 0; i < (num_p-1); i++){
												if (rel_trans[i][i+1] > max_sep) {
													System.out.println("dispClusterize() stileX = "+stileX+" stileY="+stileY+" lowplane = "+i+
															" num_sel1 = "+num_sel[i] + " num_sel2 = "+num_sel[i+1] +
															" rel_trans="+rel_trans[i][i+1]+
															" diff="+ (max_only[i+1][0]- max_only[i][0]) +
															" disp1 = "+max_only[i][0]+" disp2 = "+max_only[i+1][0]);
												}
											}
										}
2407
									}
2408
								}
2409
							} // for (int iter = 0; iter < 2; iter ++){
2410

Andrey Filippov's avatar
Andrey Filippov committed
2411
							if (dl > 3) {
2412
								String [] dbg_titles = showSupertileSeparationTitles( disp_strength, plane_sels);
2413
								double [][] dbg_img = showSupertileSeparation(false,disp_strength, plane_sels);
2414
								ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays();
2415 2416 2417
								sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2* superTileSize, true, "disp_clusterize_disp"+nsTile+"-"+debugLevel,dbg_titles);
								dbg_img = showSupertileSeparation(true, disp_strength, plane_sels);
								sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2* superTileSize, true, "disp_clusterize_world"+nsTile+"-"+debugLevel,dbg_titles);
2418 2419
							}
							plane_selections[nsTile] = plane_sels;
2420 2421 2422 2423
						}
					}
				}
			};
2424
		}
2425
		ImageDtt.startAndJoin(threads);
2426
		return plane_selections;
2427
	}
2428

2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478
	private double getSelectionStrength(
			boolean mod_strength,
			double plDispNorm,
			boolean [][] sels,
			double [][][] ds)
	{
		int num_layers = ds.length;
		int superTileSize = tileProcessor.getSuperTileSize();
		if (sels == null) return 0.0;
		double sw = 0.0;
		int num_tiles = 0;
		if (mod_strength) {
			TileNeibs tileNeibs = new TileNeibs(2 * superTileSize, 2 * superTileSize);
			for (int ml = 0; ml < num_layers; ml++) if (sels[ml] != null) {
				for (int i = 0; i < sels[ml].length; i++) {
					if (sels[ml][i]) {
						int nn = 0;
						for (int dir = 0; dir < 8; dir++) {
							int i1 = tileNeibs.getNeibIndex(i, dir);
							if ((i1 >=0) && sels[ml][i1]) {
								nn++;
							}
						}
						double w = ds[ml][1][i];
						double d = ds[ml][0][i];
						if ((plDispNorm > 0.0) && (d > 0.0) && (d < plDispNorm)) {
							w *=  d / plDispNorm;
						}
						sw +=   w * nn;
					}
				}
			}
			// increasing weight of strong compact clusters - see if it improves results
			if (num_tiles > 0) {
				sw /= Math.sqrt(num_tiles);
			}
		} else { // old way

			for (int ml = 0; ml < num_layers; ml++) if (sels[ml] != null) {
				for (int i = 0; i < sels[ml].length; i++) {
					if (sels[ml][i]) {
						sw +=  ds[ml][1][i];
					}
				}
			}
		}
		return sw;
	}


2479 2480
	/**
	 * Use both horizontal and const disparity tiles to create tile clusters
Andrey Filippov's avatar
Andrey Filippov committed
2481
	 * Add max_diff (maximal disparity difference while extracting initial tile selection) and max_tries (2..3) parameters
2482 2483 2484
	 * Add separate method to create + remove outliers from all planes (2 different ones)?
	 * TODO later re-assign pixels according to existing plane parameters
	 * Sort plane data by center (plane or supertile) disparity
2485
	 *
2486
	 * @param growSelection
2487
	 * @param stMeasSel Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510
	 * @param plDispNorm
	 * @param plMinPoints
	 * @param plPreferDisparity
	 * @param geometryCorrection
	 * @param correct_distortions
	 * @param smplMode
	 * @param smplSide
	 * @param smplNum
	 * @param smplRms
	 * @param bin_blur_hor
	 * @param bin_blur_vert
	 * @param max_diff_hor
	 * @param max_diff_vert
	 * @param max_tries
	 * @param smallDiff
	 * @param highMix
	 * @param world_hor
	 * @param debugLevel
	 * @param dbg_X
	 * @param dbg_Y
	 * @return
	 */

2511
	public boolean [][][][]  initialDiscriminateTiles(
2512
			final int        growSelection,                     // grow initial selection before processing
2513
			final int        stMeasSel,          //      = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
2514
			final double     plDispNorm,
2515
			final int        plMinPoints,       //          =     5;  // Minimal number of points for plane detection
2516 2517 2518 2519
			final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
			final GeometryCorrection geometryCorrection,
			final boolean    correct_distortions,

2520
			final boolean    smplMode,       //        = true;   // Use sample mode (false - regular tile mode)
2521 2522

			final MeasuredLayersFilterParameters mlfp,
2523

2524 2525
			final double     bin_blur_hor,   // Blur disparity histograms for horizontal clusters by this sigma (in bins)
			final double     bin_blur_vert,  // Blur disparity histograms for constant disparity clusters by this sigma (in bins)
2526
			// TODO: scale down max_diff_hor, max_diff_vert  for large disparities?
2527 2528 2529
			final double     max_diff_hor,   // maximal disparity difference (to assign to a cluster (of Double.NaN) at first run for horizontal planes
			final double     max_diff_vert,  // maximal disparity difference (to assign to a cluster (of Double.NaN) at first run for vertical plane

2530
			final int        max_tries,       // on last run - assign all remaining pixels to some cluster (disregard max_diff)
2531
			final double     smallDiff,  //       = 0.4;   // Consider merging initial planes if disparity difference below
2532
			// TODO: scale down smallDiff for large disparities?
2533
			final double     highMix,    //stHighMix         = 0.4;   // Consider merging initial planes if jumps between ratio above
2534
			final double []  world_hor, // horizontal plane normal (default [0.0, 1.0, 0.0])
2535
			final boolean    show_histograms,
2536
			final boolean [][] hor_planes, // returns plane types (hor/vert)
2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553

// Parameters for alternative initial planes that use lowest disparity for fronto planes, and farthest - for horizontal
			final boolean    mod_strength,          //  = true; // FIXME: make a parameter. when set, multiply each tile strength by the number of selected neighbors
			final boolean    clusterize_by_highest, //  = true;
			final double     clust_sigma,           //  = 0.7;
			final double     disp_arange_vert,      //  = 0.07;
			final double     disp_rrange_vert,      //  = 0.01;
			final double     disp_arange_hor,       //  =  0.035;
			final double     disp_rrange_hor,       //  =   0.005;
			final double     tolerance_above_near,  //  =  100.0; // 0.07; any?
			final double     tolerance_below_near,  //  =  -0.01;
			final double     tolerance_above_far,   //  =    0.07;
			final double     tolerance_below_far,   //  =    0.1; // 100.0; // any farther
			final int        hor_vert_overlap,      //  =       2;
			final int        used_companions,       //  =      5; // cell that has this many new used companions is considered used (borders and already use3d are considered used too)
			final int        used_true_companions,  //  = 1; // there should be at least this many new selected tiles among neighbors.,

2554 2555 2556 2557
			final int        debugLevel,
			final int        dbg_X,
			final int        dbg_Y)
	{
2558 2559
		// TODO: Make a configurable parameters (0 should also work)
		final int min_fresh_used = 1; // minimal number of new tiles not already used by the other direction (hor/vert)
2560

2561 2562 2563
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
2564
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
2565
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
2566
		final int nStiles = stilesX * stilesY;
2567
		final Thread[] threads = ImageDtt.newThreadArray((debugLevel > 1)? 1 : tileProcessor.threadsMax);
2568 2569 2570 2571 2572 2573
		final AtomicInteger ai = new AtomicInteger(0);
		this.planes = new TilePlanes.PlaneData[nStiles][];
		final int debug_stile = (debugLevel > -1)? (dbg_Y * stilesX + dbg_X):-1;
		// TODO: Remove when promoting PlaneData
		final int num_layers = measuredLayers.getNumLayers();
		final int num_tiles = 4 * superTileSize * superTileSize;
2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585
		boolean [] grown_selection = null;
		if (growSelection >= 0) {
			grown_selection = cltPass3d.getSelected();
			if (growSelection > 0) {
				grown_selection = grown_selection.clone();
				measuredLayers.growSelection(
						growSelection, // grow,
						grown_selection, // tiles,
						null); // prohibit);
			}
		}
		measuredLayers.setLayer ( // overwrite?
2586 2587 2588
				0, // int       num_layer,
				cltPass3d.getDisparity(), // double [] disparity,
				cltPass3d.getStrength(), // double [] strength,
2589
				grown_selection); // null); // boolean [] selection) // may be null
2590
		if (show_histograms && (debugLevel > 0)) {
Andrey Filippov's avatar
Andrey Filippov committed
2591
			String [] titles = {"d0","s0","d1","s1","d2","s2","d3","s3","d","s","selection"};
2592
			boolean [] dbg_sel= grown_selection; // cltPass3d.getSelected();
2593 2594 2595 2596 2597 2598 2599
			double [][] dbg_img = new double [titles.length][];
			for (int i = 0; i < measuredLayers.getNumLayers(); i++){
				dbg_img[2 * i] =     measuredLayers.getDisparity(i);
				dbg_img[2 * i + 1] = measuredLayers.getStrength(i);
			}
			dbg_img[8] = cltPass3d.getDisparity();
			dbg_img[9] = cltPass3d.getStrength();
2600 2601 2602 2603
			dbg_img[10]= new double [dbg_sel.length];
			for (int i = 0; i < dbg_sel.length; i++){
				dbg_img[10][i] = ((dbg_sel == null) || dbg_sel[i])? 1.0:0.0;
			}
2604
			ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays();
2605 2606
			sdfa_instance.showArrays(dbg_img,  tileProcessor.getTilesX(), tileProcessor.getTilesY(), true, "measuredLayers",titles);
		}
2607

2608
//		double [] world_hor = {0.0, 1.0, 0.0};
Andrey Filippov's avatar
Andrey Filippov committed
2609
		double [] const_disp = {0.0, 0.0, 1.0}; // constant z in world coordinates, same as constant disparity
2610

Andrey Filippov's avatar
Andrey Filippov committed
2611
		final double [][][][] hor_disp_strength = getPlaneDispStrengthsST(
2612 2613 2614 2615 2616 2617
				world_hor,           // final double []  world_plane_norm, // real world normal vector to a suggested plane family (0,1,0) for horizontal planes
				stMeasSel,           //final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
				plPreferDisparity,   // final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
				geometryCorrection,  // final GeometryCorrection geometryCorrection,
				correct_distortions, // final boolean    correct_distortions,
				smplMode,            // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
2618
				mlfp,
2619 2620 2621 2622
				debugLevel,
				dbg_X,
				dbg_Y);

Andrey Filippov's avatar
Andrey Filippov committed
2623 2624
		final double [][][][] vert_disp_strength = getPlaneDispStrengthsST(
				const_disp,          // final double []  world_plane_norm, // real world normal vector to a suggested plane family (0,1,0) for horizontal planes
2625 2626 2627 2628 2629
				stMeasSel,           //final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
				plPreferDisparity,   // final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
				geometryCorrection,  // final GeometryCorrection geometryCorrection,
				correct_distortions, // final boolean    correct_distortions,
				smplMode,            // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
2630
				mlfp,
2631 2632 2633 2634 2635 2636 2637
				debugLevel,
				dbg_X,
				dbg_Y);


		String [] dbg_hist_titles = {"all","hor","mm_vert","mm_hor"};
		double [][] dbg_hist = new double [dbg_hist_titles.length][];
2638 2639
		final boolean [][][] used_hor = new boolean [nStiles][num_layers][]; // num_tiles
		final boolean [][][] used_vert = (hor_vert_overlap == 0) ? used_hor : (new boolean [nStiles][num_layers][]);
2640 2641
		final boolean [][][][] planes_selections = new boolean [nStiles][][][]; // num_tiles
		for (int pass = 0; pass < max_tries; pass ++) {
2642
//			final int fpass = pass;
2643
			// get both horizontal planes and constant disparity planes histograms,
2644 2645
//			resetDisparityHistograms();
			setBlurSigma(bin_blur_hor);
2646 2647 2648
			final double [][][] mmm_hor = getMaxMinMax(
					hor_disp_strength,  // final double [][][][] disparity_strength, // pre-calculated disparity/strength [per super-tile][per-measurement layer][2][tiles] or null
					null); // final boolean [][] tile_sel // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all
2649
			if (show_histograms && (debugLevel > 0)) {
2650 2651 2652
				dbg_hist[1] = showDisparityHistogram();
				dbg_hist[3] = showMaxMinMax();
			}
2653 2654
//			resetDisparityHistograms();
			setBlurSigma(bin_blur_vert);
2655 2656 2657 2658
			final double [][][] mmm_vert = getMaxMinMax(
					vert_disp_strength,  // final double [][][][] disparity_strength, // pre-calculated disparity/strength [per super-tile][per-measurement layer][2][tiles] or null
					null); // final boolean [][] tile_sel // null  or per-measurement layer, per-tile selection. For each layer null - do not use, {} - use all

2659
			if (show_histograms && (debugLevel > 0)) {
2660 2661 2662
				dbg_hist[0] = showDisparityHistogram();
				dbg_hist[2] = showMaxMinMax();
			}
2663
			if (show_histograms && (debugLevel > 0)) {
2664 2665
				int hist_width0 =  showDisparityHistogramWidth();
				int hist_height0 = dbg_hist[0].length/hist_width0;
2666
				ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays(); // just for debugging?
2667 2668 2669
				sdfa_instance.showArrays(dbg_hist, hist_width0, hist_height0, true, "vert_hor_histograms_"+pass,dbg_hist_titles);
			}
			// try to independently (same selections) clusterize both ways
2670
			if (debugLevel > 0){
2671 2672
				System.out.println("initialDiscriminateTiles(): before new_planes_hor, pass =" + (pass + 1) + " ( of "+max_tries+" )");
			}
2673 2674 2675 2676 2677 2678 2679 2680 2681 2682
//			if (clusterize_by_highest) {
			final boolean [][][][] new_planes_hor = clusterize_by_highest ?
					dispClusterizeHighest(
							hor_disp_strength,  // final double [][][][] disparity_strengths, // either normal or tilted disparity/strengths
							null,               // final boolean [][][] selected,   // tiles OK to be assigned [supertile][measurement layer] [tile index] or null (or null or per-measurement layer)
							used_hor,           // final boolean [][][] prohibited, // already assigned tiles [supertile][measurement layer] [tile index] or null
							true,               // final boolean        search_min,
							stMeasSel,          // final int            stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
							plDispNorm,         // final double         plDispNorm,         // to increase weight of nearer planes
							clust_sigma,        // final double         sigma,
2683 2684
							disp_arange_hor,  // final double         disp_arange,
							disp_rrange_hor,  // final double         disp_rrange,
2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708
							tolerance_above_far,// final double         tolerance_above,
							tolerance_below_far,// final double         tolerance_below,
							plMinPoints,        // final int            plMinPoints, //          =     5;  // Minimal number of points for plane detection
							"hor",              // final String         suffix,
							debugLevel + 0,         // final int            debugLevel,
							dbg_X,              // final int            dbg_X,
							dbg_Y):             // final int            dbg_Y);

								dispClusterize(
										hor_disp_strength, // final double [][][][] disparity_strengths, // either normal or tilted disparity/strengths
										mmm_hor,           // final double [][][] hist_max_min_max, // histogram data: per tile array of odd number of disparity/strengths pairs, starting with first maximum
										null,              // final boolean [][][] selected,   // tiles OK to be assigned [supertile][measurement layer] [tile index] or null (or null or per-measurement layer)
										used_hor,          // final boolean [][][] prohibited, // already assigned tiles [supertile][measurement layer] [tile index] or null
										stMeasSel,         // final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
										((pass < (max_tries - 1)) ? max_diff_hor : Double.NaN), // final double     max_diff,  // maximal disparity difference (to assign to a cluster (of Double.NaN)
										plMinPoints,       // final int        plMinPoints, //          =     5;  // Minimal number of points for plane detection
										smallDiff,         // final double     smallDiff,  //       = 0.4;   // Consider merging initial planes if disparity difference below
										highMix,           // final double     highMix,    //stHighMix         = 0.4;   // Consider merging initial planes if jumps between ratio above
										true,              // final boolean    norm_max_diff,   // scale  max_diff for large (> dispNorm) average disparities
										true,              // final boolean    norm_small_diff, // scale  max_diff for large (> dispNorm) average disparities
										plDispNorm,        // final double     dispNorm, // TODO: make a separate variable?
										debugLevel, // 1, // debugLevel,
										dbg_X,
										dbg_Y);
2709

2710
			if (debugLevel > 0){
2711 2712
				System.out.println("initialDiscriminateTiles(): before new_planes_vert, pass =" + (pass + 1) + " ( of "+max_tries+" )");
			}
2713 2714
			final boolean [][][][] new_planes_vert = clusterize_by_highest ?
					dispClusterizeHighest(
2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730
							vert_disp_strength,   // final double [][][][] disparity_strengths, // either normal or tilted disparity/strengths
							null,                 // final boolean [][][] selected,   // tiles OK to be assigned [supertile][measurement layer] [tile index] or null (or null or per-measurement layer)
							used_vert,            // final boolean [][][] prohibited, // already assigned tiles [supertile][measurement layer] [tile index] or null
							false,                // final boolean        search_min,
							stMeasSel,            // final int            stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
							plDispNorm,           // final double         plDispNorm,         // to increase weight of nearer planes
							clust_sigma,          // final double         sigma,
							disp_arange_vert,     // final double         disp_arange,
							disp_rrange_vert,     // final double         disp_rrange,
							tolerance_above_near, // final double         tolerance_above,
							tolerance_below_near, // final double         tolerance_below,
							plMinPoints,          // final int            plMinPoints, //          =     5;  // Minimal number of points for plane detection
							"vert",               // final String         suffix,
							debugLevel + 0,       // final int            debugLevel,
							dbg_X,                // final int            dbg_X,
							dbg_Y):               // final int            dbg_Y)
2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746
								dispClusterize(
										vert_disp_strength, // final double [][][][] disparity_strengths, // either normal or tilted disparity/strengths
										mmm_vert,           // final double [][][] hist_max_min_max, // histogram data: per tile array of odd number of disparity/strengths pairs, starting with first maximum
										null,              // final boolean [][][] selected,   // tiles OK to be assigned [supertile][measurement layer] [tile index] or null (or null or per-measurement layer)
										used_vert,              // final boolean [][][] prohibited, // already assigned tiles [supertile][measurement layer] [tile index] or null
										stMeasSel,         // final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
										((pass < (max_tries - 1)) ? max_diff_vert : Double.NaN), // final double     max_diff,  // maximal disparity difference (to assign to a cluster (of Double.NaN)
										plMinPoints,       // final int        plMinPoints, //          =     5;  // Minimal number of points for plane detection
										smallDiff,         // final double     smallDiff,  //       = 0.4;   // Consider merging initial planes if disparity difference below
										highMix,          // final double     highMix,    //stHighMix         = 0.4;   // Consider merging initial planes if jumps between ratio above
										true,              // final boolean    norm_max_diff,   // scale  max_diff for large (> dispNorm) average disparities
										true,              // final boolean    norm_small_diff, // scale  max_diff for large (> dispNorm) average disparities
										plDispNorm,        // final double     dispNorm, // TODO: make a separate variable?
										debugLevel, // 2, // debugLevel,
										dbg_X,
										dbg_Y);
2747

2748
			// compare which vert or hor provide stronger clusters, add them to selections, recalculate "used"
2749
			ai.set(0);
2750 2751
			for (int ithread = 0; ithread < threads.length; ithread++) {
				threads[ithread] = new Thread() {
2752
					@Override
2753
					public void run() {
2754
						TileNeibs tnStile = new TileNeibs(2 * superTileSize, 2* superTileSize);
2755
						for (int nsTile = ai.getAndIncrement(); nsTile < nStiles; nsTile = ai.getAndIncrement()) {
2756
                            int dl = ((debugLevel > 0) && (nsTile == debug_stile)) ? (debugLevel + 2) : debugLevel;
2757
							if (dl > 2){
2758
								System.out.println("initialDiscriminateTiles() selecting: nsTile="+nsTile);
2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776
							}
							double [][][][] ds = {vert_disp_strength[nsTile],hor_disp_strength[nsTile]};
							boolean [][][][] sels_all = {new_planes_vert[nsTile],new_planes_hor[nsTile]}; // make possible to iterate
							class SelStrength{
								int type;
								int indx;
								double strength;
								SelStrength(int type, int indx, double strength){
									this.type = type;
									this.indx = indx;
									this.strength = strength;
								}
							}
							ArrayList<SelStrength> selStrengthList = new ArrayList <SelStrength>();
							for (int pType = 0; pType < sels_all.length; pType++){
								if (sels_all[pType] == null) sels_all[pType] = new boolean[0][][];
								// calculate strength of each selection;
								for (int np = 0; np < sels_all[pType].length; np ++) {
2777 2778 2779 2780 2781
									double sw = getSelectionStrength(
											mod_strength,        // boolean mod_strength,
											plDispNorm,          // double plDispNorm,
											sels_all[pType][np], // boolean [][] sels,
											ds[pType]);          // double [][][] ds);
2782 2783 2784
									selStrengthList.add(new SelStrength(pType, np, sw));
								}
							}
2785 2786 2787


							if (dl > 2){
2788 2789 2790 2791 2792 2793 2794
								System.out.println("initialDiscriminateTiles() got list of clusters for "+nsTile);
								for (int i = 0; i < selStrengthList.size(); i++){
									System.out.println(i+": type = "+selStrengthList.get(i).type+
											" index = "+selStrengthList.get(i).indx +
											" strength = "+selStrengthList.get(i).strength);
								}
							}
2795 2796 2797 2798 2799 2800 2801 2802
							if (selStrengthList.size() > 0) {
								Collections.sort(selStrengthList, new Comparator<SelStrength>() {
									@Override
									public int compare(SelStrength lhs, SelStrength rhs) {
										// -1 - less than, 1 - greater than, 0 - equal, all inverted for descending
										return (lhs.strength > rhs.strength) ? -1 : (lhs.strength < rhs.strength ) ? 1 : 0;
									}
								});
2803
								if (dl > 1){
2804 2805 2806 2807 2808 2809 2810
									System.out.println("initialDiscriminateTiles() sorted list of clusters for "+nsTile);
									for (int i = 0; i < selStrengthList.size(); i++){
										System.out.println(i+": type = "+selStrengthList.get(i).type+
												" index = "+selStrengthList.get(i).indx +
												" strength = "+selStrengthList.get(i).strength);
									}
								}
2811

2812 2813 2814 2815 2816 2817 2818
								int best_type = selStrengthList.get(0).type;
								int num_planes = 0;
								for (; num_planes < selStrengthList.size(); num_planes++) {
									if (selStrengthList.get(num_planes).type != best_type) {
										break;
									}
								}
2819
								int num_old_planes = (planes_selections[nsTile] == null) ? 0: planes_selections[nsTile].length;
2820
								if (dl > 1){
2821 2822 2823
									System.out.println("initialDiscriminateTiles() num_old_planes= "+num_old_planes);
								}
								boolean [][][] new_planes_selections = new boolean [num_old_planes + num_planes][][];
2824
								boolean []     new_plane_types = new boolean [num_old_planes + num_planes];
2825 2826 2827
								int np = 0;
								for (; np < num_old_planes; np++){
									new_planes_selections[np] = planes_selections[nsTile][np];
2828
									new_plane_types[np] = hor_planes[nsTile][np];
2829
								}
2830
								int planes_added = 0;
2831 2832
								for (int nnp = 0; nnp < num_planes; nnp++) { // SelStrength ss:selStrengthList){
									SelStrength ss = selStrengthList.get(nnp);
2833 2834
									new_plane_types[np] =         ss.type != 0; // 0 - vert, 1 - hor;
									new_planes_selections[np] =   sels_all[ss.type][ss.indx];
2835
									for (int ml = 0; ml < num_layers; ml++) if (sels_all[ss.type][ss.indx][ml] != null){
2836 2837 2838 2839 2840 2841 2842 2843 2844 2845
										if (used_hor[nsTile][ml] == null){
											used_hor[nsTile][ml] = new boolean[num_tiles];
										}
										// used_vert may be the same array as used_hor
										if (used_vert[nsTile][ml] == null){
											used_vert[nsTile][ml] = new boolean[num_tiles];
										}
										// Filling small gaps in new selections before marking them as "used"
										boolean [] used_before = (ss.type == 0) ? used_vert[nsTile][ml] : used_hor[nsTile][ml];
										boolean [] this_used = sels_all[ss.type][ss.indx][ml].clone();
2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866
										// See how many really new tiles has this_used;
										int num_really_new = 0;
										for (int i = 0; i < num_tiles; i++) if (this_used[i] && !used_vert[nsTile][ml][i] && !used_hor[nsTile][ml][i]) {
											num_really_new++;
										}
										// see if is enough
										if (num_really_new < min_fresh_used) {
											for (int i = 0; i < num_tiles; i++){
												used_before[i] |= this_used[i]; // Still mark them as used on this orientation
											}
											this_used = new boolean[this_used.length]; // unselect all

											if (dl > 1){
												System.out.println("initialDiscriminateTiles():"+nsTile+" selection does not provide enough previously unused tiles");
											}
											// disable these tiles in this orientation used

										} else {
											planes_added++;
										}

2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886
										boolean [] this_used_expanded = this_used.clone();
										tnStile.growSelection(
												2,
												this_used_expanded,
												null);
										for (int i = 0; i < num_tiles; i++) if (this_used_expanded[i] && !this_used[i]) {
											int n_new_used = 0, n_blocked = 0;
											for (int dir = 0; dir < 8; dir++) {
												int i1 = tnStile.getNeibIndex(i, dir);
												if (i1 < 0) {
													n_blocked++;
												} else if (sels_all[ss.type][ss.indx][ml][i1]) { // this_used is modified
													n_new_used++;
												} else if (used_before[i1]) {
													n_blocked++;
												}
											}
											if (((n_new_used + n_blocked) >= used_companions) && (n_new_used >= used_true_companions)) {
												this_used[i] = true;
											}
2887
										}
2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913

										// first apply to the same direction (or both if it is the same array)
										if (ss.type == 0) {
											for (int i = 0; i < num_tiles; i++){
												used_vert[nsTile][ml][i] |= this_used[i]; // sels_all[ss.type][ss.indx][ml][i];
											}
										} else {
											for (int i = 0; i < num_tiles; i++){
												used_hor[nsTile][ml][i] |= this_used[i]; // sels_all[ss.type][ss.indx][ml][i];
											}
										}
										if (hor_vert_overlap > 0) { // shrink selection and apply to the other direction
//											boolean [] newsel = sels_all[ss.type][ss.indx][ml].clone();
											tnStile.shrinkSelection(
													hor_vert_overlap,
													this_used,
													null);
											if (ss.type != 0) {
												for (int i = 0; i < num_tiles; i++){
													used_vert[nsTile][ml][i] |= this_used[i];
												}
											} else {
												for (int i = 0; i < num_tiles; i++){
													used_hor[nsTile][ml][i] |= this_used[i];
												}
											}
2914 2915
										}
									}
2916
									np++;
2917
								}
2918 2919 2920 2921 2922 2923 2924
								if (planes_added == 0) {
									if (dl > 1){
										System.out.println("initialDiscriminateTiles():"+nsTile+": No new planes added");
									}
									continue;
								}

2925
								planes_selections[nsTile] = new_planes_selections;
2926
								hor_planes[nsTile] =        new_plane_types;
Andrey Filippov's avatar
Andrey Filippov committed
2927
								if (dl > 2){
2928 2929 2930 2931 2932 2933
									System.out.println("initialDiscriminateTiles() new_planes_selections.length= "+new_planes_selections.length);
								}
							}
						}
					}
				};
2934
			}
2935 2936 2937 2938
			ImageDtt.startAndJoin(threads);
		}
		return planes_selections;
	}
2939

2940 2941 2942
	/**
	 * Re-assign tiles to the planes according to fitted planes. Scans each known plane parallel with specified
	 * size steps and specified number of steps, maximizing overall fit quality.
2943
	 * Total weight of the fitted tiles? RMS?
2944 2945
	 * @param planes per-supertile, per plane array of plane data instances. Should have
	 *        nonexclusiveStar and nonexclusiveStarEq calculated
2946
	 * @param stMeasSel - select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
2947
	 * @param plDispNorm - normalization of the measured disparity precision - closer objects will have disparity
2948
	 *        difference proportionally reduced
2949 2950
	 * @param plPreferDisparity kept for historical reasons - when true, select disparity-most vector even if it has higher eigenvalue
	 * @param geometryCorrection GeometryCorrection instance to use
2951
	 * @param correct_distortions correct geometrical distortions when converting to/from world coordinates
2952 2953 2954 2955
	 * @param smplMode sample mode
	 * @param smplSide sample side for averaging/filtering tile disparities
	 * @param smplNum number of best samples used fro averaging
	 * @param smplRms maximal sample disparity rms to consider sample valid
2956
	 * @param smplWnd use window functions for the samples
2957 2958 2959 2960 2961 2962 2963 2964
	 * @param max_abs_tilt pix per tile
	 * @param max_rel_tilt pix / disparity) per tile
	 * @param damp_tilt Damp tilt to handle insufficient  (co-linear)data
	 * @param min_tilt_disp Disparity switch between filtering modes - near objects use tilts, far - use max disparity
	 * @param transition Mode transition range (between tilted and maximal disparity)
	 * @param far_mode Far objects filtering mode (0 - off, 1 - power of disparity)
	 * @param far_power Raise disparity to this power before averaging for far objects
	 * @param plDiscrTolerance maximal disparity difference from the plane to consider tile
2965 2966
	 * @param plDiscrDispRange parallel move known planes around original know value for the best overall fit
	 * @param plDiscrSteps number of steps (each direction) for each plane to search for the best fit (0 - single, 1 - 1 each side)
2967
	 * @param plDiscrVariants total number of variants to try (protect from too many planes)
2968 2969 2970 2971 2972
	 * @param plDiscrMode what plane to use as a hint: 0 - weighted, 1 - equalized, 2 - best, 3 - combined
	 * @param plDiscrVarFloor squared add to variance to calculate reverse flatness (used mostly for single-cell clusters)
	 * @param plDiscrSigma Gaussian sigma to compare how measured data is attracted to planes
	 * @param plDiscrBlur sigma to blur histograms while re-discriminating
	 * @param plDiscrExclusivity tile exclusivity: 1.0 - tile belongs to one plane only, 0.0 - regardless of others
2973 2974 2975 2976 2977 2978
	 * @param debugLevel debug level
	 * @param dbg_X supertile X for elevated debug level
	 * @param dbg_Y supertile X for elevated debug level
	 * @return per-tile, per plane, per measurement layer (type of correlation - combo, 4, hor, vert), per tile selections of
	 * filtered tiles
	 */
2979

2980
	public boolean [][][][]  refineDiscriminateTiles(
2981 2982
			final TilePlanes.PlaneData [][] planes,
			final int        stMeasSel,            //      = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
2983
			final double     plDispNorm,
2984
			final boolean    plPreferDisparity,    // Always start with disparity-most axis (false - lowest eigenvalue)
2985 2986 2987
			final GeometryCorrection geometryCorrection,
			final boolean    correct_distortions,

2988
			final boolean    smplMode,             //        = true;   // Use sample mode (false - regular tile mode)
2989 2990

			final MeasuredLayersFilterParameters mlfp,
2991 2992

			final double     plDiscrTolerance,     //     =   0.4;  // Maximal disparity difference from the plane to consider tile
2993 2994 2995 2996
			final double     plDiscrDispRange,     //     =   0.6;  // Parallel move known planes around original know value for the best overall fit
			final int        plDiscrSteps,         //         =   3;    // Number of steps (each direction) for each plane to search for the best fit (0 - single, 1 - 1 each side)
			final int        plDiscrMode,          //          =   3;    // What plane to use as a hint: 0 - weighted, 1 - equalized, 2 - best, 3 - combined

Andrey Filippov's avatar
Andrey Filippov committed
2997 2998 2999
			final double     plDiscrVarFloor,    //       =   0.03;  // Squared add to variance to calculate reverse flatness (used mostly for single-cell clusters)
			final double     plDiscrSigma,       //          =   0.05;  // Gaussian sigma to compare how measured data is attracted to planes
			final double     plDiscrBlur,        //           =   0.1;   // Sigma to blur histograms while re-discriminating
3000
			final double     plDiscrExclusivity, //    =   1.5;   // Tile exclusivity: 1.0 - tile belongs to one plane only, 0.0 - regardless of others
Andrey Filippov's avatar
Andrey Filippov committed
3001 3002 3003 3004 3005 3006 3007
			final double     plDiscrExclus2,     //        =   0.8;   // For second pass if exclusivity > 1.0 - will assign only around strong neighbors
			final boolean    plDiscrStrict,      //         = true;   // When growing selection do not allow any offenders around (false - more these than others)
			final double     plDiscrCorrMax,     //        = 0.7;   // Attraction to different planes correlation that is too high for re-discrimination.
			final double     plDiscrCorrMerge,   //     = 0.85;  // Attraction to different planes correlation that is high enough to merge planes
			final int        plDiscrSteal,       //         =   4;     // If offender has this number of tiles (including center) the cell can not be used
			final int        plDiscrGrown,       //         =   0;     // Only use tiles within this range from original selection
			final double     plDiscrXMedian,     //        = 1.5;   // Remove outliers from the final selection that have distance more than scaled median
3008 3009 3010 3011
			final int        debugLevel,
			final int        dbg_X,
			final int        dbg_Y)
	{
3012
		// create a list of usable planes according to the mode
3013 3014 3015 3016 3017
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		final int tileSize =      tileProcessor.getTileSize();

3018
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
3019 3020 3021 3022
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		final int nStiles = stilesX * stilesY;
		final TilePlanes tpl = new TilePlanes(tileSize,superTileSize, geometryCorrection);
		final Thread[] threads = ImageDtt.newThreadArray((debugLevel > 1)? 1 : tileProcessor.threadsMax);
Andrey Filippov's avatar
Andrey Filippov committed
3023

3024 3025 3026 3027 3028 3029
		final AtomicInteger ai = new AtomicInteger(0);
		this.planes = new TilePlanes.PlaneData[nStiles][];
		final int debug_stile = (debugLevel > -1)? (dbg_Y * stilesX + dbg_X):-1;
		final boolean [][][][] planes_selections = new boolean [nStiles][][][]; // num_tiles
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
3030
				@Override
3031 3032
				public void run() {
					for (int nsTile = ai.getAndIncrement(); nsTile < nStiles; nsTile = ai.getAndIncrement()) {
3033 3034
//						int dl =  ((debugLevel > -1) && (nsTile == debug_stile)) ? 3 : 1;
                        int dl = ((debugLevel > 1) && (nsTile == debug_stile)) ? 3: debugLevel;
3035

3036 3037 3038
						if (dl > 1){
							System.out.println("refineDiscriminateTiles() selecting: nsTile="+nsTile);
						}
Andrey Filippov's avatar
Andrey Filippov committed
3039
						if (planes[nsTile] != null) {
3040
							int stileY = nsTile / stilesX;
Andrey Filippov's avatar
Andrey Filippov committed
3041 3042 3043
							int stileX = nsTile % stilesX;
							int [] sTiles = {stileX, stileY};
							TilePlanes.PlaneData pd0 = tpl.new  PlaneData (
3044
									sTiles, // int [] sTileXY,
Andrey Filippov's avatar
Andrey Filippov committed
3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056
									tileSize, // int tileSize,
									geometryCorrection, // GeometryCorrection   geometryCorrection,
									correct_distortions,
									measuredLayers,     // MeasuredLayers measuredLayers,
									plPreferDisparity);   // boolean preferDisparity)

							TilePlanes.PlaneData [] these_planes = planes[nsTile].clone();  // null pointer

							for (int ntry = 0; ntry < planes[nsTile].length; ntry ++) { // can be while(true), just for debugging
								int [] merge_planes = {-1, -1};
								planes_selections[nsTile] = pd0.reDiscriminateTiles(
										""+nsTile,         // String           prefix,
3057
										these_planes,  //planes[nsTile],    // final PlaneData  [] planes,
Andrey Filippov's avatar
Andrey Filippov committed
3058 3059 3060 3061
										merge_planes,      // final int []     merge_planes, // indices of planes suggested to be merged
										stMeasSel,         // final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
										plDispNorm,        // final double     dispNorm,   //  Normalize disparities to the average if above
										smplMode,          // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3062
										mlfp,
3063

Andrey Filippov's avatar
Andrey Filippov committed
3064 3065
										plDiscrTolerance,  // final double     disp_tolerance,   // maximal disparity difference from the plane to consider tile
										plDiscrVarFloor,   // final double     disp_var_floor,   // squared add to variance to calculate reverse flatness (used mostly for single-cell clusters)
3066
										plDiscrSigma,      // final double     disp_sigma,       // G.sigma to compare how measured data is attracted to planes
Andrey Filippov's avatar
Andrey Filippov committed
3067 3068 3069 3070 3071 3072
										plDiscrDispRange,  // final double     disp_range,       // parallel move known planes around original know value for the best overall fit
										plDiscrSteps,      // final int        amplitude_steps,  // number of steps (each direction) for each plane to search for the best fit (0 - single, 1 - 1 each side)
										plDiscrBlur,       // final double     hist_blur,        // Sigma to blur histogram
										plDiscrExclusivity, // final double    exclusivity,      // 1.0 - tile belongs to one plane only, 0.0 - regardless of others
										plDiscrExclus2,    // final double     excluisivity2, //        =   0.8;   // For second pass if exclusivity > 1.0 - will assign only around strong neighbors
										plDiscrStrict,     // final boolean    exclusivity_strict//         = true;   // When growing selection do not allow any offenders around (false - more these than others)
3073
										plDiscrCorrMax,    // final double     plDiscrCorrMax, //         = 0.7;   // Attraction to different planes correlation that is too high for re-discrimination.
Andrey Filippov's avatar
Andrey Filippov committed
3074 3075 3076 3077 3078 3079 3080 3081 3082 3083
										plDiscrCorrMerge,  // final double     attractionCorrMerge, //         = 0.85;  // Attraction to different planes correlation that is high enough to merge planes
										plDiscrSteal,      // final int        plDiscrSteal,        //         =   4;     // If offender has this number of tiles (including center) the cell can not be used
										plDiscrGrown,      // final int        plDiscrGrown,        //         =   0;     // Only use tiles within this range from original selection
										plDiscrXMedian,    // final double     outliersXMedian, //         = 1.5;   // Remove outliers from the final selection that have distance more than scaled median
										plDiscrMode,       // final int        mode, // 0 - weighted, 1 - equalized, 2 - best, 3 - combined
										dl);               // debugLevel); // final int        debugLevel)
								if ((planes_selections[nsTile] != null) || (merge_planes[0] < 0)){ // either OK, or does not know what to do (keep old)
									break;
								}
								// merging suggested plane pair
3084
								if (debugLevel > 0) {
Andrey Filippov's avatar
Andrey Filippov committed
3085 3086 3087 3088 3089 3090
									System.out.println("refineDiscriminateTiles(): nsTile="+nsTile+" merging pair ["+merge_planes[0]+","+merge_planes[1]+"]");
								}
								TilePlanes.PlaneData [] new_planes = new TilePlanes.PlaneData [these_planes.length -1];
								int np1 = 0;
								for (int np = 0; np < these_planes.length; np++) {
									if (np != merge_planes[1]){
3091
										new_planes[np1++] = these_planes[np];
Andrey Filippov's avatar
Andrey Filippov committed
3092 3093 3094 3095 3096
									}
								}
								TilePlanes.PlaneData plane1 = these_planes[merge_planes[0]].mergePlaneToThis(
										these_planes[merge_planes[1]], // PlaneData otherPd,
										1.0,         // double    scale_other,
3097
										1.0,         // double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
Andrey Filippov's avatar
Andrey Filippov committed
3098 3099 3100
										false,       // boolean   ignore_weights,
										true, // boolean   sum_weights,
										these_planes[merge_planes[0]].getPreferDisparity(), // preferDisparity,
3101
										dl-2); // int       debugLevel)
Andrey Filippov's avatar
Andrey Filippov committed
3102 3103
								// combine tile selection - if next time pd0.reDiscriminateTiles() will fail, it will
								// use old selections, we need to provide them (otherwise will use selection from the first plane)
3104 3105 3106 3107
								if (plane1 == null){
									System.out.println("refineDiscriminateTiles() nsTile="+nsTile+" plane1 = null");
									break;
								}
Andrey Filippov's avatar
Andrey Filippov committed
3108
								plane1.orMeasSelection(these_planes[merge_planes[1]].getMeasSelection());
3109

Andrey Filippov's avatar
Andrey Filippov committed
3110 3111
								// separately merge corresponding nonexclusiveStar and nonexclusiveStarEq of these planes - kit is not exact,
								// but is needed just for a hint and is compatible with multithreading without recalculating other planes
3112

3113 3114
								TilePlanes.PlaneData    plane1Ex =    these_planes[merge_planes[0]].getNonexclusiveStarFb();
								TilePlanes.PlaneData    plane1ExEq =  these_planes[merge_planes[0]].getNonexclusiveStarEqFb();
3115

3116 3117
								TilePlanes.PlaneData    plane2Ex =    these_planes[merge_planes[1]].getNonexclusiveStarFb();
								TilePlanes.PlaneData    plane2ExEq =  these_planes[merge_planes[1]].getNonexclusiveStarEqFb();
3118

Andrey Filippov's avatar
Andrey Filippov committed
3119 3120 3121
								TilePlanes.PlaneData plane1NonExcl = plane1Ex.mergePlaneToThis(
										plane2Ex, // PlaneData otherPd,
										1.0,         // double    scale_other,
3122
										1.0,         // double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
Andrey Filippov's avatar
Andrey Filippov committed
3123 3124 3125 3126 3127 3128 3129 3130
										false,       // boolean   ignore_weights,
										true, // boolean   sum_weights,
										these_planes[merge_planes[0]].getPreferDisparity(), // preferDisparity,
										dl-2); // int       debugLevel)

								TilePlanes.PlaneData plane1NonExclEq = plane1ExEq.mergePlaneToThis(
										plane2ExEq, // PlaneData otherPd,
										1.0,         // double    scale_other,
3131
										1.0,         // double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
Andrey Filippov's avatar
Andrey Filippov committed
3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143
										true,        // boolean   ignore_weights,
										true,        // boolean   sum_weights,
										these_planes[merge_planes[0]].getPreferDisparity(), // preferDisparity,
										dl-2); // int       debugLevel)
								plane1.setNonexclusiveStar  (plane1NonExcl);
								plane1.setNonexclusiveStarEq(plane1NonExclEq);
								new_planes[merge_planes[0]] = plane1;
								if (dl > 1){
									System.out.println("First plane ("+merge_planes[0]+"):\n"+(these_planes[merge_planes[0]].toString()));
									System.out.println("Second plane ("+merge_planes[1]+"):\n"+(these_planes[merge_planes[1]].toString()));
									System.out.println("combined plane:\n"+(plane1.toString()));
								}
3144
								these_planes = new_planes.clone();
Andrey Filippov's avatar
Andrey Filippov committed
3145 3146
							}
						}
3147 3148 3149
					}
				}
			};
3150
		}
3151 3152
		ImageDtt.startAndJoin(threads);
		return planes_selections;
3153
	}
3154 3155


Andrey Filippov's avatar
Andrey Filippov committed
3156
	public TilePlanes.PlaneData [][] createPlanesFromSelections( // never finished?
Andrey Filippov's avatar
Andrey Filippov committed
3157
			final boolean [][][][] plane_selections, //  = new boolean [nStiles][][][]; // num_tiles
3158
			final double  [][][][] disp_strength,
Andrey Filippov's avatar
Andrey Filippov committed
3159 3160 3161 3162 3163
			final double     plDispNorm,
			final int        plMinPoints, //          =     5;  // Minimal number of points for plane detection
			final double     plTargetEigen, //        =   0.1;  // Remove outliers until main axis eigenvalue (possibly scaled by plDispNorm) gets below
			final double     plFractOutliers, //      =   0.3;  // Maximal fraction of outliers to remove
			final int        plMaxOutliers, //        =    20;  // Maximal number of outliers to remove
3164
//			final double     plVertWors,    //        =    1.5  // if rotating plane vertical does not increase 'eigenvalue' more, use vertical
Andrey Filippov's avatar
Andrey Filippov committed
3165 3166 3167 3168
			final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
			final GeometryCorrection geometryCorrection,
			final boolean    correct_distortions,
			final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3169 3170

			final MeasuredLayersFilterParameters mlfp,
3171 3172 3173 3174
			final double     fronto_tol, // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable this feature
			//FIXME: use following 2 parameters
			final double     fronto_rms,    // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes
			final double     fronto_offs,   //        =   0.2;  // increasing weight of the near tiles by using difference between the reduced average as weight. <= 0 - disable
3175
			final double     fronto_pow,    //        =   1.0;  // increase weight even more
3176 3177
			// now for regenerated planes - just null as it is not known if it is hor or vert
			final boolean [][] hor_planes, // plane types (hor/vert)
Andrey Filippov's avatar
Andrey Filippov committed
3178 3179 3180 3181 3182 3183 3184 3185 3186
			final int        debugLevel,
			final int        dbg_X,
			final int        dbg_Y)
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		final int tileSize =      tileProcessor.getTileSize();

3187
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
3188
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
3189
		final int nStiles = stilesX * stilesY;
3190 3191
//		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final Thread[] threads = ImageDtt.newThreadArray((debugLevel > 1)? 1 : tileProcessor.threadsMax);
3192

Andrey Filippov's avatar
Andrey Filippov committed
3193 3194 3195 3196 3197 3198 3199 3200 3201
		final AtomicInteger ai = new AtomicInteger(0);
		final TilePlanes.PlaneData [][] result_planes = new TilePlanes.PlaneData[nStiles][];
		//		this.planes = new TilePlanes.PlaneData[nStiles][];
		final int debug_stile = (debugLevel > -1)? (dbg_Y * stilesX + dbg_X):-1;
		// TODO: Remove when promoting PlaneData
		final TilePlanes tpl = new TilePlanes(tileSize,superTileSize, geometryCorrection);

		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
3202
				@Override
Andrey Filippov's avatar
Andrey Filippov committed
3203 3204
				public void run() {
					for (int nsTile = ai.getAndIncrement(); nsTile < nStiles; nsTile = ai.getAndIncrement()) {
3205
                        int dl = ((debugLevel > 1) && (nsTile == debug_stile)) ? 3: debugLevel;
3206
						if (dl > 2){
Andrey Filippov's avatar
Andrey Filippov committed
3207 3208 3209
							System.out.println("createPlanesFromSelections(): nsTile="+nsTile);
						}
						if (plane_selections[nsTile] != null) {
3210 3211

							int stileY = nsTile / stilesX;
Andrey Filippov's avatar
Andrey Filippov committed
3212 3213
							int stileX = nsTile % stilesX;
							int [] sTiles = {stileX, stileY};
3214

Andrey Filippov's avatar
Andrey Filippov committed
3215 3216 3217
							result_planes[nsTile] = null;
							// first make a plane from all tiles
							TilePlanes.PlaneData pd0 = tpl.new  PlaneData (
3218
									sTiles, // int [] sTileXY,
Andrey Filippov's avatar
Andrey Filippov committed
3219 3220 3221 3222 3223 3224 3225 3226
									tileSize, // int tileSize,
									geometryCorrection, // GeometryCorrection   geometryCorrection,
									correct_distortions,
									measuredLayers,     // MeasuredLayers measuredLayers,
									plPreferDisparity);   // boolean preferDisparity)
							ArrayList<TilePlanes.PlaneData> st_planes = pd0.createTilePlanesFromSelections(
											"" + nsTile, // String        suffix,
											plane_selections[nsTile], // boolean [][][] plane_selections, //  = new boolean [nStiles][][][]; // num_tiles
3227
											((hor_planes == null)? null:hor_planes[nsTile]), // boolean []     hor_planes,
3228
											disp_strength[nsTile],    // double  [][][] disp_strength,
Andrey Filippov's avatar
Andrey Filippov committed
3229 3230 3231 3232 3233 3234 3235
											plDispNorm,               // double       dispNorm,   //  Normalize disparities to the average if above
											plMinPoints,              // int          min_tiles,
											plTargetEigen,            // double       plTargetEigen, //        =   0.1;  // Remove outliers until main axis eigenvalue (possibly scaled by plDispNorm) gets below
											plFractOutliers,          // double       plFractOutliers, //      =   0.3;  // Maximal fraction of outliers to remove
											plMaxOutliers,            // int          plMaxOutliers, //        =    20;  // Maximal number of outliers to remove
											correct_distortions,      // boolean      correct_distortions,
											smplMode,                 // boolean      smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3236
											mlfp,
3237 3238 3239
											fronto_tol,               // double       fronto_tol, // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable this feature
											fronto_rms,               // double       fronto_rms,  // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes. May be tighter
											fronto_offs,              // double       fronto_offs,   //        =   0.2;  // increasing weight of the near tiles by using difference between the reduced average as weight. <= 0 - disable
3240
											fronto_pow,               // double       fronto_pow,    //        =   1.0;  // increase weight even more
3241
											dl);                      // int          debugLevel);
Andrey Filippov's avatar
Andrey Filippov committed
3242 3243

							if ((st_planes != null) && (!st_planes.isEmpty())){
3244
								if (dl > 2){
3245 3246
									System.out.println("======= createPlanesFromSelections(): nsTile="+nsTile+" detecting bridges ==========");
								}
3247
								boolean [][] hs = new boolean [1][];
3248 3249
								boolean [][][] split_sels = pd0.filterBridges(
										st_planes, // ArrayList<PlaneData> tilePlanes,
3250
										hs, // ((hor_planes == null)? null:hor_planes[nsTile]), // boolean []     hor_planes,
3251 3252 3253 3254
										3, // int max_grow, // make configurable?
										3, // int max_grow_far,
										dl); // int debugLevel)
								if (split_sels !=null){
3255 3256 3257 3258
									if (hor_planes != null) {
										hor_planes[nsTile] = hs[0];
									}
									if (dl > 2){
3259 3260 3261 3262 3263
										System.out.println("======= createPlanesFromSelections(): nsTile="+nsTile+" removing bridges ==========");
									}
									if (dl > 2) {
										String [] dbg_titles = showSupertileSeparationTitles( disp_strength[nsTile], plane_selections[nsTile], result_planes[nsTile]);
										double [][] dbg_img =  showSupertileSeparation(false, disp_strength[nsTile], plane_selections[nsTile], result_planes[nsTile]);
3264
										ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays();
3265 3266 3267 3268
										sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2* superTileSize, true, "pre_bridge_disp-"+nsTile+"-"+debugLevel,dbg_titles);
										dbg_img =  showSupertileSeparation(true, disp_strength[nsTile], plane_selections[nsTile], result_planes[nsTile]);
										sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2* superTileSize, true, "pre_bridge_world-"+nsTile+"-"+debugLevel,dbg_titles);
									}
3269

3270 3271 3272
									st_planes = pd0.createTilePlanesFromSelections(
											"" + nsTile+" bridges ",  // String        suffix,
											split_sels,               // boolean [][][] plane_selections, //  = new boolean [nStiles][][][]; // num_tiles
3273 3274 3275
											// FIXME: replace null (from what type it was before detecting bridges)
											((hor_planes == null)? null:hor_planes[nsTile]), // boolean []     hor_planes,
//											null,                     // boolean []     hor_planes,
3276
											disp_strength[nsTile],    // double  [][][] disp_strength,
3277 3278 3279 3280 3281 3282 3283
											plDispNorm,               // double       dispNorm,   //  Normalize disparities to the average if above
											plMinPoints,              // int          min_tiles,
											plTargetEigen,            // double       plTargetEigen, //        =   0.1;  // Remove outliers until main axis eigenvalue (possibly scaled by plDispNorm) gets below
											0.0,                      // double       plFractOutliers, //      =   0.3;  // Maximal fraction of outliers to remove
											0,                        // plMaxOutliers,            // int          plMaxOutliers, //        =    20;  // Maximal number of outliers to remove
											correct_distortions,      // boolean      correct_distortions,
											smplMode,                 // boolean      smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3284
											mlfp,
3285 3286 3287
											fronto_tol,               // double       fronto_tol, // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable this feature
											fronto_rms,               // double       fronto_rms,  // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes. May be tighter
											fronto_offs,              // double       fronto_offs,   //        =   0.2;  // increasing weight of the near tiles by using difference between the reduced average as weight. <= 0 - disable
3288
											fronto_pow,               // double       fronto_pow,    //        =   1.0;  // increase weight even more
3289
											dl - 1);                  // int          debugLevel);
3290
								}
3291

3292
							}
3293

3294
							if ((st_planes != null) && (!st_planes.isEmpty())){
3295 3296 3297 3298 3299 3300 3301 3302
								if (dl > 2) {
									for (TilePlanes.PlaneData plane:st_planes){
										plane.getWorldXYZ(0);
										System.out.println(plane.toString());
									}
									// Calculate planes and print results
								}
//						this_new_plane.getWorldXYZ(0);
3303

Andrey Filippov's avatar
Andrey Filippov committed
3304 3305 3306
								if (LOWEST_PLANE(2) > 0) st_planes.add(0, st_planes.get(0)); // insert dummy at pos 0;
								result_planes[nsTile] = st_planes.toArray(new TilePlanes.PlaneData[0] );
								if (LOWEST_PLANE(2) > 0) result_planes[nsTile][0] = null; // remove dummy
3307
								if (dl > 2){
Andrey Filippov's avatar
Andrey Filippov committed
3308 3309
									System.out.println("createPlanesFromSelections(): nsTile="+nsTile);
								}
3310
								if (dl > 3) { // 2) {
Andrey Filippov's avatar
Andrey Filippov committed
3311 3312
									String [] dbg_titles = showSupertileSeparationTitles( disp_strength[nsTile], plane_selections[nsTile], result_planes[nsTile]);
									double [][] dbg_img =  showSupertileSeparation(false, disp_strength[nsTile], plane_selections[nsTile], result_planes[nsTile]);
3313
									ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays();
Andrey Filippov's avatar
Andrey Filippov committed
3314 3315 3316
									sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2* superTileSize, true, "create_planes_disp-"+nsTile+"-"+debugLevel,dbg_titles);
									dbg_img =  showSupertileSeparation(true, disp_strength[nsTile], plane_selections[nsTile], result_planes[nsTile]);
									sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2* superTileSize, true, "create_planes_world-"+nsTile+"-"+debugLevel,dbg_titles);
3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340
									System.out.println("createPlanesFromSelections(): disp_strength["+nsTile+"][0][0]:");
									for (int iy = 0; iy < 2 * superTileSize; iy++){
										for (int ix = 0; ix < 2 * superTileSize; ix++){
											System.out.print(disp_strength[nsTile][0][0][2 * superTileSize * iy + ix]);
											if (ix < (2 * superTileSize-1)){
												System.out.print(", ");
											} else {
												System.out.println();
											}
										}
									}
									System.out.println("createPlanesFromSelections(): disp_strength["+nsTile+"][0][1]:");
									for (int iy = 0; iy < 2 * superTileSize; iy++){
										for (int ix = 0; ix < 2 * superTileSize; ix++){
											System.out.print(disp_strength[nsTile][0][1][2 * superTileSize * iy + ix]);
											if (ix < (2 * superTileSize - 1)){
												System.out.print(", ");
											} else {
												System.out.println();
											}
										}
									}
									System.out.println();

Andrey Filippov's avatar
Andrey Filippov committed
3341 3342 3343 3344 3345 3346
								}
							}
						}
					}
				}
			};
3347
		}
Andrey Filippov's avatar
Andrey Filippov committed
3348
		ImageDtt.startAndJoin(threads); // Never finished?
3349
		return result_planes;
Andrey Filippov's avatar
Andrey Filippov committed
3350
	}
3351

3352
	public void processPlanes5(
3353
			final int        growSelection,                     // grow initial selection before processing
3354 3355 3356 3357 3358 3359 3360
			final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
			final double     plDispNorm,
			final int        plMinPoints, //          =     5;  // Minimal number of points for plane detection
			final double     plTargetEigen, //        =   0.1;  // Remove outliers until main axis eigenvalue (possibly scaled by plDispNorm) gets below
			final double     plFractOutliers, //      =   0.3;  // Maximal fraction of outliers to remove
			final int        plMaxOutliers, //        =    20;  // Maximal number of outliers to remove
			final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
3361 3362 3363
			final double     plFrontoTol,                       // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable
			final double     plFrontoRms,                       // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes
			final double     plFrontoOffs,                      // increasing weight of the near tiles by using difference between the reduced average as weight. <= 0 - disable
3364
			final double     PlFrontoPow,    //        =   1.0;  // increase weight even more
3365

3366 3367 3368 3369
			final GeometryCorrection geometryCorrection,
			final boolean    correct_distortions,

			final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3370 3371

			final MeasuredLayersFilterParameters mlfp,
3372

3373 3374 3375 3376
			final double     bin_blur_hor,   // Blur disparity histograms for horizontal clusters by this sigma (in bins)
			final double     bin_blur_vert,  // Blur disparity histograms for constant disparity clusters by this sigma (in bins)
			final double     max_diff_hor,   // maximal disparity difference (to assign to a cluster (of Double.NaN) at first run for horizontal planes
			final double     max_diff_vert,  // maximal disparity difference (to assign to a cluster (of Double.NaN) at first run for vertical plane
3377
			final int        max_tries,       // on last run - assign all remaining pixels to some cluster (disregard max_diff)
3378

Andrey Filippov's avatar
Andrey Filippov committed
3379 3380 3381
			final boolean    msUseSel,        // final boolean                   use_sel,
			final boolean    msDivideByArea,  // final boolean                   divide_by_area,
			final double     msScaleProj,     // final double                    scale_projection,
3382

3383 3384 3385
			final double     smallDiff,  //       = 0.4;   // Consider merging initial planes if disparity difference below
			final double     highMix,    //stHighMix         = 0.4;   // Consider merging initial planes if jumps between ratio above
			final double []  world_hor, // horizontal plane normal (default [0.0, 1.0, 0.0])
3386
			final boolean    show_histograms,
3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403

			// Parameters for alternative initial planes that use lowest disparity for fronto planes, and farthest - for horizontal
			final boolean    mod_strength,          //  = true; // FIXME: make a parameter. when set, multiply each tile strength by the number of selected neighbors
			final boolean    clusterize_by_highest, //  = true;
			final double     clust_sigma,           //  = 0.7;
			final double     disp_arange_vert,      //  = 0.07;
			final double     disp_rrange_vert,      //  = 0.01;
			final double     disp_arange_hor,       //  =  0.035;
			final double     disp_rrange_hor,       //  =   0.005;
			final double     tolerance_above_near,  //  =  100.0; // 0.07; any?
			final double     tolerance_below_near,  //  =  -0.01;
			final double     tolerance_above_far,   //  =    0.07;
			final double     tolerance_below_far,   //  =    0.1; // 100.0; // any farther
			final int        hor_vert_overlap,      //  =       2;
			final int        used_companions,       //  =      5; // cell that has this many new used companions is considered used (borders and already use3d are considered used too)
			final int        used_true_companions,  //  = 1; // there should be at least this many new selected tiles among neighbors.,
			final boolean    debug_initial_discriminate,
3404 3405 3406 3407 3408 3409
			final int        debugLevel,
			final int        dbg_X,
			final int        dbg_Y)
	{
		// use both horizontal and const disparity tiles to create tile clusters
		// Add max_diff (maximal disparity difference while extracting initial tile selection) and max_tries (2..3) parameters
3410

3411 3412 3413
		// Add separate method to create + remove outliers from all planes (2 different ones)?
		// TODO later re-assign pixels according to existing plane parameters
		// Sort plane data by center (plane or supertile) disparity
3414 3415 3416 3417
		final int superTileSize = tileProcessor.getSuperTileSize();
		final int nStiles = ((tileProcessor.getTilesX() + superTileSize -1)/superTileSize) * ((tileProcessor.getTilesY() + superTileSize -1)/superTileSize);

		boolean [][] hor_planes = new boolean [nStiles][];
3418

3419
		boolean [][][][]  plane_selections = initialDiscriminateTiles(
3420
				growSelection,        // final int        growSelection,                     // grow initial selection before processing
3421 3422 3423 3424 3425 3426 3427 3428
				stMeasSel,            // final int        stMeasSel,       //      = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
				plDispNorm,           // final double     plDispNorm,
				plMinPoints,          // final int        plMinPoints, //          =     5;  // Minimal number of points for plane detection
				plPreferDisparity,    // final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
				geometryCorrection,  // final GeometryCorrection geometryCorrection,
				correct_distortions, // final boolean    correct_distortions,

				smplMode,            // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3429
				mlfp,
3430 3431 3432 3433 3434 3435 3436 3437
				bin_blur_hor,   // final double     bin_blur_hor,   // Blur disparity histograms for horizontal clusters by this sigma (in bins)
				bin_blur_vert,  // final double     bin_blur_vert,  // Blur disparity histograms for constant disparity clusters by this sigma (in bins)
				max_diff_hor,   // final double     max_diff_hor,   // maximal disparity difference (to assign to a cluster (of Double.NaN) at first run for horizontal planes
				max_diff_vert,  // final double     max_diff_vert,  // maximal disparity difference (to assign to a cluster (of Double.NaN) at first run for vertical plane
				max_tries,       //final int        max_tries,       // on last run - assign all rfemaining pixels to some cluster (disregard max_diff)
				smallDiff,      // final double     smallDiff,  //       = 0.4;   // Consider merging initial planes if disparity difference below
				highMix,    //final double     highMix,    // stHighMix         = 0.4;   // Consider merging initial planes if jumps between ratio above
				world_hor, // final double []  world_hor, // horizontal plane normal (default [0.0, 1.0, 0.0])
3438
				show_histograms, // final boolean    show_histograms,
3439 3440
				hor_planes, // final boolean [][] hor_planes,

3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456
				// Parameters for alternative initial planes that use lowest disparity for fronto planes, and farthest - for horizontal
				mod_strength,          // final boolean    mod_strength,          //  = true; // FIXME: make a parameter. when set, multiply each tile strength by the number of selected neighbors
				clusterize_by_highest, // final boolean    clusterize_by_highest, //  = true;
				clust_sigma,           // final double     clust_sigma,           //  = 0.7;
				disp_arange_vert,      // final double     disp_arange_vert,      //  = 0.07;
				disp_rrange_vert,      // final double     disp_rrange_vert,      //  = 0.01;
				disp_arange_hor,       // final double     disp_arange_hor,       //  =  0.035;
				disp_rrange_hor,       // final double     disp_rrange_hor,       //  =   0.005;
				tolerance_above_near,  // final double     tolerance_above_near,  //  =  100.0; // 0.07; any?
				tolerance_below_near,  // final double     tolerance_below_near,  //  =  -0.01;
				tolerance_above_far,   // final double     tolerance_above_far,   //  =    0.07;
				tolerance_below_far,   // final double     tolerance_below_far,   //  =    0.1; // 100.0; // any farther
				hor_vert_overlap,      // final int        hor_vert_overlap,      //  =       2;
				used_companions,       // final int        used_companions,       //  =      5; // cell that has this many new used companions is considered used (borders and already use3d are considered used too)
				used_true_companions,  // final int        used_true_companions,  //  = 1; // there should be at least this many new selected tiles among neighbors.,

3457
				debugLevel+(debug_initial_discriminate? 2:0), // final int        debugLevel,
3458 3459 3460 3461
				dbg_X, // final int        dbg_X,
				dbg_Y); // final int        dbg_Y)

		// get per-tile disparity strength again (may consider using non-filtered data here)
3462

Andrey Filippov's avatar
Andrey Filippov committed
3463
		double [][][][] disp_strength = getPlaneDispStrengthsST( // here use actual disparity, not tilted
3464

Andrey Filippov's avatar
Andrey Filippov committed
3465
				null,                // final double []  world_plane_norm, // null - floating, (0,0,1) - const disparity, (0,1,0) - horizontal
3466 3467 3468 3469 3470 3471 3472
				stMeasSel,           // final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert

				plPreferDisparity,   // final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
				geometryCorrection,  // final GeometryCorrection geometryCorrection,
				correct_distortions, // final boolean    correct_distortions,

				smplMode,            // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3473
				mlfp,
3474 3475 3476
				debugLevel,          // final int        debugLevel,
				dbg_X,               // final int        dbg_X,
				dbg_Y);              // final int        dbg_Y)
3477 3478
		// Create plane data (ellipsoids) from the disparity/strength data and tile selections,
		// remove outliers, order each supertile result in ascending disparity (from far to near)
3479 3480 3481
		// TODO: consider 1) assigning of the non-assigned tiles to clusters and 2) re-assigning all clusters one by one to the "best" plane
		TilePlanes.PlaneData [][] new_planes = createPlanesFromSelections(
				plane_selections,   // final boolean [][][][] plane_selections, //  = new boolean [nStiles][][][]; // num_tiles
3482
				disp_strength,       // final double  [][][][] disp_strength,
3483 3484 3485 3486 3487 3488 3489 3490 3491 3492
				plDispNorm,          // final double     plDispNorm,
				plMinPoints,         // final int        plMinPoints, //          =     5;  // Minimal number of points for plane detection
				plTargetEigen,       // final double     plTargetEigen, //        =   0.1;  // Remove outliers until main axis eigenvalue (possibly scaled by plDispNorm) gets below
				plFractOutliers,     // final double     plFractOutliers, //      =   0.3;  // Maximal fraction of outliers to remove
				plMaxOutliers,       // final int        plMaxOutliers, //        =    20;  // Maximal number of outliers to remove
				plPreferDisparity,   // final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
				geometryCorrection,  // final GeometryCorrection geometryCorrection,
				correct_distortions, // final boolean    correct_distortions,

				smplMode,            // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3493
				mlfp,
3494 3495 3496
				plFrontoTol,         // final double     plFrontoTol,         // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable
				plFrontoRms,         // final double     plFrontoRms,                       // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes
				plFrontoOffs,        // final double     plFrontoOffs,                      // increasing weight of the near tiles by using difference between the reduced average as weight. <= 0 - disable
3497
				PlFrontoPow,      // double       fronto_pow,    //        =   1.0;  // increase weight even more
3498
				hor_planes,          // final boolean [][] hor_planes, // returns plane types (hor/vert)
3499
				debugLevel+(debug_initial_discriminate? 3:0), // 1, // 0, // 1, //  + 2, // 1,          // final int        debugLevel,
3500 3501 3502 3503 3504 3505 3506 3507 3508
				dbg_X,               // final int        dbg_X,
				dbg_Y);              // final int        dbg_Y)
		this.planes = new_planes; // save as "measured" (as opposed to "smoothed" by neighbors) planes

	}

	/**
	 * Re-assign tiles to the planes according to fitted planes. Scans each known plane parallel with specified
	 * size steps and specified number of steps, maximizing overall fit quality.
3509
	 * Total weight of the fitted tiles? RMS? (now using number of fitted planes, if the same - than rms)
3510 3511 3512 3513 3514 3515 3516 3517 3518
	 * @param stMeasSel - select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
	 * @param plDispNorm - normalization of the measured disparity precision - closer objects will have disparity
	 *        difference proportionally reduced
	 * @param plMinPoints Minimal number of plane tiles to remain
	 * @param plTargetEigen target smallest eigenvalue (try to remove outliers if above)
	 * @param plFractOutliers maximal fraction of all tiles to remove as outliers
	 * @param plMaxOutliers maximal absolute number of tiles to  remove as outliers
	 * @param plPreferDisparity kept for historical reasons - when true, select disparity-most vector even if it has higher eigenvalue
	 * @param geometryCorrection GeometryCorrection instance to use
3519
	 * @param correct_distortions correct geometrical distortions when converting to/from world coordinates
3520 3521 3522 3523
	 * @param smplMode sample mode
	 * @param smplSide sample side for averaging/filtering tile disparities
	 * @param smplNum number of best samples used fro averaging
	 * @param smplRms maximal sample disparity rms to consider sample valid
3524 3525 3526 3527 3528 3529 3530 3531 3532
	 * @param smplWnd use window functions for the samples
	 * @param max_abs_tilt pix per tile
	 * @param max_rel_tilt pix / disparity) per tile
	 * @param damp_tilt Damp tilt to handle insufficient  (co-linear)data
	 * @param min_tilt_disp Disparity switch between filtering modes - near objects use tilts, far - use max disparity
	 * @param transition Mode transition range (between tilted and maximal disparity)
	 * @param far_mode Far objects filtering mode (0 - off, 1 - power of disparity)
	 * @param far_power Raise disparity to this power before averaging for far objects
	 * @param plDiscrTolerance maximal disparity difference from the plane to consider tile
3533 3534
	 * @param plDiscrDispRange parallel move known planes around original know value for the best overall fit
	 * @param plDiscrSteps number of steps (each direction) for each plane to search for the best fit (0 - single, 1 - 1 each side)
3535
	 * @param plDiscrVariants total number of variants to try (protect from too many planes)
3536 3537 3538 3539 3540 3541 3542 3543 3544
	 * @param plDiscrMode what plane to use as a hint: 0 - weighted, 1 - equalized, 2 - best, 3 - combined
	 * @param plDiscrVarFloor squared add to variance to calculate reverse flatness (used mostly for single-cell clusters)
	 * @param plDiscrSigma Gaussian sigma to compare how measured data is attracted to planes
	 * @param plDiscrBlur sigma to blur histograms while re-discriminating
	 * @param plDiscrExclusivity tile exclusivity: 1.0 - tile belongs to one plane only, 0.0 - regardless of others
	 * @param debugLevel debug level
	 * @param dbg_X supertile X for elevated debug level
	 * @param dbg_Y supertile X for elevated debug level
	 */
3545

3546 3547 3548 3549 3550 3551 3552 3553
	public void regeneratePlanes(
			final TilePlanes.PlaneData [][] planes,
			final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
			final double     plDispNorm,
			final int        plMinPoints, //          =     5;  // Minimal number of points for plane detection
			final double     plTargetEigen, //        =   0.1;  // Remove outliers until main axis eigenvalue (possibly scaled by plDispNorm) gets below
			final double     plFractOutliers, //      =   0.3;  // Maximal fraction of outliers to remove
			final int        plMaxOutliers, //        =    20;  // Maximal number of outliers to remove
3554 3555 3556 3557
			final boolean    plPreferDisparity,                 // Always start with disparity-most axis (false - lowest eigenvalue)
			final double     plFrontoTol,                       // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable
			final double     plFrontoRms,                       // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes
			final double     plFrontoOffs,                      // increasing weight of the near tiles by using difference between the reduced average as weight. <= 0 - disable
3558
			final double     PlFrontoPow,    //        =   1.0;  // increase weight even more
3559 3560 3561 3562
			final GeometryCorrection geometryCorrection,
			final boolean    correct_distortions,

			final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3563 3564

			final MeasuredLayersFilterParameters mlfp,
3565 3566

			final double     plDiscrTolerance,     //     =   0.4;  // Maximal disparity difference from the plane to consider tile
3567 3568 3569 3570 3571 3572 3573 3574 3575
			final double     plDiscrDispRange,     //     =   0.6;  // Parallel move known planes around original know value for the best overall fit
			final int        plDiscrSteps,         //         =   3;    // Number of steps (each direction) for each plane to search for the best fit (0 - single, 1 - 1 each side)
			final int        plDiscrMode,          //          =   3;    // What plane to use as a hint: 0 - weighted, 1 - equalized, 2 - best, 3 - combined

			final double     plDiscrVarFloor, //       =   0.03;  // Squared add to variance to calculate reverse flatness (used mostly for single-cell clusters)
			final double     plDiscrSigma, //          =   0.05;  // Gaussian sigma to compare how measured data is attracted to planes
			final double     plDiscrBlur, //           =   0.1;   // Sigma to blur histograms while re-discriminating
			final double     plDiscrExclusivity, //    =   1.5;   // Tile exclusivity: 1.0 - tile belongs to one plane only, 0.0 - regardless of others
			final double     plDiscrExclus2, //        =   0.8;   // For second pass if exclusivity > 1.0 - will assign only around strong neighbors
Andrey Filippov's avatar
Andrey Filippov committed
3576 3577 3578 3579 3580 3581
			final boolean    plDiscrStrict,     //         = true;   // When growing selection do not allow any offenders around (false - more these than others)
			final double     plDiscrCorrMax,    //         = 0.7;   // Attraction to different planes correlation that is too high for re-discrimination.
			final double     plDiscrCorrMerge,  //         = 0.85;  // Attraction to different planes correlation that is high enough to merge planes
			final int        plDiscrSteal,      //         = 4;     // If offender has this number of tiles (including center) the cell can not be used
			final int        plDiscrGrown,      //         = 0;     // Only use tiles within this range from original selection
			final double     plDiscrXMedian,    //         = 1.5;   // Remove outliers from the final selection that have distance more than scaled median
3582

3583 3584 3585 3586 3587 3588
			final int        debugLevel,
			final int        dbg_X,
			final int        dbg_Y)
	{
		// use both horizontal and const disparity tiles to create tile clusters
		// Add max_diff (maximal disparity difference while extracting initial tile selection) and max_tries (2..3) parameters
3589

3590 3591 3592
		// Add separate method to create + remove outliers from all planes (2 different ones)?
		// TODO later re-assign pixels according to existing plane parameters
		// Sort plane data by center (plane or supertile) disparity
3593

3594 3595 3596 3597 3598 3599 3600 3601 3602
		boolean [][][][]  plane_selections = refineDiscriminateTiles(
				planes, // final TilePlanes.PlaneData [][] planes,
				stMeasSel,            // final int        stMeasSel,       //      = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
				plDispNorm,           // final double     plDispNorm,
				plPreferDisparity,    // final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
				geometryCorrection,   // final GeometryCorrection geometryCorrection,
				correct_distortions,  // final boolean    correct_distortions,

				smplMode,             // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3603
				mlfp,
3604 3605

				plDiscrTolerance,     //final double     plDiscrTolerance,     //     =   0.4;  // Maximal disparity difference from the plane to consider tile
3606 3607 3608 3609 3610 3611 3612 3613 3614
				plDiscrDispRange,     // final double     plDiscrDispRange,     //     =   0.6;  // Parallel move known planes around original know value for the best overall fit
				plDiscrSteps,         // final int        plDiscrSteps,         //         =   3;    // Number of steps (each direction) for each plane to search for the best fit (0 - single, 1 - 1 each side)
				plDiscrMode,          // final int        plDiscrMode,          //          =   3;    // What plane to use as a hint: 0 - weighted, 1 - equalized, 2 - best, 3 - combined

				plDiscrVarFloor,   // final double     plDiscrVarFloor, //       =   0.03;  // Squared add to variance to calculate reverse flatness (used mostly for single-cell clusters)
				plDiscrSigma,      // final double     plDiscrSigma, //          =   0.05;  // Gaussian sigma to compare how measured data is attracted to planes
				plDiscrBlur,       // final double     plDiscrBlur, //           =   0.1;   // Sigma to blur histograms while re-discriminating
				plDiscrExclusivity,// final double     plDiscrExclusivity, //    =   0.5;   // Tile exclusivity: 1.0 - tile belongs to one plane only, 0.0 - regardless of others
				plDiscrExclus2,    // final double     plDiscrExclus2, //    =   0.5;   // For second pass if exclusivity > 1.0 - will assign only around strong neighbors
Andrey Filippov's avatar
Andrey Filippov committed
3615 3616 3617 3618 3619
			    plDiscrStrict,     // final boolean    plDiscrStrict, //         = true;   // When growing selection do not allow any offenders around (false - more these than others)
				plDiscrCorrMax,    // final double     plDiscrCorrMax, //         = 0.7;   // Attraction to different planes correlation that is too high for re-discrimination.
				plDiscrCorrMerge,  // final double     plDiscrCorrMerge,  //     = 0.85;  // Attraction to different planes correlation that is high enough to merge planes
				plDiscrSteal,      // final int        plDiscrSteal,       //         =   4;     // If offender has this number of tiles (including center) the cell can not be used
				plDiscrGrown,      // final int        plDiscrGrown,       //         =   0;     // Only use tiles within this range from original selection
3620

Andrey Filippov's avatar
Andrey Filippov committed
3621
				plDiscrXMedian,    //final double    plDiscrXMedian, //         = 1.5;   // Remove outliers from the final selection that have distance more than scaled median
3622

3623
				debugLevel,           // final int        debugLevel,
3624 3625 3626 3627
				dbg_X,                // final int        dbg_X,
				dbg_Y);               // final int        dbg_Y)

		// get per-tile disparity strength again (may consider using non-filtered data here) ?
3628

Andrey Filippov's avatar
Andrey Filippov committed
3629 3630
		double [][][][] disp_strength = getPlaneDispStrengthsST( // here use actual disparity, not tilted
				null,                // final double []  world_plane_norm, // null - floating, (0,0,1) - constant disparity,  (0,1,0) for horizontal planes
3631 3632 3633 3634 3635 3636 3637
				stMeasSel,           // final int        stMeasSel, //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert

				plPreferDisparity,   // final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
				geometryCorrection,  // final GeometryCorrection geometryCorrection,
				correct_distortions, // final boolean    correct_distortions,

				smplMode,            // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3638
				mlfp,
3639 3640 3641
				debugLevel,          // final int        debugLevel,
				dbg_X,               // final int        dbg_X,
				dbg_Y);              // final int        dbg_Y)
3642 3643
        // Create plane data (ellipsoids) from the disparity/strength data and tile selections,
		// remove outliers, order each supertile result in ascending disparity (from far to near)
3644 3645 3646
		// TODO: consider 1) assigning of the non-assigned tiles to clusters and 2) re-assigning all clusters one by one to the "best" plane
		TilePlanes.PlaneData [][] new_planes = createPlanesFromSelections(
				plane_selections,   // final boolean [][][][] plane_selections, //  = new boolean [nStiles][][][]; // num_tiles
3647
				disp_strength,       // final double  [][][][] disp_strength,
3648 3649 3650 3651 3652 3653 3654 3655 3656 3657
				plDispNorm,          // final double     plDispNorm,
				plMinPoints,         // final int        plMinPoints, //          =     5;  // Minimal number of points for plane detection
				plTargetEigen,       // final double     plTargetEigen, //        =   0.1;  // Remove outliers until main axis eigenvalue (possibly scaled by plDispNorm) gets below
				plFractOutliers,     // final double     plFractOutliers, //      =   0.3;  // Maximal fraction of outliers to remove
				plMaxOutliers,       // final int        plMaxOutliers, //        =    20;  // Maximal number of outliers to remove
				plPreferDisparity,   // final boolean    plPreferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
				geometryCorrection,  // final GeometryCorrection geometryCorrection,
				correct_distortions, // final boolean    correct_distortions,

				smplMode,            // final boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
3658
				mlfp,
3659 3660 3661
				plFrontoTol,         // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable
				plFrontoRms,         // final double     plFrontoRms,                       // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes
				plFrontoOffs,        // final double     plFrontoOffs,                      // increasing weight of the near tiles by using difference between the reduced average as weight. <= 0
3662
				PlFrontoPow,         // double       fronto_pow,    //        =   1.0;  // increase weight even more
3663
				null,                // final boolean [][] hor_planes, // plane types (hor/vert)
3664
				debugLevel, //  + 2, // 1,          // final int        debugLevel,
3665 3666
				dbg_X,               // final int        dbg_X,
				dbg_Y);              // final int        dbg_Y)
Andrey Filippov's avatar
Andrey Filippov committed
3667
		// combine old and new planes (refineDiscriminateTiles will return null for the supertile if failed to re-disciminate)
3668

Andrey Filippov's avatar
Andrey Filippov committed
3669 3670 3671
		for (int nsTile = 0; nsTile < this.planes.length; nsTile++){
			this.planes[nsTile] = (new_planes[nsTile] != null) ? new_planes[nsTile] : planes[nsTile];
		}
3672
	}
3673 3674 3675



Andrey Filippov's avatar
Andrey Filippov committed
3676 3677 3678 3679 3680 3681
	public int [] getShowPlanesWidthHeight()
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
3682
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
3683 3684 3685 3686 3687 3688 3689
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		int [] wh = {
				stilesX * superTileSize,// * tileSize,
				stilesY * superTileSize};// * tileSize};
		return wh;
	}

3690
	public int fillSquares()
Andrey Filippov's avatar
Andrey Filippov committed
3691 3692 3693 3694 3695
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
3696
		final int stilesX =       (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
3697
		final int stilesY =       (tilesY + superTileSize -1)/superTileSize;
3698
//		final int nStiles =       stilesX * stilesY;
3699
		int num_added = 0;
Andrey Filippov's avatar
Andrey Filippov committed
3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722
		for (int stY = 0; stY < (stilesY - 1); stY++ ) {
			for (int stX = 0; stX < (stilesX - 1); stX++ ) {
				int nsTile = stY * stilesX + stX;
				TilePlanes.PlaneData [][] planes4 = {
						planes[nsTile],
						planes[nsTile + 1],
						planes[nsTile + stilesX],
						planes[nsTile + stilesX + 1]};
				if ((planes4[0] != null) && (planes4[1] != null) && (planes4[2] != null) && (planes4[3] != null)){
					for (int np = 0; np < planes4[0].length; np++){
						if (planes4[0][np] == null) continue;
						int [] neibs0 = planes4[0][np].getNeibBest();
						if ((neibs0[2] < 0) || (neibs0[4] < 0)) continue;
						if (planes4[1][neibs0[2]] == null) continue;
						if (planes4[2][neibs0[4]] == null) continue;
						int [] neibs1 = planes4[1][neibs0[2]].getNeibBest();
						int [] neibs2 = planes4[2][neibs0[4]].getNeibBest();
						if ((neibs1[4] < 0) || (neibs2[2] < 0) || (neibs1[4] != neibs2[2])) continue;
						int [] neibs3 = planes4[3][neibs1[4]].getNeibBest();
						// got full square, does it already have diagonals
						if (neibs0[3] < 0) {
							neibs0[3] = neibs1[4];
							neibs3[7] = np;
3723
							num_added++;
Andrey Filippov's avatar
Andrey Filippov committed
3724 3725 3726 3727
						}
						if (neibs1[5] < 0){
							neibs1[5] = neibs0[4];
							neibs2[1] = neibs0[2];
3728
							num_added++;
Andrey Filippov's avatar
Andrey Filippov committed
3729 3730 3731 3732 3733
						}
					}
				}
			}
		}
3734
		return num_added;
Andrey Filippov's avatar
Andrey Filippov committed
3735 3736
	}

3737
	public int cutCorners()
Andrey Filippov's avatar
Andrey Filippov committed
3738 3739 3740 3741 3742
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
3743
		final int stilesX =       (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
3744
		final int stilesY =       (tilesY + superTileSize -1)/superTileSize;
3745 3746
//		final int nStiles =       stilesX * stilesY;
		int num_added = 0;
Andrey Filippov's avatar
Andrey Filippov committed
3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766
		for (int stY = 0; stY < (stilesY - 1); stY++ ) {
			for (int stX = 0; stX < (stilesX - 1); stX++ ) {
				int nsTile = stY * stilesX + stX;
				TilePlanes.PlaneData [][] planes4 = {
						planes[nsTile],
						planes[nsTile + 1],
						planes[nsTile + stilesX],
						planes[nsTile + stilesX + 1]};
				if (planes4[0] != null) { // && (planes4[1] != null) && (planes4[2] != null)){
					for (int np = 0; np < planes4[0].length; np++){
						if (planes4[0][np] != null) {
							int [] neibs0 = planes4[0][np].getNeibBest();

							if ((neibs0[2] >= 0) && (neibs0[4] < 0)){
								if (planes4[1][neibs0[2]] != null) {
									int [] neibs1 = planes4[1][neibs0[2]].getNeibBest();
									if (neibs1[5] >= 0) {
										neibs0[4] = neibs1[5];
										int [] neibs2 = planes4[2][neibs1[5]].getNeibBest();
										neibs2[0] = np;  //?
3767
										num_added++;
Andrey Filippov's avatar
Andrey Filippov committed
3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778
									}
								}
							}

							if ((neibs0[2] < 0) && (neibs0[4] >= 0)){
								if (planes4[2][neibs0[4]] != null) {
									int [] neibs2 = planes4[2][neibs0[4]].getNeibBest();
									if (neibs2[1] >= 0) {
										neibs0[2] = neibs2[1];
										int [] neibs1 = planes4[1][neibs2[1]].getNeibBest();
										neibs1[6] = np;
3779
										num_added++;
Andrey Filippov's avatar
Andrey Filippov committed
3780 3781 3782 3783 3784 3785 3786 3787 3788
									}
								}
							}
							if ((neibs0[2] >= 0) && (neibs0[3] >= 0)){
								int [] neibs1 = planes4[1][neibs0[2]].getNeibBest();
								int [] neibs3 = planes4[3][neibs0[3]].getNeibBest();
								if (neibs1[4] < 0) {
									neibs1[4] = neibs0[3];
									neibs3[0] = neibs0[2];  //?
3789
									num_added++;
Andrey Filippov's avatar
Andrey Filippov committed
3790 3791 3792 3793 3794 3795 3796 3797
								}
							}
							if ((neibs0[3] >= 0) && (neibs0[4] >= 0)){
								int [] neibs3 = planes4[3][neibs0[3]].getNeibBest();
								int [] neibs2 = planes4[2][neibs0[4]].getNeibBest();
								if (neibs2[2] < 0) {
									neibs2[2] = neibs0[3];
									neibs3[6] = neibs0[4];
3798
									num_added++;
Andrey Filippov's avatar
Andrey Filippov committed
3799
								}
3800
							}
Andrey Filippov's avatar
Andrey Filippov committed
3801 3802 3803 3804 3805 3806 3807
						}
					}
				}
				if (planes4[3] != null) { // && (planes4[1] != null) && (planes4[2] != null)){
					for (int np = 0; np < planes4[3].length; np++){
						if (planes4[3][np] != null){
							int [] neibs3 = planes4[3][np].getNeibBest();
3808

Andrey Filippov's avatar
Andrey Filippov committed
3809 3810 3811 3812 3813 3814
							if ((neibs3[0] >= 0) && (neibs3[7] >= 0)){
								int [] neibs0 = planes4[0][neibs3[7]].getNeibBest();
								int [] neibs1 = planes4[1][neibs3[0]].getNeibBest();
								if (neibs0[2] < 0) {
									neibs0[2] = neibs3[0];
									neibs1[6] = neibs3[7];
3815
									num_added++;
Andrey Filippov's avatar
Andrey Filippov committed
3816 3817
								}
							}
3818 3819


Andrey Filippov's avatar
Andrey Filippov committed
3820 3821 3822 3823 3824 3825
							if ((neibs3[6] >= 0) && (neibs3[7] >= 0)){
								int [] neibs0 = planes4[0][neibs3[7]].getNeibBest();
								int [] neibs2 = planes4[2][neibs3[6]].getNeibBest();
								if (neibs0[4] < 0) {
									neibs0[4] = neibs3[6];
									neibs2[0] = neibs3[7];  //?
3826
									num_added++;
Andrey Filippov's avatar
Andrey Filippov committed
3827 3828
								}
							}
3829

3830

Andrey Filippov's avatar
Andrey Filippov committed
3831 3832
							if ((neibs3[7] >= 0) && (neibs3[6] < 0)){
								int [] neibs0 = planes4[0][neibs3[7]].getNeibBest();
3833

Andrey Filippov's avatar
Andrey Filippov committed
3834 3835 3836 3837
								if (neibs0[4] >= 0) {
									int [] neibs2 = planes4[2][neibs0[4]].getNeibBest();
									neibs3[6] = neibs0[4];
									neibs2[2] = np;  //?
3838
									num_added++;
3839 3840
								}
							}
3841

Andrey Filippov's avatar
Andrey Filippov committed
3842 3843
							if ((neibs3[6] >= 0) && (neibs3[0] < 0)){
								int [] neibs2 = planes4[2][neibs3[6]].getNeibBest();
3844

Andrey Filippov's avatar
Andrey Filippov committed
3845 3846 3847 3848
								if (neibs2[1] >= 0) {
									int [] neibs1 = planes4[1][neibs2[1]].getNeibBest();
									neibs3[0] = neibs2[1]; //?
									neibs1[4] = np;
3849
									num_added++;
3850 3851
								}
							}
Andrey Filippov's avatar
Andrey Filippov committed
3852
						}
3853
					}
3854 3855
				}
			}
Andrey Filippov's avatar
Andrey Filippov committed
3856
		}
3857 3858
		return num_added;

Andrey Filippov's avatar
Andrey Filippov committed
3859
	}
3860

3861 3862 3863
	public int [] resolveDiagonalTriangularConflicts(
			int [][][] conflicts,
			Conflicts conflict_stats, // to be updated after applying resolution
3864
			int        starSteps, // How far to look around when calculationg connection cost
3865 3866
			double     orthoWeight,
			double     diagonalWeight,
3867
			double     starPwr, // Divide cost by number of connections to this power
3868
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
3869
			double     weightToDens,    // // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
3870
			double     starValPwr, //  Raise value of each tile before averaging
3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882
			double     dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
			boolean    preferDisparity,
			int        debugLevel,
			int        dbg_X,
			int        dbg_Y)
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		final int stilesX =       (tilesX + superTileSize -1)/superTileSize;
		final int stilesY =       (tilesY + superTileSize -1)/superTileSize;
		final int dbgTile = dbg_Y * stilesX + dbg_X;
3883
		final TileNeibs tnSurface = new TileNeibs(stilesX, stilesY);
3884 3885 3886 3887
		int [] rslt = {0,0};
		for (int nsTile = 0; nsTile < conflicts.length; nsTile++) if (conflicts[nsTile] != null) {
			// conflicts may disappear after being fixed, recheck for null
			for (int nConfl = 0; (conflicts[nsTile] != null) && (nConfl < conflicts[nsTile].length); nConfl++){
3888
				int dl = ((debugLevel > -1) && (nsTile == dbgTile)) ? 3 : 0;
3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902
				Conflict confl = new Conflict(nsTile, conflicts[nsTile][nConfl]);
				for (int dir_orient = 0; dir_orient < 16; dir_orient++){
					boolean right = (dir_orient & 8) != 0;
					boolean reverse = (dir_orient & 4) != 0;
					int start_dir4 = dir_orient & 3;
					if (confl.conflictExists(
							start_dir4,
							right,
							reverse)){
						boolean OK = resolveDiagonalTriangularConflict(
								confl,           // Conflict conflict,
								start_dir4,      // int start_dir4,
								right,           // boolean right,
								reverse,         // boolean reverse,
3903
								tnSurface,       // TileNeibs tnSurface,
3904 3905
								conflicts,       // int [][][] conflicts,
								conflict_stats,  // Conflicts conflict_stats, // to be updated after applying resolution
3906
								starSteps, // How far to look around when calculationg connection cost
3907 3908
								orthoWeight,     // double     orthoWeight,
								diagonalWeight,  // double     diagonalWeight,
3909
								starPwr,         // double     starPwr, // Divide cost by number of connections to this power
3910
								starWeightPwr,    // Use this power of tile weight when calculating connection cost
3911
								weightToDens,    // // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
3912
								starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
3913 3914 3915 3916 3917
								dblTriLoss,      //  double     dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
								preferDisparity, // boolean    preferDisparity,
								dl);             // int        debugLevel)
						if (OK) rslt[0]++; // will not count if some conflicts disappeared as a result
						else    rslt[1]++;
3918 3919 3920 3921
					}
				}
			}
		}
3922
		return rslt;
3923
	}
3924 3925 3926



3927 3928 3929 3930 3931 3932
	public boolean resolveDiagonalTriangularConflict(

			Conflict conflict,
			int start_dir4,
			boolean right,
			boolean reverse,
3933
			TileNeibs tnSurface,
3934 3935
			int [][][] conflicts,
			Conflicts conflict_stats, // to be updated after applying resolution
3936
			int        starSteps, // How far to look around when calculationg connection cost
3937 3938
			double     orthoWeight,
			double     diagonalWeight,
3939
			double     starPwr, // Divide cost by number of connections to this power
3940 3941
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
			double     weightToDens,    // // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
3942
			double     starValPwr, //  Raise value of each tile before averaging
3943 3944 3945
			double     dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
			boolean    preferDisparity,
			int        debugLevel)
3946
	{
3947
		if (debugLevel > 1) {
3948
			System.out.println("resolveDiagonalTriangularConflict(): "+conflict.toString()+": start_dir4 = "+ start_dir4 + ", right = "+right+", reverse = "+reverse);
3949
		}
3950

3951 3952 3953 3954 3955 3956 3957
		if (!conflict.conflictExists(
				start_dir4,
				right,
				reverse)) {
			System.out.println("conflict does not exist");
			return false; // should be tested before to distinguish between non-existent and failure to resolve
		}
3958
		Conflicts iconflicts = new Conflicts(this);
3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974
		int dir01 = 2 * start_dir4;
		int dir12 = 2 * ((start_dir4 + (right? 1 : 3)) % 4);
		int dir20 = (dir12 + (right? 3 : 5)) % 8;
		int dir02 = (dir20 + 4) % 8;


		int nsTile = conflict.getSTile();
		int nl = conflict.getStartLayer(reverse);
		int nl_end = conflict.getEndLayer(reverse);
		int nsTile1 = tnSurface.getNeibIndex(nsTile, dir01);
		int nl1 = planes[nsTile][nl].getNeibBest(dir01);
		int nsTile2 = tnSurface.getNeibIndex(nsTile1, dir12);
		if (nl1 <0){
			System.out.println(conflict.toString()+" : start_dir4 = "+ start_dir4 + ", right = "+right+", reverse = "+reverse+" nl1 < 0 !");
			return false;
		}
3975

3976 3977 3978 3979 3980
		if (debugLevel > 1) {
			if (debugLevel > 1) {
				System.out.println("resolveDiagonalTriangularConflict(): nsTile = "+nsTile+" nsTile1 = "+nsTile1+" nsTile2="+nsTile2);
			}
		}
3981

3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998
		int nl2 = planes[nsTile1][nl1].getNeibBest(dir12);
		// now nsTile2:nl2 is supposed to be connected to nsTile:nl_end != nl

		int [] mod_supertiles = {nsTile,nsTile2};
		int [] nsTiles = getInvolvedSupertiles( // first mod_supertiles.length entries will be mod_supertiles[]
				mod_supertiles,
				tnSurface);
		if (debugLevel > 1) {
			System.out.println("Involved supertiles:");
			for (int i = 0; i < nsTiles.length; i++){
				System.out.println(i+":"+nsTiles[i]);
			}
		}
		HashMap<Integer,Integer> replacement_tiles = new HashMap<Integer,Integer>();
		for (int i = 0; i < mod_supertiles.length; i++){
			replacement_tiles.put(mod_supertiles[i], new Integer(i));
		}
3999 4000 4001 4002
		ConnectionCosts connectionCosts = new ConnectionCosts(
				orthoWeight,
				diagonalWeight,
				starPwr,    // Divide cost by number of connections to this power
4003
				starWeightPwr,    // Use this power of tile weight when calculating connection cost
4004
				weightToDens,    // // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
4005
				starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
4006 4007 4008 4009
				starSteps,
				this.planes,
				tnSurface,
				preferDisparity);
4010

4011
		int [][][] neibs_prev = connectionCosts.initConnectionCosts(mod_supertiles, debugLevel);
4012

4013
		int [][][] neibs_prev_old = new int [mod_supertiles.length][][];
4014
		double [][][]  val_weights = new double [mod_supertiles.length][][];
4015

4016
		// Calculate original costs and neighhbors
4017
		updateConnectionsCost_old (
4018 4019
				mod_supertiles,      // int []         nsTiles,
				null,         // int [][][]     neibs_prev,
4020
				neibs_prev_old,   // int [][][]     neibs,		// should be initialized at top dimension if neibs_prev==null
4021 4022 4023
				val_weights,  // double [][][]  val_weights, // should be initialized at top dimension if neibs_prev==null
				orthoWeight,
				diagonalWeight,
4024
				starPwr,        // double     starPwr, // Divide cost by number of connections to this power
4025
				starWeightPwr,    // Use this power of tile weight when calculating connection cost
4026 4027 4028
				tnSurface,
				preferDisparity,
				debugLevel);
4029

4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042
		if ((neibs_prev == null) || (neibs_prev[0] == null) || (neibs_prev[1] == null)){
			System.out.println("resolveDiagonalTriangularConflict(): BUG");
			System.out.println("neibs_prev="+neibs_prev);
			System.out.println("neibs_prev[0]="+neibs_prev[0]);
			System.out.println("neibs_prev[1]="+neibs_prev[1]);
			return false;
		}
		int [][][] neibs = {neibs_prev[0].clone(),neibs_prev[1].clone()}; // both non-null
		for (int nt = 0; nt < neibs.length; nt++){
			for (int l = 0; l < neibs_prev[nt].length; l++) if (neibs_prev[nt][l]!= null){
				neibs[nt][l] = neibs_prev[nt][l].clone();
			}
		}
4043 4044 4045 4046 4047 4048
		int [][][] neibs_old = {neibs_prev[0].clone(),neibs_prev[1].clone()}; // both non-null
		for (int nt = 0; nt < neibs.length; nt++){
			for (int l = 0; l < neibs_prev[nt].length; l++) if (neibs_prev[nt][l]!= null){
				neibs_old[nt][l] = neibs_prev_old[nt][l].clone();
			}
		}
4049 4050 4051 4052 4053 4054
		int [][][] conflicts_old = new int [nsTiles.length][][];
		for (int isTile = 0; isTile < nsTiles.length; isTile++){
			conflicts_old[isTile] = iconflicts.detectTriangularTileConflicts(
					nsTiles[isTile],   // int nsTile0,
					replacement_tiles, //HashMap<Integer,Integer> replacement_tiles, //
					neibs_prev, // int [][][] replacement_neibs,
4055
					tnSurface); // TileNeibs tnSurface)
4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066
		}
		if (debugLevel > 1) {
			System.out.println("Calculating original conflicts");
		}
		iconflicts.addConflicts(conflicts_old,
				debugLevel - 1); // debugLevel);

		if (nl2 <0){
			System.out.println(conflict.toString()+" : start_dir4 = "+ start_dir4 + ", right = "+right+", reverse = "+reverse+" nl2 < 0 !");
			return false;
		}
4067

4068 4069 4070 4071 4072 4073 4074
		// now swap diagonal connection
		neibs[0][nl][dir02] = nl2;
		neibs[1][nl2][dir20] = nl;
		neibs[0][nl_end][dir02] = neibs_prev[0][nl][dir02];
		if (neibs_prev[0][nl][dir02] >= 0) {
			neibs[1][neibs_prev[0][nl][dir02]][dir20] = nl_end;
		}
4075 4076 4077 4078 4079 4080 4081

		neibs_old[0][nl][dir02] = nl2;
		neibs_old[1][nl2][dir20] = nl;
		neibs_old[0][nl_end][dir02] = neibs_prev_old[0][nl][dir02];
		if (neibs_prev_old[0][nl][dir02] >= 0) {
			neibs_old[1][neibs_prev_old[0][nl][dir02]][dir20] = nl_end;
		}
4082 4083 4084



4085
		int [][][] new_conflicts = new int [nsTiles.length][][];
4086

4087 4088 4089
		double new_costs_diff = 	connectionCosts.getConnectionsCostDiff(
				neibs,
				debugLevel);
4090

4091 4092 4093 4094 4095
		if (debugLevel > -1) {
			System.out.println("resolveDiagonalTriangularConflict(): resolving conflict "+conflict.toString()+
					", start dir4 = "+start_dir4+
					", orientation = "+(right?"right":"left") +
					", improvement (negative diff) = "+new_costs_diff);
4096

4097
		}
4098
		double new_costs_diff_old = 	updateConnectionsCost_old (
4099
				mod_supertiles,      // int []         nsTiles,
4100
				neibs_prev_old,          // int [][][]     neibs_prev,
4101
				neibs_old,               // int [][][]     neibs,		// should be initialized at top dimension if neibs_prev==null
4102 4103 4104
				val_weights,         // double [][][]  val_weights, // should be initialized at top dimension if neibs_prev==null
				orthoWeight,
				diagonalWeight,
4105
				starPwr,        // double     starPwr, // Divide cost by number of connections to this power
4106
				starWeightPwr,    // Use this power of tile weight when calculating connection cost
4107 4108 4109
				tnSurface,
				preferDisparity,
				debugLevel);
4110

4111 4112 4113 4114 4115
		for (int isTile = 0; isTile < nsTiles.length; isTile++){
			new_conflicts[isTile] = iconflicts.detectTriangularTileConflicts(
					nsTiles[isTile],   // int nsTile0,
					replacement_tiles, //HashMap<Integer,Integer> replacement_tiles, //
					neibs, // neibs, // int [][][] replacement_neibs,
4116
					tnSurface); // TileNeibs tnSurface)
4117 4118 4119 4120 4121 4122
		}
		Conflicts new_conflicts_stats = new Conflicts(
				new_conflicts,
				this,
				debugLevel - 1); // debugLevel);
		new_conflicts_stats.subConflicts(iconflicts); // subtract old number of different types of conflicts
4123

4124
		if (debugLevel > -1) {
4125
			System.out.println("resolveDiagonalTriangularConflict() OLD: resolving conflict "+conflict.toString()+
4126 4127
					", start dir4 = "+start_dir4+
					", orientation = "+(right?"right":"left") +
4128
					", improvement (negative diff) = "+new_costs_diff_old);
4129

4130
		}
Andrey Filippov's avatar
Andrey Filippov committed
4131
		if (debugLevel > 0) { // -1) {
4132 4133 4134 4135
			new_conflicts_stats.printConflictSummary(
					"Conflicts difference after resolution:", true, true, true);
		}
		// See if it is good
Andrey Filippov's avatar
Andrey Filippov committed
4136
		if (debugLevel > 0) { // -1) {
4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184
			if (new_conflicts_stats.getNumConflicts() > 0) {
				if (debugLevel > -1) System.out.println("FAILURE: number of conflicts increased");
			} else if (new_costs_diff > dblTriLoss){
				if (debugLevel > -1) System.out.println("FAILURE: cost increased too much");
			} else if ((new_costs_diff >= 0.0) && (new_conflicts_stats.getNumConflicts() == 0)){
				if (debugLevel > -1) System.out.println("FAILURE: cost increased, but conflicts number is the same");
			} else if (new_costs_diff >= 0.0){
				if (debugLevel > -1) System.out.println("SUCCESS: cost did not decrease, but conflicts did");
			} else if (new_conflicts_stats.getNumConflicts() == 0){
				if (debugLevel > -1) System.out.println("SUCCESS: conflicts number is the same, but connection cost decreased");
			} else {
				if (debugLevel > -1) System.out.println("SUCCESS: both conflicts and connection cost decreased");
			}
			if (debugLevel > 1) {
				System.out.println("resolveDiagonalTriangularConflict(): nsTile = "+conflict.getSTile());
			}
		}

		if (new_conflicts_stats.getNumConflicts() > 0) {
			return false;
		}
		if (new_costs_diff > dblTriLoss){
			return false;
		}
		if ((new_costs_diff >= 0.0) && (new_conflicts_stats.getNumConflicts() == 0)){
			return false;
		}
		boolean apply = true;
		// apply changes
		if (apply) {
			// update statistics
			conflict_stats.addConflicts(new_conflicts_stats);
			// update conflict
			for (int i = 0; i < nsTiles.length; i++){
				conflicts[nsTiles[i]]=  new_conflicts[i];
			}

			// apply resolution
			for (int i = 0; i < mod_supertiles.length; i++){
				for (int l = 0; l < neibs[i].length; l ++) if (neibs[i][l] != null){
					if (planes[mod_supertiles[i]].length <= l) {
						System.out.println("BUG: (planes["+mod_supertiles[i]+"].length="+planes[mod_supertiles[i]].length+" <= "+l);
						return false;
					}
					planes[mod_supertiles[i]][l].setNeibBest(neibs[i][l]);
				}
			}
		}
4185
		return true;
4186
	}
4187

4188

4189 4190 4191 4192 4193
	public boolean resolveMultiTriangularConflict(
			int nsTile,
			int nl1,
			int nl2,
			int dir_mask,
4194
			TileNeibs tnSurface,
4195
			int [][][] conflicts,
4196
			Conflicts conflict_stats, // to be updated after applying resolution
4197
			int        starSteps, // How far to look around when calculationg connection cost
4198 4199
			double     orthoWeight,
			double     diagonalWeight,
4200
			double     starPwr, // Divide cost by number of connections to this power
4201
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
4202
			double     weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
4203
			double     starValPwr, //  Raise value of each tile before averaging
4204 4205
			double     dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
			boolean    preferDisparity,
4206
			int        debugLevel)
4207
	{
4208
		Conflicts iconflicts = new Conflicts(this);
4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220
		// neibs_raw may have unused directions
		int [][][][] neibs_raw = getTriangularResolutionVariants(
				nsTile,
				nl1,
				nl2,
				dir_mask,
				tnSurface,
				debugLevel);
		if (neibs_raw.length == 0){
			System.out.println("resolveMultiTriangularConflict() - zero variants. A bug?");
			return false;
		}
4221

4222 4223 4224 4225 4226 4227 4228 4229
		int num_tiles = 0;
		for (int i = 0; i < neibs_raw[0].length; i++){
			if (neibs_raw[0][i] != null) num_tiles++;
 		}
		int [] mod_supertiles = new int [num_tiles];
		int [] indices = new int[num_tiles];
		int indx = 0;
		indices[indx++] = 4;
4230
		for (int i = 0; (i < neibs_raw[0].length) && (indx < indices.length); i++){
4231 4232 4233 4234 4235
			if (neibs_raw[0][i] != null) indices[indx++] = i;
 		}
		for (int i = 0; i < indices.length; i++){
			int dir4 = indices[i];
			if (dir4 > 3) {
4236
				mod_supertiles[i] = nsTile;
4237
			} else {
4238
				mod_supertiles[i] = tnSurface.getNeibIndex(nsTile, 2 * dir4);
4239 4240 4241 4242 4243 4244 4245 4246
			}
		}
		int [][][][] neibs_vars = new int [neibs_raw.length][mod_supertiles.length][][];
		for (int ivar = 0; ivar < neibs_raw.length; ivar++){
			for (int i = 0; i < indices.length; i++){
				neibs_vars[ivar][i] = neibs_raw[ivar][indices[i]];
			}
		}
4247

4248 4249


4250
		// See how this application will influence number of conflicts
4251
		// All supertiles that may have different conflicts
4252 4253 4254 4255 4256 4257 4258
		int [] nsTiles = getInvolvedSupertiles( // first mod_supertiles.length entries will be mod_supertiles[]
				mod_supertiles,
				tnSurface);
		HashMap<Integer,Integer> replacement_tiles = new HashMap<Integer,Integer>();
		for (int i = 0; i < mod_supertiles.length; i++){
			replacement_tiles.put(mod_supertiles[i], new Integer(i));
		}
4259

4260 4261 4262 4263
		ConnectionCosts connectionCosts = new ConnectionCosts(
				orthoWeight,
				diagonalWeight,
				starPwr,    // Divide cost by number of connections to this power
4264
				starWeightPwr,    // Use this power of tile weight when calculating connection cost
4265
				weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
4266
				starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
4267 4268 4269 4270
				starSteps,
				this.planes,
				tnSurface,
				preferDisparity);
4271

4272
		int [][][] neibs_prev = connectionCosts.initConnectionCosts(mod_supertiles, debugLevel);
4273 4274

/** */
4275
		int [][][] neibs_prev_old = new int [mod_supertiles.length][][];
4276
		double [][][]  val_weights_original = new double [mod_supertiles.length][][];
4277
		updateConnectionsCost_old (
4278 4279
				mod_supertiles,      // int []         nsTiles,
				null,         // int [][][]     neibs_prev,
4280
				neibs_prev_old,   // int [][][]     neibs,		// should be initialized at top dimension if neibs_prev==null
4281
				val_weights_original,  // double [][][]  val_weights, // should be initialized at top dimension if neibs_prev==null
4282 4283
				orthoWeight,
				diagonalWeight,
4284
				starPwr,        // double     starPwr, // Divide cost by number of connections to this power
4285
				starWeightPwr,    // Use this power of tile weight when calculating connection cost
4286 4287 4288
				tnSurface,
				preferDisparity,
				debugLevel);
4289
/** */
4290 4291
		int [][][] conflicts_old = new int [nsTiles.length][][];
		for (int isTile = 0; isTile < nsTiles.length; isTile++){
4292
			conflicts_old[isTile] = iconflicts.detectTriangularTileConflicts(
4293 4294 4295
					nsTiles[isTile],   // int nsTile0,
					replacement_tiles, //HashMap<Integer,Integer> replacement_tiles, //
					neibs_prev, // int [][][] replacement_neibs,
4296
					tnSurface); // TileNeibs tnSurface)
4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308
		}
		if (debugLevel > 1) {
			System.out.println("Involved supertiles:");
			for (int i = 0; i < nsTiles.length; i++){
				System.out.println(i+":"+nsTiles[i]);
			}
		}

		if (debugLevel > 1) {
			System.out.println("Calculating original conflicts");
		}

4309 4310
		iconflicts.addConflicts(conflicts_old,
				debugLevel - 1); // debugLevel);
4311 4312 4313
		// After getting old (referfence data) iterate through all variants, for each calculate cost and number of conflicts.
		// First - just collect data - cost and full statistics of the conflicts, print them
		// Then select the best one (not incrementing number of conflicts? and reducing cost)
4314
		int [][][][] variant_conflicts = new int [neibs_vars.length][nsTiles.length][][];
4315

4316 4317
		Conflicts [] variant_conflicts_stats = new Conflicts [neibs_vars.length];

4318

4319 4320
		double [] variant_costs_diff = new double [neibs_vars.length];
		for (int variant = 0; variant < neibs_vars.length; variant ++){
4321 4322 4323 4324 4325
			if (debugLevel > 0) {
				System.out.println("resolveMultiTriangularConflict(): resolving conflict for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +
						", dir_mask = "+dir_mask+" variant = "+variant);
4326

4327
			}
4328 4329 4330
			variant_costs_diff[variant] = 	connectionCosts.getConnectionsCostDiff(
					neibs_vars[variant],
					debugLevel);
4331

4332 4333 4334 4335 4336
			if (debugLevel > -1) {
				System.out.println("resolveMultiTriangularConflict(): resolving conflict for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +
						", dir_mask = "+dir_mask+" variant = "+variant+" improvement (negative diff) = "+variant_costs_diff[variant]);
4337

4338
			}
4339

4340
			double [] variant_costs_diff_old = new double [neibs_vars.length];
4341 4342 4343 4344 4345 4346 4347
			double [][][]  val_weights = val_weights_original.clone();
			for (int nt = 0; nt < val_weights_original.length; nt++) if (val_weights_original[nt] != null){
				val_weights[nt] = val_weights_original[nt].clone();
				for (int nl = 0; nl < val_weights_original[nt].length; nl++) if (val_weights_original[nt][nl] != null){
					val_weights[nt][nl] = val_weights_original[nt][nl].clone();
				}
			}
4348
			variant_costs_diff_old[variant] = 	updateConnectionsCost_old (
4349
					mod_supertiles,      // int []         nsTiles,
4350
					neibs_prev_old,          // int [][][]     neibs_prev,
4351
					neibs_vars[variant], // int [][][]     neibs,		// should be initialized at top dimension if neibs_prev==null
4352 4353 4354
					val_weights,         // double [][][]  val_weights, // should be initialized at top dimension if neibs_prev==null
					orthoWeight,
					diagonalWeight,
4355
					starPwr,        // double     starPwr, // Divide cost by number of connections to this power
4356
					starWeightPwr,    // Use this power of tile weight when calculating connection cost
4357 4358 4359
					tnSurface,
					preferDisparity,
					debugLevel);
4360 4361 4362



4363
			for (int isTile = 0; isTile < nsTiles.length; isTile++){
4364
				variant_conflicts[variant][isTile] = iconflicts.detectTriangularTileConflicts(
4365 4366
						nsTiles[isTile],   // int nsTile0,
						replacement_tiles, //HashMap<Integer,Integer> replacement_tiles, //
4367
						neibs_vars[variant], // neibs, // int [][][] replacement_neibs,
4368
						tnSurface); // TileNeibs tnSurface)
4369
			}
4370 4371 4372 4373
			variant_conflicts_stats[variant] = new Conflicts(
					variant_conflicts[variant],
					this,
					debugLevel - 1); // debugLevel);
4374
			variant_conflicts_stats[variant].subConflicts(iconflicts); // subtract old number of different types of conflicts
4375

4376
			if (debugLevel > -1) {
4377
				System.out.println("resolveMultiTriangularConflict() OLD: resolving conflict for tile "+nsTile+
4378 4379
						", nl1 = "+nl1+
						", nl2 = "+nl2 +
4380
						", dir_mask = "+dir_mask+" variant = "+variant+" improvement (negative diff) = "+variant_costs_diff_old[variant]);
4381

4382
			}
4383
			if (debugLevel > -1) {
4384 4385
				variant_conflicts_stats[variant].printConflictSummary(
						"Conflicts difference after resolution:", true, true, false);
4386 4387 4388 4389 4390 4391
			}
		}
		// How to compare? 1 attempt: none of the conflicts get worse, some get better or cost goes down
		int best_variant = -1;
		int [][] num_better_worse = new int [neibs_vars.length][2];
		for (int variant = 0; variant < neibs_vars.length; variant ++){
4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402
			int num_worse = variant_conflicts_stats[variant].numBetterWorse(
					false, // boolean better,
					false, // boolean use_all,
					true, // boolean use_odo,
					false); // ); // boolean use_ood)

			int num_better = variant_conflicts_stats[variant].numBetterWorse(
					true, // boolean better,
					false, // boolean use_all,
					true, // boolean use_odo,
					false); // ); // boolean use_ood)
4403 4404
			num_better_worse[variant][0] = num_better;
			num_better_worse[variant][1] = num_worse;
4405 4406
			if ((num_worse == 0) &&
					(variant_costs_diff[variant] <= dblTriLoss) && // not too worse
4407
					((variant_costs_diff[variant] < 0) || (num_better > 0)) && // either
4408 4409
					((best_variant < 0) ||
							( num_better_worse[variant][0] > num_better_worse[best_variant][0]) ||
4410
							(( num_better_worse[variant][0] == num_better_worse[best_variant][0]) &&
4411
									(variant_costs_diff[variant] < variant_costs_diff[best_variant])))){
4412 4413 4414
				best_variant = variant;
			}
		}
4415

4416 4417 4418
		if (debugLevel > 1){
			System.out.println("resolveMultiTriangularConflict(): for tile "+nsTile);
		}
4419

4420
		if ((best_variant < 0) || (variant_costs_diff[best_variant] > dblTriLoss)){
4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432
			if (debugLevel > -1) {
				System.out.println("resolveMultiTriangularConflict(): FAILED find a sutable solution for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +
						", dir_mask = "+dir_mask+" of "+ neibs_vars.length+" variants");
				return false;
			}
		} else {
			if (debugLevel > -1) {
				System.out.println("resolveMultiTriangularConflict(): SUCCESS to find a sutable solution for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +
4433
						", dir_mask = "+dir_mask+". Of "+ neibs_vars.length+" variants - use variant # " + best_variant+
4434
						" cost difference (negative) = "+variant_costs_diff[best_variant]+" num conflict reductions = "+num_better_worse[best_variant][0]);
4435 4436 4437 4438 4439 4440 4441 4442 4443 4444
				variant_conflicts_stats[best_variant].printConflictSummary(
						"Conflicts number change per type: ",
						true, // use_all,
						true, //use_odo,
						true); // use_ood);
				iconflicts.printConflictSummary(
						"Conflicts before resolution: ",
						true, // use_all,
						true, //use_odo,
						true); // use_ood);
4445
				// update statistics
4446 4447
				conflict_stats.addConflicts(variant_conflicts_stats[best_variant]);

4448

4449 4450 4451 4452
				// update conflict
				for (int i = 0; i < nsTiles.length; i++){
					conflicts[nsTiles[i]]=  variant_conflicts[best_variant][i];
				}
4453 4454


4455 4456 4457 4458 4459 4460
				// apply resolution
				for (int i = 0; i < mod_supertiles.length; i++){
					for (int nl = 0; nl < neibs_vars[best_variant][i].length; nl ++) if (neibs_vars[best_variant][i][nl] != null){
						planes[mod_supertiles[i]][nl].setNeibBest(neibs_vars[best_variant][i][nl]);
					}
				}
4461 4462 4463
			}
		}
		return true;
4464
	}
4465 4466


4467 4468 4469 4470 4471 4472 4473
	public int [] resolveMultiTriangularConflicts(
			int [][][] conflicts,
			Conflicts conflict_stats, // to be updated after applying resolution
			int        starSteps, // How far to look around when calculationg connection cost
			double     orthoWeight,
			double     diagonalWeight,
			double     starPwr, // Divide cost by number of connections to this power
4474
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
4475
			double     weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
4476
			double     starValPwr, //  Raise value of each tile before averaging
4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489
			double     dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
			boolean    preferDisparity,
			int        debugLevel,
			int        dbg_X,
			int        dbg_Y)
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
		final int stilesX =       (tilesX + superTileSize -1)/superTileSize;
		final int stilesY =       (tilesY + superTileSize -1)/superTileSize;
		final int dbgTile = dbg_Y * stilesX + dbg_X;
4490
		final TileNeibs tnSurface = new TileNeibs(stilesX, stilesY);
4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508
		int [] rslt = {0,0};
		for (int nsTile = 0; nsTile < conflicts.length; nsTile++) if (conflicts[nsTile] != null) {
			// conflicts may disappear after being fixed, recheck for null
			for (int nConfl = 0; (conflicts[nsTile] != null) && (nConfl < conflicts[nsTile].length); nConfl++){
				int dl = ((debugLevel > 0) && (nsTile == dbgTile)) ? 3 : 0;
				boolean OK = resolveMultiTriangularConflict(
						nsTile,
						conflicts[nsTile][nConfl][0], // int nl1,
						conflicts[nsTile][nConfl][1], // int nl2,
						conflicts[nsTile][nConfl][2], // int dir_mask,
						tnSurface,
						conflicts,
						conflict_stats, // to be updated after applying resolution
//						maxEigen, // maximal eigenvalue of planes to consider
						starSteps, // How far to look around when calculationg connection cost
						orthoWeight,
						diagonalWeight,
						starPwr,        // double     starPwr, // Divide cost by number of connections to this power
4509
						starWeightPwr,    // Use this power of tile weight when calculating connection cost
4510
						weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
4511
						starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
4512 4513 4514 4515 4516 4517 4518 4519 4520 4521
						dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
						preferDisparity,
						dl); // debugLevel,
				if (OK) rslt[0]++;
				else    rslt[1]++;
			}
		}
		return rslt;
	}

4522

4523 4524 4525
	public int [] resolveStarConflicts(
			int [][][] conflicts,
			Conflicts conflict_stats, // to be updated after applying resolution
4526
			LinkPlanes lp,
4527 4528 4529 4530
			int        starSteps, // How far to look around when calculationg connection cost
			double     orthoWeight,
			double     diagonalWeight,
			double     starPwr, // Divide cost by number of connections to this power
4531
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
4532 4533
			double     weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
			double     starValPwr, //  Raise value of each tile before averaging
4534
			double     dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
Andrey Filippov's avatar
Andrey Filippov committed
4535
			boolean    newConfl, // Allow more conflicts if overall cost is reduced
4536
			int        maxChanges,  // Maximal number of simultaneous connection changes around one tile (0 - any)
4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548
			boolean    preferDisparity,
			int        debugLevel,
			int        dbg_X,
			int        dbg_Y)
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
		final int stilesX =       (tilesX + superTileSize -1)/superTileSize;
		final int stilesY =       (tilesY + superTileSize -1)/superTileSize;
		final int dbgTile = dbg_Y * stilesX + dbg_X;
4549
		final TileNeibs tnSurface = new TileNeibs(stilesX, stilesY);
4550 4551 4552 4553 4554 4555 4556 4557 4558
		int [] rslt = {0,0};
		for (int nsTile = 0; nsTile < conflicts.length; nsTile++) if (conflicts[nsTile] != null) {
			// conflicts may disappear after being fixed, recheck for null
			for (int nConfl = 0; (conflicts[nsTile] != null) && (nConfl < conflicts[nsTile].length); nConfl++){
				int dl = ((debugLevel > 0) && (nsTile == dbgTile)) ? 3 : 0;
				boolean OK = resolveStarConflict(
						nsTile,
						conflicts[nsTile][nConfl][0], // int nl1,
						conflicts[nsTile][nConfl][1], // int nl2,
4559
						lp, // LinkPlanes lp,
4560 4561 4562
						tnSurface,
						conflicts,
						conflict_stats, // to be updated after applying resolution
Andrey Filippov's avatar
Andrey Filippov committed
4563
						starSteps, // How far to look around when calculating connection cost
4564 4565 4566
						orthoWeight,
						diagonalWeight,
						starPwr,        // double     starPwr, // Divide cost by number of connections to this power
4567
						starWeightPwr,    // Use this power of tile weight when calculating connection cost
4568
						weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
4569 4570 4571 4572
						starValPwr,     //double     starValPwr, //  Raise value of each tile before averaging
						dblTriLoss,     //  When resolving double triangles allow minor degradation (0.0 - strict)
						newConfl,       // boolean    newConfl, // Allow more conflicts if overall cost is reduced
						maxChanges,     // int        maxChanges,  // Maximal number of simultaneous connection changes around one tile (0 - any)
4573 4574 4575 4576 4577 4578 4579 4580 4581
						preferDisparity,
						dl); // debugLevel,
				if (OK) rslt[0]++;
				else    rslt[1]++;
			}
		}
		return rslt;
	}

4582

4583
	public boolean resolveStarConflict0(
4584 4585 4586
			int nsTile,
			int nl1,
			int nl2,
4587
			TileNeibs tnSurface,
4588 4589 4590 4591 4592 4593
			int [][][] conflicts,
			Conflicts conflict_stats, // to be updated after applying resolution
			int        starSteps, // How far to look around when calculationg connection cost
			double     orthoWeight,
			double     diagonalWeight,
			double     starPwr, // Divide cost by number of connections to this power
4594
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
4595
			double     weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
4596
			double     starValPwr, //  Raise value of each tile before averaging
4597
			double     dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
Andrey Filippov's avatar
Andrey Filippov committed
4598
			boolean    newConfl, // Allow more conflicts if overall cost is reduced
4599
			int        maxChanges,  // Maximal number of simultaneous connection changes around one tile (0 - any)
4600 4601 4602
			boolean    preferDisparity,
			int        debugLevel)
	{
4603

Andrey Filippov's avatar
Andrey Filippov committed
4604 4605 4606
		if (newConfl && (dblTriLoss > 0.0)){
			dblTriLoss = 0.0; // require strict reducing of the cost if conflict increase is allowed
		}
4607
		Conflicts iconflicts = new Conflicts(this);
4608 4609

		TwoLayerNeighbors twoLayerNeighbors = new TwoLayerNeighbors();
4610

4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621
		for (int dir = -1; dir < 8; dir++){
			int nt = tnSurface.getNeibIndex(nsTile, dir);
			if ((nt >= 0) && (planes[nt] != null)) {
				int [][] neibs =  new int [planes[nt].length][];
				for (int nl = 0; nl < planes[nt].length; nl++) if ( planes[nt][nl] != null){
					neibs[nl] =  planes[nt][nl].getNeibBest();
				}
				twoLayerNeighbors.setNeighbors(neibs,dir);
			}
		}
		twoLayerNeighbors.setLayers(nl1, nl2);
Andrey Filippov's avatar
Andrey Filippov committed
4622 4623 4624
		if (debugLevel > 1) {
			System.out.println("resolveStarConflict(): nsTile ="+nsTile+" nl1="+nl1+" nl2="+nl2);
		}
4625

4626 4627
		int [][][][] neibs_vars_dir = twoLayerNeighbors.getNeighborVariants(
				maxChanges,
4628
				debugLevel);
4629 4630 4631 4632 4633 4634 4635 4636 4637 4638

		int [] mod_supertiles = {nsTile};
		mod_supertiles = getInvolvedSupertiles( // first mod_supertiles.length entries will be mod_supertiles[]
				mod_supertiles,
				tnSurface);

		HashMap<Integer,Integer> replacement_tiles = new HashMap<Integer,Integer>();
		for (int i = 0; i < mod_supertiles.length; i++){
			replacement_tiles.put(mod_supertiles[i], new Integer(i));
		}
4639

4640 4641 4642 4643
		// up to 9 tiles
		int [] indexToDir = new int[mod_supertiles.length];
		for (int i = 0; i < indexToDir.length; i++) indexToDir[i] = -1;
		for (int dir = -1; dir < 8; dir++){
4644
			int nindx = (dir < 0) ? 8 : dir;
4645
			int nt = tnSurface.getNeibIndex(nsTile, dir);
Andrey Filippov's avatar
Andrey Filippov committed
4646 4647 4648 4649 4650 4651 4652
			int indx = -1;
			Integer Indx = replacement_tiles.get(nt);
			if (Indx == null){
				System.out.println("resolveStarConflict(): nsTile = "+nsTile+" nindx="+nindx+" Indx == null ");
			} else {
				indx = Indx;
			}
4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667
			if (indx >= 0) {
				indexToDir[indx] = nindx;
			}
		}
		int [][][][] neibs_vars = new int [neibs_vars_dir.length][][][];
		for (int variant = 0; variant < neibs_vars_dir.length; variant ++){
			neibs_vars[variant] = new int [indexToDir.length][][];
			for (int i = 0; i <indexToDir.length; i++){
				if (indexToDir[i] >=0){
					neibs_vars[variant][i] = neibs_vars_dir[variant][indexToDir[i]];
				} else {
					System.out.println("resolveStarConflict(): a BUG:  indexToDir["+i+"] = "+indexToDir[i]);
				}
			}
		}
4668

4669
		// See how this application will influence number of conflicts
4670
		// All supertiles that may have different conflicts
4671 4672 4673
		int [] nsTiles = getInvolvedSupertiles( // first mod_supertiles.length entries will be mod_supertiles[]
				mod_supertiles,
				tnSurface);
4674

4675 4676 4677 4678
		ConnectionCosts connectionCosts = new ConnectionCosts(
				orthoWeight,
				diagonalWeight,
				starPwr,    // Divide cost by number of connections to this power
4679
				starWeightPwr,    // Use this power of tile weight when calculating connection cost
4680
				weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
4681
				starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
4682 4683 4684 4685
				starSteps,
				this.planes,
				tnSurface,
				preferDisparity);
4686

4687
		int [][][] neibs_prev = connectionCosts.initConnectionCosts(mod_supertiles, debugLevel);
4688

4689 4690 4691 4692 4693 4694
		int [][][] conflicts_old = new int [nsTiles.length][][];
		for (int isTile = 0; isTile < nsTiles.length; isTile++){
			conflicts_old[isTile] = iconflicts.detectTriangularTileConflicts(
					nsTiles[isTile],   // int nsTile0,
					replacement_tiles, //HashMap<Integer,Integer> replacement_tiles, //
					neibs_prev, // int [][][] replacement_neibs,
4695
					tnSurface); // TileNeibs tnSurface)
4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713
		}
		if (debugLevel > 1) {
			System.out.println("Involved supertiles:");
			for (int i = 0; i < nsTiles.length; i++){
				System.out.println(i+":"+nsTiles[i]);
			}
		}

		if (debugLevel > 1) {
			System.out.println("Calculating original conflicts");
		}

		iconflicts.addConflicts(conflicts_old,
				debugLevel - 1); // debugLevel);
		// After getting old (referfence data) iterate through all variants, for each calculate cost and number of conflicts.
		// First - just collect data - cost and full statistics of the conflicts, print them
		// Then select the best one (not incrementing number of conflicts? and reducing cost)
		int [][][][] variant_conflicts = new int [neibs_vars.length][nsTiles.length][][];
4714

4715 4716
		Conflicts [] variant_conflicts_stats = new Conflicts [neibs_vars.length];

4717

4718 4719
		double [] variant_costs_diff = new double [neibs_vars.length];
		for (int variant = 0; variant < neibs_vars.length; variant ++){
4720 4721 4722 4723 4724
			for (int isTile = 0; isTile < nsTiles.length; isTile++){
				variant_conflicts[variant][isTile] = iconflicts.detectTriangularTileConflicts(
						nsTiles[isTile],   // int nsTile0,
						replacement_tiles, //HashMap<Integer,Integer> replacement_tiles, //
						neibs_vars[variant], // neibs, // int [][][] replacement_neibs,
4725
						tnSurface); // TileNeibs tnSurface)
4726 4727 4728 4729 4730 4731
			}
			variant_conflicts_stats[variant] = new Conflicts(
					variant_conflicts[variant],
					this,
					debugLevel - 1); // debugLevel);
			variant_conflicts_stats[variant].subConflicts(iconflicts); // subtract old number of different types of conflicts
Andrey Filippov's avatar
Andrey Filippov committed
4732
			if (debugLevel > 1) {
4733 4734 4735
				System.out.println("resolveStarConflict(): resolving conflict for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +
4736 4737 4738
						", variant = "+variant+
						", num_conflicts diff = "+variant_conflicts_stats[variant].getNumConflicts()
						);
4739

4740
			}
4741 4742 4743
			if (!newConfl && (variant_conflicts_stats[variant].getNumConflicts() > 0)){
				continue;
			}
4744 4745 4746
			variant_costs_diff[variant] = 	connectionCosts.getConnectionsCostDiff(
					neibs_vars[variant],
					debugLevel);
4747

Andrey Filippov's avatar
Andrey Filippov committed
4748
			if (debugLevel > 0) {
4749 4750 4751
				System.out.println("resolveStarConflict(): resolving conflict for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +
4752 4753
						", variant = "+variant+" improvement (negative diff) = "+variant_costs_diff[variant]+
						", num_conflicts diff = "+variant_conflicts_stats[variant].getNumConflicts());
4754
			}
4755 4756


Andrey Filippov's avatar
Andrey Filippov committed
4757
			if (debugLevel > 0) { // -1) {
4758 4759 4760 4761 4762 4763
				variant_conflicts_stats[variant].printConflictSummary(
						"Conflicts difference after resolution:", true, true, false);
			}
		}
		// How to compare? 1 attempt: none of the conflicts get worse, some get better or cost goes down
		int best_variant = -1;
Andrey Filippov's avatar
Andrey Filippov committed
4764
		int best_ignore_conflicts = -1;
4765
		int [][] num_better_worse = new int [neibs_vars.length][2];
4766
		/*
4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782
		for (int variant = 0; variant < neibs_vars.length; variant ++){
			int num_worse = variant_conflicts_stats[variant].numBetterWorse(
					false, // boolean better,
					false, // boolean use_all,
					true, // boolean use_odo,
					false); // ); // boolean use_ood)

			int num_better = variant_conflicts_stats[variant].numBetterWorse(
					true, // boolean better,
					false, // boolean use_all,
					true, // boolean use_odo,
					false); // ); // boolean use_ood)
			num_better_worse[variant][0] = num_better;
			num_better_worse[variant][1] = num_worse;
			if ((num_worse == 0) &&
					(variant_costs_diff[variant] <= dblTriLoss) && // not too worse
4783
					((variant_costs_diff[variant] < 0) || (num_better > 0)) && // either
4784 4785
					((best_variant < 0) ||
							( num_better_worse[variant][0] > num_better_worse[best_variant][0]) ||
4786
							(( num_better_worse[variant][0] == num_better_worse[best_variant][0]) &&
4787 4788 4789
									(variant_costs_diff[variant] < variant_costs_diff[best_variant])))){
				best_variant = variant;
			}
Andrey Filippov's avatar
Andrey Filippov committed
4790 4791 4792
			if ((best_ignore_conflicts <0) || (variant_costs_diff[variant] < variant_costs_diff[best_ignore_conflicts])){
				best_ignore_conflicts = variant;
			}
4793
		}
4794 4795 4796 4797 4798 4799 4800
*/
		int [] num_var_conflicts = new int [neibs_vars.length];
		for (int variant = 0; variant < neibs_vars.length; variant ++){
//			int num_conflicts = variant_conflicts_stats[variant].getNumConflicts();
			num_var_conflicts[variant] = variant_conflicts_stats[variant].getNumConflicts();
			if ((num_var_conflicts[variant] <= 0) &&
					(variant_costs_diff[variant] <= dblTriLoss) && // not too worse
4801
					((variant_costs_diff[variant] < 0) || (num_var_conflicts[variant] < 0)) && // either
4802 4803
					((best_variant < 0) ||
							(num_var_conflicts[variant] < num_var_conflicts[best_variant]) ||
4804
							((num_var_conflicts[variant] == num_var_conflicts[best_variant]) &&
4805 4806 4807 4808 4809 4810 4811
									(variant_costs_diff[variant] < variant_costs_diff[best_variant])))){
				best_variant = variant;
			}
			if ((best_ignore_conflicts <0) || (variant_costs_diff[variant] < variant_costs_diff[best_ignore_conflicts])){
				best_ignore_conflicts = variant;
			}
		}
4812 4813 4814 4815

		if (debugLevel > 1){
			System.out.println("resolveStarConflict(): for tile "+nsTile);
		}
4816

Andrey Filippov's avatar
Andrey Filippov committed
4817 4818 4819 4820 4821 4822 4823 4824
		if ((best_variant < 0) && newConfl && (variant_costs_diff[best_ignore_conflicts] < 0)){ // should be cost improvement
			best_variant = best_ignore_conflicts;
			if (debugLevel > -1) {
				System.out.println("resolveMultiTriangularConflict(): conflicts increase but cost decreases "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +" of "+ neibs_vars.length+" variants");
			}
		}
4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836
		if ((best_variant < 0) || (variant_costs_diff[best_variant] > dblTriLoss)){
			if (debugLevel > -1) {
				System.out.println("resolveMultiTriangularConflict(): FAILED find a sutable solution for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +" of "+ neibs_vars.length+" variants");
				return false;
			}
		} else {
			if (debugLevel > -1) {
				System.out.println("resolveStarConflict(): SUCCESS to find a sutable solution for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +". Of "+ neibs_vars.length+" variants - use variant # " + best_variant+
4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851
						" cost difference (negative) = "+variant_costs_diff[best_variant]+
						" num conflict reductions = "+(-num_var_conflicts[best_variant])+" (old "+num_better_worse[best_variant][0]+")");
				variant_conflicts_stats[best_variant].printConflictSummary(
						"Conflicts number change per type: ",
						true, // use_all,
						true, //use_odo,
						true); // use_ood);
				iconflicts.printConflictSummary(
						"Conflicts before resolution: ",
						true, // use_all,
						true, //use_odo,
						true); // use_ood);
				// update statistics
				conflict_stats.addConflicts(variant_conflicts_stats[best_variant]);

4852

4853 4854 4855 4856
				// update conflict
				for (int i = 0; i < nsTiles.length; i++){
					conflicts[nsTiles[i]]=  variant_conflicts[best_variant][i];
				}
4857 4858


4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883
				// apply resolution
				for (int i = 0; i < mod_supertiles.length; i++){
					if (debugLevel > 1){
						System.out.println("resolveStarConflict(): nsTile = "+nsTile+ "mod_supertiles["+i+"]="+mod_supertiles[i]);
					}
					if (neibs_vars[best_variant][i] != null) {
						for (int nl = 0; nl < neibs_vars[best_variant][i].length; nl ++){
							if (debugLevel > 1){
								System.out.println("resolveStarConflict(): nl= = "+nl);
							}
							if (neibs_vars[best_variant][i][nl] != null){
								planes[mod_supertiles[i]][nl].setNeibBest(neibs_vars[best_variant][i][nl]);
							}
						}
					}
				}
			}
		}
		return true;
	}

	public boolean resolveStarConflict(
			int nsTile,
			int nl1,
			int nl2,
4884
			LinkPlanes lp,
4885
			TileNeibs tnSurface,
4886 4887 4888 4889 4890 4891
			int [][][] conflicts,
			Conflicts conflict_stats, // to be updated after applying resolution
			int        starSteps, // How far to look around when calculationg connection cost
			double     orthoWeight,
			double     diagonalWeight,
			double     starPwr, // Divide cost by number of connections to this power
4892
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
4893
			double     weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
4894
			double     starValPwr, //  Raise value of each tile before averaging
4895 4896
			double     dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
			boolean    newConfl, // Allow more conflicts if overall cost is reduced
4897
			int        maxChanges,  // Maximal number of simultaneous connection changes around one tile (0 - any)
4898 4899 4900
			boolean    preferDisparity,
			int        debugLevel)
	{
4901

4902 4903 4904
		if (newConfl && (dblTriLoss > 0.0)){
			dblTriLoss = 0.0; // require strict reducing of the cost if conflict increase is allowed
		}
4905
		Conflicts iconflicts = new Conflicts(this);
4906 4907

		TwoLayerNeighbors twoLayerNeighbors = new TwoLayerNeighbors();
4908

4909 4910 4911 4912
		for (int dir = -1; dir < 8; dir++){
			int nt = tnSurface.getNeibIndex(nsTile, dir);
			if ((nt >= 0) && (planes[nt] != null)) {
				int [][] neibs =  new int [planes[nt].length][];
4913
				boolean [][][] merge_valid = new boolean [planes[nt].length][][];
4914 4915
				for (int nl = 0; nl < planes[nt].length; nl++) if ( planes[nt][nl] != null){
					neibs[nl] =  planes[nt][nl].getNeibBest();
4916
					merge_valid[nl] = planes[nt][nl].getMergedValid();
4917 4918
				}
				twoLayerNeighbors.setNeighbors(neibs,dir);
4919
				twoLayerNeighbors.setMergeValid(merge_valid,dir);
4920 4921 4922 4923 4924 4925 4926
			}
		}
		twoLayerNeighbors.setLayers(nl1, nl2);
		if (debugLevel > 1) {
			System.out.println("resolveStarConflict(): nsTile ="+nsTile+" nl1="+nl1+" nl2="+nl2);
		}

4927 4928
		int [][][][] neibs_vars_dir = twoLayerNeighbors.getNeighborVariants(
				maxChanges,
4929
				debugLevel);
4930 4931 4932 4933 4934 4935 4936 4937 4938 4939

		int [] mod_supertiles = {nsTile};
		mod_supertiles = getInvolvedSupertiles( // first mod_supertiles.length entries will be mod_supertiles[]
				mod_supertiles,
				tnSurface);

		HashMap<Integer,Integer> replacement_tiles = new HashMap<Integer,Integer>();
		for (int i = 0; i < mod_supertiles.length; i++){
			replacement_tiles.put(mod_supertiles[i], new Integer(i));
		}
4940

4941 4942 4943 4944
		// up to 9 tiles
		int [] indexToDir = new int[mod_supertiles.length];
		for (int i = 0; i < indexToDir.length; i++) indexToDir[i] = -1;
		for (int dir = -1; dir < 8; dir++){
4945
			int nindx = (dir < 0) ? 8 : dir;
4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968
			int nt = tnSurface.getNeibIndex(nsTile, dir);
			int indx = -1;
			Integer Indx = replacement_tiles.get(nt);
			if (Indx == null){
				System.out.println("resolveStarConflict(): nsTile = "+nsTile+" nindx="+nindx+" Indx == null ");
			} else {
				indx = Indx;
			}
			if (indx >= 0) {
				indexToDir[indx] = nindx;
			}
		}
		int [][][][] neibs_vars = new int [neibs_vars_dir.length][][][];
		for (int variant = 0; variant < neibs_vars_dir.length; variant ++){
			neibs_vars[variant] = new int [indexToDir.length][][];
			for (int i = 0; i <indexToDir.length; i++){
				if (indexToDir[i] >=0){
					neibs_vars[variant][i] = neibs_vars_dir[variant][indexToDir[i]];
				} else {
					System.out.println("resolveStarConflict(): a BUG:  indexToDir["+i+"] = "+indexToDir[i]);
				}
			}
		}
4969

4970
		// See how this application will influence number of conflicts
4971
		// All supertiles that may have different conflicts
4972 4973 4974 4975 4976 4977 4978 4979
		int [] nsTiles = getInvolvedSupertiles( // first mod_supertiles.length entries will be mod_supertiles[]
				mod_supertiles,
				tnSurface);

		ConnectionCosts connectionCosts = new ConnectionCosts(
				orthoWeight,
				diagonalWeight,
				starPwr,    // Divide cost by number of connections to this power
4980
				starWeightPwr,    // Use this power of tile weight when calculating connection cost
4981
				weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
4982
				starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
4983 4984 4985 4986
				starSteps,
				this.planes,
				tnSurface,
				preferDisparity);
4987

4988
		int [][][] neibs_prev = connectionCosts.initConnectionCosts(mod_supertiles, debugLevel);
4989 4990
// connectionCosts now contains last calculated	val/weight pairs for broader array of tile data

4991 4992 4993 4994 4995 4996 4997
		int [][][] conflicts_old = new int [nsTiles.length][][];
		double conflicts_old_cost = 0.0;
		for (int isTile = 0; isTile < nsTiles.length; isTile++){
			conflicts_old[isTile] = iconflicts.detectTriangularTileConflicts(
					nsTiles[isTile],   // int nsTile0,
					replacement_tiles, // HashMap<Integer,Integer> replacement_tiles, //
					neibs_prev, // int [][][] replacement_neibs,
4998
					tnSurface); // TileNeibs tnSurface)
4999 5000
// calculate cost of conflicts

5001 5002 5003 5004 5005 5006 5007
			conflicts_old_cost += iconflicts.getConflictsCost(
					nsTiles[isTile],       // int           nsTile0,
					1.0,                   // double        scaleStartEnd, // include start and and layer tiles in the center in overall cost for each triangle (1.0)
					conflicts_old[isTile], // int [][]      conflicts, //
					replacement_tiles,     // HashMap<Integer,Integer> replacement_tiles, // null is OK
					neibs_prev,            // int [][][]    replacement_neibs,               // null OK if  replacement_tiles == null
					connectionCosts,       // ConnectionCosts connectionCosts,
5008
					tnSurface); // TileNeibs tnSurface)
5009

5010

5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029
		}
		if (debugLevel > 1) {
			System.out.println("Sum of old conflict costs around " + nsTile + " is "+conflicts_old_cost);
			System.out.println("Involved supertiles:");
			for (int i = 0; i < nsTiles.length; i++){
				System.out.println(i+":"+nsTiles[i]);
			}
		}

		if (debugLevel > 1) {
			System.out.println("Calculating original conflicts");
		}

		iconflicts.addConflicts(conflicts_old,
				debugLevel - 1); // debugLevel);
		// After getting old (referfence data) iterate through all variants, for each calculate cost and number of conflicts.
		// First - just collect data - cost and full statistics of the conflicts, print them
		// Then select the best one (not incrementing number of conflicts? and reducing cost)
		int [][][][] variant_conflicts = new int [neibs_vars.length][nsTiles.length][][];
5030

5031 5032
		Conflicts [] variant_conflicts_stats = new Conflicts [neibs_vars.length];

5033

5034 5035 5036
		double [] variant_costs_diff = new double [neibs_vars.length];
		double [] conflicts_var_cost = new double [neibs_vars.length];
		for (int variant = 0; variant < neibs_vars.length; variant ++){
5037
			// connections costs are needed before conflicts
5038 5039 5040
			variant_costs_diff[variant] = 	connectionCosts.getConnectionsCostDiff(
					neibs_vars[variant],
					debugLevel);
5041
			conflicts_var_cost[variant] = 0.0;
5042 5043 5044 5045 5046
			for (int isTile = 0; isTile < nsTiles.length; isTile++){
				variant_conflicts[variant][isTile] = iconflicts.detectTriangularTileConflicts(
						nsTiles[isTile],   // int nsTile0,
						replacement_tiles, //HashMap<Integer,Integer> replacement_tiles, //
						neibs_vars[variant], // neibs, // int [][][] replacement_neibs,
5047
						tnSurface); // TileNeibs tnSurface)
5048 5049 5050 5051 5052 5053 5054 5055
				// connectionCosts now contains last calculated	val/weight pairs for broader array of tile data
				conflicts_var_cost[variant] += iconflicts.getConflictsCost(
						nsTiles[isTile],                    // int           nsTile0,
						1.0,                                // double        scaleStartEnd, // include start and and layer tiles in the center in overall cost for each triangle (1.0)
						variant_conflicts[variant][isTile], // int [][]      conflicts, //
						replacement_tiles,                  // HashMap<Integer,Integer> replacement_tiles, // null is OK
						neibs_vars[variant],                // int [][][]    replacement_neibs,               // null OK if  replacement_tiles == null
						connectionCosts,                    // ConnectionCosts connectionCosts,
5056
						tnSurface);                         // TileNeibs tnSurface)
5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070
			}
			variant_conflicts_stats[variant] = new Conflicts(
					variant_conflicts[variant],
					this,
					debugLevel - 1); // debugLevel);
			variant_conflicts_stats[variant].subConflicts(iconflicts); // subtract old number of different types of conflicts
			if (debugLevel > 1) {
				System.out.println("resolveStarConflict(): resolving conflict for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +
						", variant = "+variant+
						"  conflit cost change = "+ (conflicts_var_cost[variant] - conflicts_old_cost)+
						", num_conflicts diff = "+variant_conflicts_stats[variant].getNumConflicts()
						);
5071 5072

// Initially do not process conflicts cost difference, just view it
5073
			}
5074
/*
5075 5076 5077
			if (!newConfl && (variant_conflicts_stats[variant].getNumConflicts() > 0)){
				continue;
			}
5078 5079
*/

5080 5081 5082 5083 5084 5085 5086 5087
			if (debugLevel > 0) {
				System.out.println("resolveStarConflict(): resolving conflict for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +
						", variant = "+variant+" improvement (negative diff) = "+variant_costs_diff[variant]+
						"  conflit cost change = "+ (conflicts_var_cost[variant] - conflicts_old_cost)+
						", num_conflicts diff = "+variant_conflicts_stats[variant].getNumConflicts());
			}
5088 5089


5090 5091 5092 5093 5094 5095 5096 5097 5098 5099
			if (debugLevel > 0) { // -1) {
				variant_conflicts_stats[variant].printConflictSummary(
						"Conflicts difference after resolution:", true, true, false);
			}
		}
		// How to compare? 1 attempt: none of the conflicts get worse, some get better or cost goes down
		int best_variant = -1;
		int best_ignore_conflicts = -1;
//		int [][] num_better_worse = new int [neibs_vars.length][2];
		int [] num_var_conflicts = new int [neibs_vars.length];
5100 5101


5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117
		for (int variant = 0; variant < neibs_vars.length; variant ++){
			if (variant_costs_diff[variant] <= dblTriLoss) {
				if  (conflicts_var_cost[variant] < conflicts_old_cost) {
					if ((best_variant < 0) || (conflicts_var_cost[variant] < conflicts_var_cost[best_variant])) {
						best_variant = variant;
					}
				}
				if ((best_ignore_conflicts < 0) || (variant_costs_diff[variant] < variant_costs_diff[best_ignore_conflicts])){
					best_ignore_conflicts = variant;
				}
			}
		}

		if (debugLevel > 1){
			System.out.println("resolveStarConflict(): for tile "+nsTile);
		}
5118
/*
5119
		if ((best_variant < 0) && newConfl && (best_ignore_conflicts >= 0) && (variant_costs_diff[best_ignore_conflicts] < 0)){ // should be cost improvement
5120 5121 5122 5123 5124 5125 5126
			best_variant = best_ignore_conflicts;
			if (debugLevel > -1) {
				System.out.println("resolveMultiTriangularConflict(): conflicts increase but cost decreases "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +" of "+ neibs_vars.length+" variants");
			}
		}
5127 5128 5129
*/
		if (newConfl){ // should be cost improvement
			best_variant = best_ignore_conflicts;
5130
			if (debugLevel > -1) {
5131 5132 5133 5134 5135
				System.out.println("resolveStarConflict(): ignoring conflicts if any for "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +" of "+ neibs_vars.length+" variants");
			}
		}
5136 5137


5138
		if ((best_variant < 0) || (variant_costs_diff[best_variant] > dblTriLoss) ||
5139 5140
//				((variant_costs_diff[best_variant] >= 0.0) && (conflicts_var_cost[best_variant] >= conflicts_old_cost) &&
				((conflicts_var_cost[best_variant] >= conflicts_old_cost) && // try always prohibit worse conflicts
5141 5142 5143
						(num_var_conflicts[best_variant] >= 0))){
			if (debugLevel > -1) {
				System.out.println("resolveStarConflict(): FAILED find a sutable solution for tile "+nsTile+
5144 5145
						", nl1 = "+nl1+
						", nl2 = "+nl2 +" of "+ neibs_vars.length+" variants");
5146 5147 5148
				if (debugLevel > 1){
					System.out.println("resolveStarConflict(): for tile "+nsTile+" FAILURE");
				}
5149 5150 5151 5152 5153 5154 5155 5156 5157 5158
				return false;
			}
		} else {
			if (debugLevel > -1) {
				System.out.println("resolveStarConflict(): SUCCESS to find a sutable solution for tile "+nsTile+
						", nl1 = "+nl1+
						", nl2 = "+nl2 +". Of "+ neibs_vars.length+" variants - use variant # " + best_variant+
						"  conflit cost change = "+ (conflicts_var_cost[best_variant] - conflicts_old_cost)+
						" cost difference (negative) = "+variant_costs_diff[best_variant]+
						" num conflict reductions = "+(-num_var_conflicts[best_variant]));
5159 5160 5161 5162 5163 5164 5165 5166 5167 5168
				variant_conflicts_stats[best_variant].printConflictSummary(
						"Conflicts number change per type: ",
						true, // use_all,
						true, //use_odo,
						true); // use_ood);
				iconflicts.printConflictSummary(
						"Conflicts before resolution: ",
						true, // use_all,
						true, //use_odo,
						true); // use_ood);
5169 5170 5171
			}
			// update statistics
			conflict_stats.addConflicts(variant_conflicts_stats[best_variant]);
5172

5173 5174 5175 5176 5177 5178 5179 5180 5181 5182
			// update conflict
			for (int i = 0; i < nsTiles.length; i++){
				conflicts[nsTiles[i]]=  variant_conflicts[best_variant][i];
			}


			// apply resolution
			for (int i = 0; i < mod_supertiles.length; i++){
				if (debugLevel > 1){
					System.out.println("resolveStarConflict(): nsTile = "+nsTile+ "mod_supertiles["+i+"]="+mod_supertiles[i]);
5183
				}
5184 5185 5186 5187 5188 5189 5190
				if (neibs_vars[best_variant][i] != null) {
					for (int nl = 0; nl < neibs_vars[best_variant][i].length; nl ++){
						if (debugLevel > 1){
							System.out.println("resolveStarConflict(): nl= = "+nl);
						}
						if (neibs_vars[best_variant][i][nl] != null){
							planes[mod_supertiles[i]][nl].setNeibBest(neibs_vars[best_variant][i][nl]);
Andrey Filippov's avatar
Andrey Filippov committed
5191
						}
5192 5193 5194
					}
				}
			}
5195
			// recalculate starValueWeights for and around tiles with modified  neighbors (no outside connections changed )nsTiles
5196
			lp.updateStarValueStrength(
5197 5198 5199 5200
					nsTiles,          // final int []         mod_supertiles,
					orthoWeight,      // final double         orthoWeight,
					diagonalWeight,   // final double         diagonalWeight,
					starPwr,          // final double         starPwr,    // Divide cost by number of connections to this power
5201
					starWeightPwr,    // Use this power of tile weight when calculating connection cost
5202 5203 5204 5205 5206 5207
					weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
					starValPwr,       //double     starValPwr, //  Raise value of each tile before averaging
					starSteps,        // final int            steps,
					planes,           // final TilePlanes.PlaneData [][] planes,
					preferDisparity, // final boolean        preferDisparity)
					debugLevel);
5208
		}
5209 5210 5211 5212
		if (debugLevel > 1){
			System.out.println("resolveStarConflict(): for tile "+nsTile+" OK");
		}

5213 5214
		return true;
	}
5215

5216
	public void calcStarValueStrengthOld(
5217 5218 5219
			final double         orthoWeight,
			final double         diagonalWeight,
			final double         starPwr,    // Divide cost by number of connections to this power
5220
			final double         starWeightPwr,    // Use this power of tile weight when calculating connection cost
5221
			final double         weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5222
			final double         starValPwr, //  Raise value of each tile before averaging
5223 5224
			final int            steps,
			final TilePlanes.PlaneData [][] planes,
5225 5226
			final boolean        preferDisparity,
			final int            debugLevel)
5227 5228 5229 5230 5231
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
5232
		final int stilesX =       (tilesX + superTileSize -1)/superTileSize;
5233
		final int stilesY =       (tilesY + superTileSize -1)/superTileSize;
5234
		final int nStiles =       stilesX * stilesY;
5235
		final TileNeibs tnSurface = new TileNeibs(stilesX, stilesY);
5236 5237 5238 5239
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
5240
				@Override
5241 5242 5243 5244 5245
				public void run() {
					ConnectionCosts connectionCosts = new ConnectionCosts(
							orthoWeight,    // double         orthoWeight,
							diagonalWeight, // double         diagonalWeight,
							starPwr,        // double         starPwr,    // Divide cost by number of connections to this power
5246
							starWeightPwr,  // double         starWeightPwr,    // Use this power of tile weight when calculating connection cost
5247
							weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5248
							starValPwr,     //double          starValPwr, //  Raise value of each tile before averaging
5249 5250
							steps,          // int            steps,
							planes,         // TilePlanes.PlaneData [][] planes,
5251
							tnSurface,      // TileNeibs tnSurface,
5252 5253 5254 5255 5256
							preferDisparity); // boolean preferDisparity)
					int [] mod_supertiles = new int[1];
					for (int nsTile = ai.getAndIncrement(); nsTile < nStiles; nsTile = ai.getAndIncrement()) {
						if ( planes[nsTile] != null) {
							mod_supertiles[0] = nsTile;
5257
							connectionCosts.initConnectionCosts(mod_supertiles, debugLevel);
5258 5259 5260 5261 5262 5263 5264 5265 5266 5267
							double [][][] val_weights = connectionCosts.getValWeights();
							for (int np = 0; np < planes[nsTile].length; np++){ // nu
								if (planes[nsTile][np] != null) {
									planes[nsTile][np].setStarValueWeight(val_weights[0][np]);
								}
							}
						}
					}
				}
			};
5268
		}
5269 5270 5271
		ImageDtt.startAndJoin(threads);
	}

5272
	public void updateStarValueStrengthOld(
5273 5274 5275 5276
			final int []         mod_supertiles,
			final double         orthoWeight,
			final double         diagonalWeight,
			final double         starPwr,    // Divide cost by number of connections to this power
5277
			final double         starWeightPwr,    // Use this power of tile weight when calculating connection cost
5278
			final double         weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5279
			final double         starValPwr, //  Raise value of each tile before averaging
5280 5281
			final int            steps,
			final TilePlanes.PlaneData [][] planes,
5282 5283
			final boolean        preferDisparity,
			final int            debugLevel)
5284 5285 5286 5287 5288
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
5289
		final int stilesX =       (tilesX + superTileSize -1)/superTileSize;
5290
		final int stilesY =       (tilesY + superTileSize -1)/superTileSize;
5291
		final TileNeibs tnSurface = new TileNeibs(stilesX, stilesY);
5292 5293 5294 5295
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
5296
				@Override
5297 5298 5299 5300 5301
				public void run() {
					ConnectionCosts connectionCosts = new ConnectionCosts(
							orthoWeight,    // double         orthoWeight,
							diagonalWeight, // double         diagonalWeight,
							starPwr,        // double         starPwr,    // Divide cost by number of connections to this power
5302
							starWeightPwr,    // Use this power of tile weight when calculating connection cost
5303
							weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5304
							starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
5305 5306
							steps,          // int            steps,
							planes,         // TilePlanes.PlaneData [][] planes,
5307
							tnSurface,      // TileNeibs tnSurface,
5308
							preferDisparity); // boolean preferDisparity)
5309
					int [] supertiles = new int[1];
5310 5311 5312
					for (int isTile = ai.getAndIncrement(); isTile < mod_supertiles.length; isTile = ai.getAndIncrement()) {
						int nsTile = mod_supertiles[isTile];
						if ((nsTile >= 0) && ( planes[nsTile] != null)) {
5313 5314
							supertiles[0] = nsTile;
							connectionCosts.initConnectionCosts(supertiles, debugLevel - 2);
5315 5316 5317 5318 5319 5320 5321 5322 5323 5324
							double [][][] val_weights = connectionCosts.getValWeights();
							for (int np = 0; np < planes[nsTile].length; np++){ // nu
								if (planes[nsTile][np] != null) {
									planes[nsTile][np].setStarValueWeight(val_weights[0][np]);
								}
							}
						}
					}
				}
			};
5325
		}
5326 5327
		ImageDtt.startAndJoin(threads);
	}
5328 5329 5330


	//
5331 5332 5333 5334 5335 5336 5337 5338 5339
	/**
	 * Generate variants for changing connections while preserving number of connections between each pair of tiles
	 * each variant is free of own conflicts, but may lead to conflicts on other layers or tiles
	 * These variants should be checked on number of conflicts and overall cost to make sure conflict resolution leads
	 * to improvement - either in number of conflicts or global connection cost
	 * @param nsTile linescan tile index of the supertile
	 * @param nl1 first layer at nsTile to have triangle (2 ortho and a diagonal between them) conflict
	 * @param nl2 second layer at nsTile to have a triangle conflict, nl2 > nl1
	 * @param dir_mask start directions for the triangle conflicts 1 - N, 2 - E, 4 - S, 8 - W (starting from nl1),
5340
	 * next 4 bits - similar fro starting from nl2
5341 5342 5343 5344 5345 5346
	 * @param tnSurface ileSurface.TileNeibs instance to generate indices of the tiles at certain direction from the current
	 * @param debugLevel debug level
	 * @return [variant][5][nl][8] [5] = 4 directions and center ([4]), some may be null - should be removed by the caller
	 */

	public int [][][][] getTriangularResolutionVariants(
5347 5348 5349 5350
			int nsTile,
			int nl1,
			int nl2,
			int dir_mask,
5351
			TileNeibs tnSurface,
5352
			int        debugLevel)
5353
	{
5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365
		int [][] layers0 = new int[5][2]; // 4 - center, 0 - N, 1 - E, 2 - S, 3 - w. 4 has 2, each other 0,1 or 2 layers
		for (int i = 0; i < (layers0.length - 1); i++){
			layers0[i][0] = -1;
			layers0[i][1] = -1;
		}
		layers0[4][0] = nl1;
		layers0[4][1] = nl2;
		int [] neibs1 = planes[nsTile][nl1].getNeibBest();
		int [] neibs2 = planes[nsTile][nl2].getNeibBest();
		for (int dir4 = 0; dir4 < 4; dir4++){
			if ((dir_mask & (1 << dir4)) != 0) {
				layers0[dir4][0] = neibs1[2 * dir4];
5366
				layers0[(dir4 + 1) % 4][1] = neibs2[(2 * (dir4 + 1)) % 8];
5367 5368
			}
			if ((dir_mask & (16 << dir4)) != 0) {
5369
				layers0[(dir4 + 1) % 4][0] = neibs1[(2 * (dir4 + 1)) % 8];
5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381
				layers0[dir4][1] = neibs2[2 * dir4];
			}
		}
		int [][] layers = new int[5][];
		int [] nsTiles = new int [5];
		nsTiles[4] = nsTile;
		for (int i = 0; i < 5; i++){
			if ((layers0[i][0] >=0 ) || (layers0[i][1] >=0 )) {
				if ((layers0[i][0] >=0 ) && (layers0[i][1] >=0 )){
					layers[i] = layers0[i].clone();
				} else {
					layers[i] = new int[1];
5382
					layers[i][0] = (layers0[i][0] >=0 ) ? layers0[i][0] : layers0[i][1];
5383
				}
5384

5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411
			} else {
				layers[i] = new int[0];
				nsTiles[i] = -1;
			}
		}
		for (int dir4 = 0; dir4 < 4; dir4++){
			nsTiles[dir4] = tnSurface.getNeibIndex(nsTile, 2 * dir4);
		}
		int [] diag_connections = new int [4];// number of variants for diagonal connections (1 or 2 where applicable)
		for (int dir4 = 0; dir4 < 4; dir4 ++){
			int dir4_next = (dir4 + 1) % 4;
			int dir_diag = (2 * dir4 + 3) % 8;
			diag_connections[dir4] = 0;
			for (int il1 = 0; il1 < layers[dir4].length; il1++){
				int [] neibs_s = planes[nsTiles[dir4]][layers[dir4][il1]].getNeibBest();
				for (int il2 = 0; il2 < layers[dir4_next].length; il2++){
					if (neibs_s[dir_diag] == layers[dir4_next][il2]) diag_connections[dir4] ++;
				}
			}
		}
		int num_vars = 1;
		for (int dir4 = 0; dir4 < 4; dir4 ++){
			if (layers[dir4].length > 0) num_vars *=2;
			// number of ways to connect diagonals, preserving same number of links
			if ((layers[dir4].length == 2) && (layers[(dir4 + 1) % 4].length == 2) && (diag_connections[dir4] == 1)) num_vars *= 2;
		}
		if (debugLevel > -1){
5412
			System.out.println("getTriangularResolutionVariants() nsTile = "+nsTile+" variants: "+num_vars+" (may be actually less)");
5413 5414 5415 5416 5417 5418 5419 5420
		}
		int [][][][] neib_vars = new int [num_vars][][][]; // [5][][];
		int [][][] neib_var_zero = new int [nsTiles.length][][];
		for (int i = 0; i < nsTiles.length; i++){
			if (layers[i].length > 0){
				neib_var_zero[i] = new int [planes[nsTiles[i]].length][];
				for (int nl = 0; nl < planes[nsTiles[i]].length; nl++){
					if (planes[nsTiles[i]][nl] != null){
5421
						neib_var_zero[i][nl] = planes[nsTiles[i]][nl].getNeibBest();
5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434
					}
				}
			}
		}
		 // [i][0] - which of the neighbors layers to connect to nl1, [i][1] which of the diagonal connections (if choice) to keep
		boolean [][] selection = new boolean [4][2];
		int var_num = 0;
		while(true){
			int [][][] neib_var = neib_var_zero.clone();
			for (int i = 0; i < neib_var_zero.length; i++) if (neib_var_zero[i] != null){
				neib_var[i] = neib_var_zero[i].clone();
				for (int nl = 0; nl < neib_var_zero[i].length; nl++) if (neib_var_zero[i][nl] != null){
					neib_var[i][nl] = neib_var_zero[i][nl].clone();
5435 5436
				}
			}
5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449
			// use current selection to build neib_vars[var_num]. Increment [var_num] if OK, not to skip invalid variants
			// start with connecting no nl1, then - to nl2 and finally - diagonals
			good_variant:
			{
				for (int dir4 = 0; dir4 < 4; dir4 ++){
					int dir4_next = (dir4 + 1) % 4;
					int dir_f = 2 * dir4;
					int dir_r = (dir_f +4 ) % 8;
					int dir12_f = (2 * dir4 + 3 ) % 8;
					int dir12_r = (dir12_f + 4 ) % 8;

					if (layers[dir4].length > 0) {
						if (layers[dir4].length > 1){
5450 5451 5452 5453
							neib_var[4][nl1][dir_f] = selection[dir4][0] ? layers[dir4][1] : layers[dir4][0];
							neib_var[4][nl2][dir_f] = selection[dir4][0] ? layers[dir4][0] : layers[dir4][1];
							neib_var[dir4][layers[dir4][0]][dir_r] = selection[dir4][0] ? nl2 : nl1;
							neib_var[dir4][layers[dir4][1]][dir_r] = selection[dir4][0] ? nl1 : nl2;
5454 5455 5456

						} else { // only 1 connection
							int other_layer = (neib_var_zero[4][nl1][dir_f] == layers[dir4][0]) ? neib_var_zero[4][nl2][dir_f] : neib_var_zero[4][nl1][dir_f];
5457 5458
							neib_var[4][nl1][dir_f] = selection[dir4][0] ? other_layer : layers[dir4][0];
							neib_var[4][nl2][dir_f] = selection[dir4][0] ? layers[dir4][0] : other_layer;
5459 5460
							neib_var[dir4][layers[dir4][0]][dir_r] = selection[dir4][0] ? nl2 : nl1;
							if (other_layer >= 0) { // only if it is connected
5461
								neib_var[dir4][other_layer][dir_r] = selection[dir4][0] ? nl1 : nl2; // null
5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477
							}
						}
						// diagonal connections - some make this variant invalid
						if (layers[dir4_next].length > 0) { // only add and verify connections if there are both radial connections
							int last_index_1 = (layers[dir4].length > 1) ? 1 :0;
							int last_index_2 = (layers[dir4_next].length > 1) ? 1 :0;
							int [][] neibs1_x = {neib_var_zero[dir4][layers[dir4][0]], // layers connected the first/single tile at dir4 from the center
									neib_var_zero[dir4][layers[dir4][last_index_1]]}; // layers connected the second/single tile at dir4 from the center
							int [][] neibs2_x = {
									neib_var_zero[dir4_next][layers[dir4_next][0]], // layers connected the first/single tile at dir4_next from the center
									neib_var_zero[dir4_next][layers[dir4_next][last_index_2]]}; // layers connected the last/single tile at dir4_next from the center
							// if there is a single variant. ( already connected)
							//if ((layers[dir4].length => 1)))
							if ((layers[dir4].length == 1) && (layers[dir4_next].length == 1)){ // 1 + 1
								if (selection[dir4][0] == selection[dir4_next][0]) continue; // no more checks - connected or not
								if (neibs1_x[0][dir12_f] != layers[dir4_next][0]) continue;     // not connected - keep whatever connections they had
5478
								// connected, but radials are to the to different layers - invalid
5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493
								break good_variant;
							} else if ((layers[dir4].length == 2) && (layers[dir4_next].length == 2)){ // 2 + 2
								if      (diag_connections[dir4] == 0) continue;
								// want to connect layers[dir4][0] (in the direction dir12_f) to :
								int want_10 = (selection[dir4][0] ^ selection[dir4_next][0]) ? layers[dir4_next][1] : layers[dir4_next][0];
								// want to connect layers[dir4][1] (in the direction dir12_f) to :
								int want_11 = (selection[dir4][0] ^ selection[dir4_next][0]) ? layers[dir4_next][0] : layers[dir4_next][1];
								// want to connect layers[dir4_next][0] (in the direction dir12_r) to :
								int want_20 = (selection[dir4][0] ^ selection[dir4_next][0]) ? layers[dir4][1] : layers[dir4][0];
								// want to connect layers[dir4_next][1] (in the direction dir12_rf) to :
								int want_21 = (selection[dir4][0] ^ selection[dir4_next][0]) ? layers[dir4][0] : layers[dir4][1];

								if (diag_connections[dir4] == 2) {
									neib_var[dir4][layers[dir4][0]][dir12_f] = want_10;
									neib_var[dir4][layers[dir4][1]][dir12_f] = want_11;
5494 5495
									neib_var[dir4_next][layers[dir4_next][0]][dir12_r] = want_20;
									neib_var[dir4_next][layers[dir4_next][1]][dir12_r] = want_21;
5496 5497 5498 5499 5500 5501 5502
								} else { // 1 connection, (possibly) 2 variants
									// if correct connection, skip second variant. If not - selection[dir4][1]==false - swap first pair, true - the second
									if ((want_10 == neibs1_x[0][dir12_f]) || (want_11 == neibs1_x[1][dir12_f])){
										// Already connected correctly, so just a single variant - skip the second one
										if (!selection[dir4_next][1]) continue;
										break good_variant; // prevent duplicate
									}
5503
									if (!selection[dir4_next][1]) {
5504 5505 5506
										neib_var[dir4][layers[dir4][0]][dir12_f] = neibs1_x[1][dir12_f];
										neib_var[dir4][layers[dir4][1]][dir12_f] = neibs1_x[0][dir12_f];
										// back links only if they existed
5507 5508
										if (neibs1_x[0][dir12_f] >= 0) neib_var[dir4_next][neibs1_x[0][dir12_f]][dir12_r] = layers[dir4][1];
										if (neibs1_x[1][dir12_f] >= 0) neib_var[dir4_next][neibs1_x[1][dir12_f]][dir12_r] = layers[dir4][0];
5509 5510 5511 5512
									} else {
										neib_var[dir4_next][layers[dir4_next][0]][dir12_r] = neibs2_x[1][dir12_r];
										neib_var[dir4_next][layers[dir4_next][1]][dir12_r] = neibs2_x[0][dir12_r];
										// back links only if they existed
5513 5514
										if (neibs2_x[0][dir12_r] >= 0) neib_var[dir4_next][neibs2_x[0][dir12_r]][dir12_f] = layers[dir4_next][1];
										if (neibs2_x[1][dir12_r] >= 0) neib_var[dir4_next][neibs2_x[1][dir12_r]][dir12_f] = layers[dir4_next][0];
5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528
									}
								}
							}  else {// remaining 2 + 1 and 1 + 2
								if (diag_connections[dir4] == 0) continue; // no links existed - nothing to do
								// here there was one link
								int conn_indx = (selection[dir4][0] ^ selection[dir4_next][0]) ? 1 : 0;
								int other_indx = 1 - conn_indx;
								if (layers[dir4].length == 1){
									if (neibs1_x[0][dir12_f] == layers[dir4_next][conn_indx]){
										continue; // already matched
									} else { // swap at dir4_next
										neib_var[dir4]     [layers[dir4][0]][dir12_f] = layers[dir4_next][conn_indx];
										neib_var[dir4_next][layers[dir4_next][conn_indx]][dir12_r] = layers[dir4][0];
										neib_var[dir4_next][layers[dir4_next][other_indx]][dir12_r] = neibs2_x[conn_indx][dir12_r];
5529
										if (neibs2_x[conn_indx][dir12_r] >= 0) neib_var[dir4][neibs2_x[conn_indx][dir12_r]][dir12_f] = layers[dir4_next][other_indx];
5530 5531 5532 5533 5534 5535 5536 5537
									}
								} else {
									if (neibs2_x[0][dir12_r] == layers[dir4][conn_indx]){
										continue; // already matched
									} else { // swap at dir4
										neib_var[dir4_next][layers[dir4_next][0]]         [dir12_r] = layers[dir4]     [conn_indx];
										neib_var[dir4]     [layers[dir4]     [conn_indx]] [dir12_f] = layers[dir4_next][0];
										neib_var[dir4]     [layers[dir4]     [other_indx]][dir12_f] = neibs1_x[conn_indx][dir12_f];
5538
										if (neibs1_x[conn_indx][dir12_f] >= 0) neib_var[dir4_next][neibs1_x[conn_indx][dir12_f]][dir12_r] = layers[dir4][other_indx];
5539 5540 5541
									}
								}
							}
5542

5543 5544 5545 5546 5547 5548 5549
						}
					}
				}
				neib_vars[var_num++] = neib_var;
			}
			// calculate next selection
			next_sel:{
5550
				for (int dir4 = 3; dir4 >= 0; dir4--){
5551 5552 5553
					if (!selection[dir4][1] && (layers[dir4].length == 2) && (layers[(dir4 + 1) % 4].length == 2) && (diag_connections[dir4] == 1)){
						selection[dir4][1] = true;
						break next_sel;
5554 5555
//					} else if (!selection[dir4][0] && (layers[dir4].length > 1)){
					} else if (!selection[dir4][0] && (layers[dir4].length > 0)){
5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567
						selection[dir4][0] = true;
						selection[dir4][1] = false;
						break next_sel;
					} else {
						selection[dir4][0] = false;
						selection[dir4][1] = false;
					}
				}
				break; // while(true) - all done
			}
		}
// trim neib_vars
5568 5569 5570
		if (debugLevel > -1){
			System.out.println("getTriangularResolutionVariants() nsTile = "+nsTile+" ACTUAL variants: "+var_num);
		}
5571 5572 5573
		if (var_num == neib_vars.length) return neib_vars;
		int [][][][] neib_vars_trimmed = new int [var_num][][][];
		for (int i = 0; i < var_num; i++ ) neib_vars_trimmed[i] = neib_vars[i];
5574 5575

		return neib_vars_trimmed;
5576
	}
5577

5578
	public void resolveConflicts(
5579
			LinkPlanes lp,
5580 5581 5582 5583
			double     maxEigen,      // maximal eigenvalue of planes to consider
	  		boolean    conflDualTri,  // Resolve dual triangles conflict (odoodo)
	  		boolean    conflMulti,    // Resolve multiple odo triangles conflicts
	  		boolean    conflDiag,     // Resolve diagonal (ood) conflicts
5584
	  		boolean    conflStar,     // Resolve all conflicts around a supertile
5585 5586 5587
			int        starSteps, // How far to look around when calculationg connection cost
			double     orthoWeight,
			double     diagonalWeight,
5588 5589 5590
			double     starPwr,         // Divide cost by number of connections to this power
			double     starWeightPwr,   // Use this power of tile weight when calculating connection cost
			double     weightToDens,    // // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5591
			double     starValPwr, //  Raise value of each tile before averaging
5592
			double     dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
Andrey Filippov's avatar
Andrey Filippov committed
5593
			boolean    newConfl, // Allow more conflicts if overall cost is reduced
5594
			int        maxChanges,  // Maximal number of simultaneous connection changes around one tile (0 - any)
5595
			boolean    preferDisparity,
5596 5597 5598
			int        debugLevel,
			int        dbg_X,
			int        dbg_Y)
5599

5600
	{
5601 5602
		lp.calcStarValueStrength(
				true, // boolean set_start_planes,
5603 5604 5605
				orthoWeight,      // final double         orthoWeight,
				diagonalWeight,   // final double         diagonalWeight,
				starPwr,          // final double         starPwr,    // Divide cost by number of connections to this power
5606
				starWeightPwr,    // final double         starWeightPwr,    // Use this power of tile weight when calculating connection cost
5607
				weightToDens,     // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5608
				starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
5609 5610
				starSteps,        // final int            steps,
				this.planes,      // final TilePlanes.PlaneData [][] planes,
5611 5612
				preferDisparity,  // final boolean        preferDisparity)
				debugLevel);
5613 5614

		Conflicts iconflicts0 = new Conflicts(this);
5615 5616 5617 5618 5619
		int [][][] conflicts0 = iconflicts0.detectTriangularConflicts(
				1); // final int debugLevel)
		Conflicts conflicts0_stats =  new Conflicts(
				conflicts0,
				this,
5620 5621
				-1); // debugLevel);

5622
		for (int pass = 0; pass < 10; pass ++) {
5623 5624
			int [] dual_tri_results =            {0,0};
			int [] multi_resoultion_results =    {0,0};
5625
			int [] diagonal_resoultion_results = {0,0};
5626 5627 5628 5629 5630 5631
			int [] conflict_star_results = 	     {0,0};
			if (conflDualTri) {
				dual_tri_results = resolveDualTriangularConflicts(
						conflicts0, // int [][][] conflicts,
						conflicts0_stats,
						maxEigen,
5632
						starSteps, // How far to look around when calculating connection cost
5633 5634 5635
						orthoWeight, // double     orthoWeight,
						diagonalWeight, // double     diagonalWeight,
						starPwr,        // double     starPwr, // Divide cost by number of connections to this power
5636 5637
						starWeightPwr,    // Use this power of tile weight when calculating connection cost
						weightToDens,    // // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5638
						starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653
						dblTriLoss, // double     diagonalWeight,
						preferDisparity,
						debugLevel, // 1, //  final int debugLevel)
						dbg_X,
						dbg_Y);
				System.out.println("Pass "+(pass+1)+": dual_tri_results (success/failures) = "+dual_tri_results[0]+" / "+dual_tri_results[1]);
			}
			if (conflMulti) {
				multi_resoultion_results = resolveMultiTriangularConflicts(
						conflicts0, // int [][][] conflicts,
						conflicts0_stats,
						starSteps, // How far to look around when calculationg connection cost
						orthoWeight, // double     orthoWeight,
						diagonalWeight, // double     diagonalWeight,
						starPwr,        // double     starPwr, // Divide cost by number of connections to this power
5654
						starWeightPwr,    // Use this power of tile weight when calculating connection cost
5655
						weightToDens,    // // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5656
						starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671
						dblTriLoss, // double     diagonalWeight,
						preferDisparity,
						debugLevel, // 1, //  final int debugLevel)
						dbg_X,
						dbg_Y);
				System.out.println("Pass "+(pass+1)+": multi_tri_results (success/failures) = "+multi_resoultion_results[0]+" / "+multi_resoultion_results[1]);
			}
			if (conflDiag) {
				diagonal_resoultion_results = resolveDiagonalTriangularConflicts(
						conflicts0, // int [][][] conflicts,
						conflicts0_stats,
						starSteps, // How far to look around when calculationg connection cost
						orthoWeight, // double     orthoWeight,
						diagonalWeight, // double     diagonalWeight,
						starPwr,        // double     starPwr, // Divide cost by number of connections to this power
5672
						starWeightPwr,    // Use this power of tile weight when calculating connection cost
5673
						weightToDens,    // // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5674
						starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
5675 5676 5677 5678 5679 5680
						dblTriLoss, // double     diagonalWeight,
						preferDisparity,
						((pass == 3)? 1: 0), // debugLevel, // 1, //  final int debugLevel)
						dbg_X,
						dbg_Y);
				System.out.println("Pass "+(pass+1)+": resolveDiagonalTriangularConflicts (success/failures) = "+diagonal_resoultion_results[0]+" / "+diagonal_resoultion_results[1]);
5681
			}
5682 5683 5684 5685
			if (conflStar) {
				conflict_star_results = 	resolveStarConflicts(
						conflicts0, // int [][][] conflicts,
						conflicts0_stats,
5686
						lp, // LinkPlanes lp,
5687 5688 5689 5690
						starSteps, // How far to look around when calculationg connection cost
						orthoWeight, // double     orthoWeight,
						diagonalWeight, // double     diagonalWeight,
						starPwr,        // double     starPwr, // Divide cost by number of connections to this power
5691
						starWeightPwr,    // Use this power of tile weight when calculating connection cost
5692
						weightToDens,    // // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5693
						starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
5694
						dblTriLoss, // double     diagonalWeight,
Andrey Filippov's avatar
Andrey Filippov committed
5695
						newConfl, // Allow more conflicts if overall cost is reduced
5696
						maxChanges,     // int        maxChanges,  // Maximal number of simultaneous connection changes around one tile (0 - any)
5697 5698 5699 5700 5701 5702
						preferDisparity,
						debugLevel, // 1, //  final int debugLevel)
						dbg_X,
						dbg_Y);
				System.out.println("Pass "+(pass+1)+": resolveStarConflicts (success/failures) = "+conflict_star_results[0]+" / "+conflict_star_results[1]);
			}
5703 5704

			if (    (dual_tri_results[0] == 0) &&
5705 5706 5707
					(multi_resoultion_results[0] == 0) &&
					(diagonal_resoultion_results[0] == 0) &&
					(conflict_star_results[0] ==       0)) {
5708 5709 5710 5711 5712 5713 5714
				System.out.println("No more improvements");
				break;
			}
		}
		Conflicts conflicts1_stats =  new Conflicts(
				conflicts0,
				this,
5715
				1); // -1); // debugLevel);
5716 5717 5718 5719

		conflicts1_stats.printConflictSummary("Detected conflicts (all):", true,false,false);
		conflicts1_stats.printConflictSummary("Detected conflicts (ortho-diag-ortho):", false, true,false);
		conflicts1_stats.printConflictSummary("Detected conflicts(ortho-ortho-diag):", false, false, true);
5720

5721 5722 5723 5724 5725
		iconflicts0.resetConflicts();
		conflicts0 = iconflicts0.detectTriangularConflicts(
				1); // final int debugLevel)
		conflicts1_stats.printConflictSummary("Recounted conflicts (all):", true,false,false);
		conflicts1_stats.printConflictSummary("Recounted conflicts (ortho-diag-ortho):", false, true,false);
5726
		conflicts1_stats.printConflictSummary("Recounted conflicts (ortho-ortho-diag):", false, false, true);
5727 5728


5729
	}
5730 5731 5732 5733 5734 5735 5736 5737








5738 5739
	public int [] resolveDualTriangularConflicts(
			int [][][] conflicts,
5740
			Conflicts conflict_stats, // to be updated after applying resolution
5741
			double     maxEigen, // maximal eigenvalue of planes to consider
5742
			int        starSteps, // How far to look around when calculationg connection cost
5743 5744
			double     orthoWeight,
			double     diagonalWeight,
5745
			double     starPwr, // Divide cost by number of connections to this power
5746 5747
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
			double     weightToDens,    // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5748
			double     starValPwr, //  Raise value of each tile before averaging
5749
			double     dblTriLoss, //  When resolving double triangles allow minor degradation (0.0 - strict)
5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761
			boolean    preferDisparity,
			int        debugLevel,
			int        dbg_X,
			int        dbg_Y)
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
		final int stilesX =       (tilesX + superTileSize -1)/superTileSize;
		final int stilesY =       (tilesY + superTileSize -1)/superTileSize;
		final int dbgTile = dbg_Y * stilesX + dbg_X;
5762
		final TileNeibs tnSurface = new TileNeibs(stilesX, stilesY);
5763
		final Conflicts iconflicts = new Conflicts(this);
5764

5765 5766
		int [] rslt = {0,0};
		for (int nsTile = 0; nsTile < conflicts.length; nsTile++) if (conflicts[nsTile] != null) {
5767 5768
			// conflicts may disappear after being fixed, recheck for null
			for (int nConfl = 0; (conflicts[nsTile] != null) && (nConfl < conflicts[nsTile].length); nConfl++){
5769
				Conflict confl = new Conflict(nsTile, conflicts[nsTile][nConfl]); // getDualTriOrthoDiagOrthoConflicts
5770 5771
//				if (numDualTri(conflicts[nsTile][nConfl][2]) > 0) {
				if (confl.getDualTriOrthoDiagOrthoConflicts() > 0) {
5772
					for (int dir4 = 0; dir4 < 4; dir4 ++ ){
5773 5774
						// conflicts may disappear after being fixed, recheck for null
						if ((conflicts[nsTile] != null) && (conflicts[nsTile][nConfl] != null) && ((conflicts[nsTile][nConfl][2] & (1 << dir4)) > 0) && ((conflicts[nsTile][nConfl][2] & (16 << dir4)) > 0)) {
5775
							if (debugLevel > 0) { //1){
5776 5777 5778 5779
								System.out.println("resolveDualTriangularConflicts(): resolving dual triangular conflict for tile "+nsTile+
										", nl1 = "+conflicts[nsTile][nConfl][0]+
										", nl2 = "+conflicts[nsTile][nConfl][1]+
										", dir4 = "+dir4);
5780 5781 5782
								if (nsTile == dbgTile){
									System.out.println("resolveDualTriangularConflicts(): nsTile == dbgTile");
								}
5783 5784 5785 5786 5787 5788 5789
							}
							boolean [] dual_resol = resolveDualTriangularConflict(
									nsTile,
									conflicts[nsTile][nConfl][0],
									conflicts[nsTile][nConfl][1],
									dir4,
									maxEigen, // maximal eigenvalue of planes to consider
5790
									starWeightPwr,    // Use this power of tile weight when calculating connection cost
5791 5792 5793 5794
									tnSurface,
									preferDisparity,
									debugLevel + ((nsTile == dbgTile)? 1 : 0));
							if (dual_resol == null){
5795
								if (debugLevel > 1) {
5796 5797 5798 5799 5800 5801 5802
									System.out.println("resolveDualTriangularConflicts(): resolving dual triangular conflict for tile "+nsTile+
											", nl1 = "+conflicts[nsTile][nConfl][0]+
											", nl2 = "+conflicts[nsTile][nConfl][1]+
											", dir4 = "+dir4+"FAILED");
									rslt[1]++;
								}
							} else {
5803
								if (debugLevel > 1) {
5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819
									System.out.println("resolveDualTriangularConflicts(): resolving dual triangular conflict for tile "+nsTile+
											", nl1 = "+conflicts[nsTile][nConfl][0]+
											", nl2 = "+conflicts[nsTile][nConfl][1]+
											", dir4 = "+dir4+" RESOLVED:");
									if (dual_resol[0])	System.out.println("swap links in dir4 = "+dir4);
									if (dual_resol[1])	System.out.println("swap links in dir4 = "+((dir4 + 1) % 4));
									if (dual_resol[2])	System.out.println("swap links in a digonal between dir4 = "+dir4+" and "+((dir4 + 1) % 4));
								}
								// calculate cost of swap
								int [] mod_supertiles = {
										nsTile,
										tnSurface.getNeibIndex(nsTile, 2 * dir4),
										tnSurface.getNeibIndex(nsTile, 2 * ((dir4 + 1) % 4))};
								int nl1 = conflicts[nsTile][nConfl][0];
								int nl2 = conflicts[nsTile][nConfl][1];

5820 5821 5822 5823
								ConnectionCosts connectionCosts = new ConnectionCosts(
										orthoWeight,
										diagonalWeight,
										starPwr,    // Divide cost by number of connections to this power
5824
										starWeightPwr,    // Use this power of tile weight when calculating connection cost
5825
										weightToDens,    // // Balance weighted density against density. 0.0 - density, 1.0 - weighted density
5826
										starValPwr,      //double     starValPwr, //  Raise value of each tile before averaging
5827 5828 5829 5830
										starSteps,
										this.planes,
										tnSurface,
										preferDisparity);
5831
								int [][][] neibs_prev = connectionCosts.initConnectionCosts(mod_supertiles, debugLevel);
5832 5833

								int [][][] neibs_prev_old = new int [mod_supertiles.length][][];
5834
								double [][][]  val_weights = new double [mod_supertiles.length][][];
5835
								updateConnectionsCost_old (
5836
										mod_supertiles,      // int []         nsTiles,
5837
										null,         // int [][][]     neibs_prev,
5838
										neibs_prev_old,   // int [][][]     neibs,		// should be initialized at top dimension if neibs_prev==null
5839 5840 5841
										val_weights,  // double [][][]  val_weights, // should be initialized at top dimension if neibs_prev==null
										orthoWeight,
										diagonalWeight,
5842
										starPwr,        // double     starPwr, // Divide cost by number of connections to this power
5843
										starWeightPwr,    // Use this power of tile weight when calculating connection cost
5844 5845 5846
										tnSurface,
										preferDisparity,
										debugLevel);
5847

5848 5849 5850 5851 5852 5853 5854 5855 5856
								int [][][] neibs = neibs_prev.clone();
								for (int i = 0; i < neibs.length; i++) if (neibs_prev[i] != null){
									neibs[i] = neibs_prev[i].clone();
									for (int j = 0; j < neibs[i].length; j++) if (neibs_prev[i][j] != null){
										neibs[i][j] = neibs_prev[i][j].clone();
									}
								}
								//apply swaps:
//								int [] indices = {tile_index.get
5857
								int dir1f = 2 * dir4;
5858
								int dir1r = (2 * dir4 + 4) % 8;
5859
								int dir2f = (2 * dir4 + 3) % 8;
5860
								int dir2r = (2 * dir4 + 7) % 8;
5861
								int dir3f = (2 * dir4 + 6) % 8;
5862 5863 5864 5865 5866 5867 5868 5869
								int dir3r = (2 * dir4 + 2) % 8;
								int nl1_1 = neibs_prev[0][nl1][dir1f]; // layer on the first that was connected from nl1->N
								int nl2_1 = neibs_prev[0][nl2][dir1f]; // layer on the first that was connected from nl2->N
								int nl1_2 = neibs_prev[1][nl1_1][dir2f]; // layer on second that was connected from nl1->N->SE
								int nl2_2 = neibs_prev[1][nl2_1][dir2f]; // layer on second that was connected from nl2->N->SE
								//  2->0 was already swapped

								if (dual_resol[0])	{
5870
									if (debugLevel > 0) System.out.println("swapping links in dir4 = "+dir4);
5871
									neibs[0][nl1][dir1f] = neibs_prev[0][nl2][dir1f];
5872
									neibs[0][nl2][dir1f] = neibs_prev[0][nl1][dir1f];
5873 5874 5875
									neibs[1][nl1_1][dir1r] = neibs_prev[1][nl2_1][dir1r];
									neibs[1][nl2_1][dir1r] = neibs_prev[1][nl1_1][dir1r];

5876 5877
								}
								if (dual_resol[1])	{
5878
									if (debugLevel > 0) System.out.println("swapping links in dir4 = "+((dir4 + 1) % 4));
5879
									neibs[0][nl1][dir3r] = neibs_prev[0][nl2][dir3r];
5880
									neibs[0][nl2][dir3r] = neibs_prev[0][nl1][dir3r];
5881 5882
									neibs[2][nl1_2][dir3f] = neibs_prev[2][nl2_2][dir3f];
									neibs[2][nl2_2][dir3f] = neibs_prev[2][nl1_2][dir3f];
5883 5884
								}
								if (dual_resol[2]){
5885
									if (debugLevel > 0) System.out.println("swapping links in a digonal between dir4 = "+dir4+" and "+((dir4 + 1) % 4));
5886
									neibs[1][nl1_1][dir2f] = neibs_prev[1][nl2_1][dir2f];
5887
									neibs[1][nl2_1][dir2f] = neibs_prev[1][nl1_1][dir2f];
5888 5889 5890

									neibs[2][nl1_2][dir2r] = neibs_prev[2][nl2_2][dir2r];
									neibs[2][nl2_2][dir2r] = neibs_prev[2][nl1_2][dir2r];
5891
								}
5892

5893 5894 5895
								double cost_diff = 	connectionCosts.getConnectionsCostDiff(
										neibs,
										debugLevel);
5896

5897 5898 5899 5900 5901 5902
								if (debugLevel > 0) {
									System.out.println("resolveDualTriangularConflicts(): resolving dual triangular conflict for tile "+nsTile+
											", nl1 = "+conflicts[nsTile][nConfl][0]+
											", nl2 = "+conflicts[nsTile][nConfl][1]+
											", dir4 = "+dir4+" improvement (negative diff) = "+cost_diff);
								}
5903

5904
								double cost_diff_old = 	updateConnectionsCost_old (
5905 5906
										mod_supertiles, // int []         nsTiles,
										neibs_prev,     // int [][][]     neibs_prev,
5907
										neibs,          // int [][][]     neibs,		// should be initialized at top dimension if neibs_prev==null
5908
										val_weights,    // double [][][]  val_weights, // should be initialized at top dimension if neibs_prev==null
5909 5910
										orthoWeight,
										diagonalWeight,
5911
										starPwr,        // double     starPwr, // Divide cost by number of connections to this power
5912
										starWeightPwr,    // Use this power of tile weight when calculating connection cost
5913 5914 5915
										tnSurface,
										preferDisparity,
										debugLevel);
5916

5917
								if (debugLevel > 0) {
5918
									System.out.println("resolveDualTriangularConflicts()_OLD: resolving dual triangular conflict for tile "+nsTile+
5919 5920
											", nl1 = "+conflicts[nsTile][nConfl][0]+
											", nl2 = "+conflicts[nsTile][nConfl][1]+
5921
											", dir4 = "+dir4+" improvement (negative diff) = "+cost_diff_old);
5922
								}
5923 5924 5925 5926 5927 5928 5929 5930 5931 5932
								if (cost_diff < dblTriLoss) {
									if (debugLevel > 1) {
										if (cost_diff > 0 ) {
											System.out.println("resolveDualTriangularConflicts(): Score is WORSE, but degrading is less than "+
													dblTriLoss+", considered OK.");
										} else {
											System.out.println("resolveDualTriangularConflicts(): SUCCESS");
										}
									}
									// See how this application will influence number of conflicts
5933
									// All supertiles that may have different conflicts
5934 5935 5936 5937 5938 5939 5940 5941 5942 5943
									int [] nsTiles = getInvolvedSupertiles( // first 3 entries will be mod_supertiles[]
											mod_supertiles,
											tnSurface);
									HashMap<Integer,Integer> replacement_tiles = new HashMap<Integer,Integer>();
									for (int i = 0; i < mod_supertiles.length; i++){
										replacement_tiles.put(mod_supertiles[i], new Integer(i));
									}
									int [][][] conflicts_old = new int [nsTiles.length][][];
									int [][][] conflicts_new = new int [nsTiles.length][][];
									for (int isTile = 0; isTile < nsTiles.length; isTile++){
5944
										conflicts_old[isTile] = iconflicts.detectTriangularTileConflicts(
5945 5946 5947
												nsTiles[isTile],   // int nsTile0,
												replacement_tiles, //HashMap<Integer,Integer> replacement_tiles, //
												neibs_prev, // int [][][] replacement_neibs,
5948
												tnSurface); // TileNeibs tnSurface)
5949
										conflicts_new[isTile] = iconflicts.detectTriangularTileConflicts(
5950 5951 5952
												nsTiles[isTile],   // int nsTile0,
												replacement_tiles, //HashMap<Integer,Integer> replacement_tiles, //
												neibs, // int [][][] replacement_neibs,
5953
												tnSurface); // TileNeibs tnSurface)
5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965
									}
									if (debugLevel > 1) {
										System.out.println("Involved supertiles:");
										for (int i = 0; i < nsTiles.length; i++){
											System.out.println(i+":"+nsTiles[i]);
										}
									}

									if (debugLevel > 1) {
										System.out.println("Calculating original conflicts");
									}

5966 5967
									iconflicts.addConflicts(conflicts_old,
											debugLevel - 1); // debugLevel);
5968 5969 5970
									if (debugLevel > 1) {
										System.out.println("Calculating resolved conflicts");
									}
5971 5972 5973 5974 5975
									Conflicts conflict_stats_new = new Conflicts(
											conflicts_new,
											this,
											debugLevel - 1); // debugLevel);
									conflict_stats_new.subConflicts(iconflicts);
5976

5977
									if (debugLevel > 0) {
5978
										/*
5979
										System.out.print("Conflicts difference after resolution:");
5980 5981 5982 5983
										printConflictSummary(conflict_stats_diff);
										*/
										conflict_stats_new.printConflictSummary(
												"Conflicts difference after resolution:", true, true, false);
5984

5985
									}
5986 5987
									if ((conflict_stats_new.getNumOrthoIncompat() >= 0) && (cost_diff > -dblTriLoss)){
										//getNumOrthoIncompat
5988 5989 5990 5991 5992 5993
										if (debugLevel > 1) {
											System.out.println("Number of incompatible triangles is not reduced and no significant cost reduction, resolution WILL NOT BE APPLIED");
										}
										rslt[1]++;
									} else {
										if (debugLevel > 0) {
5994
											if (conflict_stats_new.getNumOrthoIncompat() < 0) {
5995 5996 5997 5998 5999 6000
												System.out.println("Number of incompatible triangles is reduced, resolution WILL BE APPLIED");
											} else {
												System.out.println("Number of incompatible triangles is not reduced but a good cost reduction, resolution WILL BE APPLIED");
											}
										}
										// update statistics
6001 6002
										conflict_stats.addConflicts(conflict_stats_new);

6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013
										// update conflict
										for (int i = 0; i < nsTiles.length; i++){
											conflicts[nsTiles[i]]=  conflicts_new[i];
										}
										// apply resolution
										for (int i = 0; i < mod_supertiles.length; i++){
											for (int nl = 0; nl < neibs[i].length; nl ++) if (neibs[i][nl] != null){
												planes[mod_supertiles[i]][nl].setNeibBest(neibs[i][nl]);
											}
										}
										rslt[0]++;
6014 6015
									}
								} else {
6016
									if (debugLevel > 0) {
6017 6018 6019 6020 6021
										System.out.println("resolveDualTriangularConflicts(): FAILURE");
									}
									rslt[1]++;
								}
							}
6022 6023
						}
					}
6024 6025 6026 6027 6028
				}
			}
		}
		return rslt;
	}
6029 6030


6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042
	/**
	 *  Resolve dual triangle, where NL1 -> N -> SE -> W -> NL2 -> N -> SE -> W -> NL1 (or similar)
	 * @param nsTile supertile index
	 * @param nl1 first conflicting layer (lower of the too
	 * @param nl2 second conflicting layer
	 * @param dir4 start direction to (turn right)  0 - N, 1 - E, 2 - S, 3 - W
	 * @param maxEigen maximal sum of 2 eigenvalues of the tri-plane combinations
	 * @param tnSurface TileNeibs instance to navigate tile index and control array borders
	 * @param preferDisparity - the first eigenvalue/vector is the most disparity-like
	 *                          (false - smallest eigenvalue)
	 * @param debugLevel
	 * @return links to swap : [0] first in dir, [1] - first in dir + 1, [2] - other diagonal. Or null if failed
6043
	 * total number of bits set is odd
6044 6045 6046 6047 6048 6049 6050
	 */
	public boolean [] resolveDualTriangularConflict(
			int nsTile,
			int nl1,
			int nl2,
			int dir4,
			double maxEigen, // maximal eigenvalue of planes to consider
6051
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
6052
			TileNeibs tnSurface,
6053 6054 6055 6056 6057 6058 6059 6060 6061
			boolean preferDisparity,
			int debugLevel)
	{
		int [] neibs1 = planes[nsTile][nl1].getNeibBest();
		int [] neibs2 = planes[nsTile][nl2].getNeibBest();
		int dir1 = 2 * dir4;
		int dir2 = (2 * dir4 + 2) % 8;
		int nsTile1 = tnSurface.getNeibIndex(nsTile, dir1);
		int nsTile2 = tnSurface.getNeibIndex(nsTile, dir2);
6062

6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075
		TilePlanes.PlaneData [][] tri_pd = {
				{planes[nsTile][nl1], planes[nsTile][nl2]},
				{planes[nsTile1][neibs1[dir1]], planes[nsTile1][neibs2[dir1]]},
				{planes[nsTile2][neibs1[dir2]], planes[nsTile2][neibs2[dir2]]}};
		TilePlanes.PlaneData [][] tri_merged = new TilePlanes.PlaneData [4][2]; // keep to the very end for debugging
		// initial connections: [0][0] -> [1][0] -> [2][1] -> [0][1] -> [1][1]-> [2][0] -> [0][0]
		// 4 variants for 3-supertile sets. get with smallest sum of the 2 main eigenvalues, as long as each
		// is below maxEigen
		if (debugLevel > 1) {
			System.out.println ("resolveDualTriangularConflict() + nsTile = "+nsTile+", nl1 = "+nl1+", nl2 = "+nl2+" dir4="+dir4);
		}
		double [][] ev_variants = new double [4][2];
		int best_pair = -1;
6076
		double best_value = Double.NaN;
6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089
		for (int variant = 0; variant < 4; variant++){
			TilePlanes.PlaneData [][] tri_sets = {
					{tri_pd[0][0], tri_pd[1][    (variant & 1)], tri_pd[2][    ((variant >> 1) & 1)]},
					{tri_pd[0][1], tri_pd[1][1 - (variant & 1)], tri_pd[2][1 - ((variant >> 1) & 1)]}};
			for (int nt = 0; nt < tri_sets.length; nt++){
				TilePlanes.PlaneData tri_plane = tri_sets[nt][0];
				for (int indx = 1; indx <  tri_sets[nt].length; indx++){
					TilePlanes.PlaneData other_plane = tri_sets[nt][0].getPlaneToThis(  // layer here does not matter
							tri_sets[nt][indx],
							debugLevel - 2); // debugLevel);
					tri_plane = tri_plane.mergePlaneToThis(
							other_plane,     // PlaneData otherPd,
							1.0,             // double    scale_other,
6090
							starWeightPwr,    // Use this power of tile weight when calculating connection cost
6091 6092
							false,           // boolean   ignore_weights,
							true,            // boolean   sum_weights,
6093
							preferDisparity,
6094 6095
							debugLevel - 2); // int       debugLevel)
				}
6096 6097
//				ev_variants[variant][nt] = tri_plane.getValue();
				ev_variants[variant][nt] = tri_plane.getNormValue();
6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120
				tri_merged[variant][nt] = tri_plane;
			}
			if ((best_pair < 0) || ((ev_variants[variant][0] + ev_variants[variant][1]) < best_value)){
				best_value = ev_variants[variant][0] + ev_variants[variant][1];
				best_pair = variant;
			}
			if (debugLevel > 1) {
				System.out.println ("variant="+variant+" value1="+ev_variants[variant][0]+
						" value2="+ev_variants[variant][1]+" sum value = "+(ev_variants[variant][0]+ev_variants[variant][1]));
			}
		}
		if (debugLevel > 1) {
			System.out.println ("resolveDualTriangularConflict() + nsTile = "+nsTile+", nl1 = "+nl1+", nl2 = "+nl2+" dir4="+dir4+" best variant ="+ best_pair);
		}
		if (best_value < maxEigen) {
			boolean [] rslt = {
					((best_pair & 1) != 0),
					((best_pair & 2) != 0),
					false};
			rslt[2] = !rslt[0] ^ rslt[1];
			return rslt;
		}
		return null;
6121 6122
	}

6123 6124 6125 6126 6127 6128 6129
	/**
	 * Calculate main eigenvalue of the current plane and all connected ones - used to estimate advantage of connection swap
	 * @param nsTile supertile index
	 * @param nl surface layer
	 * @param neibs array of 8 neighbors layers (N,NE,...NW), -1 - not connected
	 * @param orthoWeight multiply contribution of ortho neighbors
	 * @param diagonalWeight  multiply contribution of diagonal neighbors
6130
	 * @param diagonalWeight  divide value by number of connections to this power (if !=0)
6131 6132 6133 6134 6135 6136
	 * @param tnSurface TileNeibs instance to navigate tile index and control array borders
	 * @param preferDisparity - the first eigenvalue/vector is the most disparity-like
	 *                          (false - smallest eigenvalue)
	 * @param debugLevel
	 * @return a pair of eigenvalue of the combine plane and its weight
	 */
6137

6138
	public double [] getStarValueWeight_old(
6139 6140 6141 6142 6143
			int    nsTile,
			int    nl,
			int [] neibs,
			double orthoWeight,
			double diagonalWeight,
6144
			double starPwr,    // Divide cost by number of connections to this power
6145
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
6146
			TileNeibs tnSurface,
6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159
			boolean preferDisparity,
			int    debugLevel)
	{
		TilePlanes.PlaneData merged_plane = planes[nsTile][nl];
		for (int dir = 0; dir < 8; dir++){
			if (neibs[dir] >= 0){
				double other_weight = ((dir & 1) != 0) ? diagonalWeight : orthoWeight;
				TilePlanes.PlaneData other_plane = merged_plane.getPlaneToThis(  // layer here does not matter
						planes[tnSurface.getNeibIndex(nsTile, dir)][neibs[dir]],
						debugLevel - 1); // debugLevel);
				merged_plane = merged_plane.mergePlaneToThis(
						other_plane,     // PlaneData otherPd,
						other_weight,    // double    scale_other,
6160
						starWeightPwr,   // Use this power of tile weight when calculating connection cost
6161 6162
						false,           // boolean   ignore_weights,
						true,            // boolean   sum_weights,
6163
						preferDisparity,
6164 6165 6166
						debugLevel - 1); // int       debugLevel)
			}
		}
6167 6168
//		double [] value_weight = {merged_plane.getValue(),merged_plane.getWeight()};
		double [] value_weight = {merged_plane.getNormValue(),merged_plane.getWeight()};
6169 6170 6171 6172 6173 6174
		if (starPwr != 0){
			value_weight[0] /= (Math.pow((planes[nsTile][nl].getNumNeibBest() + 1.0), starPwr));
		}
		return value_weight;
	}

6175 6176 6177 6178 6179 6180 6181
	/**
	 * Calculate array of supertile indices that need to have connection cost recalculated when they are updated
	 * first entries of the result will be the same in input array
	 * @param mod_supertiles array of supertile indices that will be modified
	 * @param tnSurface TileNeibs instance to navigate tile index and control array borders
	 * @return array of supertile indices to watch connection cost
	 */
6182 6183


6184 6185
	public int [] getInvolvedSupertiles(
			int [] mod_supertiles,
6186
			TileNeibs tnSurface)
6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206
	{
		HashSet<Integer> stiles_set = new HashSet<Integer>();
		for (int i = 0; i < mod_supertiles.length; i++){
			stiles_set.add(new Integer(mod_supertiles[i]));
			for (int dir = 0; dir < 8; dir++){
				Integer nsTile = tnSurface.getNeibIndex(mod_supertiles[i], dir);
				if (nsTile >= 0) stiles_set.add (nsTile);
			}
		}
		int [] stiles = new int [stiles_set.size()];
		int indx = 0;
		for (; indx < mod_supertiles.length; indx++){
			stiles_set.remove(new Integer(mod_supertiles[indx]));
			stiles[indx] = mod_supertiles[indx];
		}
		for (Integer nsTile: stiles_set){
			stiles[indx++] = nsTile;
		}
		return stiles;
	}
6207

6208 6209 6210 6211
	/**
	 * Update cost of involved connections after swapping some of them. Total number of links should probably stay
	 *  the same.
	 * @param nsTiles array of indices of the supertiles to watch
6212
	 * @param neibs_prev 3-d array [per supertile index][per layer][per direction] of previous connections for which
6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225
	 * the cost was already calculated. Or null - in that case established connections will be used and returned in
	 * neibs array
	 * @param neibs new connections to calculate cost for. If neibs_prev == null, this array should be initialized
	 * by the caller as new int [nsTiles.length][][]
	 * @param val_weights array of values*weights and weights per supertile index, per layer of {val*weight, weight}
	 * @param orthoWeight multiply contribution of ortho neighbors
	 * @param diagonalWeight  multiply contribution of diagonal neighbors
	 * @param tnSurface TileNeibs instance to navigate tile index and control array borders
	 * @param preferDisparity - the first eigenvalue/vector is the most disparity-like
	 *                          (false - smallest eigenvalue)
	 * @param debugLevel
	 * @return difference between new cost and old cost, negative means improvement
	 */
6226 6227


6228
	public double updateConnectionsCost_old (
6229 6230
			int []         nsTiles,
			int [][][]     neibs_prev,
6231
			int [][][]     neibs,		// should be initialized at top dimension if neibs_prev==null
6232
			double [][][]  val_weights, // should be initialized at top dimension if neibs_prev==null
6233 6234 6235
			double         orthoWeight,
			double         diagonalWeight,
			double         starPwr,    // Divide cost by number of connections to this power
6236
			double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
6237
			TileNeibs tnSurface,
6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249
			boolean preferDisparity,
			int    debugLevel)
	{
		if (neibs_prev == null){
//			neibs_prev = new int [nsTiles.length][][];
			for (int isTile = 0; isTile < nsTiles.length; isTile++){
				int nsTile = nsTiles[isTile];
				if (planes[nsTile] != null){
					neibs[isTile] = new int [planes[nsTile].length][];
					val_weights[isTile] = new double [planes[nsTile].length][];
					for (int nl = 0; nl < planes[nsTile].length; nl++) if ( planes[nsTile][nl] != null){
						neibs[isTile][nl] =  planes[nsTile][nl].getNeibBest();
6250
						//getNumNeibBest()
6251
						val_weights[isTile][nl] = new double[2];
6252 6253 6254
					}
				}
			}
6255 6256 6257 6258 6259 6260 6261 6262 6263 6264
		}
		// calculate old cost
		double old_value = 0.0;
		double old_weight = 0.0; // should not change during update
		for (int isTile = 0; isTile < nsTiles.length; isTile++){
			if (val_weights[isTile] != null){
				for (int nl = 0; nl < val_weights[isTile].length; nl++) if ( val_weights[isTile][nl] != null){
					old_value += val_weights[isTile][nl][0] * val_weights[isTile][nl][1];
					old_weight += val_weights[isTile][nl][1];
				}
6265 6266
			}
		}
6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277
		// now re-calculate val_weights where neibs are different from neibs_prev
		for (int isTile = 0; isTile < nsTiles.length; isTile++){
			int nsTile = nsTiles[isTile];
			if (planes[nsTile] != null) {
				if (neibs[isTile] != null){
					for (int nl = 0; nl < planes[nsTile].length; nl++) if (planes[nsTile][nl] != null){
						if  (neibs[isTile][nl] != null) {
							boolean neibs_changed = false;
							if ((neibs_prev == null) || (neibs_prev[isTile] == null)  || (neibs_prev[isTile][nl] == null)){
								neibs_changed = true;
							} else {
6278
								for (int dir = 0; dir < 8; dir++) if (neibs[isTile][nl][dir] != neibs_prev[isTile][nl][dir]){
6279 6280 6281 6282 6283
									neibs_changed = true;
									break;
								}
							}
							if (neibs_changed){
6284
								val_weights[isTile][nl] = getStarValueWeight_old(
6285 6286 6287 6288 6289
										nsTile,
										nl,
										neibs[isTile][nl],
										orthoWeight,
										diagonalWeight,
6290
										starPwr, // double         starPwr,    // Divide cost by number of connections to this power
6291
										starWeightPwr,    // Use this power of tile weight when calculating connection cost
6292 6293
										tnSurface,
										preferDisparity,
6294
										-1); // debugLevel);
6295 6296 6297 6298
							}
						} else {
							val_weights[isTile][nl] = null;
						}
6299
					}
6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319
				} else {
					val_weights[isTile] = null;
				}
			}
		}
		// calculate new cost
		double new_value = 0.0;
		double new_weight = 0.0; // should not change during update
		for (int isTile = 0; isTile < nsTiles.length; isTile++){
			if (val_weights[isTile] != null){
				for (int nl = 0; nl < val_weights[isTile].length; nl++) if ( val_weights[isTile][nl] != null){
					new_value += val_weights[isTile][nl][0] * val_weights[isTile][nl][1];
					new_weight += val_weights[isTile][nl][1];
				}
			}
		}
		// Likely weight will never change except first run, but we will still normalize by weight
		if (old_weight != 0.0) old_value /= old_weight;
		if (new_weight != 0.0) new_value /= new_weight;
		return new_value - old_value; // negative - improvement
6320
	}
6321 6322 6323



6324 6325 6326 6327
	public double [][] getShowPlanes(
			TilePlanes.PlaneData [][] planes,
			double minWeight,
			double maxEigen,
6328
			double dispNorm,
6329 6330 6331
			boolean use_NaN,
			double arrow_dark,
			double arrow_white)
6332 6333 6334 6335 6336
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
6337
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
6338 6339 6340
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		final int width =  stilesX * superTileSize; // * tileSize;
		final int height = stilesY * superTileSize; // * tileSize;
6341 6342
		final double [] nan_plane = new double [superTileSize*superTileSize];
		for (int i = 0; i < nan_plane.length; i++) nan_plane[i] = Double.NaN;
6343 6344 6345 6346 6347 6348 6349 6350 6351
		final int centerIndex = (superTileSize+1) * superTileSize / 2;
		final int [] dirs = {-superTileSize,
				-superTileSize + 1,
				1,
				superTileSize +  1,
				superTileSize,
				superTileSize -  1,
				-1,
				-superTileSize - 1};
Andrey Filippov's avatar
Andrey Filippov committed
6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362
		//				final int debug_stile = 17 * stilesX + 27;
		final int debug_stile = 20 * stilesX + 27;
		//				final int debug_stile = 19 * stilesX + 27;
		// scan all get maximal number of satisfying planes
		int num_planes = 0;
		for (int i = 0; i < planes.length; i++) {
			if (i == debug_stile) {
				System.out.println("getShowPlanes():1, tile = "+i);
			}
			if ((planes[i] != null) && (planes[i].length > num_planes)){
				int num_sat = 0;
6363 6364
				for (int j = 0; j < planes[i].length; j++) if (planes[i][j] != null){
//					if (planes[i][j].getWeight() >= minWeight){ /// Later does not compare too minWeight
6365 6366
//						double eigVal = planes[i][j].getValue(); // ************** generated does not have value ????????????
						double eigVal = planes[i][j].getNormValue(); // ************** generated does not have value ????????????
6367
						double disp = planes[i][j].getSinglePlaneDisparity(false)[centerIndex];
Andrey Filippov's avatar
Andrey Filippov committed
6368
						/*
6369 6370 6371 6372
								if (disp > dispNorm) {
									eigVal *= dispNorm / disp;
								}
								if (eigVal < maxEigen) num_sat ++;
Andrey Filippov's avatar
Andrey Filippov committed
6373 6374 6375 6376 6377
						 */
						if (eigVal < corrMaxEigen(
								maxEigen,
								dispNorm,
								disp)) num_sat ++;
6378
//					}
6379
				}
Andrey Filippov's avatar
Andrey Filippov committed
6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397
				if (num_sat > num_planes) num_planes = num_sat;
			}
		}
		double [][] data = new double[num_planes][width*height];
		for (int sty = 0; sty < stilesY; sty++){
			for (int stx = 0; stx < stilesX; stx++){
				int nsTile = sty * stilesX + stx;
				if (nsTile == debug_stile) {
					System.out.println("getShowPlanes():2, tile = "+nsTile);
				}
				int ns = 0;
				double [] plane = nan_plane;
				int indx = (sty * superTileSize) * width + (stx * superTileSize);
				boolean debug = (nsTile == debug_stile) ; // (sty == 18) && (stx == 28);
				if (debug) {
					System.out.println("getShowPlanes():"+((planes[nsTile] != null)? planes[nsTile].length : "null"));
				}
				if (planes[nsTile] != null) {
6398 6399
//					for (int np = 0; np < planes[nsTile].length; np++) if (planes[nsTile][np] != null){
					for (int np = 0; np < planes[nsTile].length; np++) if ((planes[nsTile][np] != null) && (planes[nsTile][np].getWeight() > 0.0)){ // disregard 0-weight planes
6400

Andrey Filippov's avatar
Andrey Filippov committed
6401 6402
						if (planes[nsTile][np].getWeight() >= minWeight){
							//&& (planes[nsTile][np].getValue() < maxEigen)){
6403 6404
//							double eigVal = planes[nsTile][np].getValue();
							double eigVal = planes[nsTile][np].getNormValue();
Andrey Filippov's avatar
Andrey Filippov committed
6405 6406
							double disp = planes[nsTile][np].getZxy()[0];
							/*
6407 6408 6409
									if (disp > dispNorm) {
										eigVal *= dispNorm / disp;
									}
Andrey Filippov's avatar
Andrey Filippov committed
6410 6411 6412 6413 6414
							 */
							if (eigVal < corrMaxEigen(
									maxEigen,
									dispNorm,
									disp)) {
6415
								plane = planes[nsTile][np].getSinglePlaneDisparity(use_NaN);
Andrey Filippov's avatar
Andrey Filippov committed
6416 6417 6418 6419 6420 6421 6422
								// add connections to neighbors if available
								int [] neib_best = planes[nsTile][np].getNeibBest();
								if (neib_best != null){
									for (int dir = 0; dir < neib_best.length; dir ++) if (neib_best[dir] >= 0){
										// draw a line
										//int center_index = indx + centerIndex;
										for (int i = 0; i < (superTileSize / 2); i++){
6423
											plane[centerIndex + i * dirs[dir]] = ((i & 1) == 0) ? arrow_white:arrow_white; //  arrow_dark : arrow_white;
6424
										}
6425 6426
									}
								}
6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439
								//superTileSize
								// mark fronto tiles with NaN - center 3x3 tiles
								//superTileSize
								if (planes[nsTile][np].fronto) {
									plane[centerIndex + 0] =             Double.NaN;
									plane[centerIndex + superTileSize] = Double.NaN;
									plane[centerIndex - superTileSize] = Double.NaN;
								}
								if (planes[nsTile][np].horizontal) {
									plane[centerIndex + 0] =             Double.NaN;
									plane[centerIndex + 1] =             Double.NaN;
									plane[centerIndex - 1] =             Double.NaN;
								}
Andrey Filippov's avatar
Andrey Filippov committed
6440
								for (int y = 0; y < superTileSize; y++) {
Andrey Filippov's avatar
Andrey Filippov committed
6441 6442 6443 6444 6445
									if (data.length < (ns+1)){
										System.out.println("BUG in getShowPlanes()!, ns = "+ns+", data.length="+data.length);
									} else {
										System.arraycopy(plane, superTileSize * y, data[ns], indx + width * y, superTileSize); //java.lang.ArrayIndexOutOfBoundsException: 5
									}
Andrey Filippov's avatar
Andrey Filippov committed
6446 6447
								}
								ns ++;
6448 6449
							}
						}
6450

6451 6452
					}
				}
Andrey Filippov's avatar
Andrey Filippov committed
6453 6454 6455 6456
				// fill same (nearest) plane or NaN if none was available
				for (; ns < num_planes; ns++){
					for (int y = 0; y < superTileSize; y++) {
						System.arraycopy(plane, superTileSize * y, data[ns], indx + width * y, superTileSize);
Andrey Filippov's avatar
Andrey Filippov committed
6457 6458
					}
				}
Andrey Filippov's avatar
Andrey Filippov committed
6459 6460 6461 6462 6463 6464 6465

			}
		}
		return data;
	}

	public double [][] getShowShells(
6466
			int  nlayer, // over multi-layer - do not render more than nlayer on top of each other
Andrey Filippov's avatar
Andrey Filippov committed
6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480
			TilePlanes.PlaneData [][] planes,
			int [][] shells,
			int max_shells,
			boolean fuse,
			boolean show_connections,
			boolean use_NaN,
			double arrow_dark,
			double arrow_white)
	{

		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
6481
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		final int width =  stilesX * superTileSize; // * tileSize;
		final int height = stilesY * superTileSize; // * tileSize;
		final double [] nan_plane = new double [superTileSize*superTileSize];
		for (int i = 0; i < nan_plane.length; i++) nan_plane[i] = Double.NaN;
		final int centerIndex = (superTileSize+1) * superTileSize / 2;
		final int [] dirs = {-superTileSize,
				-superTileSize + 1,
				1,
				superTileSize +  1,
				superTileSize,
				superTileSize -  1,
				-1,
				-superTileSize - 1};
		final int [] neib_offsets={
				-stilesX,
				-stilesX + 1,
				1,
				stilesX +  1,
				stilesX,
				stilesX -  1,
				-1,
				-stilesX - 1};
		//				final int debug_stile = 17 * stilesX + 27;
		final int debug_stile = -1; // 18 * stilesX + 30;

		int num_shells = 0;
		for (int nsTile = 0; nsTile < shells.length; nsTile++) if (shells[nsTile] != null){
			for (int np = 0; np < shells[nsTile].length; np++){
				if (shells[nsTile][np] > num_shells) {
6512
					num_shells = shells[nsTile][np]; // starts with 1, not 0
Andrey Filippov's avatar
Andrey Filippov committed
6513
				}
Andrey Filippov's avatar
Andrey Filippov committed
6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538
			}
		}
		if (num_shells > max_shells){
			num_shells = max_shells;
		}
		double [][] data = new double [num_shells][width*height];
		for (int nShell = 0; nShell < num_shells; nShell++) {
			for (int sty = 0; sty < stilesY; sty++){
				for (int stx = 0; stx < stilesX; stx++){
					int nsTile = sty * stilesX + stx;
					boolean debug = (nsTile == debug_stile) ; // (sty == 18) && (stx == 28);
					String [] dbg_titles = {"Center","N","NE","E","SE","S","SW","W","NW"};
					double [][] dbg_img3 = null;
					double [][] dbg_img = null;
					double [][] dbg_this = null;
					double [][] dbg_other = null;
					if (debug) {
						System.out.println("getShowShells():2, tile = "+nsTile);
					}
					double [] plane = nan_plane;
					int indx = (sty * superTileSize) * width + (stx * superTileSize);
					if (debug) {
						System.out.println("getShowShells():"+((planes[nsTile] != null)? planes[nsTile].length : "null"));
					}
					if (planes[nsTile] != null) {
6539
						int num_rendered = 0;
Andrey Filippov's avatar
Andrey Filippov committed
6540
						for (int np = 0; np < planes[nsTile].length; np++){
6541 6542
							if ((shells[nsTile][np] == (nShell + 1)) && ((nlayer == 0) || (num_rendered < nlayer)) ) {
								num_rendered ++;
6543
								plane = planes[nsTile][np].getSinglePlaneDisparity(use_NaN);
Andrey Filippov's avatar
Andrey Filippov committed
6544 6545 6546 6547 6548 6549 6550 6551
								int [] neib_best = planes[nsTile][np].getNeibBest();
								if (fuse && (neib_best != null)){
									if (debug) {
										dbg_img3 = new double [dbg_titles.length][];
										dbg_img = new double [dbg_titles.length][];
										dbg_this = new double [dbg_titles.length][];
										dbg_other = new double [dbg_titles.length][];
										dbg_img3[0] = planes[nsTile][np].getTriplePlaneDisparity();
6552
										dbg_img[0] = planes[nsTile][np].getSinglePlaneDisparity(false);
Andrey Filippov's avatar
Andrey Filippov committed
6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566
									}


									double [] weight_this =  new double [superTileSize*superTileSize];
									double [] weight_other = new double [superTileSize*superTileSize];
									double [] plane_combo =  new double [superTileSize*superTileSize];
									for (int dir = 0; dir < 8; dir++){
										if (neib_best[dir] >=0){
											int nsTileOther = nsTile + neib_offsets[dir];
											int npOther = neib_best[dir];
											int dirOther = (dir + 4) % 8;
											double [] plane_other =	planes[nsTileOther][npOther].getTriplePlaneDisparity(dirOther);
											double [] fuse_this =  getFuseThis(dir);
											double [] fuse_other = getFuseOther(dir);
Andrey Filippov's avatar
Andrey Filippov committed
6567
											if (debug) {
Andrey Filippov's avatar
Andrey Filippov committed
6568 6569 6570 6571
												dbg_img3[dir + 1] =   planes[nsTileOther][npOther].getTriplePlaneDisparity();
												dbg_img[dir + 1] =    planes[nsTileOther][npOther].getTriplePlaneDisparity(dirOther);
												dbg_this[dir + 1] =   fuse_this.clone();
												dbg_other[dir + 1] =  fuse_other.clone();
Andrey Filippov's avatar
Andrey Filippov committed
6572 6573
											}
											for (int i = 0; i < weight_this.length; i++){
Andrey Filippov's avatar
Andrey Filippov committed
6574 6575 6576
												weight_this[i] +=  fuse_this[i];
												weight_other[i] += fuse_other[i];
												plane_combo[i] +=  fuse_other[i] * plane_other[i];
Andrey Filippov's avatar
Andrey Filippov committed
6577 6578
											}
										}
Andrey Filippov's avatar
Andrey Filippov committed
6579 6580
									}
									if (debug) {
6581
										ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays(); // just for debugging?
Andrey Filippov's avatar
Andrey Filippov committed
6582 6583 6584 6585 6586
										sdfa_instance.showArrays(dbg_img, superTileSize, superTileSize, true, "plane_"+nsTile,dbg_titles);
										sdfa_instance.showArrays(dbg_img3, 3*superTileSize, 3*superTileSize, true, "plane3_"+nsTile,dbg_titles);
										sdfa_instance.showArrays(dbg_this, superTileSize, superTileSize, true, "weights_this_"+nsTile,dbg_titles);
										sdfa_instance.showArrays(dbg_other, superTileSize, superTileSize, true, "weights_other_"+nsTile,dbg_titles);
									}
6587
									double [] plane_other = planes[nsTile][np].getSinglePlaneDisparity(false);
Andrey Filippov's avatar
Andrey Filippov committed
6588 6589 6590 6591 6592 6593 6594 6595
									for (int i = 0; i < weight_this.length; i++){
										plane_combo[i] += weight_this[i] * plane_other[i];
										double w = weight_this[i] + weight_other[i];
										if (w > 0){
											plane_combo[i] /= w;
										} else {
											plane_combo[i] = plane_other[i];
										}
6596
									}
Andrey Filippov's avatar
Andrey Filippov committed
6597 6598 6599 6600
									if (use_NaN){
										for (int i = 0; i < plane_combo.length; i++){
											if (Double.isNaN(plane[i])){
												plane_combo[i] = Double.NaN;
Andrey Filippov's avatar
Andrey Filippov committed
6601 6602
											}
										}
Andrey Filippov's avatar
Andrey Filippov committed
6603 6604 6605 6606 6607 6608 6609 6610 6611 6612
									}
									plane = plane_combo;
								}

								if (show_connections) {
									if (neib_best != null){
										for (int dir = 0; dir < neib_best.length; dir ++) if (neib_best[dir] >= 0){
											// draw a line
											//int center_index = indx + centerIndex;
											for (int i = 0; i < (superTileSize / 2); i++){
6613
												plane[centerIndex + i * dirs[dir]] = ((i & 1) == 0) ? arrow_dark : arrow_white;
Andrey Filippov's avatar
Andrey Filippov committed
6614
											}
Andrey Filippov's avatar
Andrey Filippov committed
6615 6616 6617
										}
									}
								}
Andrey Filippov's avatar
Andrey Filippov committed
6618 6619 6620
								for (int y = 0; y < superTileSize; y++) {
									System.arraycopy(plane, superTileSize * y, data[nShell], indx + width * y, superTileSize);
								}
Andrey Filippov's avatar
Andrey Filippov committed
6621
							}
Andrey Filippov's avatar
Andrey Filippov committed
6622
						}
Andrey Filippov's avatar
Andrey Filippov committed
6623
					}
6624
				}
Andrey Filippov's avatar
Andrey Filippov committed
6625
			}
Andrey Filippov's avatar
Andrey Filippov committed
6626 6627 6628
		}
		return data;
	}
Andrey Filippov's avatar
Andrey Filippov committed
6629

6630

6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646
	public double [][][] getOverlappingShells(
			int  nlayer, // over multi-layer - do not render more than nlayer on top of each other
			TilePlanes.PlaneData [][] planes,
			int [][] shells,
			int max_shells,
			boolean fuse,
			boolean show_connections,
			boolean use_NaN,
			double arrow_dark,
			double arrow_white)
	{

		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
6647
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		final int width =  stilesX * superTileSize; // * tileSize;
		final int height = stilesY * superTileSize; // * tileSize;
		final double [] nan_plane = new double [superTileSize*superTileSize];
		for (int i = 0; i < nan_plane.length; i++) nan_plane[i] = Double.NaN;
		final int centerIndex = (superTileSize+1) * superTileSize / 2;
		final int [] dirs = {-superTileSize,
				-superTileSize + 1,
				1,
				superTileSize +  1,
				superTileSize,
				superTileSize -  1,
				-1,
				-superTileSize - 1};
		final int [] neib_offsets={
				-stilesX,
				-stilesX + 1,
				1,
				stilesX +  1,
				stilesX,
				stilesX -  1,
				-1,
				-stilesX - 1};
		//				final int debug_stile = 17 * stilesX + 27;
		final int debug_stile = -1; // 18 * stilesX + 30;

		int num_shells = 0;
		for (int nsTile = 0; nsTile < shells.length; nsTile++) if (shells[nsTile] != null){
			for (int np = 0; np < shells[nsTile].length; np++){
				if (shells[nsTile][np] > num_shells) {
6678
					num_shells = shells[nsTile][np]; // starts with 1, not 0
6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708
				}
			}
		}
		if (num_shells > max_shells){
			num_shells = max_shells;
		}
		double [][] data = new double [num_shells][width*height];
		for (int nShell = 0; nShell < num_shells; nShell++) {
			for (int sty = 0; sty < stilesY; sty++){
				for (int stx = 0; stx < stilesX; stx++){
					int nsTile = sty * stilesX + stx;
					boolean debug = (nsTile == debug_stile) ; // (sty == 18) && (stx == 28);
					String [] dbg_titles = {"Center","N","NE","E","SE","S","SW","W","NW"};
					double [][] dbg_img3 = null;
					double [][] dbg_img = null;
					double [][] dbg_this = null;
					double [][] dbg_other = null;
					if (debug) {
						System.out.println("getShowShells():2, tile = "+nsTile);
					}
					double [] plane = nan_plane;
					int indx = (sty * superTileSize) * width + (stx * superTileSize);
					if (debug) {
						System.out.println("getShowShells():"+((planes[nsTile] != null)? planes[nsTile].length : "null"));
					}
					if (planes[nsTile] != null) {
						int num_rendered = 0;
						for (int np = 0; np < planes[nsTile].length; np++){
							if ((shells[nsTile][np] == (nShell + 1)) && ((nlayer == 0) || (num_rendered < nlayer)) ) {
								num_rendered ++;
6709
								plane = planes[nsTile][np].getSinglePlaneDisparity(use_NaN);
6710 6711 6712 6713 6714 6715 6716 6717
								int [] neib_best = planes[nsTile][np].getNeibBest();
								if (fuse && (neib_best != null)){
									if (debug) {
										dbg_img3 = new double [dbg_titles.length][];
										dbg_img = new double [dbg_titles.length][];
										dbg_this = new double [dbg_titles.length][];
										dbg_other = new double [dbg_titles.length][];
										dbg_img3[0] = planes[nsTile][np].getTriplePlaneDisparity();
6718
										dbg_img[0] = planes[nsTile][np].getSinglePlaneDisparity(false);
6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746
									}


									double [] weight_this =  new double [superTileSize*superTileSize];
									double [] weight_other = new double [superTileSize*superTileSize];
									double [] plane_combo =  new double [superTileSize*superTileSize];
									for (int dir = 0; dir < 8; dir++){
										if (neib_best[dir] >=0){
											int nsTileOther = nsTile + neib_offsets[dir];
											int npOther = neib_best[dir];
											int dirOther = (dir + 4) % 8;
											double [] plane_other =	planes[nsTileOther][npOther].getTriplePlaneDisparity(dirOther);
											double [] fuse_this =  getFuseThis(dir);
											double [] fuse_other = getFuseOther(dir);
											if (debug) {
												dbg_img3[dir + 1] =   planes[nsTileOther][npOther].getTriplePlaneDisparity();
												dbg_img[dir + 1] =    planes[nsTileOther][npOther].getTriplePlaneDisparity(dirOther);
												dbg_this[dir + 1] =   fuse_this.clone();
												dbg_other[dir + 1] =  fuse_other.clone();
											}
											for (int i = 0; i < weight_this.length; i++){
												weight_this[i] +=  fuse_this[i];
												weight_other[i] += fuse_other[i];
												plane_combo[i] +=  fuse_other[i] * plane_other[i];
											}
										}
									}
									if (debug) {
6747
										ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays(); // just for debugging?
6748 6749 6750 6751 6752
										sdfa_instance.showArrays(dbg_img, superTileSize, superTileSize, true, "plane_"+nsTile,dbg_titles);
										sdfa_instance.showArrays(dbg_img3, 3*superTileSize, 3*superTileSize, true, "plane3_"+nsTile,dbg_titles);
										sdfa_instance.showArrays(dbg_this, superTileSize, superTileSize, true, "weights_this_"+nsTile,dbg_titles);
										sdfa_instance.showArrays(dbg_other, superTileSize, superTileSize, true, "weights_other_"+nsTile,dbg_titles);
									}
6753
									double [] plane_other = planes[nsTile][np].getSinglePlaneDisparity(false);
6754 6755 6756 6757 6758 6759 6760 6761
									for (int i = 0; i < weight_this.length; i++){
										plane_combo[i] += weight_this[i] * plane_other[i];
										double w = weight_this[i] + weight_other[i];
										if (w > 0){
											plane_combo[i] /= w;
										} else {
											plane_combo[i] = plane_other[i];
										}
6762
									}
6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778
									if (use_NaN){
										for (int i = 0; i < plane_combo.length; i++){
											if (Double.isNaN(plane[i])){
												plane_combo[i] = Double.NaN;
											}
										}
									}
									plane = plane_combo;
								}

								if (show_connections) {
									if (neib_best != null){
										for (int dir = 0; dir < neib_best.length; dir ++) if (neib_best[dir] >= 0){
											// draw a line
											//int center_index = indx + centerIndex;
											for (int i = 0; i < (superTileSize / 2); i++){
6779
												plane[centerIndex + i * dirs[dir]] = ((i & 1) == 0) ? arrow_dark : arrow_white;
6780 6781 6782 6783 6784 6785 6786 6787 6788 6789
											}
										}
									}
								}
								for (int y = 0; y < superTileSize; y++) {
									System.arraycopy(plane, superTileSize * y, data[nShell], indx + width * y, superTileSize);
								}
							}
						}
					}
6790
				}
6791 6792 6793 6794
			}
		}
		return  null; // data;
	}
Andrey Filippov's avatar
Andrey Filippov committed
6795

6796 6797 6798



6799
	/**
6800
	 * Prepare visualization of the plane separation lines
6801 6802 6803 6804 6805 6806 6807 6808 6809
	 * @param split_planes per supertile, per plane sets of 3 plane data instances
	 *  (first, second, merged)
	 * @param debugLevel debug level
	 * @param dbg_X supertile horizontal index to show debug information
	 * @param dbg_Y supertile vertical index to show debug information
	 * @return array to be visualized as width=superTileSize*stilesX,
	 *  height = superTileSize*stilesY data. Lines value match plane index,
	 *  length corresponds to triple-sized supertiles
	 */
6810

6811 6812 6813 6814 6815 6816 6817 6818 6819 6820
	public double [] showSplitLines(
			final TilePlanes.PlaneData[][][] split_planes,
			final int                        debugLevel,
			final int                        dbg_X,
			final int                        dbg_Y)
	{
		final int [][] dirsYX = {{-1, 0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
6821
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
6822 6823 6824 6825 6826 6827 6828 6829
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		final int width = superTileSize * stilesX;
		final int height = superTileSize * stilesY;
		final int debug_stile = dbg_Y * stilesX + dbg_X;
		double [] split_lines = new double[width * height];
		final int  ss3 = 3 * superTileSize;
		for (int nsTile = 0; nsTile < split_planes.length; nsTile++) {
			if (split_planes[nsTile] != null) {
6830
				int sty = nsTile / stilesX;
6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841
				int stx = nsTile % stilesX;
				int dl = ((debugLevel > -1) && (nsTile == debug_stile)) ? 1:0;
				int min_np = (split_planes[nsTile].length > 1)? 1 : 0;
				for (int np = min_np; np < split_planes[nsTile].length; np++){
					if (split_planes[nsTile][np] != null){
						TilePlanes.PlaneData split_plane1 = split_planes[nsTile][np][0];
						TilePlanes.PlaneData split_plane2 = split_planes[nsTile][np][1];
						if ((split_plane1 != null) && ( split_plane2 != null)){
							double [] tpd =  split_plane1.getTriplePlaneDisparity();
							double [] tpd1 = split_plane2.getTriplePlaneDisparity();
							// difference of the 2 split planes disparities, show where
6842
							// they have lowest value in any of the 2 orthogonal directions
6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870
							for (int i = 0; i < tpd.length; i++) {
								tpd[i] = Math.abs(tpd[i] - tpd1[i]);
							}

							int [] vby = new int [ss3];
							for (int x = 0; x < ss3; x ++){
								vby[x] = 0;
								for (int y = 1; y < ss3; y ++){
									if (tpd[y * ss3 + x] < tpd[vby[x] * ss3 + x]){
										vby[x] = y;
									}
								}
							}
							int [] vbx = new int [ss3];
							for (int y = 0; y < ss3; y ++){
								vbx[y] = 0;
								for (int x = 1; x < ss3; x ++){
									if (tpd[y * ss3 + x] < tpd[y * ss3 + vbx[y]]){
										vbx[y] = x;
									}
								}
							}

							for (int dx = 0; dx < ss3; dx ++){
								if ((vby[dx] > 0) && (vby[dx] < (ss3-1))) {
									int y = vby[dx] + superTileSize * (sty - 1);
									int x = dx + superTileSize * (stx - 1);
									if ((y >= 0) && (y < height) && (x >= 0) && (x < width)){
6871
										split_lines[ y* width + x]	= np - min_np + 1;
6872 6873 6874 6875 6876 6877 6878 6879 6880
									}
								}
							}

							for (int dy = 0; dy < ss3; dy ++){
								if ((vbx[dy] > 0) && (vbx[dy] < (ss3-1))) {
									int x = vbx[dy] + superTileSize * (stx - 1);
									int y = dy + superTileSize * (sty - 1);
									if ((y >= 0) && (y < height) && (x >= 0) && (x < width)){
6881
										split_lines[ y* width + x]	= np - min_np + 1;
6882 6883 6884 6885 6886 6887 6888
									}
								}
							}
						}
					}
				}
			}
6889
		}
6890 6891
		return split_lines;
	}
6892

6893 6894 6895 6896 6897 6898
	/**
	 * Apply same supertile planes merge by combining tiles and re-generating ellipsoids by diagonalizing
	 * covariance matrices. Some outliers may be removed after merge
	 * @param planes per supertile, per plane - array of supertile instances - will be modified =by merge
	 * @param merge_groups per-supertile group sets for merging. Each group set is an array of groups. Each group is an array
	 * of plane indices
6899
	 * Parameters to generate planes (ellipsoids):
6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913
	 * @param disp_far disparity lower limit (Double.NaN - any)
	 * @param disp_near disparity upper limit (Double.NaN - any)
	 * @param dispNorm disparity normalization value (when average disparity is above, difference is proportionally reduced)
	 * @param min_weight minimal tile strength to be used
	 * @param min_tiles minimal number of tiles to generate ellipsoid
	 * Parameters for outlier removal:
	 * @param targetEigen target main eigenvalue (thickness in disparity space)
	 * @param fractOutliers maximal fraction of all tiles to be removed as outliers
	 * @param maxOutliers maximal absolute number of outliers to be removed from each plane (ellipsoid)
	 * @param debugLevel debug level
	 * @param dbg_X tile x-index for detailed debug data
	 * @param dbg_Y tile y-index for detailed debug data
	 * @return total number of plane groups merged
	 */
6914 6915
	public int applyMergePlanes(
			final TilePlanes.PlaneData[][]   planes,
6916 6917
			final int [][][]                 merge_groups,
			// parameters to generate ellipsoids
6918 6919 6920 6921 6922
			final double                     disp_far, // minimal disparity to select (or NaN)
			final double                     disp_near, // maximal disparity to select (or NaN)
			final double                     dispNorm,   //  Normalize disparities to the average if above
			final double                     min_weight,
			final int                        min_tiles,
6923
			// parameters to reduce outliers
6924
			final double                     targetEigen,   //     =   0.1;  // Remove outliers until main axis eigenvalue (possibly scaled by plDispNorm) gets below
6925
			final double                     inFractOutliers, //     =   0.3;  // Maximal fraction of outliers to remove
6926
			final int                        maxOutliers,   //     =   20;  // Maximal number of outliers to remove
6927 6928 6929 6930
			final double                     fronto_tol,    // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable this feature
// FIXME: the following 2 parameters are not yet used
			final double                     fronto_rms,    // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes
			final double                     fronto_offs,   //        =   0.2;  // increasing weight of the near tiles by using difference between the reduced average as weight. <= 0 - disable
6931
			final double                     fronto_pow,    //        =   1.0;  // increase weight even more
6932 6933 6934 6935 6936 6937
			final int                        debugLevel,
			final int                        dbg_X,
			final int                        dbg_Y)
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int superTileSize = tileProcessor.getSuperTileSize();
6938
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
6939
		final int debug_stile = dbg_Y * stilesX + dbg_X;
6940
		final Thread[] threads = ImageDtt.newThreadArray((debugLevel > 1)? 1 : tileProcessor.threadsMax);
6941
		final AtomicInteger ai = new AtomicInteger(0);
6942

6943 6944
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
6945
				@Override
6946 6947
				public void run() {
					for (int nsTile = ai.getAndIncrement(); nsTile < planes.length; nsTile = ai.getAndIncrement()) {
6948 6949
//						int dl = ((debugLevel > -1) && (nsTile == debug_stile)) ? 4:0;
                        int dl = ((debugLevel > 1) && (nsTile == debug_stile)) ? 4: debugLevel;
6950

6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969
						if (merge_groups[nsTile] != null){
							// first merge all to the lowest plane (they are ordered), then re-order remaining planes
							for (int ng = 0; ng < merge_groups[nsTile].length; ng++) {
								int np0 = merge_groups[nsTile][ng][0];
								 TilePlanes.PlaneData this_pd = planes[nsTile][np0];
								for (int i = 1; i < merge_groups[nsTile][ng].length; i++ ){
									int np = merge_groups[nsTile][ng][i];
									this_pd.orMeasSelection(planes[nsTile][np].getMeasSelection());
									planes[nsTile][np] = null;
								}
								this_pd.invalidateCalculated(); // is it needed?
								double [][][] disp_strength = this_pd.getPlaneFromMeas(
										null,           // boolean [][] tile_sel,null - use measuredSelection already OR-ed
										null,           //double [][][] disp_str, null - calculate
										disp_far,       // double       disp_far, // minimal disparity to select (or NaN)
										disp_near,      // double       disp_near, // maximal disparity to select (or NaN)
										dispNorm,       // double       dispNorm,   //  Normalize disparities to the average if above
										min_weight,     // double       min_weight,
										min_tiles,      // int          min_tiles,
6970
//OK?
6971
										smplMode,
6972
										mlfp,
6973
										dl - 2);            // int          debugLevel)
6974
								if (disp_strength == null) {
6975
									System.out.println("=== BUG in applyMergePlanes(): failed to getPlaneFromMeas() for merged planes");
6976 6977
									break;
								}
6978

6979 6980 6981 6982 6983 6984 6985 6986
								this_pd.getWorldPlaneFromMeas( // re-calculate world-based planes too
										null,           // tile_sel,       // boolean [][] tile_sel, // null - do not use, {} use all (will be modified)
										disp_strength,
										disp_far,       // double       disp_far, // minimal disparity to select (or NaN)
										disp_near,      // double       disp_near, // maximal disparity to select (or NaN)
										dispNorm,       // double       dispNorm,   //  Normalize disparities to the average if above
										min_weight,     // double       min_weight,
										min_tiles,      // int          min_tiles,
6987
//OK?
6988
										smplMode,
6989
										mlfp,
6990
										dl - 2);            // int          debugLevel)
6991 6992 6993



6994 6995
								// remove outliers //removeOutliers
								// now try to remove outliers
6996

6997 6998 6999 7000
								double targetV = corrMaxEigen(
										targetEigen,
										dispNorm,
										planes[nsTile][np0]);
7001 7002 7003 7004 7005 7006 7007

								boolean almost_fronto = this_pd.isFronto(
										fronto_tol,    // double fronto_tol,
										disp_strength,      // double [][][] disp_str,
										debugLevel);   // int debugLevel);
								// seems it is OK not to normalize fronto_rms, as it is only needed for far surfaces
								double targetEigen = almost_fronto ? (fronto_rms*fronto_rms): targetV;
7008
//								if (this_pd.getValue() > targetV) {
7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022
								// FIXME: temporary - make a configurable parameter
								double fronto_fract_outliers = 0.8; // 2 * inFractOutliers;
								double fractOutliers = almost_fronto ? (fronto_fract_outliers) : inFractOutliers;
								int max_outliers = (int) Math.round(this_pd.getNumPoints() * fractOutliers);
								if (max_outliers > maxOutliers) max_outliers = maxOutliers;
								// in fronto mode - run at least once
								if (almost_fronto) {
									this_pd.growFrontoSelection(
											5,              // int           min_neib,
											0.1,            // double        max_over_avg,
											0.00,           // double        max_under_avg,
											disp_strength); // double [][][] disp_str)
								}
								if ((this_pd.getNormValue() > targetEigen) || almost_fronto) { // targetV) {
7023
									boolean OK = this_pd.removeOutliers( // getPlaneFromMeas should already have run
7024 7025
											fronto_tol, // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable this feature
											fronto_rms,    // double        fronto_rms,  // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes. May be tighter
7026 7027
											fronto_offs,   // double        fronto_offs,   //        =   0.2;  // increasing weight of the near tiles by using difference between the reduced average as weight.
											fronto_pow,    // double        fronto_pow,    //        =   1.0;  // increase weight even more
7028 7029 7030 7031 7032
											disp_strength,
											targetV,      // double     targetEigen, // target eigenvalue for primary axis (is disparity-dependent, so is non-constant)
											max_outliers, // int        maxRemoved,  // maximal number of tiles to remove (not a constant)
											dl); // int        debugLevel)
									if (!OK) {
7033
										System.out.println("=== BUG in applyMergePlanes(): failed to removeOutliers() for merged planes");
7034 7035
										break;
									}
7036
								}
7037 7038 7039
								if (this_pd.fronto) {
									//?
								}
7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058
							}
// remove all null planes (but number zero - it may be null for historical reasons)
							ArrayList<Integer> remaining_planes = new ArrayList<Integer>();
							remaining_planes.add(0);
							for (int np = 1; np < planes[nsTile].length; np++){
								if (planes[nsTile][np] != null) {
									remaining_planes.add(np);
								}
							}
							TilePlanes.PlaneData[] stack_pd = new TilePlanes.PlaneData[remaining_planes.size()];
							int indx = 0;
							for (Integer np : remaining_planes){
								stack_pd[indx++] = planes[nsTile][np];
							}
							planes[nsTile] = stack_pd;
						}
					}
				}
			};
7059
		}
7060 7061 7062 7063 7064 7065 7066 7067 7068
		ImageDtt.startAndJoin(threads);
		int num_merged = 0;
		for (int nsTile = 0; nsTile < merge_groups.length; nsTile++) if (merge_groups[nsTile] != null){
			for (int ng = 0; ng < merge_groups[nsTile].length; ng++){
				num_merged += merge_groups[nsTile][ng].length - 1;
			}
		}
		return num_merged;
	}
7069 7070 7071 7072




7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096
	/**
	 * Re-generate "planes" (ellipsoids) from the measured data according to provided
	 * plane pairs for some supertiles.
	 * Current version destroys connections between neighbor planes, they need to be
	 * re-calculated
	 * TODO: consider amplifying difference (angle) between planes before/during/after
	 * running this method. Like 3d "sharpening" to compensate for being washed out.
	 * @param planes per-supertile (in linescan order), per-plane data to be replaced
	 * @param brokenPd per-supertile , per-plane 3 PD instances (two first make the pair).
	 *        generated by breakPlanesToPairs method. This data will not be modified.
	 * @param max_diff maximal normalized disparity difference from the plane to consider
	 * @param other_diff maximal difference of the added tile ratio to the average
	 *  disparity difference of the exclusively selected tiles
	 * @param non_exclusive allow tiles to belong to both planes of the pair
	 * @param use_other_planes allow other tiles from the same supertile
	 * @param measSel (with use_other_planes) select measurements for supertiles:
	 *  +1 - combo, +2 - quad +4 - hor +8 - vert
	 * @param allow_parallel allow parallel shift of the specified planes before adding
	 *  more tiles (from the same pair and/or other tiles of the supertile (see
	 *  non_exclusive, use_other_planes
	 * @param splitXY generate XY separation masks for split planes, so tiles will not
	 *        be allowed to snap to the other plane in pair
	 * @param splitXYTolerance XY separation disparity tolerance (there will be some
	 *  overlapping if > 0.0
7097
	 * @param disp_far disparity low limit
7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108
	 * @param disp_near disparity high limit (Double.NaN - no limit)
	 * @param dispNorm normalize disparity difference (keep relative) for disparities above
	 * @param min_weight minimal total weight of the plane
	 * @param min_tiles minimal number of tiles in a plane
	 * @param targetEigen target primary eigenvalue when removing outliers
	 * @param fractOutliers maximal fraction of outliers from all tiles to remove
	 * @param maxOutliers maximal number of outliers to remove
	 * @param strength_floor subtract from correlation strength (and limit by 0) to use
	 *  correlation strength as weight
	 * @param strength_pow raise correlation strength (after subtracting strength_floor) to
	 *  this power before using as weight
7109 7110 7111
	 * @param smplMode use square sample mode, false - single-tile samples
	 * @param smplSide size of the square sample side
	 * @param smplNum number of averaged samples (should be <= smplSide * smplSide and > 1)
7112
	 * @param smplRms maximal square root of variance (in disparity pixels) to accept the result
7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123
	 * @param debugLevel debug level
	 * @param dbg_X supertile horizontal index to show debug information
	 * @param dbg_Y supertile vertical index to show debug information
	 * @return number of planes replaced
	 */
	// TODO: Mark replaced planes and reduce eigenvalue requirements for them (in case they are small)
	// TODO:  planesSmooth() add power function to modify pull/neighbors relation (8 pull stronger than 1, but not 8 times stronger
	public int replaceBrokenPlanes(
			final TilePlanes.PlaneData[][]   planes,
			final TilePlanes.PlaneData[][][] brokenPd,
			final double                     max_diff, // maximal disparity difference (0 - any), will be normalized by dispNorm
7124
			final double                     other_diff,
7125 7126 7127 7128
			final boolean                    non_exclusive,
			final boolean                    use_other_planes, // TODO:
			final int                        measSel, // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
			final boolean                    allow_parallel,
7129

7130 7131
			final boolean                    splitXY,
			final double                     splitXYTolerance,
7132 7133

			// parameters to generate ellipsoids
7134 7135 7136 7137 7138
			final double                     disp_far, // minimal disparity to select (or NaN)
			final double                     disp_near, // maximal disparity to select (or NaN)
			final double                     dispNorm,   //  Normalize disparities to the average if above
			final double                     min_weight,
			final int                        min_tiles,
7139
			// parameters to reduce outliers
7140
			final double                     targetEigen,   //     =   0.1;  // Remove outliers until main axis eigenvalue (possibly scaled by plDispNorm) gets below
7141
			final double                     inFractOutliers, //     =   0.3;  // Maximal fraction of outliers to remove
7142
			final int                        maxOutliers,   //     =   20;  // Maximal number of outliers to remove
7143
			final boolean                    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
7144
			final MeasuredLayersFilterParameters mlfp,
7145 7146 7147 7148
			final double                     fronto_tol, // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable this feature
//FIXME: use following 2 parameters
			final double                     fronto_rms,    // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes
			final double                     fronto_offs,   //        =   0.2;  // increasing weight of the near tiles by using difference between the reduced average as weight. <= 0 - disable
7149
			final double                     fronto_pow,    //        =   1.0;  // increase weight even more
7150 7151 7152 7153 7154 7155
			final int                        debugLevel,
			final int                        dbg_X,
			final int                        dbg_Y)
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int superTileSize = tileProcessor.getSuperTileSize();
7156
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
7157 7158 7159 7160 7161 7162
		final int debug_stile = dbg_Y * stilesX + dbg_X;
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		final AtomicInteger ai_numThread = new AtomicInteger(0);
		final int [] replaced = new int[threads.length];
		final int [][] dbg_dirsYX = {{-1, 0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
7163

7164 7165
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
7166
				@Override
7167 7168 7169
				public void run() {
					double [][] dbg_img = null;
					String [] dbg_titles = null;
7170
					TilePlanes.PlaneData[][]   dbg_planes = planes;
7171 7172
					int numThread = ai_numThread.getAndIncrement(); // unique number of thread to write to rslt_diffs[numThread]
					for (int nsTile = ai.getAndIncrement(); nsTile < planes.length; nsTile = ai.getAndIncrement()) {
7173
						int sty = nsTile / stilesX;
7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207
						int stx = nsTile % stilesX;
						int dl = ((debugLevel > -1) && (nsTile == debug_stile)) ? 4:0;
						int num_bplanes = 2; // brokenPd[nsTile].length;
						int num_meas_layers = measuredLayers.getNumLayers();
						int [] dbg_indices = {
								0,
								num_bplanes,
								num_bplanes + 3 * num_meas_layers,
								num_bplanes + 3 * num_meas_layers + 2 * (num_bplanes * num_meas_layers),
								num_bplanes + 3 * num_meas_layers + 2 * (num_bplanes * num_meas_layers) + num_bplanes,
						};

						if ( brokenPd[nsTile] != null) {
							if (dl > 0){
								System.out.println("replaceBrokenPlanes nsTile="+nsTile);
								dbg_titles = new String[dbg_indices[4]];
								for (int i = 0; i < num_bplanes; i++){
									dbg_titles[i + dbg_indices[0]]="src_plane_"+i;
								}
								for (int j = 0; j < num_meas_layers; j++){
									dbg_titles[3* j + dbg_indices[1] + 0] =     "disp_"+j;
									dbg_titles[3* j + dbg_indices[1] + 1] =     "mask_disp_"+j;
									dbg_titles[3* j + dbg_indices[1] + 2] =     "str_"+j;
								}
								for (int i = 0; i < num_bplanes; i++){
									for (int j = 0; j < num_meas_layers; j++){
										dbg_titles[2 * (num_meas_layers * i +j) + dbg_indices[2] + 0] =  "t"+i+"_m"+j;
										dbg_titles[2 * (num_meas_layers * i +j) + dbg_indices[2] + 1] =  "ft"+i+"_m"+j;
									}
								}
								for (int i = 0; i < num_bplanes; i++){
									dbg_titles[i + dbg_indices[3]]="plane_"+i;
								}
							}
7208

7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224
							TilePlanes.PlaneData[][] bpd = new TilePlanes.PlaneData[brokenPd[nsTile].length][];
							for (int np = 0; np < bpd.length; np++){
								if (brokenPd[nsTile][np] != null){
									bpd[np] = new TilePlanes.PlaneData[2];
									bpd[np][0] = brokenPd[nsTile][np][0].clone();
									bpd[np][1] = brokenPd[nsTile][np][1].clone(); // no need to clone [2]
								}
							}
							if (splitXY) {
								for (int np = 0; np < bpd.length; np++){
									if (brokenPd[nsTile][np] != null){
										// if it will fail (return false) no selection masks, still possible to separate
										planes[nsTile][np].calcSelMasks(
												bpd[np][0],
												bpd[np][1],
												splitXYTolerance, // double    tolerance,
7225
												min_tiles,
7226 7227 7228 7229
												dl); // int       debugLevel
									}
								}
							}
7230

7231
							// now works on the pairs in bpd, null them out in case of failure
7232
							for (int np = 0; np < bpd.length; np++){
7233
								if ((dl > 1) && (bpd[np] !=null)) {
7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259
									int ss2 = 2 * superTileSize;
									dbg_img = new double [dbg_titles.length][];
									for (int ni = 0; ni < num_bplanes ; ni++) {
										dbg_img[ni + dbg_indices[0]] =  bpd[np][ni].getDoublePlaneDisparity(false);
										boolean [] sm = bpd[np][ni].getSelMask();
										// checkerboard pattern over disabled part of the plane
										if (sm != null) {
											for (int i = 0; i < sm.length; i++){
												if (!sm[i] && ((((i % ss2)+ (i / ss2)) & 1) != 0)){
													dbg_img[ni + dbg_indices[0]][i] = Double.NaN;
												}
											}
										}
									}
									// add connections to neighbors
									for (int dir = 0; dir <8; dir++){
										int indx = (ss2 / 2) * (ss2 + 1);
										int dindx = dbg_dirsYX[dir][0] * ss2 + dbg_dirsYX[dir][1];
										for (int l = 0; l < (ss2 / 2 - 2); l++){
											if ( l > 2){ // keep center not modified
												for (int ni = 0; ni < num_bplanes ; ni++) {
													if (bpd[np][ni].getNeibBest(dir) >= 0){
														dbg_img[ni + dbg_indices[0]][indx] = Double.NaN;
													}
												}
											}
7260
											indx += dindx;
7261 7262 7263 7264
										}
									}
									// show disparity (all and masked for this plane) and strength
									for (int ml = 0; ml < num_meas_layers; ml++) {
Andrey Filippov's avatar
Andrey Filippov committed
7265
										double [][] dbg_disp_str = planes[nsTile][np].getMeasuredLayers().getDisparityStrengthML(
7266 7267 7268 7269
												ml,                     // int num_layer,
												stx,        // int stX,
												sty,        // int stY,
												null,       // boolean [] sel_in,
7270 7271 7272
												mlfp,
//												strength_floor,         //  double strength_floor,
//												strength_pow,  // double strength_pow,
7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285
												true);                  // boolean null_if_none);
										if (dbg_disp_str != null){
											boolean [] dbg_msel = planes[nsTile][np].getMeasSelection(ml);
											dbg_img[3 * ml + dbg_indices[1] + 0] = dbg_disp_str[0];
											dbg_img[3 * ml + dbg_indices[1] + 2] = dbg_disp_str[1];
											dbg_img[3 * ml + dbg_indices[1] + 1] = dbg_disp_str[0].clone();
											if (dbg_msel != null) {
												for (int i = 0; i < dbg_msel.length; i++){
													if (!dbg_msel[i]) dbg_img[3 * ml + dbg_indices[1] + 1][i] = Double.NaN;
												}
											}
										}
									}
7286

7287
								} // (dl > 1)
7288

7289 7290 7291 7292
								if (brokenPd[nsTile][np] != null){
									// Is it a single set to replace current plane? If yes, use all tiles, not just original selection
									int np_min = LOWEST_PLANE(planes[nsTile].length);
									boolean single_plane = (np_min == (planes[nsTile].length - 1));
7293

7294 7295 7296 7297 7298 7299 7300
									Boolean OK = planes[nsTile][np].splitPlaneTiles ( // now always OK TODO: add layer mask or make use_other_planes int
											bpd[np],          // PlaneData [] pd_set,
											single_plane,     // boolean      single_plane,
											max_diff,         // double       max_diff, // maximal disparity difference (0 - any), will be normalized by dispNorm
											other_diff,
											non_exclusive,    // boolean      non_exclusive,
											use_other_planes, // boolean      use_other_planes,
7301
											smplMode,
7302
											mlfp,
7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323
											measSel,          // int          measSel, // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert
											allow_parallel,   //boolean      allow_parallel,
											dl); // int          debugLevel)
									if (!OK) {
										brokenPd[nsTile][np] = null;
										continue;
									}
									if (dl > 1) {// show initial selection (made of disparity clone - dbg_img[3 * ml + dbg_indices[1] + 0] = dbg_disp_str[0];
										for (int ni = 0; ni < num_bplanes ; ni++) {
											boolean [][] msel = new boolean [num_meas_layers][];
											for (int ml = 0; ml < num_meas_layers; ml++) {
												msel[ml] = bpd[np][ni].getMeasSelection(ml);
												if (msel[ml] != null) {
													dbg_img[2 * (num_meas_layers * ni +ml) + dbg_indices[2] + 0] =  dbg_img[3 * ml + dbg_indices[1] + 0].clone();
													for (int i = 0; i < msel[ml].length; i++){
														if (!msel[ml][i]) dbg_img[2 * (num_meas_layers * ni +ml) + dbg_indices[2] + 0][i] = Double.NaN;
													}
												}
											}
										}
									}
7324

7325
									for (int npip = 0; npip < bpd[np].length; npip++) {
7326
										double [][][] disp_strength = bpd[np][npip].getPlaneFromMeas(
7327
												null,           // boolean [][] tile_sel, // null - do not use, {} use all (will be modified)
7328
												null,
7329 7330 7331 7332 7333
												disp_far,       // double       disp_far, // minimal disparity to select (or NaN)
												disp_near,      // double       disp_near, // maximal disparity to select (or NaN)
												dispNorm,       // double       dispNorm,   //  Normalize disparities to the average if above
												min_weight,     // double       min_weight,
												min_tiles,      // int          min_tiles,
7334
// OK?
7335
												smplMode,
7336
												mlfp,
7337
												dl);            // int          debugLevel)
7338
										if (disp_strength == null) break;
7339 7340 7341 7342 7343 7344
										// remove outliers //removeOutliers
										// now try to remove outliers
										double targetV = corrMaxEigen(
												targetEigen,
												dispNorm,
												bpd[np][npip]);
7345
//										if (bpd[np][npip].getValue() > targetV) {
7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369
										boolean almost_fronto = bpd[np][npip].isFronto(
												fronto_tol,    // double fronto_tol,
												disp_strength,      // double [][][] disp_str,
												debugLevel);   // int debugLevel);
										// seems it is OK not to normalize fronto_rms, as it is only needed for far surfaces
										double targetEigen = almost_fronto ? (fronto_rms*fronto_rms): targetV;
										// FIXME: temporary - make a configurable parameter
										double fronto_fract_outliers = 0.8; // 2 * inFractOutliers;
										double fractOutliers = almost_fronto ? (fronto_fract_outliers) : inFractOutliers;
										int max_outliers = (int) Math.round(bpd[np][npip].getNumPoints() * fractOutliers);
										if (max_outliers > maxOutliers) max_outliers = maxOutliers;


//										if (bpd[np][npip].getNormValue() > targetV) {
										// in fronto mode - run at least once
										if (almost_fronto) {
											bpd[np][npip].growFrontoSelection(
													4,              // int           min_neib,
													0.1,            // double        max_over_avg,
													0.00,           // double        max_under_avg,
													disp_strength); // double [][][] disp_str)
										}

										if ((bpd[np][npip].getNormValue() > targetEigen) || almost_fronto) { // targetV) {
7370
											OK = bpd[np][npip].removeOutliers( // getPlaneFromMeas should already have run
7371 7372
													fronto_tol, // fronto tolerance (pix) - treat almost fronto as fronto (constant disparity). <= 0 - disable this feature
													fronto_rms,    // double        fronto_rms,  // Target rms for the fronto planes - same as sqrt(plMaxEigen) for other planes. May be tighter
7373 7374
													fronto_offs,   // double        fronto_offs,   //        =   0.2;  // increasing weight of the near tiles by using difference between the reduced
													fronto_pow,    // double        fronto_pow,    //        =   1.0;  // increase weight even more
7375
													disp_strength,
7376 7377 7378 7379
													targetV,      // double     targetEigen, // target eigenvalue for primary axis (is disparity-dependent, so is non-constant)
													max_outliers, // int        maxRemoved,  // maximal number of tiles to remove (not a constant)
													dl); // int        debugLevel)
											if (!OK) break;
7380
										}
7381

7382 7383 7384 7385 7386 7387 7388 7389
										bpd[np][npip].getWorldPlaneFromMeas(
												null,           // boolean [][] tile_sel, // null - do not use, {} use all (will be modified)
												disp_strength,
												disp_far,       // double       disp_far, // minimal disparity to select (or NaN)
												disp_near,      // double       disp_near, // maximal disparity to select (or NaN)
												dispNorm,       // double       dispNorm,   //  Normalize disparities to the average if above
												min_weight,     // double       min_weight,
												min_tiles,      // int          min_tiles,
7390 7391
//												strength_floor, // double       strength_floor,
//												strength_pow,   // double       strength_pow,
7392
// OK?
7393
												smplMode,
7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406
												mlfp,
//												smplSide,
//												smplNum,
//												smplRms,
//												smplWnd,           // was not here: final boolean    smplWnd,  // use window functions for the samples

//												max_abs_tilt,  // 2.0; // Maximal absolute tilt in pixels/tile
//												max_rel_tilt,  // 0.2; // Maximal relative tilt in pixels/tile/disparity
//												damp_tilt,     //    0.001; // Damp tilt to handle insufficient  (co-linear)data
//												min_tilt_disp, // 4.0; // Disparity switch between filtering modes - near objects use tilts, far - use max disparity
//												transition,    // 1.0; // Mode transition range (between tilted and maximal disparity)
//												far_mode,      //     1;   // Far objects filtering mode (0 - off, 1 - power of disparity)
//												far_power,     //    1.0; // Raise disparity to this power before averaging for far objects
7407

7408
												dl);            // int          debugLevel)
7409 7410 7411 7412 7413
									}
									if (!OK) {
										brokenPd[nsTile][np] = null;
										continue;
									}
7414

7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432
									if (dl > 1) {// filtered selection (made of disparity clone - dbg_img[3 * ml + dbg_indices[1] + 0] = dbg_disp_str[0];
										for (int ni = 0; ni < num_bplanes ; ni++) {
											boolean [][] msel = new boolean [num_meas_layers][];
											for (int ml = 0; ml < num_meas_layers; ml++) {
												msel[ml] = bpd[np][ni].getMeasSelection(ml);
												if (msel[ml] != null) {
													dbg_img[2 * (num_meas_layers * ni +ml) + dbg_indices[2] +1] =  dbg_img[3 * ml + dbg_indices[1] + 0].clone();
													for (int i = 0; i < msel[ml].length; i++){
														if (!msel[ml][i]) dbg_img[2 * (num_meas_layers * ni +ml) + dbg_indices[2] + 1][i] = Double.NaN;
													}
												}
											}
										}
										// show new planes
										for (int ni = 0; ni < num_bplanes ; ni++) {
											dbg_img[ni + dbg_indices[3]] =  bpd[np][ni].getDoublePlaneDisparity(false);
										}
										// actually show the image
7433

7434
										if (debugLevel > -1){
7435
											ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays();
7436 7437 7438 7439 7440 7441 7442 7443 7444 7445
											sdfa_instance.showArrays(dbg_img, 2 * superTileSize, 2 * superTileSize, true, "replaceBrokenPlanes"+stx+"_y"+sty+"_p"+np, dbg_titles);
										}
									}
								}
							}
							// now see if anything is left
							int npairs = 0;
							for (int np = 0; np < bpd.length; np++){
								if (bpd[np] != null) npairs++;
							}
7446

7447 7448 7449 7450 7451
							// Fixing that first plane in multi=-plane is not processed
							int np_start = LOWEST_PLANE(2); // planes[nsTile].length);

							if (npairs > 0){
								TilePlanes.PlaneData[] old_planes = planes[nsTile];
7452
								int old_len = old_planes.length - LOWEST_PLANE(old_planes.length);
7453
								planes[nsTile] = new TilePlanes.PlaneData[old_len + npairs + np_start];
7454
								int npr = 0;
7455
								for (int np = LOWEST_PLANE(old_planes.length); np < np_start;  np++) {
7456
									planes[nsTile][npr++] = null; // see if there will be any conflicts, fix or replace with old_planes[0];
7457 7458 7459
								}
								for (int np = 0; np < bpd.length; np++){
									if (bpd[np] != null) {
7460 7461
										planes[nsTile][npr++] = bpd[np][0];
										planes[nsTile][npr++] = bpd[np][1];
7462
									} else {
7463
										planes[nsTile][npr++] = old_planes[np];
7464 7465 7466 7467
									}
								}
							}
							replaced[numThread] += npairs;
7468
						}
7469 7470 7471
					}
				}
			};
7472
		}
7473 7474 7475 7476 7477
		ImageDtt.startAndJoin(threads);
		int replaced_planes = 0;
		for (int i = 0; i < replaced.length; i++) replaced_planes += replaced[i];
		return replaced_planes;
	}
7478

7479 7480 7481
	/**
	 * Create candidate planes to break a single plane in 2 by splitting consecutive connected
	 * neighbors in 2 groups that make the smallest weighted sum of the eigenvalues
7482 7483
	 * Groups may be optionally supplemented by the center supertile
	 * Result weights are sums of participating supertile weights, for normalization  (if needed)
7484
	 * divide by number of neighbors plus center_pull
7485 7486 7487 7488 7489 7490
	 * @param center_planes [per supertile][per plane] array of plane objects to use as
	 *        the source of connections and optionally other data for the center tiles
	 * @param neib_planes  [per supertile][per plane] array of plane objects to use for
	 *        neighbor data. May be the same as center_planes or different
	 * @param center_pull - merge with center plane when calculating half-planes with this
	 *  relative weight: 0.0 - only neighbors, 1.0 - same weight of the center as each neighbor.
7491 7492
	 * @param min_neibs - minimal number of connected neighbors to work with (>=2)
	 * @param splitMinWeight -  minimal weight of the tile to split
7493
	 * @param splitMinQuality - minimal quality of split (EV of the single plane over weighted average
7494
	 *        of each half-plane
7495 7496 7497 7498 7499 7500 7501 7502 7503
	 * @param preferDisparity - the first eigenvalue/vector is the most disparity-like
	 *                          (false - smallest eigenvalue)
	 * @param debugLevel debug level
	 * @param dbg_X supertile horizontal index to show debug information
	 * @param dbg_Y supertile vertical index to show debug information
	 * @return a pair of plane objects for each [supertile][plane][3] and a combination of both
	 *         (to compare eigenvalues)
	 */
	public TilePlanes.PlaneData[][][] breakPlanesToPairs(
7504 7505
			final TilePlanes.PlaneData[][] center_planes,   // measured_planes,
			final TilePlanes.PlaneData[][] neib_planes,     //mod_planes,
7506
			final double                   center_pull,
7507 7508 7509
			final int                      min_neibs,       // 2
			final double                   splitMinWeight,  //     =  2.0;  // Minimal weight of split plains to show
			final double                   splitMinQuality, //    =  1.1;  // Minimal split quality to show
7510 7511 7512 7513 7514 7515 7516 7517 7518
			final boolean                  preferDisparity, // Always start with disparity-most axis (false - lowest eigenvalue)
			final int                      debugLevel,
			final int                      dbg_X,
			final int                      dbg_Y)
	{
		final int [][] dirsYX = {{-1, 0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
		final int tilesX =        tileProcessor.getTilesX();
//		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
7519
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
7520 7521 7522 7523 7524
//		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		final int debug_stile = dbg_Y * stilesX + dbg_X;
		final TilePlanes.PlaneData[][][] rslt_planes = new TilePlanes.PlaneData[center_planes.length][][];
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
7525
		final String [] titles= {"center", "first", "second", "all", "f-s"};
7526 7527 7528

		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
7529
				@Override
7530 7531 7532
				public void run() {
					double [][] dbg_img=null;
					for (int nsTile0 = ai.getAndIncrement(); nsTile0 < center_planes.length; nsTile0 = ai.getAndIncrement()) {
7533
						int sty0 = nsTile0 / stilesX;
7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544
						int stx0 = nsTile0 % stilesX;
						int dl = ((debugLevel > -1) && (nsTile0 == debug_stile)) ? 1:0;
						if ( center_planes[nsTile0] != null) {
							rslt_planes[nsTile0] = new TilePlanes.PlaneData[center_planes[nsTile0].length][];
							if (dl > 0){
								System.out.println("breakPlanesToPairs nsTile0="+nsTile0);
								dbg_img = new double [titles.length][];
							}
							int np0_min = (center_planes[nsTile0].length > 1) ? 1:0; // Modify if overall plane will be removed
							for (int np0 = np0_min; np0 < center_planes[nsTile0].length; np0 ++){
								TilePlanes.PlaneData center_plane = center_planes[nsTile0][np0];
7545 7546 7547 7548 7549 7550 7551 7552 7553 7554
								if (center_plane.getWeight() >= splitMinWeight) {
									if (dl > 0) dbg_img[ 0] = center_plane. getTriplePlaneDisparity();
									int [] neibs = center_plane.getNeibBest();
									int num_neibs = 0;
									for (int i = 0; i < neibs.length; i++) if (neibs[i] >= 0) num_neibs++;
									if (num_neibs >= min_neibs) {
										// create all pairs to test
										int num_splits = num_neibs * (num_neibs - 1) / 2;
										double [] split_quality = new double [num_splits]; // weighted sum of eigenvalues of merged
										int [][][] neibs12 = new int [2][num_splits][];
7555
										TilePlanes.PlaneData[][] plane_triads = new TilePlanes.PlaneData[num_splits][3];
7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569
										int [] neib_index = new int [num_neibs];
										int nn = 0;
										for (int i = 0; i < neibs.length; i++) if (neibs[i] >= 0) neib_index[nn++] = i;
										nn = 0;
										for (int nStart = 1; nStart < num_neibs; nStart++) {
											for (int nEnd = nStart+1; nEnd <= num_neibs; nEnd++){
												neibs12[0][nn] = neibs.clone();
												neibs12[1][nn] = neibs.clone();
												for (int i = 0; i < neib_index.length; i++) {
													if ((i < nStart) || (i >= nEnd)){
														neibs12[0][nn][neib_index[i]] = -1;
													} else {
														neibs12[1][nn][neib_index[i]] = -1;
													}
7570
												}
7571
												nn++;
7572 7573
											}
										}
7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593

										for (int nSplit = 0; nSplit < num_splits; nSplit++) {
											// Calculate merged plane for each selection (and other), weighted average and store to split_quality
											for (int nis = 0; nis < 2; nis++) {
												plane_triads[nSplit][nis] = center_planes[nsTile0][np0].clone();
												plane_triads[nSplit][nis].scaleWeight(center_pull);
												for (int dir = 0; dir <8; dir++){
													int np = neibs12[nis][nSplit][dir];
													if (np >= 0){
														int stx = stx0 + dirsYX[dir][1];
														int sty = sty0 + dirsYX[dir][0];
														int nsTile = sty * stilesX + stx; // from where to get
														TilePlanes.PlaneData other_plane = plane_triads[nSplit][nis].getPlaneToThis(
																neib_planes[nsTile][np],
																dl-1); // debugLevel);
														if (other_plane != null){
															if (plane_triads[nSplit][nis].getWeight() > 0.0){
																plane_triads[nSplit][nis] = plane_triads[nSplit][nis].mergePlaneToThis(
																		other_plane, // PlaneData otherPd,
																		1.0,         // double    scale_other,
7594
																		1.0,         // double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
7595 7596 7597 7598 7599
																		false,       // boolean   ignore_weights,
																		true, // boolean   sum_weights,
																		preferDisparity,
																		dl-1); // int       debugLevel)
															} else {
7600
																plane_triads[nSplit][nis] = other_plane;
7601
															}
7602
														} else {
7603 7604
															plane_triads[nSplit][nis] = null;
															break;
7605 7606 7607
														}
													}
												}
7608 7609 7610 7611
											} // for (int nis = 0; nis < 2; nis++) {
											if ((plane_triads[nSplit][0] != null) && (plane_triads[nSplit][1] != null)){
												double w1 = plane_triads[nSplit][0].getWeight();
												double w2 = plane_triads[nSplit][1].getWeight();
7612 7613
//												split_quality[nSplit] = (w1 * plane_triads[nSplit][0].getValue() + w2 * plane_triads[nSplit][1].getValue())/
												split_quality[nSplit] = (w1 * plane_triads[nSplit][0].getNormValue() + w2 * plane_triads[nSplit][1].getNormValue())/
7614 7615 7616 7617 7618
														(w1 + w2);
												if (dl >0){
													plane_triads[nSplit][2] = plane_triads[nSplit][0].clone().mergePlaneToThis(
															plane_triads[nSplit][1], // PlaneData otherPd,
															1.0,                    // double    scale_other,
7619
															1.0,                    // double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
7620 7621 7622
															false,                  // boolean   ignore_weights,
															true, // boolean   sum_weights,
															preferDisparity,
7623
															dl-1);
7624 7625 7626 7627 7628 7629
												}
											} else {
												split_quality[nSplit] = Double.NaN;
											}
											if (dl >0){
												System.out.println("breakPlanesToPairs(): split_quality["+nSplit+"] = "+split_quality[nSplit]);
7630 7631
											}
										}
7632 7633
										// find minimum in split_quality and generate a pair of plane objects, setting neighbors for each
										// later use these plane pairs to assign tiles to each and generate a new eigenvalues/vectors
7634
										// TODO: How to handle a pair? Any special treatment (like fusing?),
7635 7636 7637 7638 7639 7640
										// if the plane intersection line is inside supertile - use min/max for snapping
										int best_index = -1;
										for (int nSplit = 0; nSplit < num_splits; nSplit++) {
											if (!Double.isNaN(split_quality[nSplit]) && ((best_index < 0) || (split_quality[nSplit] < split_quality[best_index]))){
												best_index = nSplit;
											}
7641
										}
7642 7643 7644 7645
										if (best_index >= 0) {
											plane_triads[best_index][2] = plane_triads[best_index][0].clone().mergePlaneToThis(
													plane_triads[best_index][1], // PlaneData otherPd,
													1.0,                     // double    scale_other,
7646
													1.0, // double     starWeightPwr,    // Use this power of tile weight when calculating connection cost
7647 7648
													false,                   // boolean   ignore_weights,
													true,                    // boolean   sum_weights,
7649
													preferDisparity,
7650 7651 7652
													dl-1);
											//  check quality
											if ((plane_triads[best_index][2] != null) &&
7653 7654
//													(plane_triads[best_index][2].getValue()/split_quality[best_index] > splitMinQuality)) {
													(plane_triads[best_index][2].getNormValue()/split_quality[best_index] > splitMinQuality)) {
7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694
												for (int nis = 0; nis < 2; nis++) {
													plane_triads[best_index][nis].setNeibBest(neibs12[nis][best_index]);
												}
												rslt_planes[nsTile0][np0] = plane_triads[best_index];
												if (dl > 0) {
													int ss3 = 3 * superTileSize;
													dbg_img[ 1] = plane_triads[best_index][0].getTriplePlaneDisparity();
													dbg_img[ 2] = plane_triads[best_index][1].getTriplePlaneDisparity();
													dbg_img[ 3] = plane_triads[best_index][2].getTriplePlaneDisparity();
													dbg_img[ 4] = new double [dbg_img[ 1].length];
													for (int i = 0; i< dbg_img[ 1].length; i++){
														dbg_img[ 4][i] = dbg_img[ 1][i] - dbg_img[ 2][i];
													}
													int [] vby = new int [ss3];
													double [] dbg_split = dbg_img[ 4];
													for (int dx = 0; dx < ss3; dx ++){
														vby[dx] = 0;
														for (int dy = 1; dy < ss3; dy ++){
															int indx = dy * ss3 + dx;
															if (Math.abs(dbg_split[indx]) < Math.abs(dbg_split[vby[dx] * ss3 + dx])){
																vby[dx] = dy; // indx;
															}
														}
													}
													for (int dy = 0; dy < ss3; dy ++){
														int bx = 0;
														for (int dx = 1; dx < ss3; dx ++){
															if (Math.abs(dbg_split[dy * ss3 + dx]) < Math.abs(dbg_split[dy * ss3 + bx])){
																bx = dx;
															}
														}
														if ((bx > 0) && (bx < (ss3-1))) {
															dbg_split[dy * ss3 + bx] = Double.NaN;
															dbg_img[ 3][dy * ss3 + bx] = Double.NaN;
														}
													}

													for (int dx = 0; dx < ss3; dx ++){
														int by = vby[dx];
														if ((by > 0) && (by < (ss3-1))) {
7695
															dbg_split[by * ss3 + dx] = Double.NaN;
7696 7697
															dbg_img[ 3][by * ss3 + dx] = Double.NaN;
														}
7698
													}
7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712

													for (int dir = 0; dir <8; dir++){
														int indx = (ss3 / 2) * (ss3 + 1);
														int dindx = dirsYX[dir][0] * ss3 + dirsYX[dir][1];

														for (int l = 0; l < (ss3 / 2 - 2); l++){
															if ( l > 2){ // keep center not modified
																if (plane_triads[best_index][0].getNeibBest(dir) >= 0){
																	dbg_img[ 1][indx] = Double.NaN;
																}
																if (plane_triads[best_index][1].getNeibBest(dir) >= 0){
																	dbg_img[ 2][indx] = Double.NaN;
																}
															}
7713
															indx += dindx;
7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731
														}
													}
													System.out.println("breakPlanesToPairs(): num_splits="+num_splits+", best_index="+best_index);
													for (int nSplit = 0; nSplit < num_splits; nSplit++) {
														if ((plane_triads[nSplit][0] != null) && (plane_triads[nSplit][1] != null) && (plane_triads[nSplit][2] != null)){
															System.out.print("breakPlanesToPairs():"+nSplit+" ");
															for (int dir = 0; dir < 8; dir++){
																System.out.print((neibs12[0][nSplit][dir] >=0)?"+":"-");
															}
															System.out.print(" ");
															for (int dir = 0; dir < 8; dir++){
																System.out.print((neibs12[1][nSplit][dir] >=0)?"+":"-");
															}
															System.out.print(" ");
															for (int dir = 0; dir < 8; dir++){
																System.out.print((plane_triads[nSplit][2].getNeibBest(dir) >=0)?"+":"-");
															}
															System.out.println(" : "+split_quality[nSplit]+
7732 7733 7734 7735 7736 7737
//																	" "+plane_triads[nSplit][0].getValue()+
//																	" "+plane_triads[nSplit][1].getValue()+
//																	" "+plane_triads[nSplit][2].getValue()+
																	" "+plane_triads[nSplit][0].getNormValue()+
																	" "+plane_triads[nSplit][1].getNormValue()+
																	" "+plane_triads[nSplit][2].getNormValue()+
7738 7739 7740 7741 7742 7743 7744 7745 7746
																	" w"+plane_triads[nSplit][0].getWeight()+
																	" w"+plane_triads[nSplit][1].getWeight()+
																	" w"+plane_triads[nSplit][2].getWeight()
																	);
														}
													}

													// merged_eig_val are not set - will have to be recalculated when updating after changing tile selections
													// to make each plane
7747
													// TODO save gain from splitting to planes
7748

7749
													if (debugLevel > 3){
7750
														ShowDoubleFloatArrays sdfa_instance = new ShowDoubleFloatArrays();
7751 7752 7753 7754
														sdfa_instance.showArrays(dbg_img, 3*superTileSize, 3*superTileSize, true, "breakPlanesToPairs"+stx0+"_y"+sty0+"_p"+np0, titles);
													}
												}
											}
7755 7756 7757 7758
										}
									}
								}
							}
7759
						}
7760 7761 7762
					}
				}
			};
7763
		}
7764 7765 7766 7767 7768
		ImageDtt.startAndJoin(threads);
		return rslt_planes;
	}


Andrey Filippov's avatar
Andrey Filippov committed
7769 7770 7771 7772
	public boolean [][] selectPlanes(
			final double dispNorm,
			final double maxEigen, // maximal eigenvalue of planes to consider
			final double minWeight, // minimal pain weight to consider
7773
			final boolean weak_connected, // select connected planes even if they are weak/thick
Andrey Filippov's avatar
Andrey Filippov committed
7774 7775 7776 7777 7778 7779
			TilePlanes.PlaneData [][] planes)
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
		//				final int tileSize =      tileProcessor.getTileSize();
7780
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
7781 7782 7783 7784 7785 7786 7787 7788
		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		boolean [][] selection = new boolean [planes.length][];
		for (int sty = 0; sty < stilesY; sty++){
			for (int stx = 0; stx < stilesX; stx++){
				int nsTile = sty * stilesX + stx;
				if (planes[nsTile] != null) {
					selection[nsTile] = new boolean [planes[nsTile].length];
					for (int np = 0; np < planes[nsTile].length; np++){
7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801
//						if ((planes[nsTile][np] != null) && (planes[nsTile][np].getWeight() >= minWeight)){
						if (planes[nsTile][np] != null){
							boolean has_conn = false;
							for (int dir = 0; dir < 8; dir++){
								if (planes[nsTile][np].getNeibBest(dir) >= 0){
									has_conn = true;
									break;
								}
							}
							if (weak_connected && has_conn) {
								selection[nsTile][np] = true;
							} else if  (planes[nsTile][np].getWeight() >= minWeight) {
								//&& (planes[nsTile][np].getValue() < maxEigen)){
7802 7803
//								double eigVal = planes[nsTile][np].getValue();
								double eigVal = planes[nsTile][np].getNormValue();
7804 7805 7806 7807 7808 7809
								double disp = planes[nsTile][np].getZxy()[0];
								selection[nsTile][np] = (eigVal < corrMaxEigen(
										maxEigen,
										dispNorm,
										disp));
							}
Andrey Filippov's avatar
Andrey Filippov committed
7810 7811 7812 7813
						}
					}
				}
			}
Andrey Filippov's avatar
Andrey Filippov committed
7814 7815 7816
		}
		return selection;
	}
Andrey Filippov's avatar
Andrey Filippov committed
7817

Andrey Filippov's avatar
Andrey Filippov committed
7818 7819 7820 7821 7822 7823
	public int [][] createSupertileShells(
			boolean[][]                     selection, // may be null
			boolean                         use_all, // use plane 0 even if there are more than 1
			boolean                         keep_orphans, // single-cell shells
			double                          orphan_strength, // minimal strength no keep orphans (single-tile planes)
			final TilePlanes.PlaneData [][] planes,
7824 7825 7826
			final int         debugLevel,
			final int         dbg_X,
			final int         dbg_Y)
Andrey Filippov's avatar
Andrey Filippov committed
7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839
	{
		class TPW {
			int t;
			int p;
			double w;
			TPW (int t, int p){
				this.t= t;
				this.p= p;
				this.w = planes[t][p].getWeight();
			}
		}
		final int tilesX =        tileProcessor.getTilesX();
		final int superTileSize = tileProcessor.getSuperTileSize();
7840
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851
		final int [] dirs= {-stilesX, -stilesX+1, 1, stilesX+1, stilesX, stilesX-1, -1, -stilesX-1};
		boolean [][] field = new boolean [planes.length][];
		for (int nsTile = 0; nsTile < planes.length; nsTile++){
			if (nsTile==724){
				System.out.println("createSupertileShells()1 nsTile="+nsTile);
			}
			if (planes[nsTile] != null){
				field[nsTile] = new boolean [planes[nsTile].length];
				if (selection != null) {
					for (int i = 0; i < selection[nsTile].length; i++){
						if (!selection[nsTile][i]) field[nsTile][i] = true; // used/prohibited
Andrey Filippov's avatar
Andrey Filippov committed
7852 7853
					}
				}
Andrey Filippov's avatar
Andrey Filippov committed
7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867
				if (!use_all && (planes[nsTile].length > 1)){
					field[nsTile][0] = true; // used/prohibited
				}
			}
		}
		ArrayList<ArrayList<TPW>> listShells = new ArrayList<ArrayList<TPW>>();
		for (int nsTile = 0; nsTile < field.length; nsTile++){
			if (nsTile==724){
				System.out.println("createSupertileShells()2 nsTile="+nsTile);
			}

			if (field[nsTile] != null){
				for (int np = 0; np < field[nsTile].length; np++){
					if (!field[nsTile][np]){
7868
						// see if
Andrey Filippov's avatar
Andrey Filippov committed
7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896
						ArrayList<TPW> listWave = new ArrayList<TPW>();
						int read_p = 0;
						//								int num_cluster = listShells.size()+1;
						TPW sp = new TPW(nsTile,np);
						field[sp.t][sp.p] = true; // just 1 would be OK
						listWave.add(sp);
						while (read_p < listWave.size()) { // keeping all list, not just front
							TPW tail = listWave.get(read_p++);
							int [] neibs = planes[tail.t][tail.p].getNeibBest();
							for (int dir = 0; dir < neibs.length; dir++){
								if (neibs[dir] >= 0) {
									sp = new TPW(
											tail.t + dirs[dir],
											neibs[dir]);
									if (!field[sp.t][sp.p] && ((selection == null) || (selection[sp.t][sp.p]))){
										field[sp.t][sp.p] = true;
										listWave.add(sp);
									}
								}
							}

						}
						if (listWave.size() > 1) {
							listShells.add(listWave);
						} else if (keep_orphans && (listWave.size() == 1)){ // so far always >= 1
							TPW tail = listWave.get(0);
							if (planes[tail.t][tail.p].getWeight() >= orphan_strength){
								listShells.add(listWave);
Andrey Filippov's avatar
Andrey Filippov committed
7897 7898
							}
						}
Andrey Filippov's avatar
Andrey Filippov committed
7899 7900
						if (debugLevel > 1){
							System.out.println("CreateSupertileShells(): "+(listShells.size())+":"+listWave.size());
Andrey Filippov's avatar
Andrey Filippov committed
7901 7902 7903
						}
					}
				}
Andrey Filippov's avatar
Andrey Filippov committed
7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969
			}
		}
		// sort list
		Collections.sort(listShells, new Comparator<ArrayList<TPW>>() {
			@Override
			public int compare(ArrayList<TPW> lhs, ArrayList<TPW> rhs) {
				// -1 - less than, 1 - greater than, 0 - equal, all inverted for descending
				int sgn = lhs.size() > rhs.size() ? -1 : (lhs.size() < rhs.size() ) ? 1 : 0;
				if (sgn != 0) return sgn;
				double wl = 0.0, wr = 0.0;
				for (TPW p:lhs) wl += p.w;
				for (TPW p:rhs) wr += p.w;
				return wl > wr ? -1 : (wl < wr ) ? 1 : 0;
			}
		});


		int [][] shells = new int [planes.length][];
		for (int nsTile = 0; nsTile < planes.length; nsTile++){
			if (planes[nsTile] != null){
				shells[nsTile] = new int [planes[nsTile].length];
			}
		}
		for (int num_shell = 0; num_shell < listShells.size(); num_shell++){
			for (TPW p:listShells.get(num_shell)){
				shells[p.t][p.p] = num_shell+1;
			}
			if (debugLevel > 0){
				double w = 0;
				for (TPW p:listShells.get(num_shell)){
					w += p.w;
				}
				System.out.println("CreateSupertileShells(): "+(num_shell + 1)+":"+listShells.get(num_shell).size()+", total strength = "+w);
			}

		}
		return shells;
	}

	public double normDispADiff(
			double disp1,
			double disp2,
			double disp_norm
			)
	{
		double disp_avg = 0.5* (disp1 + disp2);
		double adiff = Math.abs(disp1 - disp2);
		return (disp_avg <= disp_norm) ? adiff : (adiff * disp_norm / disp_avg);
	}

	public double [] snapDisparity(
			final double []  disparity,
			final double []  strength,
			final boolean [] selection,       // can be null
			final double     dispNorm, // plDispNorm
			final double     snapDispAny,    //    =  .2,   // Maximal (scaled by plDispNorm) disparity difference to snap to plane at any strength
			final double     snapStrengthAny,    //    =  .2,   //  Maximal strength to fit any distance (if does not fit otherwise - treat as zero strength
			final double     snapNegAny,     //    =  .2,   // Maximal negative disparity difference from the best match
			final double     snapDispMax,    //    =  .5,   // Maximal (scaled by plDispNorm) disparity difference to snap to plane at low strength
			final double     snapDispWeight, //    =  .5,   // Maximal disparity diff. by weight product to snap to plane
			final int        snapZeroMode,   // Zero strength snap mode: 0: no special treatment, 1 - strongest, 2 - farthest
			final int        debugLevel)
	{
		final int tilesX =        tileProcessor.getTilesX();
//		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
7970
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
7971 7972 7973 7974 7975 7976 7977 7978 7979 7980
//		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		final double [][] surfaces = getSurfaces();
		final int [][] shell_map =   getShellMap();
		final TilePlanes.PlaneData [][] planes = getPlanesMod(); // to get strength;
		final double [] snap_disp =  disparity.clone();

		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
7981
				@Override
Andrey Filippov's avatar
Andrey Filippov committed
7982 7983 7984
				public void run() {
					for (int nTile = ai.getAndIncrement(); nTile < disparity.length; nTile = ai.getAndIncrement()) {
						if ((selection == null) || selection[nTile]) {
7985
							int tX = nTile % tilesX;
Andrey Filippov's avatar
Andrey Filippov committed
7986 7987 7988 7989
							int tY = nTile / tilesX;
							int stX = tX / superTileSize;
							int stY = tY / superTileSize;
							int nsTile = stY * stilesX + stX;
7990
							int nTile_st = (tY * stilesX * superTileSize) + tX; // surfaces maybe (is) larger than tilesX *tilesY if
Andrey Filippov's avatar
Andrey Filippov committed
7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010
							// tilesX, tilesY are not multiples of superTileSize !
							if (nsTile == 724){
//								System.out.println("snapDisparity(): tX:tY = "+tX+":"+tY+", stX:stY="+stX+":"+stY+
//										", nTile="+nTile+", nsTile="+nsTile+", nTile_st = "+nTile_st);
							}

							// is there any surface to snap to?
							boolean no_surf = true;
							if (shell_map[nsTile] != null){
								for (int np = 0; no_surf && (np < shell_map[nsTile].length); np++){
									if (shell_map[nsTile][np] > 0) no_surf = false;
								}
							}
							if (!no_surf) {
								double [] surf_disparity = new double[shell_map[nsTile].length];
								for (int np = 0; np < surf_disparity.length; np++){
									if (shell_map[nsTile][np] > 0) {
										surf_disparity[np] = surfaces[shell_map[nsTile][np] -1][nTile_st];
									} else {
										surf_disparity[np] = Double.NaN;
Andrey Filippov's avatar
Andrey Filippov committed
8011
									}
Andrey Filippov's avatar
Andrey Filippov committed
8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027
								}
								int best_indx = -1;
								double best_disp_diff = Double.NaN;
								double this_disp = disparity[nTile];
								double this_strength = strength[nTile];
								if (Double.isNaN(this_disp)){
									this_disp = 0.0;
									this_strength = 0.0;
								}
								for (int np = 0; np < surf_disparity.length; np++){
									if (shell_map[nsTile][np] > 0) {
										double disp_diff = normDispADiff (this_disp,surf_disparity[np], dispNorm);
										if ((best_indx < 0) || (disp_diff < best_disp_diff)) {
											best_disp_diff = disp_diff;
											best_indx =      np;
										}
8028 8029
									}
								}
Andrey Filippov's avatar
Andrey Filippov committed
8030 8031
								if ((this_strength > 0.0) || (snapZeroMode == 0)){
									if ((best_disp_diff <= snapDispAny) ||
8032
											((best_disp_diff <= snapDispMax) && (best_disp_diff * this_strength < snapDispWeight )) ||
Andrey Filippov's avatar
Andrey Filippov committed
8033 8034 8035 8036 8037
											((best_disp_diff <= snapNegAny) && (this_disp <  surf_disparity[best_indx]))  // farther than surface - higher tolerance
											){
										snap_disp[nTile] = surf_disparity[best_indx]; // snapped (default - keep source disparity
									} else if ((this_strength < snapStrengthAny) && (snapZeroMode != 0)){ // treat as zero strength?
										this_strength = 0.0;
Andrey Filippov's avatar
Andrey Filippov committed
8038 8039
									}
								}
Andrey Filippov's avatar
Andrey Filippov committed
8040

8041
								if ((this_strength == 0) && (snapZeroMode > 0)) {
Andrey Filippov's avatar
Andrey Filippov committed
8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067
									if (snapZeroMode == 1) {  // zero strength and non-zero snapZeroMode, consider 1 (strongest shell)
										best_indx = -1;
										double best_strength = Double.NaN;
										for (int np = 0; np < surf_disparity.length; np++){
											if (shell_map[nsTile][np] > 0) {
												double w = planes[nsTile][np].getWeight();
												if ((best_indx < 0) || (w >  best_strength)) {
													best_strength = w;
													best_indx =     np;
												}
											}
										}
										snap_disp[nTile] = surf_disparity[best_indx]; // snapped (default - keep source disparity
									} else { // zero strength and snapZeroMode > 1 (now only 2) - farthest surface (smallest disparity)
										best_indx = -1;
										double smallest_disparity = Double.NaN;
										for (int np = 0; np < surf_disparity.length; np++){
											if (shell_map[nsTile][np] > 0) {
												if ((best_indx < 0) || ( surf_disparity[np] <  smallest_disparity)) {
													smallest_disparity = surf_disparity[np];
													best_indx =     np;
												}
											}
										}
										snap_disp[nTile] = surf_disparity[best_indx]; // snapped (default - keep source disparity
									}
Andrey Filippov's avatar
Andrey Filippov committed
8068 8069 8070 8071 8072
								}
							}
						}
					}
				}
Andrey Filippov's avatar
Andrey Filippov committed
8073
			};
8074
		}
Andrey Filippov's avatar
Andrey Filippov committed
8075 8076 8077 8078 8079
		ImageDtt.startAndJoin(threads);
		return snap_disp;
	}

	/**
8080
	 * Get number of used surfaces (some may be empty)
Andrey Filippov's avatar
Andrey Filippov committed
8081 8082 8083 8084 8085 8086 8087 8088 8089 8090
	 * @param snap_surf surface indices (per-tile), 0 - unmatched
	 * @param selected boolean tile selection or null (use all tiles)
	 * @return maximal number of surface used
	 */
	public int getNumSurf(
			int []     snap_surf,
			boolean [] selected) // or null
	{
		final int tilesX =        tileProcessor.getTilesX();
		final int superTileSize = tileProcessor.getSuperTileSize();
8091 8092
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;

Andrey Filippov's avatar
Andrey Filippov committed
8093 8094
		int num_surf = 0;
		for (int nTile = 0; nTile < snap_surf.length; nTile ++) if (snap_surf[nTile] > 0){
8095
			int tX = nTile % tilesX;
Andrey Filippov's avatar
Andrey Filippov committed
8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125
			int tY = nTile / tilesX;
			int stX = tX / superTileSize;
			int stY = tY / superTileSize;
			int nsTile = stY * stilesX + stX;
			int np = snap_surf[nTile] - 1;
			if ((shell_map[nsTile][np] > num_surf) && ((selected == null) || selected[nTile])) {
				num_surf = shell_map[nsTile][np];
			}
		}
		return num_surf;
	}

	/**
	 * Get number of unmatched tiles
	 * @param snap_surf surface indices (per-tile), 0 - unmatched
	 * @param selected boolean tile selection or null (use all tiles)
	 * @return number of unmatched tiles
	 */
	public int getNumNotMatched(
			int []     snap_surf,
			boolean [] selected) // or null
	{
		int num_notmatched = 0;
		for (int i = 0; i < snap_surf.length; i++){
			if ((snap_surf[i] == 0) && ((selected == null) || selected[i])) {
				num_notmatched ++;
			}
		}
		return num_notmatched;
	}
8126

Andrey Filippov's avatar
Andrey Filippov committed
8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149
	public int getNeibMask(
			int x,
			int y,
			int width,
			int height)
	{
		final int [] corn_side_neib = { // of +1 - up (N), +2 - up-right - NE, ... +0x80 - NW
				0b00011100,    // top left corner
				0b01111100,    // top middle
				0b01110000,    // top right
				0b00011111,    // middle left
				0b11111111,    // middle
				0b11110001,    // middle right
				0b00000111,    // bottom left
				0b11000111,    // bottom middle
				0b11000001};   // bottom right
		int tileType = getNeibType(
				x,
				y,
				width,
				height);
		return corn_side_neib[tileType];
	}
8150

Andrey Filippov's avatar
Andrey Filippov committed
8151 8152
	/**
	 * Returns 8-element array - which supertile neighbor enables this tile neighbor (-1 - none)
8153
	 * @param x horizontal position of the tile in supertile
Andrey Filippov's avatar
Andrey Filippov committed
8154 8155 8156 8157 8158
	 * @param y vertical position of the tile in supertile
	 * @param width supertile width
	 * @param height supertile height
	 * @return 8-element array
	 */
8159

Andrey Filippov's avatar
Andrey Filippov committed
8160 8161 8162 8163 8164 8165 8166
	public int[] getNeibBordDir(
			int x,
			int y,
			int width,
			int height)
	{
		final int [][] dir_dir = { // of +1 - up (N), +2 - up-right - NE, ... +0x80 - NW
8167
			    //N  NE   E  SE   S  SW   W  NW
Andrey Filippov's avatar
Andrey Filippov committed
8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195
				{ 0,  0, -1, -1, -1,  6,  6,  7},    // top left corner
				{ 0,  0, -1, -1, -1, -1, -1,  0},    // top middle
				{ 0,  1,  2,  2, -1, -1, -1, -1},    // top right
				{-1, -1, -1, -1, -1,  6,  6,  6},    // middle left
				{-1, -1, -1, -1, -1, -1, -1, -1},    // middle
				{ 0,  2,  2,  2, -1, -1, -1, -1},    // middle right
				{-1, -1, -1,  4,  4,  5,  6,  6},    // bottom left
				{-1, -1, -1,  4,  4,  4, -1, -1},    // bottom middle
				{-1,  2,  2,  3,  4,  4, -1, -1}};   // bottom right
		int tileType = getNeibType(
				x,
				y,
				width,
				height);
		return dir_dir[tileType];
	}

	public int getNeibType(
			int x,
			int y,
			int width,
			int height)
	{
		int tileType = 4;
		int hm1 = height -1;
		int wm1 = width - 1;
		if (y == 0){
			if (x == 0){
8196
				tileType = 0;
Andrey Filippov's avatar
Andrey Filippov committed
8197
			} else if (x == wm1) {
8198
				tileType = 2;
Andrey Filippov's avatar
Andrey Filippov committed
8199
			} else {
8200
				tileType = 1;
Andrey Filippov's avatar
Andrey Filippov committed
8201 8202 8203
			}
		} else if (y == hm1) {
			if (x == 0){
8204
				tileType = 6;
Andrey Filippov's avatar
Andrey Filippov committed
8205
			} else if (x == wm1) {
8206
				tileType = 8;
Andrey Filippov's avatar
Andrey Filippov committed
8207
			} else {
8208
				tileType = 7;
Andrey Filippov's avatar
Andrey Filippov committed
8209 8210 8211
			}
		} else {
			if (x == 0){
8212
				tileType = 3;
Andrey Filippov's avatar
Andrey Filippov committed
8213
			} else if (x == wm1) {
8214
				tileType = 5;
Andrey Filippov's avatar
Andrey Filippov committed
8215 8216 8217
			}
		}
		return tileType;
8218

Andrey Filippov's avatar
Andrey Filippov committed
8219
	}
8220

Andrey Filippov's avatar
Andrey Filippov committed
8221 8222 8223 8224 8225 8226
/**
 * Build tile connections to neighbors form optional selection, per-tile plane indices,
 * and a surface index.
 * @param selected tile selection (or null)
 * @param snap_surf per tile array of supertile plane index plus 1 or 0 for unmatched tiles
 * @param surf_index number of the surface to extract
8227
 * @return per-tile array of -256 for unselected tiles or 8-bit bit mask of the neighbors (0 - N, 1 - NE, ...)
Andrey Filippov's avatar
Andrey Filippov committed
8228 8229 8230 8231 8232 8233
 */
	public int [] getNeighbors( // creates neighbors mask from bitmask
			final boolean [] selected, // or null
			final int []     snap_surf, // use this size - it matches image, not supertiles
			final int        surf_index)
	{
8234
// TODO: see which are needed
Andrey Filippov's avatar
Andrey Filippov committed
8235 8236 8237
		final int tilesX =        tileProcessor.getTilesX();
		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
8238
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
8239 8240 8241 8242 8243 8244 8245 8246 8247 8248
//		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
//		final double [][] surfaces = getSurfaces();
		final int [][] shell_map =   getShellMap();
		final TilePlanes.PlaneData [][] planes = getPlanesMod(); // to get strength and connections
		final int [] neibs = new int [selected.length];
		final int [] dirs8 =   {-tilesX,   -tilesX +  1, 1, tilesX + 1,  tilesX,  tilesX - 1,  -1, -tilesX -  1};
//		final int [] dirs8st = {-stilesX,  -stilesX + 1, 1, stilesX + 1, stilesX, stilesX - 1, -1, -stilesX - 1};
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		final int surf_index_plus1 = surf_index + 1;
8249
		final int emptyTile = -256;
Andrey Filippov's avatar
Andrey Filippov committed
8250 8251
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
8252
				@Override
Andrey Filippov's avatar
Andrey Filippov committed
8253 8254 8255 8256 8257 8258
				public void run() {
					for (int nTile = ai.getAndIncrement(); nTile < snap_surf.length; nTile = ai.getAndIncrement()) {
						neibs[nTile] = emptyTile;
						if ((selected == null) || selected[nTile]) {
							int np = snap_surf[nTile] - 1;
							if (np >= 0) {
8259
								int tX = nTile % tilesX;
Andrey Filippov's avatar
Andrey Filippov committed
8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303
								int tY = nTile / tilesX;
								int stX = tX / superTileSize;
								int stY = tY / superTileSize;
								int fX = tX % superTileSize;
								int fY = tY % superTileSize;
								int nsTile = stY * stilesX + stX;
								if (nsTile == 724){
//									System.out.println("getNeighbors(): tX:tY = "+tX+":"+tY+", stX:stY="+stX+":"+stY+
//											", nTile="+nTile+", nsTile="+nsTile);
								}
								if (shell_map[nsTile][np] == surf_index_plus1) {
									int tileMask = getNeibMask(
											tX,
											tY,
											tilesX,
											tilesY);
									int localMask = getNeibMask(
											fX,
											fY,
											superTileSize,
											superTileSize);
									int [] dir_dir = getNeibBordDir(
											fX,
											fY,
											superTileSize,
											superTileSize);
									neibs[nTile] = tileMask;
									for (int i = 0; i < 8; i++) {
										int b = 1 << i;
										if ((neibs[nTile] & b) != 0){ // that will prevent tile array bounds violation
											int nTile1 = nTile + dirs8[i];
											if (!(((selected == null) || selected[nTile1]) && (snap_surf[nTile1] == snap_surf[nTile]))){
												neibs[nTile] &= ~b; // same supertile, different index
											} else if ((localMask & b) == 0) {// going to the other supertile
												int [] neib_best = planes[nsTile][np].getNeibBest(); // array of connected planes indices/ -1s
												if ((dir_dir[i] < 0) || (neib_best[dir_dir[i]] != (snap_surf[nTile1] -1))) {
													neibs[nTile] &= ~b;
												}
											}
										}
									}
								}
							}
						}
Andrey Filippov's avatar
Andrey Filippov committed
8304 8305
					}
				}
Andrey Filippov's avatar
Andrey Filippov committed
8306
			};
8307
		}
Andrey Filippov's avatar
Andrey Filippov committed
8308 8309 8310 8311
		ImageDtt.startAndJoin(threads);
		return neibs;

	}
8312 8313 8314 8315




Andrey Filippov's avatar
Andrey Filippov committed
8316
	/**
8317
	 * Sort per-tile disparity map values to one of the surfaces
Andrey Filippov's avatar
Andrey Filippov committed
8318 8319 8320 8321 8322 8323
	 * @param disparity per-tile array of disparity values
	 * @param strength  per-tile array of correlation strength values
	 * @param selection tile selection (or null to process all tiles)
	 * @param dispNorm  disparity difference normalization - differences for average disparities
	 *                  below this value are unchanged, above - proportionally scaled down)
	 * @param snapDispAny tiles with disparity difference below this will snap to the nearest
8324
	 *                  surface for any correlation strength
Andrey Filippov's avatar
Andrey Filippov committed
8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337
	 * @param snapStrengthAny tiles that have lower strength and can not be snapped otherwise are
	 *                  treated as zero-strength and obey snapZeroMode parameter
	 * @param snapNegAny allow snap for tiles that are below (farther) than the closest surface,
	 *                  if the disparity difference is below this value
	 * @param snapDispMax do not snap low-strength tiles if they are farther from the nearest surface
	 *                  than this.
	 * @param snapDispWeight snap tiles in the range snapDispAny and snapDispMax if the product
	 * 					of the disparity difference by the strength is below this
	 * @param snapZeroMode : 0 - no special treatment, 1 snap to strongest surface,
	 *                  2 - snap to the farthest (lowest disparity) surface
	 * @param debugLevel debug level
	 * @return integer array with per-tile elements. 0 - no surface candidate found (keep original
	 *                  disparity), > 0 - number of the plane plus 1 (use shell_map to get
8338
	 *                  the surface number)
Andrey Filippov's avatar
Andrey Filippov committed
8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356
	 */

	public int [] snapSort(
			final double []  disparity,
			final double []  strength,
			final boolean [] selection,       // can be null
			final double     dispNorm, // plDispNorm
			final double     snapDispAny,    //    =  .2,   // Maximal (scaled by plDispNorm) disparity difference to snap to plane at any strength
			final double     snapStrengthAny,    //    =  .2,   //  Maximal strength to fit any distance (if does not fit otherwise - treat as zero strength
			final double     snapNegAny,     //    =  .2,   // Maximal negative disparity difference from the best match
			final double     snapDispMax,    //    =  .5,   // Maximal (scaled by plDispNorm) disparity difference to snap to plane at low strength
			final double     snapDispWeight, //    =  .5,   // Maximal disparity diff. by weight product to snap to plane
			final int        snapZeroMode,   // Zero strength snap mode: 0: no special treatment, 1 - strongest, 2 - farthest
			final int        debugLevel)
	{
		final int tilesX =        tileProcessor.getTilesX();
//		final int tilesY =        tileProcessor.getTilesY();
		final int superTileSize = tileProcessor.getSuperTileSize();
8357
		final int stilesX = (tilesX + superTileSize -1)/superTileSize;
Andrey Filippov's avatar
Andrey Filippov committed
8358 8359 8360 8361 8362 8363
//		final int stilesY = (tilesY + superTileSize -1)/superTileSize;
		final double [][] surfaces = getSurfaces();
		final int [][] shell_map =   getShellMap();
		final TilePlanes.PlaneData [][] planes = getPlanesMod(); // to get strength;
//		final double [] snap_disp =  disparity.clone();
		final int [] snap_sort =  new int [disparity.length];
8364

Andrey Filippov's avatar
Andrey Filippov committed
8365 8366 8367 8368
		final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
8369
				@Override
Andrey Filippov's avatar
Andrey Filippov committed
8370 8371 8372
				public void run() {
					for (int nTile = ai.getAndIncrement(); nTile < disparity.length; nTile = ai.getAndIncrement()) {
						if ((selection == null) || selection[nTile]) {
8373
							int tX = nTile % tilesX;
Andrey Filippov's avatar
Andrey Filippov committed
8374 8375 8376 8377
							int tY = nTile / tilesX;
							int stX = tX / superTileSize;
							int stY = tY / superTileSize;
							int nsTile = stY * stilesX + stX;
8378
							int nTile_st = (tY * stilesX * superTileSize) + tX; // surfaces maybe (is) larger than tilesX *tilesY if
Andrey Filippov's avatar
Andrey Filippov committed
8379 8380 8381 8382 8383
							// tilesX, tilesY are not multiples of superTileSize !
							if (nsTile == 724){
//								System.out.println("snapDisparity(): tX:tY = "+tX+":"+tY+", stX:stY="+stX+":"+stY+
//										", nTile="+nTile+", nsTile="+nsTile+", nTile_st = "+nTile_st);
							}
8384

Andrey Filippov's avatar
Andrey Filippov committed
8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415
							// is there any surface to snap to?
							boolean no_surf = true;
							if (shell_map[nsTile] != null){
								for (int np = 0; no_surf && (np < shell_map[nsTile].length); np++){
									if (shell_map[nsTile][np] > 0) no_surf = false;
								}
							}
							if (!no_surf) {
								double [] surf_disparity = new double[shell_map[nsTile].length];
								for (int np = 0; np < surf_disparity.length; np++){
									if (shell_map[nsTile][np] > 0) {
										surf_disparity[np] = surfaces[shell_map[nsTile][np] -1][nTile_st];
									} else {
										surf_disparity[np] = Double.NaN;
									}
								}
								int best_indx = -1;
								double best_disp_diff = Double.NaN;
								double this_disp = disparity[nTile];
								double this_strength = strength[nTile];
								if (Double.isNaN(this_disp)){
									this_disp = 0.0;
									this_strength = 0.0;
								}
								for (int np = 0; np < surf_disparity.length; np++){
									if (shell_map[nsTile][np] > 0) {
										double disp_diff = normDispADiff (this_disp,surf_disparity[np], dispNorm);
										if ((best_indx < 0) || (disp_diff < best_disp_diff)) {
											best_disp_diff = disp_diff;
											best_indx =      np;
										}
8416 8417
									}
								}
Andrey Filippov's avatar
Andrey Filippov committed
8418 8419
								if ((this_strength > 0.0) || (snapZeroMode == 0)){
									if ((best_disp_diff <= snapDispAny) ||
8420
											((best_disp_diff <= snapDispMax) && (best_disp_diff * this_strength < snapDispWeight )) ||
Andrey Filippov's avatar
Andrey Filippov committed
8421 8422 8423 8424 8425 8426 8427
											((best_disp_diff <= snapNegAny) && (this_disp <  surf_disparity[best_indx]))  // farther than surface - higher tolerance
											){
										snap_sort[nTile] = best_indx+1; // snapped (default - keep source disparity
									} else if ((this_strength < snapStrengthAny) && (snapZeroMode != 0)){ // treat as zero strength?
										this_strength = 0.0;
									}
								}
8428 8429

								if ((this_strength == 0) && (snapZeroMode > 0)) {
Andrey Filippov's avatar
Andrey Filippov committed
8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457
									if (snapZeroMode == 1) {  // zero strength and non-zero snapZeroMode, consider 1 (strongest shell)
										best_indx = -1;
										double best_strength = Double.NaN;
										for (int np = 0; np < surf_disparity.length; np++){
											if (shell_map[nsTile][np] > 0) {
												double w = planes[nsTile][np].getWeight();
												if ((best_indx < 0) || (w >  best_strength)) {
													best_strength = w;
													best_indx =     np;
												}
											}
										}
										snap_sort[nTile] = best_indx+1; // snapped (default - keep source disparity
									} else { // zero strength and snapZeroMode > 1 (now only 2) - farthest surface (smallest disparity)
										best_indx = -1;
										double smallest_disparity = Double.NaN;
										for (int np = 0; np < surf_disparity.length; np++){
											if (shell_map[nsTile][np] > 0) {
												if ((best_indx < 0) || ( surf_disparity[np] <  smallest_disparity)) {
													smallest_disparity = surf_disparity[np];
													best_indx =     np;
												}
											}
										}
										snap_sort[nTile] = best_indx+1;
									}
								}
							}
Andrey Filippov's avatar
Andrey Filippov committed
8458 8459 8460
						}
					}
				}
Andrey Filippov's avatar
Andrey Filippov committed
8461
			};
8462
		}
Andrey Filippov's avatar
Andrey Filippov committed
8463 8464 8465 8466
		ImageDtt.startAndJoin(threads);
		return snap_sort;
	}

8467 8468 8469 8470 8471 8472
	public double [][][] getDisparityStrengths(
			int        stMeasSel) //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert)
	{
		int numMeasLayers = measuredLayers.getNumLayers();
		double [][][] ds = new double[numMeasLayers][][];
		for (int ml = 0; ml <  numMeasLayers; ml++) if ((stMeasSel & ( 1 << ml)) != 0) {
Andrey Filippov's avatar
Andrey Filippov committed
8473
			ds[ml] = 	measuredLayers.getDisparityStrengthML (
8474
					ml, // int num_layer,
8475 8476 8477
					this.mlfp);
//					this.mlfp.strength_floor, // double strength_floor,
//					this.mlfp.strength_pow); //  double strength_pow)
8478 8479 8480
		}
		return ds;
	}
Andrey Filippov's avatar
Andrey Filippov committed
8481

8482 8483 8484 8485 8486 8487 8488 8489 8490 8491
	public boolean [][] getMeasurementSelections(
			int        stMeasSel) //            = 1;      // Select measurements for supertiles : +1 - combo, +2 - quad +4 - hor +8 - vert)
	{
		int numMeasLayers = measuredLayers.getNumLayers();
		boolean [][] sels = new boolean[numMeasLayers][];
		for (int ml = 0; ml <  numMeasLayers; ml++) if ((stMeasSel & ( 1 << ml)) != 0) {
			sels[ml] = 	measuredLayers.getSelection (ml);
		}
		return sels;
	}
8492

Andrey Filippov's avatar
Andrey Filippov committed
8493
} // end of class SuperTiles