CLTPass3d.java 53.6 KB
Newer Older
1
package com.elphel.imagej.tileprocessor;
2 3 4 5 6 7 8 9
/**
 **
 ** CLTPass3d - A single processing "pass" over the image set. May be both actual
 ** FPGA operation or result of merging data from multiple passes
 **
 ** Copyright (C) 2017 Elphel, Inc.
 **
 ** -----------------------------------------------------------------------------**
10
 **
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 **  CLTPass3d.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/>.
 ** -----------------------------------------------------------------------------**
 **
 */

import java.awt.Rectangle;
28
import java.util.Arrays;
29 30
import java.util.concurrent.atomic.AtomicInteger;

31 32
import com.elphel.imagej.gpu.GPUTileProcessor;

33
public class CLTPass3d{
34
//	static double  max_overexposed = 0.8; // TODO: make parameter
35
		public   double [][]    disparity; // per-tile disparity set for the pass[tileY][tileX]
Andrey Filippov's avatar
Andrey Filippov committed
36
		public   int    [][]    tile_op;   // what was done in the current pass
Andrey Filippov's avatar
Andrey Filippov committed
37
		private  double [][]    disparity_sav; // saved disparity
Andrey Filippov's avatar
Andrey Filippov committed
38
		private  int    [][]    tile_op_sav;   // saved tile_op
39
		public   double [][]    disparity_map =            null; // add 4 layers - worst difference for the port
40 41
		public   double []      second_max =               null; // second maximal difference between channels
		public   double []      avg_val =                  null; // average pixel value for all channels (for cold sky)
42 43
		public   double [][]    lazy_eye_data =            null;
		public   int            lma_cluster_size =         -1;
44
		public   boolean []     lazy_eye_force_disparity = null;
45
		public   int []         num_tile_max =             null; // number of maximums in a tile
46

47
		double []               calc_disparity = null; // composite disparity, calculated from "disparity", and "disparity_map" fields
48

49 50 51 52 53
		                                       // using horizontal features and corr_magic_scale
		// used directly in TileProcessor.compositeScan()
		double []               calc_disparity_hor =   null; // composite disparity, calculated from "disparity", and "disparity_map" fields
		double []               calc_disparity_vert =  null; // composite disparity, calculated from "disparity", and "disparity_map" fields
		double []               calc_disparity_combo = null; // composite disparity, calculated from "disparity", and "disparity_map" fields
Andrey Filippov's avatar
Andrey Filippov committed
54
		double []               strength =             null; // composite strength, initially uses a copy of raw 4-sensor correlation strength
55 56 57 58 59
		double []               strength_hor =         null; // updated hor strength, initially uses a copy of raw measured
		double []               strength_vert =        null; // updated hor strength, initially uses a copy of raw measured
		// Bg disparity & strength is calculated from the supertiles and used instead of the tile disparity if it is too weak. Assuming, that
		// foreground features should have good correlation details, and if the tile does not nhave them it likely belongs to the background.
		// calculate disparity and strength from the (lapped) supertiles, using lowest allowed (>= minBgDisparity) disparity histogram maximums
60
		// of the supertiles this tile belongs to
61 62 63 64 65
		private double          minBgDisparity =        0.0;
		private double          minBgFract =            0.0; // Use the lowest maximum if the strength strength (of all maximus >= minBgDisparity)
		                                                     // exceeds minBgFract, otherwise proceed to the next one (and accumulate strength)
		private double []       bgTileDisparity =      null;
		private double []       bgTileStrength =       null;
66 67 68
		private boolean []      border_tiles =         null; // these are border tiles, zero out alpha
		private boolean []      selected =             null; // which tiles are selected for this layer
		boolean []              has_lma =              null; // which tiles are measured with LMA (reliable strength)
69
		public  double [][][][] texture_tiles;
70 71
		// texture_selection is only used for the GPU and if not null means it is for the GPU
		public boolean []       texture_selection =    null; // use by the GPU to set texture to generate
Andrey Filippov's avatar
Andrey Filippov committed
72
				
73 74
		public  double [][]     max_tried_disparity =  null; //[ty][tx] used for combined passes, shows maximal disparity for this tile, regardless of results
		public  int             clust_radius =         0;    // 0 - no clusters, 1 = 1x1 (same as 0, just different program), 2 - 3x3, 3 - 5x5
75 76 77
		public  boolean         is_combo =             false;
		public  boolean         is_measured =          false;
		public  String          texture = null; // relative (to x3d) path
78
		public  Rectangle       texture_bounds; // in tiles, not pixels !
79
		public  int             dbg_index;
80
		public  int             disparity_index =      ImageDtt.DISPARITY_INDEX_CM; // may also be ImageDtt.DISPARITY_INDEX_POLY
81
		public  int             lma_disparity_index =  ImageDtt.DISPARITY_INDEX_POLY; // set to -1 to ignore and always use just CM (also applies to lma_strength - next)
82
		public double [][]      tiles_RBGA =           null;
83

84
		SuperTiles              superTiles = null;
85 86 87 88 89
		final TileProcessor     tileProcessor;
		public int getNumSensors() {
			return tileProcessor.getNumSensors();
		}
		
90 91 92 93
		public CLTPass3d (TileProcessor tileProcessor)
		{
			this.tileProcessor = tileProcessor;
		}
94

95 96 97 98 99 100 101 102
		public CLTPass3d (TileProcessor tileProcessor, int mode)
		{
			this.tileProcessor = tileProcessor;
			switch (mode){
			case 0:
				tile_op =   new int [tileProcessor.getTilesY()][tileProcessor.getTilesX()];
				disparity = new double [tileProcessor.getTilesY()][tileProcessor.getTilesX()];
				break;
103

104 105
			}
		}
106 107 108 109 110 111 112 113
		public int getClustRadius() {
			return clust_radius;
		}
		
		public void setClustRadius (int clust_radius) {
			this.clust_radius = clust_radius;
		}
		
114 115 116 117
		public TileProcessor getTileProcessor()
		{
			return this.tileProcessor;
		}
118

119 120 121 122
		public double [][][][] getTextureTiles()
		{
			return 	texture_tiles;
		}
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
		// texture_selection is only used for the GPU and if not null means it is for the GPU
		public boolean [] getTextureSelection()
		{
			return texture_selection;
		}
		
		public void setTextureSelection(boolean [] selection) {
			texture_selection = selection;
		}

		public void setTextureSelection(int indx, boolean sel) {
			texture_selection[indx] = sel;
		}

		public double [][] getTilesRBGA()
		{
			return tiles_RBGA;
		}
Andrey Filippov's avatar
Andrey Filippov committed
141

142 143 144 145 146 147
		public void setTilesRBGA(double [][] rgba)
		{
			tiles_RBGA = rgba;
		}
		
		/*
Andrey Filippov's avatar
Andrey Filippov committed
148 149 150 151 152 153 154 155 156
		public float [][] getTextureImages()
		{
			return 	texture_img;
		}

		public Rectangle getTextureWoi()
		{
			return 	texture_woi;
		}
157
		*/
Andrey Filippov's avatar
Andrey Filippov committed
158
		
159 160 161 162
		public double [][] getMaxTriedDisparity()
		{
			return max_tried_disparity;
		}
163 164
		
		
165
		public double [][] getTileRBGA(
Andrey Filippov's avatar
Andrey Filippov committed
166
				int num_layers) // 4 or 12
167
		{
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
//			if (texture_img != null) {
//				System.out.println("FIXME: implement replacement for the GPU-generated textures (using macro mode?)");
//			}
			double [][] tones = getTilesRBGA();
			if (tones != null) {
				int nl = tones.length;
				if (nl > num_layers) {
					double [][] tones1 = new double [num_layers][tones[0].length];
					for (int n = 0; n < num_layers; n++) {
						tones1[n] = tones[n];
					}
					return tones1;
				} else {
					return tones;
				}
Andrey Filippov's avatar
Andrey Filippov committed
183
			}
184 185
			System.out.println("FIXME: should not get here, tones should be calculated earlier");
			
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
			if (texture_tiles == null) return null;
			int tilesY = texture_tiles.length;
			int tilesX = 0;
			int nl = 0;
			for (int ty = 0; ty < tilesY; ty++){
				if (texture_tiles[ty] != null){
					tilesX = texture_tiles[ty].length;
					for (int tx = 0; tx < tilesX; tx++){
						if (texture_tiles[ty][tx] != null){
							nl = texture_tiles[ty][tx].length;
							break;
						}
					}
					if (nl > 0) break;
				}
				if (nl > 0) break;
			}
			if (num_layers > nl) num_layers = nl;
			int numTiles = tilesX * tilesY;
			double [] scales = new double [num_layers];
			for (int n = 0; n < num_layers; n++){
				if       (n < 3)  scales[n] = 1.0/255.0; // R,B,G
				else if  (n == 3) scales[n] = 1.0; //alpha
				else if  (n < 8)  scales[n] = 1.0; // ports 0..3
210
				else              scales[n] = 1.0/255.0; // RBG rms, in 1/255 units, but small
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
			}
			double [][] tileTones = new double [num_layers][numTiles];
			for (int ty = 0; ty < tilesY; ty++ ) if (texture_tiles[ty] != null){
				for (int tx = 0; tx < tilesX; tx++ ) if (texture_tiles[ty][tx] != null) {
					int indx = ty * tilesX + tx;
					for (int n = 0; n < num_layers; n++) if (texture_tiles[ty][tx][n] != null){
						double s = 0.0;
						for (int i = 0; i < texture_tiles[ty][tx][n].length; i++){
							s += texture_tiles[ty][tx][n][i];
						}
						s /= (texture_tiles[ty][tx][n].length/4); // overlapping tiles
						s *= scales[n];
						tileTones[n][indx] = s;
					}
				}
			}
			return tileTones;
		}
229

230 231 232 233 234 235 236 237
		public String getTextureName()
		{
			if (texture != null) {
				return texture;
			} else {
				return "null-texture-name";
			}
		}
238 239


Andrey Filippov's avatar
Andrey Filippov committed
240
		// Will not work if texture is disabled
241
		public  void            updateSelection(){ // add updating border tiles? -- only for CPU!
242 243 244 245
			int tilesX = tileProcessor.getTilesX();
			int tilesY = tileProcessor.getTilesY();
			selected = new boolean[tilesY*tilesX];
			int minX = tilesX, minY = tilesY, maxX = -1, maxY = -1;
246
			/*
Andrey Filippov's avatar
Andrey Filippov committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
			if (texture_img != null) { // using GPU output
//tileProcessor.getTileSize()
				if (texture_woi != null) {
					int tile_size = tileProcessor.getTileSize();
					texture_bounds = new Rectangle(
							texture_woi.x/tile_size, texture_woi.y/tile_size, texture_woi.width/tile_size, texture_woi.height/tile_size);
					// setting full rectangle as selected, not just textures? Use some other method?
					for (int ty = texture_bounds.y; ty < (texture_bounds.y + texture_bounds.height); ty++) {
						for (int tx = texture_bounds.x; tx < (texture_bounds.x + texture_bounds.width); tx++) {
							selected[ty*tilesX+tx] = true;
						}
					}
					return;
				}
			}
262
			*/
Andrey Filippov's avatar
Andrey Filippov committed
263 264 265 266 267 268 269 270 271 272 273
			if (texture_tiles != null) {
				for (int ty = 0; ty < tilesY; ty++) for (int tx = 0; tx < tilesX; tx++){
					if (texture_tiles[ty][tx] != null) {
						selected[ty * tilesX + tx] = true;
						if (maxX < tx) maxX  = tx;
						if (minX > tx) minX  = tx;
						if (maxY < ty) maxY  = ty;
						if (minY > ty) minY  = ty;
					} else {
						selected[ty * tilesX + tx] = false; // may be omitted
					}
274 275
				}
			}
276 277 278 279 280
			if (maxX < 0) {
				texture_bounds = null;
			} else {
				texture_bounds = new Rectangle(minX, minY, maxX - minX +1, maxY - minY +1 );
			}
Andrey Filippov's avatar
Andrey Filippov committed
281 282 283
		}
		public  Rectangle  getTextureBounds(){
			return texture_bounds;
284
		}
285

286
		public boolean isProcessed(){
287
			return calc_disparity != null;
288
		}
289

290 291 292 293
		public boolean isMeasured(){
			return is_measured;
//			return (disparity_map != null) && (disparity != null); // 	disparity == null for composite scans
		}
294

295
		public boolean isCombo(){
296
			return is_combo;
297
		}
298

299 300 301
		/**
		 * Called after each measurement
		 */
302 303
		public void resetProcessed(){

304
			if (disparity_map != null) fixNaNDisparity();
305 306 307 308 309 310 311 312 313
			calc_disparity =       null; // composite disparity, calculated from "disparity", and "disparity_map" fields
			calc_disparity_hor =   null; // composite disparity, calculated from "disparity", and "disparity_map" fields
			calc_disparity_vert =  null; // composite disparity, calculated from "disparity", and "disparity_map" fields
			calc_disparity_combo = null; // composite disparity, calculated from "disparity", and "disparity_map" fields
			strength =             null; // composite strength, initially uses a copy of raw 4-sensor correleation strength
			strength_hor =         null; // updated hor strength, initially uses a copy of raw measured
			strength_vert =        null; // updated hor strength, initially uses a copy of raw measured
			bgTileDisparity =      null;
			bgTileStrength =       null;
314 315
//			border_tiles =         null; // these are border tiles, zero out alpha
//			selected =             null; // which tiles are selected for this layer
316
			superTiles =           null;
317
			setTilesRBGA(null);
318

319 320 321
		}
		/**
		 * Get FPGA-calculated per-tile maximal differences between the particular image and the average one.
322
		 * @return per-camera sensor array of line-scan differences
323 324 325
		 */

		public double [][] getDiffs (){
326
			if (disparity_map == null) return null;
327 328
			double  [][] these_diffs =    new double[getNumSensors()][];
			for (int i = 0; i< these_diffs.length; i++) these_diffs[i] = disparity_map[ImageDtt.IMG_DIFF0_INDEX + i]; // IMG_DIFF0_INDEX does not depend on num sensors
329 330
			return these_diffs;
		}
331 332 333 334 335 336 337 338 339 340
		
		public double [][] getRBGs (){
			if (disparity_map == null) return null;
			int numcol = tileProcessor.isMonochrome()? 1: 3;
			double  [][] these_RBGs =    new double[numcol*getNumSensors()][];
			for (int i = 0; i< these_RBGs.length; i++) these_RBGs[i] = disparity_map[ImageDtt.getImgToneRGB(getNumSensors()) + i]; // IMG_DIFF0_INDEX does not depend on num sensors
			return these_RBGs;
		}
		
	//getImgToneRGB() 	
341

342 343 344 345 346 347
		public void resetCalc(){ // only needed if the same task was reused
			calc_disparity = null;
			strength =       null;
			strength_hor =   null;
			strength_vert =  null;
			superTiles =     null;
348

349
		}
Andrey Filippov's avatar
Andrey Filippov committed
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
		public boolean [] getLazyEyeForceDisparity() {
			return lazy_eye_force_disparity;
		}

		public void setLazyEyeForceDisparity(boolean [] lazy_eye_force_disparity) {
			this.lazy_eye_force_disparity = lazy_eye_force_disparity;
		}

		public double [][] getLazyEyeData() {
			return lazy_eye_data;
		}

		public void setLazyEyeData(double [][] lazy_eye_data) {
			this.lazy_eye_data = lazy_eye_data;
		}

		public int getLazyEyeClusterSize() {
			return lma_cluster_size;
		}
		public void setLazyEyeClusterSize(int lma_cluster_size) {
			this.lma_cluster_size = lma_cluster_size;
		}



376 377 378
		public boolean [] getSelected(){
			return selected;
		}
379 380 381 382 383 384 385 386 387 388 389 390 391 392
		
		public boolean [] getSelectedOrTileOp(){ // to use instead of getSelected if it is null
			if (selected != null) return selected;
			if (tile_op== null) return null;
			boolean [] to_selected = new boolean [tile_op.length * tile_op[0].length];
			int indx = 0;
			for (int ty = 0; ty < tile_op.length; ty++) {
				for (int tx = 0; tx < tile_op[ty].length; tx++) {
					to_selected[indx++] = tile_op[ty][tx] != 0;
				}
			}
			return to_selected;
		}
		
393

394 395 396
		public boolean [] getBorderTiles(){
			return this.border_tiles;
		}
397

Andrey Filippov's avatar
Andrey Filippov committed
398 399 400
		public void setSelected (boolean [] selected) {
			this.selected = selected;
		}
Andrey Filippov's avatar
Andrey Filippov committed
401 402 403
		public void setBorderTiles (boolean [] border_tiles) {
			this.border_tiles = border_tiles;
		}
404 405 406 407 408 409 410
		
		public boolean [] getLMA() {
			if (has_lma == null) {
				has_lma = hasLMADefined();
			}
			return has_lma;
		}
411

412 413 414
		public void setLMA(boolean [] has_lma) {// use for combo tiles
			this.has_lma = has_lma;
		}
415

416 417 418 419 420 421 422 423 424 425 426
		public void resetLMA() {
			this.has_lma = null;
		}
		public void setLMA(double [] disparity_lma) {// use for combo tiles
			this.has_lma = new boolean [disparity_lma.length];
			for (int i = 0; i < disparity_lma.length; i++) {
				this.has_lma[i] = !Double.isNaN(disparity_lma[i]);
			}
		}
		
		
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
		public void fixNaNDisparity()
		{
			fixNaNDisparity(
					null,
					disparity_map[disparity_index],
					disparity_map[ImageDtt.DISPARITY_STRENGTH_INDEX]);
			fixNaNDisparity(
					null,
					disparity_map[ImageDtt.DISPARITY_INDEX_HOR],
					disparity_map[ImageDtt.DISPARITY_INDEX_HOR_STRENGTH]);
			fixNaNDisparity(
					null,
					disparity_map[ImageDtt.DISPARITY_INDEX_VERT],
					disparity_map[ImageDtt.DISPARITY_INDEX_VERT_STRENGTH]);
		}
442 443


444 445 446 447 448
		public void fixNaNDisparity(
				boolean [] select,   // which tiles to correct (null - all)
				double [] disparity,
				double [] strength)
		{
449 450 451
			if ((disparity == null) || (strength == null)) {
				return;
			}
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
			// depends on direction, but that is OK - just converge faster when smoothing
			int tilesX = tileProcessor.getTilesX();
			int tilesY = tileProcessor.getTilesY();
			int [] dirs8 = {-tilesX,  -tilesX + 1, 1, tilesX +1, tilesX, tilesX - 1, -1, -tilesX - 1};
			for (int ty = 1; ty < (tilesY -1); ty ++) for (int tx = 1; tx < (tilesX -1); tx++){
				int nt = ty * tilesX + tx;
				if (Double.isNaN(disparity[nt]) && ((select == null) || select[nt])) {
					if (strength != null) strength[nt] = 0.0;
					double sd = 0.0, sw = 0.0;
					for (int dir=0; dir < dirs8.length; dir++){
						int nt1 = nt + dirs8[dir];
//						if (!Double.isNaN(disparity[nt1]) && ((select == null) || !select[nt1])) {
						if (!Double.isNaN(disparity[nt1])) { // for wide borders - use neighbors already defined too
							double w = (strength == null) ? 1.0 : strength[nt1];
							sd += w * disparity[nt1];
							sw += w;
						}
					}
					if (sw > 0.0) sd /= sw;
					disparity[nt] = sd;
				}
			}
			// on top/bottom/right/left rows replace NaN disparity with 0.0;
			for (int ty = 0; ty < tilesY; ty ++) {
				int nt = ty * tilesX + 0;
				if (Double.isNaN(disparity[nt]) && ((select == null) || select[nt])) {
					if (strength != null) strength[nt] = 0.0;
					disparity[nt] = 0.0;
				}
				nt = ty * tilesX + tilesX -1;
				if (Double.isNaN(disparity[nt]) && ((select == null) || select[nt])) {
					if (strength != null) strength[nt] = 0.0;
					disparity[nt] = 0.0;
				}
			}
			for (int tx = 0; tx < tilesX; tx ++) {
				int nt = 0 * tilesX + tx;
				if (Double.isNaN(disparity[nt]) && ((select == null) || select[nt])) {
					if (strength != null) strength[nt] = 0.0;
					disparity[nt] = 0.0;
				}
				nt = (tilesY -1) * tilesX + tx;
				if (Double.isNaN(disparity[nt]) && ((select == null) || select[nt])) {
					if (strength != null) strength[nt] = 0.0;
					disparity[nt] = 0.0;
				}
			}
		}
500

501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
		public double [] combineHorVertStrength(
				boolean combineHor,
				boolean combineVert)
		{
			getStrength();     // clone if not done yet
			if (combineHor){
				double [] hstrength = getHorStrength();
				for (int i = 0; i < strength.length; i++) {
					if (strength[i] < hstrength[i]) strength[i] = hstrength[i];
				}
			}
			if (combineVert){
				double [] vstrength = getVertStrength();
				for (int i = 0; i < strength.length; i++) {
					if (strength[i] < vstrength[i]) strength[i] = vstrength[i];
				}
			}
			return strength;
		}
520

521 522 523 524 525 526 527 528 529 530
		public double [] combineSuper(
				boolean updateStrength, // use ST strength if true, keep original (update disparity only) if false
				double  stStrengthScale,
				double useSuper){
			if (bgTileDisparity == null) { // no supertile disparity is available
				return null;
			}

			double [] strength = getStrength();
			double [] disparity = getDisparity(0);
531

532 533 534 535 536 537 538 539
			for (int i = 0; i < disparity.length; i++){
				if (strength[i] < useSuper)  {
					disparity[i] = bgTileDisparity[i];
					if (updateStrength) strength[i] =  stStrengthScale*bgTileStrength[i];
				}
			}
			return disparity;
		}
540 541 542 543

		public double [] getOverexposedFraction(){
			return (disparity_map != null)? disparity_map[ImageDtt.OVEREXPOSED] : null;
		}
544 545


546
		/**
547
		 * Returns per-tile correlation "strength". Initially - copy of the FPGA-generated data, but later may be replaced by a combination
548
		 * of the combined data from 4-sensor (4-pair) correlation and horizontal/vertical pairs only to improve detection of vertical/
549
		 * horizontal features
550 551 552 553
		 * @return line-scan array of per-tile correlation strength by reference (not a copy), so it can be modified
		 */
		public double [] getStrength(){
			double trustedCorrelation = tileProcessor.getTrustedCorrelation();
554
			double max_overexposure = tileProcessor.getMaxOverexposure();
555 556 557 558
			if (strength == null){
				strength =  disparity_map[ImageDtt.DISPARITY_STRENGTH_INDEX].clone();
				if (trustedCorrelation > 0.0){
					for (int i = 0; i < strength.length; i++){
559
						if (Math.abs(disparity_map[disparity_index][i]) > trustedCorrelation) strength[i] = 0.0; // too far
560 561
					}
				}
562 563 564
				double [] overexposed = disparity_map[ImageDtt.OVEREXPOSED];
				if ((max_overexposure > 0.0) && (overexposed != null)){
					for (int i = 0; i < strength.length; i++){
565
						if (overexposed[i] > max_overexposure) strength[i] = 0.0; // too overexposed
566 567
					}
				}
568 569 570
			}
			return strength;
		}
571 572 573 574 575
		
		public void setStrength(double [] strength) {
			this.strength = strength;
		}
		
576 577 578 579 580
		/**
		 * Get four pairs (original) correlation strength. Not a copy
		 * @return line-scan array of per-tile horizontal pairs correlation strength by reference (not a copy)
		 */
		public double [] getOriginalStrength(){
581 582
			if (disparity_map != null) return disparity_map[ImageDtt.DISPARITY_STRENGTH_INDEX];
			else return getStrength(); // after replacing with rig data
583 584 585 586 587 588 589
		}
		/**
		 * Get horizontal pairs correlation strength for vertical features. Not a copy
		 * @return line-scan array of per-tile horizontal pairs correlation strength by reference (not a copy)
		 */
		public double [] getHorStrength(){
			double trustedCorrelation = tileProcessor.getTrustedCorrelation();
590
			double max_overexposure = tileProcessor.getMaxOverexposure();
591
			if (strength_hor == null) {
592 593 594
				if (disparity_map[ImageDtt.DISPARITY_INDEX_HOR_STRENGTH] == null) {
					return null;
				}
595 596 597
				strength_hor = disparity_map[ImageDtt.DISPARITY_INDEX_HOR_STRENGTH].clone();
				if (trustedCorrelation > 0.0){
					for (int i = 0; i < strength_hor.length; i++){
598
						if (Math.abs(disparity_map[ImageDtt.DISPARITY_INDEX_HOR][i]) > trustedCorrelation) strength_hor[i] = 0.0; // too far
599 600
					}
				}
601 602 603
				double [] overexposed = disparity_map[ImageDtt.OVEREXPOSED];
				if ((max_overexposure > 0.0) && (overexposed != null)){
					for (int i = 0; i < strength_hor.length; i++){
604
						if (overexposed[i] > max_overexposure) strength_hor[i] = 0.0; // too overexposed
605 606
					}
				}
607

608 609 610 611
			}
			return strength_hor;
		}
		/**
612
		 * Get vertical pairs correlation strength for horizontal features. Not a copy
613 614 615 616
		 * @return line-scan array of per-tile horizontal pairs correlation strength by reference (not a copy)
		 */
		public double [] getVertStrength(){
			double trustedCorrelation = tileProcessor.getTrustedCorrelation();
617
			double max_overexposure = tileProcessor.getMaxOverexposure();
618
			if (strength_vert == null) {
619 620 621
				if (disparity_map[ImageDtt.DISPARITY_INDEX_VERT_STRENGTH] == null) {
					return null;
				}
622 623 624
				strength_vert = disparity_map[ImageDtt.DISPARITY_INDEX_VERT_STRENGTH].clone();
				if (trustedCorrelation > 0.0){
					for (int i = 0; i < strength_vert.length; i++){
625
						if (Math.abs(disparity_map[ImageDtt.DISPARITY_INDEX_VERT][i]) > trustedCorrelation) strength_vert[i] = 0.0; // too far
626 627
					}
				}
628 629 630
				double [] overexposed = disparity_map[ImageDtt.OVEREXPOSED];
				if ((max_overexposure > 0.0) && (overexposed != null)){
					for (int i = 0; i < strength_hor.length; i++){
631
						if (overexposed[i] > max_overexposure) strength_vert[i] = 0.0; // too overexposed
632 633
					}
				}
634

635 636 637
			}
			return strength_vert;
		}
638

639
		/**
640
		 * Combine per-tile disparity values from correlation combined with pre-programmed initial disparity shift.
641 642
		 * @return line-scan array of per-tile disparity by reference (not a copy), so it can be modified
		 */
643

644 645 646 647 648 649
		public double [] getDisparity() // get calculated combo disparity
		{
			return getDisparity(0);
		}
		/**
		 * Get one of the line-scan per-tile correlation data.
Andrey Filippov's avatar
Andrey Filippov committed
650
		 * @param mode 0 - final data (initially copy FPGA generated 4-pair correlation)
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
		 *             1 - original FPGA generated 4-sensor correlation
		 *             2 - 2 - horizontal pairs correlation, detecting vertical features
		 *             3 - 2 - vertical pairs correlation, detecting horizontal features
		 * @return line-scan array of per-tile disparity by reference (not a copy), so it can be modified
		 */

		public double [] getDisparity(int mode) // mode = 0 - normal disparity, 1 - hor, 2 - vert
		{
			if (calc_disparity == null) conditionDisparity();
			switch (mode) {
			case 1: return calc_disparity;
			case 2: return calc_disparity_hor;
			case 3: return calc_disparity_vert;
			default: if (calc_disparity_combo == null) calc_disparity_combo = calc_disparity.clone();
				return calc_disparity_combo;
			}
		}
668 669 670 671 672 673 674 675 676 677
		public double [] getDisparityLMA() {
			if (calc_disparity == null) conditionDisparity(); // sets has_lma;
			double [] disparityLMA = calc_disparity.clone();
			for (int i = 0; i < disparityLMA.length; i++) {
				if (!has_lma[i]) {
					disparityLMA[i] = Double.NaN;
				}
			}
			return disparityLMA;
		}
678 679 680 681 682 683 684 685 686 687 688 689 690
		public int [] getNumTileMax() {
			if (num_tile_max == null) {
				if (disparity_map[ImageDtt.DISPARITY_VARIATIONS_INDEX] == null) {
					return null;
				}
				num_tile_max = new int [disparity_map[ImageDtt.DISPARITY_VARIATIONS_INDEX].length];
				for (int i = 0; i < num_tile_max.length; i++) {
					///https://stackoverflow.com/questions/6341896/cast-int-to-double-then-back-to-int-in-java
					num_tile_max[i] = (int)	disparity_map[ImageDtt.DISPARITY_VARIATIONS_INDEX][i];
				}
			}
			return num_tile_max;
		}
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
		
		public double getDisprityHor(int nt) {
			return (disparity_map[ImageDtt.DISPARITY_INDEX_HOR] == null) ? Double.NaN : disparity_map[ImageDtt.DISPARITY_INDEX_HOR][nt]; 
		}
		public double getDisprityVert(int nt) {
			return (disparity_map[ImageDtt.DISPARITY_INDEX_VERT] == null) ? Double.NaN : disparity_map[ImageDtt.DISPARITY_INDEX_VERT][nt]; 
		}
		public double getStrengthHor(int nt) {
			return (disparity_map[ImageDtt.DISPARITY_INDEX_HOR_STRENGTH] == null) ? 0.0 : disparity_map[ImageDtt.DISPARITY_INDEX_HOR_STRENGTH][nt]; 
		}
		public double getStrengthVert(int nt) {
			return (disparity_map[ImageDtt.DISPARITY_INDEX_VERT_STRENGTH] == null) ? 0.0 : disparity_map[ImageDtt.DISPARITY_INDEX_VERT_STRENGTH][nt]; 
		}
		
		
		
707 708 709 710 711
		// methods to "condition" measured disparity values
		public void conditionDisparity()
		{
			int tilesX = tileProcessor.getTilesX();
			int tilesY = tileProcessor.getTilesY();
712 713
			double corr_magic_scale =     tileProcessor.getMagicScale();
			double corr_magic_scale_LMA = 1.0;
714 715 716
			calc_disparity =      new double[tilesY*tilesX];
			calc_disparity_hor =  new double[tilesY*tilesX];
			calc_disparity_vert = new double[tilesY*tilesX];
717 718 719
			Arrays.fill(calc_disparity,      Double.NaN);
			Arrays.fill(calc_disparity_hor,  Double.NaN);
			Arrays.fill(calc_disparity_vert, Double.NaN);
720
			
721
			double [] lma_disparity = (lma_disparity_index >= 0) ? disparity_map[lma_disparity_index] : null;
722 723 724
			double [] lma_strength =  (lma_disparity_index >= 0) ? disparity_map[lma_disparity_index+1] : null;
			has_lma = (lma_disparity != null) ? new boolean[tilesX * tilesY] : null;

725 726 727
			for (int i = 0; i < tilesY; i++){
				for (int j = 0; j < tilesX; j++){
					int indx = i * tilesX + j;
728
					if ((lma_disparity != null) && !Double.isNaN(lma_disparity[indx]) && (lma_strength[indx] > 0.0)) {
729
						calc_disparity[indx] =  lma_disparity[indx]/corr_magic_scale_LMA +                            this.disparity[i][j];
730
						has_lma[indx] = true;
731 732 733
					} else {
						calc_disparity[indx] =  disparity_map[disparity_index][indx]/corr_magic_scale +               this.disparity[i][j];
					}
734 735 736
				}
			}
			calc_disparity_combo = calc_disparity.clone(); // for now - just clone, can be modified separately and combined with hor/vert
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
			if (disparity_map[ImageDtt.DISPARITY_INDEX_HOR] != null) {
				for (int i = 0; i < tilesY; i++){
					for (int j = 0; j < tilesX; j++){
						int indx = i * tilesX + j;
						calc_disparity_hor[indx] =  disparity_map[ImageDtt.DISPARITY_INDEX_HOR][indx]/corr_magic_scale +  this.disparity[i][j];
					}
				}
			}
			if (disparity_map[ImageDtt.DISPARITY_INDEX_VERT] != null) {
				for (int i = 0; i < tilesY; i++){
					for (int j = 0; j < tilesX; j++){
						int indx = i * tilesX + j;
						calc_disparity_vert[indx] = disparity_map[ImageDtt.DISPARITY_INDEX_VERT][indx]/corr_magic_scale + this.disparity[i][j];
					}
				}
			}
753
		}
Andrey Filippov's avatar
Andrey Filippov committed
754
		
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
		/**
		 * Remove correlation results for tiles that have large variations - this normally leads to fake high-disparity
		 * values in the sky (at a distance of disparity from the high-contrast skyline). This method should only be used
		 * during initial disparity scan as FG/BG overlap also causes mismatch.
		 * This method calculates ands sets this.
		 * Images have to be equalized.second_max
		 * @param max_diff maximal difference for the sane correlation results (50-100 for LWIR?) 
		 * @param mismatch_override keep tile with large mismatch if there is LMA with really strong correlation 
		 */
		public void resetByDiff(
				double max_diff,
				double mismatch_override) {
			if ((disparity_map == null) ||(disparity_map[ImageDtt.DISPARITY_STRENGTH_INDEX] == null)) {
				System.out.println("resetByDiff(): strength is null! (no tiles left)");
				return;
			}
			int len = disparity_map[ImageDtt.DISPARITY_STRENGTH_INDEX].length; // null
			if ((lma_disparity_index >= 0) && (disparity_map[lma_disparity_index] != null) && (disparity_map[lma_disparity_index+1] != null)){
				for (int i = 0; i < len; i++ ) {
					if (second_max[i] > max_diff) {
						if ((mismatch_override <= 0) || !(disparity_map[lma_disparity_index +1][i] >= mismatch_override)) {
							disparity_map[lma_disparity_index][i] =    Double.NaN;
							disparity_map[lma_disparity_index +1][i] = 0.0;
							disparity_map[ImageDtt.DISPARITY_STRENGTH_INDEX][i] = 0.0; // disparity_cm will stay
						}
					}
				}
			} else { // Seems first are all non-LMA
				for (int i = 0; i < len; i++ ) {
					if ((second_max[i] > max_diff) && 
							((mismatch_override <= 0) || !(disparity_map[ImageDtt.DISPARITY_STRENGTH_INDEX][i] >= mismatch_override))) {
						disparity_map[ImageDtt.DISPARITY_STRENGTH_INDEX][i] = 0.0;
					}
				}
			}
		}
		
		
793 794 795 796 797 798 799 800 801 802 803 804
		public boolean [] hasLMADefined(){ // will try not to create this.has_lma
			if (disparity_map == null) {
				if (has_lma==null) {
					return null;
				} else {
					return has_lma;
				}
				
			}
			int tilesX = tileProcessor.getTilesX();
			int tilesY = tileProcessor.getTilesY();
			double [] lma_disparity = (lma_disparity_index >= 0) ? disparity_map[lma_disparity_index] : null;
805
			double [] lma_strength =  (lma_disparity_index >= 0) ? disparity_map[lma_disparity_index+1] : null;
806 807 808
			boolean [] lma_defined = new boolean[tilesX * tilesY];
			if (lma_disparity != null) {
				for (int i = 0; i < lma_disparity.length; i++) {
809
					lma_defined[i] = !Double.isNaN(lma_disparity[i]) && (lma_strength[i] > 0);
810 811 812 813 814 815
				}
			}
			return lma_defined;
		}
		
		
Andrey Filippov's avatar
Andrey Filippov committed
816 817 818 819 820 821
		// bypassing calculations
		public void setCalcDisparityStrength(
				double [] disparity,
				double [] strength) {
			this.calc_disparity = disparity;
			this.strength =       strength;
Andrey Filippov's avatar
Andrey Filippov committed
822 823 824
			if (calc_disparity_combo != null) {
				calc_disparity_combo = calc_disparity.clone();
			}
Andrey Filippov's avatar
Andrey Filippov committed
825
		}
826

827 828 829 830
		/**
		 * Replaces current combo disparity for tiles that are weak and do not have any neighbor within disparity range from this one
		 * @param selection optional boolean mask of tiles to use/update
		 * @param weakStrength maximal strength of the tile to be considered weak one
831
		 * @param maxDiff maximal difference from the most similar neighbor to be considered an outlier
832 833 834
		 * @param disparityFar minimal acceptable disparity for weak tiles
		 * @param disparityNear maximal acceptable disparity for weak tiles
		 * @return mask of weak (replaced) tiles
835 836
		 *
		 * Replace weak by a weighted average of non-weak. If there are none - use weak ones, including this one too.
837
		 */
838
		public boolean[] replaceWeakOutliers( // does not replace tiles with LMA available, busts LMA-defined strengths when averaging
839 840 841
				final boolean [] selection,
				final double weakStrength,    // strength to be considered weak, subject to this replacement
				final double maxDiff,
842 843
				final double maxDiffPos,      // Replace weak outlier tiles that have higher disparity than weighted average
				final double maxDiffNeg,      // Replace weak outlier tiles that have lower disparity than weighted average
844 845 846 847
				final double disparityFar,
				final double disparityNear,
				final int debugLevel)
		{
848
			final double  scale_strength_lma = 5.0; // increase LMA-defined strength during averaging
849 850
			final int tilesX = tileProcessor.getTilesX();
			final int tilesY = tileProcessor.getTilesY();
851

852
			final int nTiles = tilesX*tilesY;
853
			final boolean [] weakOutliers = new boolean [nTiles];
854 855 856 857
			int [] dirs8 = {-tilesX,  -tilesX + 1, 1, tilesX +1, tilesX, tilesX - 1, -1, -tilesX - 1};
			final int [] dirs = dirs8;
			final double [] disparity = getDisparity(0);
			final double [] strength =  getStrength();
858 859
			final boolean [] has_lma =  getLMA();

860
			final double absMinDisparity = 0.5 * disparityFar; // adjust? below this is definitely wrong (weak)
861 862 863
			final double absMaxDisparity = 1.5 * disparityNear; // change?
			final int dbg_nTile = (debugLevel > 0) ? 43493: -1; // x=77,y=134; // 42228; // x = 108, y = 130 46462; // 41545;
			final Thread[] threads = ImageDtt.newThreadArray(tileProcessor.threadsMax);
864
			// first pass = find outliers
865 866 867
			final AtomicInteger ai = new AtomicInteger(0);
			for (int ithread = 0; ithread < threads.length; ithread++) {
				threads[ithread] = new Thread() {
868
					@Override
869 870
					public void run() {
						for (int nTile = ai.getAndIncrement(); nTile < nTiles; nTile = ai.getAndIncrement()) {
871
							if (((!has_lma[nTile] && (strength[nTile] < weakStrength)) ||
872 873 874
									(disparity[nTile] < absMinDisparity) ||
									(disparity[nTile] > absMaxDisparity))&& ((selection == null) || selection[nTile])) {
								if (nTile == dbg_nTile){
875
									System.out.println("replaceWeakOutliers():1 nTile="+nTile);
876 877 878 879 880
								}
								double [] dbg_disparity = disparity;
								double dbg_disparity_nTile = disparity[nTile];
								double dbg_disparityFar = disparityFar;
								double dbg_disparityNear = disparityNear;
881
								boolean [] dbg_weakOutliers = weakOutliers;
882 883 884
								int tileY = nTile / tilesX;
								int tileX = nTile % tilesX;
								if ((tileY > 0) && (tileY < (tilesY -1)) &&(tileX > 0) && (tileX < (tilesX -1))){ // disregard outer row/cols
885
									weakOutliers[nTile] = true;
886 887 888 889 890 891 892 893 894
									boolean hasNeighbors = false;
									double sd = 0.0, sw = 0.0;
									for (int dir = 0; dir< dirs.length; dir++){
										int nTile1 = nTile + dirs[dir];
										double dbg_disparity_nTile1 = disparity[nTile1];
										if (((selection == null) || selection[nTile1]) &&
												 (disparity[nTile1] >= disparityFar) && // don't count on too near/too far for averaging
												 (disparity[nTile1] <= disparityNear)){
											double w = strength[nTile1];
895 896 897
											if (has_lma[nTile1]) {
												w *= scale_strength_lma;
											}
898 899 900
											sw += w;
											sd += w * disparity[nTile1];
											hasNeighbors = true;
901
											if (Math.abs(disparity[nTile]-disparity[nTile1]) <= maxDiff){ // any outlier - will be false
902
												weakOutliers[nTile] = false;
903 904 905 906 907 908
//												break;
											}
										}
									}
									if (sw >= 0.0) {
										sd /= sw;
909 910
										if      (disparity[nTile] < (sd - maxDiffNeg)) weakOutliers[nTile] = true;
										else if (disparity[nTile] > (sd + maxDiffPos)) weakOutliers[nTile] = true;
911
									}
912 913
									if (disparity[nTile] < disparityFar)  weakOutliers[nTile] = true;
									if (disparity[nTile] > disparityNear) weakOutliers[nTile] = true;
914
									if (!hasNeighbors) {
915
										weakOutliers[nTile] = false; // lone tile or NaN among NaNs
916 917 918 919 920 921
									}
								}
							}
						}
					}
				};
922
			}
923
			ImageDtt.startAndJoin(threads);
924

925
			// second pass - replace outliers
926 927 928 929
			final double [] src_disparity = disparity.clone();
			ai.set(0);
			for (int ithread = 0; ithread < threads.length; ithread++) {
				threads[ithread] = new Thread() {
930
					@Override
931 932 933
					public void run() {
						for (int nTile = ai.getAndIncrement(); nTile < nTiles; nTile = ai.getAndIncrement()) {
							if (nTile == dbg_nTile){
934
								System.out.println("replaceWeakOutliers():2 nTile="+nTile);
935
							}
936
							if (weakOutliers[nTile]) {
937 938 939
								double sw = 0.0, sd = 0.0;
								for (int dir = 0; dir< dirs.length; dir++){
									int nTile1 = nTile + dirs[dir];
940
									if (!weakOutliers[nTile1] && ((selection == null) || selection[nTile1 ]) ) {
941
										double w = strength[nTile1];
942 943 944
										if (has_lma[nTile1]) {
											w *= scale_strength_lma;
										}
945
										sw += w;
946
										sd += w * src_disparity[nTile1];
947 948 949 950
									}
								}
								if (sw == 0) { // Nothing strong around - repeat with weak and this one too.
									double w = strength[nTile];
951 952 953
									if (has_lma[nTile]) {
										w *= scale_strength_lma;
									}
954 955 956 957 958 959 960 961
									if (!Double.isNaN( src_disparity[nTile])) {
										sw += w;
										sd += w * src_disparity[nTile];
									}
									for (int dir = 0; dir< dirs.length; dir++){
										int nTile1 = nTile + dirs[dir];
										if ((selection == null) || selection[nTile1 ]) {
											w = strength[nTile1];
962 963 964
											if (has_lma[nTile1]) {
												w *= scale_strength_lma;
											}
965 966
											if (!Double.isNaN( src_disparity[nTile1])) {
												sw += w;
967
												sd += w * src_disparity[nTile1];
968 969 970 971 972 973 974 975 976 977 978
											}
										}
									}
								}
								if (sw > 0) { // should be, do nothing if not
									disparity[nTile] = sd/sw;
								}
							}
						}
					}
				};
979
			}
980
			ImageDtt.startAndJoin(threads);
981
			return weakOutliers;
982
		}
983

984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
		public boolean [] getUntestedBackgroundBorder (
				final boolean    [] known,
				final double     [] disparity,
				final double        grow_disp_step,
				final int     debugLevel)
		{
			final int tilesX = tileProcessor.getTilesX();
			final int tilesY = tileProcessor.getTilesY();
			final int num_tiles = tilesX * tilesY;
			final TileNeibs tnImage = new TileNeibs(tilesX, tilesY); // num_tiles/tilesX);
			final boolean [] untested_bgnd = new boolean [num_tiles];
			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() {
999
					@Override
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
					public void run() {
						for (int nTile = ai.getAndIncrement(); nTile < num_tiles; nTile = ai.getAndIncrement()) {
							if (known[nTile]){
								int tX = nTile % tilesX;
								int tY = nTile / tilesX;
								double max_disp = max_tried_disparity[tY][tX] + grow_disp_step;
								for (int dir = 0; dir < 8; dir++){
									int nTile1 = tnImage.getNeibIndex(nTile, dir);
									if ((nTile1 >=0) && known[nTile1] && (disparity[nTile1] > max_disp)) {
										untested_bgnd[nTile] = true;
										break;
									}
								}
							}
						}
					}
				};
1017
			}
1018 1019 1020
			ImageDtt.startAndJoin(threads);
			return untested_bgnd;
		}
1021

1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
		public boolean [] measuredTiles ()
		{
			final int tilesX = tileProcessor.getTilesX();
			final int tilesY = tileProcessor.getTilesY();
			final int num_tiles = tilesX * tilesY;
			final boolean [] measured = new boolean [num_tiles];
			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() {
1032
					@Override
1033 1034 1035 1036 1037 1038 1039 1040
					public void run() {
						for (int nTile = ai.getAndIncrement(); nTile < num_tiles; nTile = ai.getAndIncrement()) {
								int tX = nTile % tilesX;
								int tY = nTile / tilesX;
								measured[nTile] = tile_op[tY][tX] != 0;
						}
					}
				};
1041
			}
1042 1043 1044
			ImageDtt.startAndJoin(threads);
			return measured;
		}
1045

Andrey Filippov's avatar
Andrey Filippov committed
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
		public void saveTileOpDisparity()
		{
			disparity_sav =disparity.clone();
			for (int i = 0; i < disparity.length; i++ ) if (disparity[i]!= null) disparity_sav[i] = disparity[i].clone();
			tile_op_sav =tile_op.clone();
			for (int i = 0; i < tile_op.length; i++ ) if (tile_op[i]!= null) tile_op_sav[i] = tile_op[i].clone();
		}
		public void restoreTileOpDisparity()
		{
			disparity = disparity_sav;
			tile_op = tile_op_sav;
		}
		public void restoreKeepTileOpDisparity()
		{
			restoreTileOpDisparity();
			saveTileOpDisparity();
		}
1063 1064
		public int setTileOpDisparity(
				double []  disparity) {
1065 1066 1067
			if (disparity== null) {
				disparity=new double[tileProcessor.getTilesX() * tileProcessor.getTilesY()]; // all defined, infinity 
			}
1068 1069 1070 1071 1072 1073 1074 1075
			boolean [] selection = new boolean [disparity.length];
			for (int i = 0; i < disparity.length; i++) {
				selection[i] = !Double.isNaN(disparity[i]);
			}
			return setTileOpDisparity(
					selection, // boolean [] selection,
					disparity); // double []  disparity)
		}
1076

Andrey Filippov's avatar
Andrey Filippov committed
1077 1078 1079 1080 1081 1082 1083
		public int setTileOpDisparity(
				boolean [] selection,
				double []  disparity)
		{
			int op = ImageDtt.setImgMask(0, 0xf);
			op =     ImageDtt.setPairMask(op,0xf);
			op =     ImageDtt.setForcedDisparity(op,true);
1084 1085
			// New as for 11/18/2022 - no CPU support yet 
			op |= (1 << GPUTileProcessor.TASK_TEXT_EN) | (1 << GPUTileProcessor.TASK_CORR_EN) | (1 << GPUTileProcessor.TASK_INTER_EN);
Andrey Filippov's avatar
Andrey Filippov committed
1086 1087 1088 1089 1090
			return setTileOpDisparity(
					op,         // int        tile_op,
					selection,  // boolean [] selection,
					disparity); // double []  disparity)
		}
1091

Andrey Filippov's avatar
Andrey Filippov committed
1092 1093 1094 1095 1096 1097 1098 1099
		public int setTileOpDisparity(
				int        tile_op,
				boolean [] selection,
				double []  disparity)
		{
			final int tilesX = tileProcessor.getTilesX();
			final int tilesY = tileProcessor.getTilesY();
			this.disparity =   new double [tilesY][tilesX];
1100 1101 1102
			if (selection != null) {
				this.tile_op =     new int [tilesY][tilesX];
			}
Andrey Filippov's avatar
Andrey Filippov committed
1103 1104 1105 1106
			int num_op_tiles = 0;

			for (int ty = 0; ty < tilesY; ty++) for (int tx = 0; tx <tilesX; tx++){
				int indx =  tilesX * ty + tx;
1107 1108 1109 1110 1111
				if (selection == null) {
					this.disparity[ty][tx] = (disparity == null)? 0.0: disparity[indx];
					if (this.tile_op[ty][tx] != 0){
						num_op_tiles ++;
					}
Andrey Filippov's avatar
Andrey Filippov committed
1112
				} else {
1113
					if (selection[indx]) {
1114
//						this.disparity[ty][tx] = (disparity == null)? 0.0: disparity[indx];
1115 1116 1117
						this.tile_op[ty][tx] = tile_op;
						num_op_tiles ++;
					} else {
1118
//						this.disparity[ty][tx] = 0.0;
1119 1120
						this.tile_op[ty][tx] = 0;
					}
1121 1122
					this.disparity[ty][tx] = (disparity == null)? 0.0: disparity[indx];
					
Andrey Filippov's avatar
Andrey Filippov committed
1123 1124 1125 1126
				}
			}
			return num_op_tiles;
		}
1127
		/*
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
		public void setTileOp(
				int  tile_op)
		{
			final int tilesX = tileProcessor.getTilesX();
			final int tilesY = tileProcessor.getTilesY();
			this.tile_op =     new int [tilesY][tilesX];

			for (int ty = 0; ty < tilesY; ty++) for (int tx = 0; tx <tilesX; tx++){
				this.tile_op[ty][tx] = tile_op;
			}
		}
1139
*/
1140 1141 1142 1143 1144 1145 1146 1147 1148
		public double [] getDA() {
			final int tilesX = tileProcessor.getTilesX();
			final int tilesY = tileProcessor.getTilesY();
			double [] da = new double [tilesX*tilesY];
			for (int ty = 0; ty < tilesY; ty++) for (int tx = 0; tx <tilesX; tx++){
				da[tilesX * ty + tx] = this.disparity[ty][tx];
			}
			return da;
		}
1149

1150 1151 1152 1153 1154 1155 1156 1157
		public void setDA(double [] da) {
			final int tilesX = tileProcessor.getTilesX();
			final int tilesY = tileProcessor.getTilesY();
			for (int ty = 0; ty < tilesY; ty++) for (int tx = 0; tx <tilesX; tx++){
				this.disparity[ty][tx] = da[tilesX * ty + tx];
			}
		}
		
1158 1159 1160 1161 1162
		/**
		 * Set next measurement disparity from last calculated
		 */
		public void updateDisparity()
		{
1163 1164 1165
			if (disparity_map != null) {
				setTileOpDisparity(null, getDisparity(0));
			}
1166
		}
1167

Andrey Filippov's avatar
Andrey Filippov committed
1168 1169 1170
        public void setSecondMax(double [] second_max) { // setting "fake" for the non-measurement scan
        	this.second_max = second_max;
        }
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
        public void setSecondMax() {
        	this.second_max = getSecondMaxDiff(false);
        }
        public double [] getSecondMax() {
        	if (this.second_max == null) {
        		setSecondMax();
        	}
        	return this.second_max;
        }
		
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 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 1233 1234 1235 1236
        public void setAvgVal(double [] avg_val) { // setting "fake" for the non-measurement scan
        	this.avg_val = avg_val;
        }
        public void setAvgVal() {
        	this.avg_val = getLowResChn();
        }
        public double [] getAvgVal() {
        	if (this.avg_val == null) {
        		setAvgVal();
        	}
        	return this.avg_val;
        }
        
        
        
		public double [] getLowResChn ()
		{
			final int numcolors = tileProcessor.isMonochrome()?1:3;
			final double [][] rbg = getRBGs();
			if (rbg == null) return null;
			for (int i = 0; i < rbg.length; i++) {
				if (rbg[i] == null) return null;
			}
			final double [] col_weights = {0.25,0.25,0.5};
			final int tilesX = tileProcessor.getTilesX();
			final int tilesY = tileProcessor.getTilesY();
			final int num_tiles = tilesX * tilesY;
			final double [] lowres = new double [num_tiles];
			final boolean [] measured =  measuredTiles ();
			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() {
					@Override
					public void run() {
						for (int nTile = ai.getAndIncrement(); nTile < num_tiles; nTile = ai.getAndIncrement()) {
							double d = 0.0;
							if (numcolors == 1) {
								for (int i = 0; i < rbg.length; i++) {
									d += rbg[i][nTile];
								}
							} else {
								for (int i = 0; i < rbg.length; i++) {
									int col= i%numcolors;
									d += rbg[i][nTile]*col_weights[col];
								}
							}
							lowres[nTile] = d/getNumSensors();
						}
					}
				};
			}
			ImageDtt.startAndJoin(threads);
			return lowres;
		}        
        
1237 1238 1239 1240 1241
		public double [] getSecondMaxDiff (
				final boolean averaged)
		{
			final double [][] diffs = getDiffs();
			if (diffs == null) return null;
1242 1243 1244
			for (int i = 0; i < diffs.length; i++) {
				if (diffs[i] == null) return null;
			}
1245 1246 1247 1248 1249 1250 1251 1252 1253
			final int tilesX = tileProcessor.getTilesX();
			final int tilesY = tileProcessor.getTilesY();
			final int num_tiles = tilesX * tilesY;
			final double [] second_max = new double [num_tiles];
			final boolean [] measured =  measuredTiles ();
			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() {
1254
					@Override
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
					public void run() {
						for (int nTile = ai.getAndIncrement(); nTile < num_tiles; nTile = ai.getAndIncrement()) {
							int imax1 = 0;
							for (int ip = 1; ip < diffs.length; ip++){
								if (diffs[ip][nTile] > diffs[imax1][nTile]) imax1 = ip;
							}
							int imax2 = (imax1 == 0)? 1 : 0;
							for (int ip = 0; ip < diffs.length; ip++) if (ip != imax1) {
								if (diffs[ip][nTile] > diffs[imax2][nTile]) imax2 = ip;
							}
							second_max[nTile] = diffs[imax2][nTile];
						}
					}
				};
1269
			}
1270 1271 1272 1273 1274 1275 1276 1277
			ImageDtt.startAndJoin(threads);
			if (!averaged) return second_max;
			final TileNeibs tnImage = new TileNeibs(tilesX, tilesY); // num_tiles/tilesX);
			final double [] second_max_averaged = new double [num_tiles];
			final double [] dir_weights = {1.0/16, 1.0/8, 1.0/16, 1.0/8, 1.0/16, 1.0/8, 1.0/16, 1.0/8, 1.0/4};
			ai.set(0);
			for (int ithread = 0; ithread < threads.length; ithread++) {
				threads[ithread] = new Thread() {
1278
					@Override
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
					public void run() {
						for (int nTile = ai.getAndIncrement(); nTile < num_tiles; nTile = ai.getAndIncrement()) if (measured[nTile]) {
							double sw = 0.0;
							double swd = 0.0;
							for (int dir = 0; dir < 9; dir++){ // including 8 - center
								int nTile1 = tnImage.getNeibIndex(nTile, dir);
								if ((nTile1 >=0) && measured[nTile1]) {
									sw +=  dir_weights[dir];
									swd += dir_weights[dir] * second_max[nTile1] ;
								}
							}
1290
							second_max_averaged[nTile] = swd/sw;
1291 1292 1293
						}
					}
				};
1294
			}
1295 1296 1297
			ImageDtt.startAndJoin(threads);
			return second_max_averaged;
		}
1298 1299 1300
		
		
		
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
		@Deprecated
		public double [] getFOM(
				double w_adisp,
				double w_cdiff
				) {
			// should it use getDisparity(), getStrength()?
			final double [] strength =        disparity_map[ImageDtt.DISPARITY_STRENGTH_INDEX];
			final double [] disparity =       disparity_map[ImageDtt.DISPARITY_INDEX_CM]; // is it combined with LMA?
//			final double [] second_max_diff = getSecondMaxDiff(false);
 			final double [] fom = new double [strength.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() {
					@Override
					public void run() {
						for (int nTile = ai.getAndIncrement(); nTile < fom.length; nTile = ai.getAndIncrement()) {
							double tfom = strength[nTile] - w_adisp * Math.abs(disparity[nTile]) - w_cdiff * second_max[nTile];
							if ((strength[nTile] <= 0) || Double.isNaN(tfom)) {
								fom[nTile] = Double.NEGATIVE_INFINITY;
							} else {
								fom[nTile] = tfom;
							}
						}
					}
				};
			}
			ImageDtt.startAndJoin(threads);
 			return fom;
		}
		public double getFOM(
				int    nTile,
				double min_strength,
				double w_adisp,
				double w_cdiff
				){
			final double strength =        disparity_map[ImageDtt.DISPARITY_STRENGTH_INDEX][nTile];
			final double disparity =       disparity_map[ImageDtt.DISPARITY_INDEX_CM][nTile]; // is it combined with LMA?
//			double fom = strength - w_adisp * Math.abs(disparity) - w_cdiff * second_max;
1341
			double cdiff = (second_max == null) ? 0.0:second_max[nTile];
1342 1343
			double fom = strength
					- w_adisp * Math.abs(disparity)
1344
					- w_cdiff * cdiff *(min_strength/strength);
1345 1346 1347 1348 1349 1350 1351 1352
			
			
			if ((strength <= 0) || (strength <= min_strength) || Double.isNaN(fom)) {
				return Double.NEGATIVE_INFINITY;
			} else {
				return fom;
			}
		}
1353

1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
		// same, but 2 steps around
		public boolean [] getUntestedBackgroundBorder2 (
				final boolean    [] known,
				final double     [] disparity,
				final double        grow_disp_step,
				final int     debugLevel)
		{
			final int tilesX = tileProcessor.getTilesX();
			final int tilesY = tileProcessor.getTilesY();
			final int num_tiles = tilesX * tilesY;
			final TileNeibs tnImage = new TileNeibs(tilesX, tilesY); // num_tiles/tilesX);
			final boolean [] untested_bgnd = new boolean [num_tiles];
			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() {
1370
					@Override
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
					public void run() {
						for (int nTile = ai.getAndIncrement(); nTile < num_tiles; nTile = ai.getAndIncrement()) {
							if (known[nTile]){
								int tX = nTile % tilesX;
								int tY = nTile / tilesX;
								double max_disp = max_tried_disparity[tY][tX] + grow_disp_step;
								for (int dir = 0; dir < 24; dir++){
									int nTile1 = tnImage.getNeibIndex2(nTile, dir);
									if ((nTile1 >=0) && known[nTile1] && (disparity[nTile1] > max_disp)) {
										untested_bgnd[nTile] = true;
										break;
									}
								}
							}
						}
					}
				};
1388
			}
1389 1390 1391
			ImageDtt.startAndJoin(threads);
			return untested_bgnd;
		}
1392

1393 1394 1395 1396 1397





1398 1399 1400 1401
		public SuperTiles getSuperTiles()
		{
			return this.superTiles;
		}
1402

Andrey Filippov's avatar
Andrey Filippov committed
1403
		public SuperTiles setSuperTiles(
1404 1405 1406 1407 1408
				double     step_near,
				double     step_far,
				double     step_threshold,
				double     min_disparity,
				double     max_disparity,
1409
				double     stBlurSigma,
1410
				boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
1411
				MeasuredLayersFilterParameters mlfp,
1412
				int        measSel)
1413 1414 1415 1416 1417 1418 1419 1420
		{
			this.superTiles = new SuperTiles(
					this,
					step_near,
					step_far,
					step_threshold,
					min_disparity,
					max_disparity,
1421
					stBlurSigma,
1422
					smplMode, //        = true;   // Use sample mode (false - regular tile mode)
1423
					mlfp,
1424
					measSel);
Andrey Filippov's avatar
Andrey Filippov committed
1425
			return this.superTiles;
1426
		}
1427
		public double [] showDisparityHistogram(
1428 1429
				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
1430

1431
				boolean    smplMode, //        = true;   // Use sample mode (false - regular tile mode)
1432
				MeasuredLayersFilterParameters mlfp,
1433
				int        measSel)
1434 1435 1436 1437
		{
			if (this.superTiles == null){
				return null;
			}
1438
			return this.superTiles.showDisparityHistogram(
1439 1440 1441
					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

1442
					smplMode, //        = true;   // Use sample mode (false - regular tile mode)
1443
					mlfp,
1444
					measSel);
1445 1446
		}

1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
		public double[] getSuperTileStrength()
		{
			if (this.superTiles == null){
				return null;
			}
			return superTiles.stStrength;
		}

		public double [][] getBgDispStrength()
		{
			if ((bgTileDisparity == null) || (bgTileStrength == null)){
				double [][] rslt = {bgTileDisparity,bgTileStrength};
				return rslt;
			}
			return getBgDispStrength(
1462
					this.minBgDisparity,
1463 1464
					this.minBgFract);
		}
1465 1466


1467
		public double [][] getBgDispStrength(
1468
				final double minBgDisparity,
1469 1470 1471 1472 1473 1474 1475
				final double minBgFract)
		{
			if (superTiles == null){
				return null;
			}
			if ((minBgDisparity != this.minBgDisparity) || (minBgFract != this.minBgFract)){
				this.minBgDisparity = minBgDisparity;
1476
				this.minBgFract = minBgFract;
1477 1478 1479 1480 1481 1482 1483
				superTiles.bgDisparity = null; // per super-tile
				superTiles.bgStrength = null; // per super-tile
				bgTileDisparity = null; // per tile
				bgTileStrength = null; // per tile
			}
			if ((superTiles.bgDisparity == null) || (superTiles.bgStrength == null)){
				if (superTiles.getBgDispStrength(
1484
						minBgDisparity,
1485 1486 1487 1488 1489 1490 1491 1492
						minBgFract) == null) {
					superTiles.bgDisparity = null; // per super-tile
					superTiles.bgStrength = null; // per super-tile
					bgTileDisparity = null; // per tile
					bgTileStrength = null; // per tile
					return null; // failed
				}
				// now lap-combine supertiles, get this.* from superTiles.*
1493

1494 1495 1496 1497 1498 1499 1500
				double [][] bgTileDispStrength = superTiles.getBgTileDispStrength();
				bgTileDisparity = bgTileDispStrength[0];
				bgTileStrength =  bgTileDispStrength[1];
			}
			double [][] rslt = {bgTileDisparity,bgTileStrength};
			return rslt;
		}
1501

1502 1503 1504 1505 1506 1507 1508 1509
		public double [] getBgDisparity(){
			return bgTileDisparity;
		}
		public double [] getBgStrength(){
			return bgTileStrength;
		}

	} // end of class CLTPass3d