Loading src/main/java/com/elphel/imagej/cameras/CLTParameters.java +22 −3 Original line number Diff line number Diff line Loading @@ -426,6 +426,9 @@ public class CLTParameters { public boolean tex_debug_disp_tri = false; // !batch_mode && (debugLevel > 0); // TODO: use clt_parameters public int tex_add_bg_tiles = 0; // If there is gap between clusters, add extra row of background tiles public boolean tex_save_full_textures = true; // false; // true; public boolean tex_save_interm_textures = false; // Save intermediate texture public boolean tex_save_um_texture0 = true; // Save full-res texture (only first slice) after unsharp mask filter public boolean tex_save_preview = true; // Save normalized texture0 as a scene sequence preview public double tex_alpha_threshold = 0.5; public boolean tex_renormalize = true; // false - use normalizations from previous scenes to keep consistent colors public boolean tex_alpha = false; // also - use jpeg? Loading @@ -438,9 +441,9 @@ public class CLTParameters { public boolean tex_um_fixed = false; // Use fixed range after unsharp mask instead of autorange public double tex_um_range = 500; // Full range after unsharp mask public boolean tex_hist_norm = true; // Normalize texture histogram public double tex_hist_amount = 0.7; // Texture histogram normalization amount (0.0 - no normalization, 1.0 - full normalization) public double tex_hist_amount = 0.5; // Texture histogram normalization amount (0.0 - no normalization, 1.0 - full normalization) public int tex_hist_bins = 1024; // Number of histogram bins to use for texture histograms public int tex_hist_segments = 32; // Number of evenly-spaced percentiles to use for histogram normalization public int tex_hist_segments = 128; // Number of evenly-spaced percentiles to use for histogram normalization public boolean tex_color = true; // Use pseudo-colored textures public int tex_palette = 1; // Palette number for pseudo colors Loading Loading @@ -1548,6 +1551,9 @@ public class CLTParameters { properties.setProperty(prefix+"tex_debug_disp_tri", this.tex_debug_disp_tri+""); // boolean properties.setProperty(prefix+"tex_add_bg_tiles", this.tex_add_bg_tiles+""); // int properties.setProperty(prefix+"tex_save_full_textures", this.tex_save_full_textures+""); // boolean properties.setProperty(prefix+"tex_save_interm_textures", this.tex_save_interm_textures+"");// boolean properties.setProperty(prefix+"tex_save_um_texture0", this.tex_save_um_texture0+""); // boolean properties.setProperty(prefix+"tex_save_preview", this.tex_save_preview+""); // boolean properties.setProperty(prefix+"tex_alpha_threshold", this.tex_alpha_threshold+""); // double properties.setProperty(prefix+"tex_renormalize", this.tex_renormalize+""); // boolean properties.setProperty(prefix+"tex_alpha", this.tex_alpha+""); // boolean Loading Loading @@ -2547,6 +2553,9 @@ public class CLTParameters { if (properties.getProperty(prefix+"tex_debug_disp_tri")!=null) this.tex_debug_disp_tri=Boolean.parseBoolean(properties.getProperty(prefix+"tex_debug_disp_tri")); if (properties.getProperty(prefix+"tex_add_bg_tiles")!=null) this.tex_add_bg_tiles=Integer.parseInt(properties.getProperty(prefix+"tex_add_bg_tiles")); if (properties.getProperty(prefix+"tex_save_full_textures")!=null)this.tex_save_full_textures=Boolean.parseBoolean(properties.getProperty(prefix+"tex_save_full_textures")); if (properties.getProperty(prefix+"tex_save_interm_textures")!=null)this.tex_save_interm_textures=Boolean.parseBoolean(properties.getProperty(prefix+"tex_save_interm_textures")); if (properties.getProperty(prefix+"tex_save_um_texture0")!=null) this.tex_save_um_texture0=Boolean.parseBoolean(properties.getProperty(prefix+"tex_save_um_texture0")); if (properties.getProperty(prefix+"tex_save_preview")!=null) this.tex_save_preview=Boolean.parseBoolean(properties.getProperty(prefix+"tex_save_preview")); if (properties.getProperty(prefix+"tex_alpha_threshold")!=null) this.tex_alpha_threshold=Double.parseDouble(properties.getProperty(prefix+"tex_alpha_threshold")); if (properties.getProperty(prefix+"tex_renormalize")!=null) this.tex_renormalize=Boolean.parseBoolean(properties.getProperty(prefix+"tex_renormalize")); if (properties.getProperty(prefix+"tex_alpha")!=null) this.tex_alpha=Boolean.parseBoolean(properties.getProperty(prefix+"tex_alpha")); Loading Loading @@ -3740,6 +3749,13 @@ public class CLTParameters { gd.addCheckbox ("Save full textures", this.tex_save_full_textures, "Will save anyway if !tex_split_textures."); gd.addCheckbox ("Save intermediate textures", this.tex_save_interm_textures, "Save intermediate textures - all slices as floating-point TIFFs."); gd.addCheckbox ("Save texture slice0", this.tex_save_um_texture0, "Save full-res texture (only first slice) after unsharp mask filter. Used for flat down-views from UAS."); gd.addCheckbox ("Save texture as preview", this.tex_save_preview, "Save full-res texture (first slice) after unsharp mask and histogram normalilzationas a scene sequence preview image."); gd.addNumericField("Alpha threshold", this.tex_alpha_threshold, 5,7,"", "Alpha threshold to consider it opaque."); gd.addCheckbox ("Re-normalize photometric range", this.tex_renormalize, Loading Loading @@ -4969,6 +4985,9 @@ public class CLTParameters { this.tex_debug_disp_tri = gd.getNextBoolean(); this.tex_add_bg_tiles = (int) gd.getNextNumber(); this.tex_save_full_textures = gd.getNextBoolean(); this.tex_save_interm_textures = gd.getNextBoolean(); this.tex_save_um_texture0 = gd.getNextBoolean(); this.tex_save_preview = gd.getNextBoolean(); this.tex_alpha_threshold = gd.getNextNumber(); this.tex_renormalize = gd.getNextBoolean(); this.tex_alpha = gd.getNextBoolean(); Loading src/main/java/com/elphel/imagej/tileprocessor/IntersceneMatchParameters.java +11 −3 Original line number Diff line number Diff line Loading @@ -264,7 +264,8 @@ public class IntersceneMatchParameters { public double min_offset = 1.5; // pixels - minimal average pixel offset between images to consider interscene matching public double max_rel_offset = 0.5; // maximal interscene offset as a fraction of image width public double max_roll_deg = 10.0; // maximal interscene roll to consider matching public double max_roll_deg = 5.0; // maximal interscene roll to consider matching public double max_zoom_diff = 0; // for down-views when changing altitude (0 - ignore) public boolean fpn_skip = true; // skip too close scenes (false - abort, previous behavior) public boolean fpn_rematch = true; // match fpn-failed scenes to later scenes with larger difference Loading Loading @@ -809,6 +810,8 @@ public class IntersceneMatchParameters { "Maximal interscene offset as a fraction of image width to handle low overlap"); gd.addNumericField("Maximal interscene roll", this.max_roll_deg, 6,7,"degrees", "Maximal interscene roll to consider matching"); gd.addNumericField("Maximal interscene relative zoom difference", this.max_zoom_diff, 6,7,"", "Applicable for the down views from a drone. Saet to 0 to ignore."); gd.addCheckbox ("Skip too close to reference scenes", this.fpn_skip, "Skip too close to reference scenes (false - abort, previous behavior)"); gd.addCheckbox ("Match FPN-failed with other scenes", this.fpn_rematch, Loading Loading @@ -1193,6 +1196,8 @@ public class IntersceneMatchParameters { this.min_offset = gd.getNextNumber(); this.max_rel_offset = gd.getNextNumber(); this.max_roll_deg = gd.getNextNumber(); this.max_zoom_diff = gd.getNextNumber(); this.fpn_skip = gd.getNextBoolean(); this.fpn_rematch = gd.getNextBoolean(); Loading Loading @@ -1528,6 +1533,7 @@ public class IntersceneMatchParameters { properties.setProperty(prefix+"min_offset", this.min_offset+""); // double properties.setProperty(prefix+"max_rel_offset", this.max_rel_offset+""); // double properties.setProperty(prefix+"max_roll_deg", this.max_roll_deg+""); // double properties.setProperty(prefix+"max_zoom_diff", this.max_zoom_diff+""); // double properties.setProperty(prefix+"fpn_skip", this.fpn_skip+""); // boolean properties.setProperty(prefix+"fpn_rematch", this.fpn_rematch+""); // boolean Loading Loading @@ -1821,6 +1827,7 @@ public class IntersceneMatchParameters { if (properties.getProperty(prefix+"min_offset")!=null) this.min_offset=Double.parseDouble(properties.getProperty(prefix+"min_offset")); if (properties.getProperty(prefix+"max_rel_offset")!=null) this.max_rel_offset=Double.parseDouble(properties.getProperty(prefix+"max_rel_offset")); if (properties.getProperty(prefix+"max_roll_deg")!=null) this.max_roll_deg=Double.parseDouble(properties.getProperty(prefix+"max_roll_deg")); if (properties.getProperty(prefix+"max_zoom_diff")!=null) this.max_zoom_diff=Double.parseDouble(properties.getProperty(prefix+"max_zoom_diff")); if (properties.getProperty(prefix+"fpn_skip")!=null) this.fpn_skip=Boolean.parseBoolean(properties.getProperty(prefix+"fpn_skip")); if (properties.getProperty(prefix+"fpn_rematch")!=null) this.fpn_rematch=Boolean.parseBoolean(properties.getProperty(prefix+"fpn_rematch")); Loading Loading @@ -2125,6 +2132,7 @@ public class IntersceneMatchParameters { imp.min_offset = this.min_offset; imp.max_rel_offset = this.max_rel_offset; imp.max_roll_deg = this.max_roll_deg; imp.max_zoom_diff = this.max_zoom_diff; imp.fpn_skip = this.fpn_skip; imp.fpn_rematch = this.fpn_rematch; Loading src/main/java/com/elphel/imagej/tileprocessor/OpticalFlow.java +85 −21 Original line number Diff line number Diff line Loading @@ -86,13 +86,29 @@ public class OpticalFlow { public static int COMBO_DSN_INDX_DISP_BG_ALL =10; // cumulative BG disparity (Use FG where no BG is available) public static int COMBO_DSN_INDX_BLUE_SKY = 11; // Detected featureless infinity (sky) // interscene adjustments failure reasons. public static int FAIL_REASON_LMA = 1; // LMA failed public static int FAIL_REASON_INTERSCENE = 2; // clt_process_tl_interscene() returned null public static int FAIL_REASON_MIN = 3; // average pixel offset is below specified threshold (FPN) public static int FAIL_REASON_MAX = 4; // average pixel offset is above specified threshold (overlap) public static int FAIL_REASON_NULL = 5; // null offsets array public static int FAIL_REASON_EMPTY = 6; // No offset pairs in offsets array public static int FAIL_REASON_ROLL = 7; // Too high roll between the images public static final int FAIL_REASON_LMA = 1; // LMA failed public static final int FAIL_REASON_INTERSCENE = 2; // clt_process_tl_interscene() returned null public static final int FAIL_REASON_MIN = 3; // average pixel offset is below specified threshold (FPN) public static final int FAIL_REASON_MAX = 4; // average pixel offset is above specified threshold (overlap) public static final int FAIL_REASON_NULL = 5; // null offsets array public static final int FAIL_REASON_EMPTY = 6; // No offset pairs in offsets array public static final int FAIL_REASON_ROLL = 7; // Too high roll between the images public static final int FAIL_REASON_ZOOM = 8; // Too high zoom ratio between the images public static String getFailReason(int fr) { switch (fr) { case FAIL_REASON_LMA: return "FAIL_REASON_LMA"; case FAIL_REASON_INTERSCENE: return "FAIL_REASON_INTERSCENE"; case FAIL_REASON_MIN: return "FAIL_REASON_MIN"; case FAIL_REASON_MAX: return "FAIL_REASON_MAXv"; case FAIL_REASON_NULL: return "FAIL_REASON_NULL"; case FAIL_REASON_EMPTY: return "FAIL_REASON_EMPTY"; case FAIL_REASON_ROLL: return "FAIL_REASON_ROLL"; case FAIL_REASON_ZOOM: return "FAIL_REASON_ZOOM"; default: return "unknown scene-matching failure reason="+fr; } } public static double [] ZERO3 = {0.0,0.0,0.0}; public static double LINE_ERR = 0.1; Loading Loading @@ -4531,12 +4547,11 @@ public class OpticalFlow { double min_offset = 0.0; // clt_parameters.imp.min_offset; double max_offset = clt_parameters.imp.max_rel_offset * tilesX * tile_size; double max_roll = clt_parameters.imp.max_roll_deg*Math.PI/180.0; double max_zoom_diff = clt_parameters.imp.max_zoom_diff; boolean fpn_skip = clt_parameters.imp.fpn_skip; // if false - fail as before boolean fpn_rematch = clt_parameters.imp.fpn_rematch; // if false - keep previous double [] min_max = {min_offset, max_offset, 0.0} ; // {min, max, actual rms) int [] fail_reason = new int[1]; // null or int[1]: 0 - OK, 2 - LMA, 3 - min, 4 - max for (int scene_index = ref_index - 1; scene_index >= 0 ; scene_index--) { // to include ref scene photometric calibration quadCLTs[scene_index] = quadCLTs[ref_index].spawnNoModelQuadCLT( Loading Loading @@ -4573,6 +4588,17 @@ public class OpticalFlow { "reliable_ref"); } } double max_z_change = Double.NaN; // only applicable for drone images if (max_zoom_diff > 0) { // ignore if set to double avg_z = quadCLTs[ref_index].getAverageZ(true); // use lma max_z_change = avg_z * max_zoom_diff; if (debugLevel > -3) { System.out.println("Setting maximal Z-direction movement to "+ max_z_change+" m."); } } double [][][] scenes_xyzatr = new double [quadCLTs.length][][]; // previous scene relative to the next one scenes_xyzatr[ref_index] = new double[2][3]; // all zeros boolean after_spiral = false; Loading Loading @@ -4684,15 +4710,24 @@ public class OpticalFlow { clt_parameters.imp.debug_level); // 1); // -1); // int debug_level); boolean adjust_OK = scenes_xyzatr[scene_index] != null; if (adjust_OK && (Math.abs(scenes_xyzatr[scene_index][1][2]) > max_roll)) { if (adjust_OK) { // check only for initial orientation, do not check on readjustments if (Math.abs(scenes_xyzatr[scene_index][1][2]) > max_roll) { fail_reason[0] = FAIL_REASON_ROLL; adjust_OK = false; } if (max_zoom_diff > 0) { // ignore if set to if (Math.abs(scenes_xyzatr[scene_index][0][2]) > max_z_change) { fail_reason[0] = FAIL_REASON_ZOOM; adjust_OK = false; } } } // FAIL_REASON_ROLL handle_failure: { if (!adjust_OK) { // boolean OK = false; System.out.println("LMA failed at nscene = "+scene_index+". Reason = "+fail_reason[0]); System.out.println("LMA failed at nscene = "+scene_index+". Reason = "+fail_reason[0]+ " ("+getFailReason(fail_reason[0])+")"); if ((fail_reason[0]==FAIL_REASON_MIN) || ((fail_reason[0]==FAIL_REASON_LMA) && !got_spiral)) { if (fpn_skip) { System.out.println("fpn_skip is set, just using initial pose"); Loading @@ -4708,7 +4743,8 @@ public class OpticalFlow { if (debugLevel > -4) { System.out.println("Pass multi scene "+scene_index+" (of "+ quadCLTs.length+") "+ quadCLTs[ref_index].getImageName() + "/" + scene_QuadClt.getImageName()+ " FAILED. Setting earliest_scene to "+earliest_scene + " Failure reason: " + fail_reason[0]); " FAILED. Setting earliest_scene to "+earliest_scene + " Failure reason: " + fail_reason[0]+ " ("+getFailReason(fail_reason[0])+")"); } // set this and all previous to null for (; scene_index >= 0 ; scene_index--) { Loading Loading @@ -12841,7 +12877,7 @@ public class OpticalFlow { for (int i = 0; i < scene_disparity_strength[0].length; i++) { // scene_disparity_strength[0][i] = (scene_disparity_strength[0][i] - average_disparity) / average_absolute_disparity; scene_disparity_strength[0][i] = (scene_disparity_strength[0][i] - average_disparity) /magic_scale; scene_disparity_strength[0][i] = 1.0 / average_absolute_disparity; scene_disparity_strength[1][i] = 1.0 / average_absolute_disparity; } } } Loading Loading @@ -14144,6 +14180,7 @@ public class OpticalFlow { int debugLevel) { System.out.println("reAdjustPairsLMAInterscene(): using mb_max_gain="+mb_max_gain); boolean fail_on_zoom_roll=false; // it should fail on initial adjustment int avg_len = clt_parameters.imp.avg_len; // boolean test_motion_blur = true;//false // Set up velocities from known coordinates, use averaging Loading Loading @@ -14183,7 +14220,8 @@ public class OpticalFlow { int tile_size = quadCLTs[ref_index].getTileProcessor().getTileSize(); double min_offset = clt_parameters.imp.min_offset; double max_offset = second_margin*clt_parameters.imp.max_rel_offset * tilesX * tile_size; double max_roll = clt_parameters.imp.max_roll_deg*Math.PI/180.0; double max_roll = second_margin*clt_parameters.imp.max_roll_deg*Math.PI/180.0; double max_zoom_diff = second_margin*clt_parameters.imp.max_zoom_diff; boolean fpn_skip = clt_parameters.imp.fpn_skip; // if false - fail as before boolean fpn_rematch = clt_parameters.imp.fpn_rematch; // if false - keep previous double [] min_max = {min_offset, max_offset, 0.0} ; // {min, max, actual rms) Loading Loading @@ -14297,6 +14335,17 @@ public class OpticalFlow { } System.out.println(); } double max_z_change = Double.NaN; // only applicable for drone images if (max_zoom_diff > 0) { // ignore if set to double avg_z = quadCLTs[ref_index].getAverageZ(true); // use lma max_z_change = avg_z * max_zoom_diff; if (fail_on_zoom_roll) { if (debugLevel > -3) { System.out.println("Setting maximal Z-direction movement to "+ max_z_change+" m."); } } } boolean [] failed_scenes = new boolean[quadCLTs.length]; int num_failed =0; for (int nscene = ref_index; nscene >= earliest_scene; nscene--) { Loading Loading @@ -14517,15 +14566,29 @@ public class OpticalFlow { mb_vectors, // double [][] mb_vectors, // now [2][ntiles]; clt_parameters.imp.debug_level); // 1); // -1); // int debug_level); boolean adjust_OK = scenes_xyzatr[nscene] != null; if (adjust_OK && (Math.abs(scenes_xyzatr[nscene][1][2]) > max_roll)) { // if (adjust_OK && (Math.abs(scenes_xyzatr[nscene][1][2]) > max_roll)) { // fail_reason[0] = FAIL_REASON_ROLL; // adjust_OK = false; // } if (adjust_OK && fail_on_zoom_roll) { // check only for initial orientation, do not check on readjustments if (Math.abs(scenes_xyzatr[nscene][1][2]) > max_roll) { fail_reason[0] = FAIL_REASON_ROLL; adjust_OK = false; } if (max_zoom_diff > 0) { // ignore if set to if (Math.abs(scenes_xyzatr[nscene][0][2]) > max_z_change) { // NaN OK - will not fail fail_reason[0] = FAIL_REASON_ZOOM; adjust_OK = false; } } } // FAIL_REASON_ROLL handle_failure: { if (!adjust_OK) { boolean OK = false; System.out.println("LMA failed at nscene = "+nscene+". Reason = "+fail_reason[0]); System.out.println("LMA failed at nscene = "+nscene+". Reason = "+fail_reason[0]+ " ("+getFailReason(fail_reason[0])+")"); if ((fail_reason[0]==FAIL_REASON_MIN) || ((fail_reason[0]==FAIL_REASON_LMA))) { if (fpn_skip) { System.out.println("fpn_skip is set, just skipping this scene"); Loading @@ -14547,7 +14610,8 @@ public class OpticalFlow { if (debugLevel > -4) { System.out.println("reAdjustPairsLMAInterscene "+nscene+" (of "+ quadCLTs.length+") "+ quadCLTs[ref_index].getImageName() + "/" + ts+ " FAILED. Setting earliest_scene to "+earliest_scene + " Failure reason: " + fail_reason[0]); " FAILED. Setting earliest_scene to "+earliest_scene + " Failure reason: " + fail_reason[0]+ " ("+getFailReason(fail_reason[0])+")"); } // set this and all previous to null for (; nscene >= 0 ; nscene--) { src/main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java +93 −0 Original line number Diff line number Diff line Loading @@ -203,6 +203,21 @@ public class QuadCLTCPU { } public double getAverageZ(boolean use_lma) { double [][] dls = getDLS(); if (dls==null) { return Double.NaN; } double [][] ds = new double [][] {dls[use_lma?1:0], dls[2]}; double sw=0, swd=0; for (int i = 0; i < ds[0].length; i++) if (!Double.isNaN(ds[0][i])){ sw += ds[1][i]; swd += ds[0][i] * ds[1][i]; } double disp_avg = swd/sw; double z_avg = getGeometryCorrection().getZFromDisparity(disp_avg); return z_avg; } public double [][] getDLS(){ // get disparity, disparity_lma, strength if (dsi == null) { Loading Loading @@ -2205,6 +2220,25 @@ public class QuadCLTCPU { return imp; } public ImagePlus saveDoubleArrayInModelDirectory( String suffix, double [] data, int width, int height) { double [][] data2= new double[][] {data}; String x3d_path = getX3dDirectory(); String file_name = image_name + suffix; String file_path = x3d_path + Prefs.getFileSeparator() + file_name + ".tiff"; ImageStack imageStack = ShowDoubleFloatArrays.makeStack(data2, width, height, null); ImagePlus imp = new ImagePlus( file_name, imageStack); FileSaver fs=new FileSaver(imp); fs.saveAsTiff(file_path); System.out.println("saveDoubleArrayInModelDirectory(): saved "+file_path); return imp; } public String saveImagePlusInModelDirectory( String suffix, // null - use title from the imp ImagePlus imp) Loading Loading @@ -15115,6 +15149,65 @@ public class QuadCLTCPU { return true; } public boolean writeLwirPreview( final CLTParameters clt_parameters, double [] data, QuadCLT scene, int tex_palette, String suffix, int debugLevel) { if (scene == null) { scene = (QuadCLT) this; } double [][] rendered_texture = new double[][] {data, new double[data.length]}; for (int i = 0; i < rendered_texture[0].length; i++) { rendered_texture[1][i] = Double.isNaN(rendered_texture[0][i])? 0.0: 1.0; } double [] minmax = scene.getColdHot(); // used in linearStackToColor (from this current scene) int width = getTileProcessor().getTilesX() *getTileProcessor().getTileSize(); int height = data.length/width; String set_name = getImageName(); if (set_name == null ) { QuadCLTCPU.SetChannels [] set_channels = setChannels(debugLevel); set_name = set_channels[0].set_name; } String model_dir= correctionsParameters.selectX3dDirectory( set_name, // quad timestamp. Will be ignored if correctionsParameters.use_x3d_subdirs is false null, true, // smart, true); //newAllowed, // save\ String title = getImageName()+suffix+"-preview"; ImagePlus imp = QuadCLTCPU.linearStackToColorLWIR( clt_parameters, // CLTParameters clt_parameters, tex_palette, // int lwir_palette, // <0 - do not convert minmax, // double [] minmax, title, // String name, "", // String suffix, // such as disparity=... true, // boolean toRGB, rendered_texture, // faded_textures[nslice], // double [][] texture_data, width, // int width, // int tilesX, height, // int height, // int tilesY, debugLevel); // int debugLevel ) String preview_path = model_dir + Prefs.getFileSeparator() + title+".jpeg"; if (new File(preview_path).exists() && !correctionsParameters.thumb_overwrite) { System.out.println("file "+preview_path+" exists, skipping preview generation"); return false; } if (debugLevel > -2) { System.out.println("Saving preview image to "+preview_path); } EyesisCorrections.saveAndShow( imp, model_dir, false, false, correctionsParameters.JPEG_quality, // jpegQuality); // jpegQuality){// <0 - keep current, 0 - force Tiff, >0 use for JPEG (debugLevel > -2) ? debugLevel : 1); // int debugLevel (print what it saves) return true; } public boolean writeRatingFile( // USED in lwir int debugLevel ) Loading
src/main/java/com/elphel/imagej/cameras/CLTParameters.java +22 −3 Original line number Diff line number Diff line Loading @@ -426,6 +426,9 @@ public class CLTParameters { public boolean tex_debug_disp_tri = false; // !batch_mode && (debugLevel > 0); // TODO: use clt_parameters public int tex_add_bg_tiles = 0; // If there is gap between clusters, add extra row of background tiles public boolean tex_save_full_textures = true; // false; // true; public boolean tex_save_interm_textures = false; // Save intermediate texture public boolean tex_save_um_texture0 = true; // Save full-res texture (only first slice) after unsharp mask filter public boolean tex_save_preview = true; // Save normalized texture0 as a scene sequence preview public double tex_alpha_threshold = 0.5; public boolean tex_renormalize = true; // false - use normalizations from previous scenes to keep consistent colors public boolean tex_alpha = false; // also - use jpeg? Loading @@ -438,9 +441,9 @@ public class CLTParameters { public boolean tex_um_fixed = false; // Use fixed range after unsharp mask instead of autorange public double tex_um_range = 500; // Full range after unsharp mask public boolean tex_hist_norm = true; // Normalize texture histogram public double tex_hist_amount = 0.7; // Texture histogram normalization amount (0.0 - no normalization, 1.0 - full normalization) public double tex_hist_amount = 0.5; // Texture histogram normalization amount (0.0 - no normalization, 1.0 - full normalization) public int tex_hist_bins = 1024; // Number of histogram bins to use for texture histograms public int tex_hist_segments = 32; // Number of evenly-spaced percentiles to use for histogram normalization public int tex_hist_segments = 128; // Number of evenly-spaced percentiles to use for histogram normalization public boolean tex_color = true; // Use pseudo-colored textures public int tex_palette = 1; // Palette number for pseudo colors Loading Loading @@ -1548,6 +1551,9 @@ public class CLTParameters { properties.setProperty(prefix+"tex_debug_disp_tri", this.tex_debug_disp_tri+""); // boolean properties.setProperty(prefix+"tex_add_bg_tiles", this.tex_add_bg_tiles+""); // int properties.setProperty(prefix+"tex_save_full_textures", this.tex_save_full_textures+""); // boolean properties.setProperty(prefix+"tex_save_interm_textures", this.tex_save_interm_textures+"");// boolean properties.setProperty(prefix+"tex_save_um_texture0", this.tex_save_um_texture0+""); // boolean properties.setProperty(prefix+"tex_save_preview", this.tex_save_preview+""); // boolean properties.setProperty(prefix+"tex_alpha_threshold", this.tex_alpha_threshold+""); // double properties.setProperty(prefix+"tex_renormalize", this.tex_renormalize+""); // boolean properties.setProperty(prefix+"tex_alpha", this.tex_alpha+""); // boolean Loading Loading @@ -2547,6 +2553,9 @@ public class CLTParameters { if (properties.getProperty(prefix+"tex_debug_disp_tri")!=null) this.tex_debug_disp_tri=Boolean.parseBoolean(properties.getProperty(prefix+"tex_debug_disp_tri")); if (properties.getProperty(prefix+"tex_add_bg_tiles")!=null) this.tex_add_bg_tiles=Integer.parseInt(properties.getProperty(prefix+"tex_add_bg_tiles")); if (properties.getProperty(prefix+"tex_save_full_textures")!=null)this.tex_save_full_textures=Boolean.parseBoolean(properties.getProperty(prefix+"tex_save_full_textures")); if (properties.getProperty(prefix+"tex_save_interm_textures")!=null)this.tex_save_interm_textures=Boolean.parseBoolean(properties.getProperty(prefix+"tex_save_interm_textures")); if (properties.getProperty(prefix+"tex_save_um_texture0")!=null) this.tex_save_um_texture0=Boolean.parseBoolean(properties.getProperty(prefix+"tex_save_um_texture0")); if (properties.getProperty(prefix+"tex_save_preview")!=null) this.tex_save_preview=Boolean.parseBoolean(properties.getProperty(prefix+"tex_save_preview")); if (properties.getProperty(prefix+"tex_alpha_threshold")!=null) this.tex_alpha_threshold=Double.parseDouble(properties.getProperty(prefix+"tex_alpha_threshold")); if (properties.getProperty(prefix+"tex_renormalize")!=null) this.tex_renormalize=Boolean.parseBoolean(properties.getProperty(prefix+"tex_renormalize")); if (properties.getProperty(prefix+"tex_alpha")!=null) this.tex_alpha=Boolean.parseBoolean(properties.getProperty(prefix+"tex_alpha")); Loading Loading @@ -3740,6 +3749,13 @@ public class CLTParameters { gd.addCheckbox ("Save full textures", this.tex_save_full_textures, "Will save anyway if !tex_split_textures."); gd.addCheckbox ("Save intermediate textures", this.tex_save_interm_textures, "Save intermediate textures - all slices as floating-point TIFFs."); gd.addCheckbox ("Save texture slice0", this.tex_save_um_texture0, "Save full-res texture (only first slice) after unsharp mask filter. Used for flat down-views from UAS."); gd.addCheckbox ("Save texture as preview", this.tex_save_preview, "Save full-res texture (first slice) after unsharp mask and histogram normalilzationas a scene sequence preview image."); gd.addNumericField("Alpha threshold", this.tex_alpha_threshold, 5,7,"", "Alpha threshold to consider it opaque."); gd.addCheckbox ("Re-normalize photometric range", this.tex_renormalize, Loading Loading @@ -4969,6 +4985,9 @@ public class CLTParameters { this.tex_debug_disp_tri = gd.getNextBoolean(); this.tex_add_bg_tiles = (int) gd.getNextNumber(); this.tex_save_full_textures = gd.getNextBoolean(); this.tex_save_interm_textures = gd.getNextBoolean(); this.tex_save_um_texture0 = gd.getNextBoolean(); this.tex_save_preview = gd.getNextBoolean(); this.tex_alpha_threshold = gd.getNextNumber(); this.tex_renormalize = gd.getNextBoolean(); this.tex_alpha = gd.getNextBoolean(); Loading
src/main/java/com/elphel/imagej/tileprocessor/IntersceneMatchParameters.java +11 −3 Original line number Diff line number Diff line Loading @@ -264,7 +264,8 @@ public class IntersceneMatchParameters { public double min_offset = 1.5; // pixels - minimal average pixel offset between images to consider interscene matching public double max_rel_offset = 0.5; // maximal interscene offset as a fraction of image width public double max_roll_deg = 10.0; // maximal interscene roll to consider matching public double max_roll_deg = 5.0; // maximal interscene roll to consider matching public double max_zoom_diff = 0; // for down-views when changing altitude (0 - ignore) public boolean fpn_skip = true; // skip too close scenes (false - abort, previous behavior) public boolean fpn_rematch = true; // match fpn-failed scenes to later scenes with larger difference Loading Loading @@ -809,6 +810,8 @@ public class IntersceneMatchParameters { "Maximal interscene offset as a fraction of image width to handle low overlap"); gd.addNumericField("Maximal interscene roll", this.max_roll_deg, 6,7,"degrees", "Maximal interscene roll to consider matching"); gd.addNumericField("Maximal interscene relative zoom difference", this.max_zoom_diff, 6,7,"", "Applicable for the down views from a drone. Saet to 0 to ignore."); gd.addCheckbox ("Skip too close to reference scenes", this.fpn_skip, "Skip too close to reference scenes (false - abort, previous behavior)"); gd.addCheckbox ("Match FPN-failed with other scenes", this.fpn_rematch, Loading Loading @@ -1193,6 +1196,8 @@ public class IntersceneMatchParameters { this.min_offset = gd.getNextNumber(); this.max_rel_offset = gd.getNextNumber(); this.max_roll_deg = gd.getNextNumber(); this.max_zoom_diff = gd.getNextNumber(); this.fpn_skip = gd.getNextBoolean(); this.fpn_rematch = gd.getNextBoolean(); Loading Loading @@ -1528,6 +1533,7 @@ public class IntersceneMatchParameters { properties.setProperty(prefix+"min_offset", this.min_offset+""); // double properties.setProperty(prefix+"max_rel_offset", this.max_rel_offset+""); // double properties.setProperty(prefix+"max_roll_deg", this.max_roll_deg+""); // double properties.setProperty(prefix+"max_zoom_diff", this.max_zoom_diff+""); // double properties.setProperty(prefix+"fpn_skip", this.fpn_skip+""); // boolean properties.setProperty(prefix+"fpn_rematch", this.fpn_rematch+""); // boolean Loading Loading @@ -1821,6 +1827,7 @@ public class IntersceneMatchParameters { if (properties.getProperty(prefix+"min_offset")!=null) this.min_offset=Double.parseDouble(properties.getProperty(prefix+"min_offset")); if (properties.getProperty(prefix+"max_rel_offset")!=null) this.max_rel_offset=Double.parseDouble(properties.getProperty(prefix+"max_rel_offset")); if (properties.getProperty(prefix+"max_roll_deg")!=null) this.max_roll_deg=Double.parseDouble(properties.getProperty(prefix+"max_roll_deg")); if (properties.getProperty(prefix+"max_zoom_diff")!=null) this.max_zoom_diff=Double.parseDouble(properties.getProperty(prefix+"max_zoom_diff")); if (properties.getProperty(prefix+"fpn_skip")!=null) this.fpn_skip=Boolean.parseBoolean(properties.getProperty(prefix+"fpn_skip")); if (properties.getProperty(prefix+"fpn_rematch")!=null) this.fpn_rematch=Boolean.parseBoolean(properties.getProperty(prefix+"fpn_rematch")); Loading Loading @@ -2125,6 +2132,7 @@ public class IntersceneMatchParameters { imp.min_offset = this.min_offset; imp.max_rel_offset = this.max_rel_offset; imp.max_roll_deg = this.max_roll_deg; imp.max_zoom_diff = this.max_zoom_diff; imp.fpn_skip = this.fpn_skip; imp.fpn_rematch = this.fpn_rematch; Loading
src/main/java/com/elphel/imagej/tileprocessor/OpticalFlow.java +85 −21 Original line number Diff line number Diff line Loading @@ -86,13 +86,29 @@ public class OpticalFlow { public static int COMBO_DSN_INDX_DISP_BG_ALL =10; // cumulative BG disparity (Use FG where no BG is available) public static int COMBO_DSN_INDX_BLUE_SKY = 11; // Detected featureless infinity (sky) // interscene adjustments failure reasons. public static int FAIL_REASON_LMA = 1; // LMA failed public static int FAIL_REASON_INTERSCENE = 2; // clt_process_tl_interscene() returned null public static int FAIL_REASON_MIN = 3; // average pixel offset is below specified threshold (FPN) public static int FAIL_REASON_MAX = 4; // average pixel offset is above specified threshold (overlap) public static int FAIL_REASON_NULL = 5; // null offsets array public static int FAIL_REASON_EMPTY = 6; // No offset pairs in offsets array public static int FAIL_REASON_ROLL = 7; // Too high roll between the images public static final int FAIL_REASON_LMA = 1; // LMA failed public static final int FAIL_REASON_INTERSCENE = 2; // clt_process_tl_interscene() returned null public static final int FAIL_REASON_MIN = 3; // average pixel offset is below specified threshold (FPN) public static final int FAIL_REASON_MAX = 4; // average pixel offset is above specified threshold (overlap) public static final int FAIL_REASON_NULL = 5; // null offsets array public static final int FAIL_REASON_EMPTY = 6; // No offset pairs in offsets array public static final int FAIL_REASON_ROLL = 7; // Too high roll between the images public static final int FAIL_REASON_ZOOM = 8; // Too high zoom ratio between the images public static String getFailReason(int fr) { switch (fr) { case FAIL_REASON_LMA: return "FAIL_REASON_LMA"; case FAIL_REASON_INTERSCENE: return "FAIL_REASON_INTERSCENE"; case FAIL_REASON_MIN: return "FAIL_REASON_MIN"; case FAIL_REASON_MAX: return "FAIL_REASON_MAXv"; case FAIL_REASON_NULL: return "FAIL_REASON_NULL"; case FAIL_REASON_EMPTY: return "FAIL_REASON_EMPTY"; case FAIL_REASON_ROLL: return "FAIL_REASON_ROLL"; case FAIL_REASON_ZOOM: return "FAIL_REASON_ZOOM"; default: return "unknown scene-matching failure reason="+fr; } } public static double [] ZERO3 = {0.0,0.0,0.0}; public static double LINE_ERR = 0.1; Loading Loading @@ -4531,12 +4547,11 @@ public class OpticalFlow { double min_offset = 0.0; // clt_parameters.imp.min_offset; double max_offset = clt_parameters.imp.max_rel_offset * tilesX * tile_size; double max_roll = clt_parameters.imp.max_roll_deg*Math.PI/180.0; double max_zoom_diff = clt_parameters.imp.max_zoom_diff; boolean fpn_skip = clt_parameters.imp.fpn_skip; // if false - fail as before boolean fpn_rematch = clt_parameters.imp.fpn_rematch; // if false - keep previous double [] min_max = {min_offset, max_offset, 0.0} ; // {min, max, actual rms) int [] fail_reason = new int[1]; // null or int[1]: 0 - OK, 2 - LMA, 3 - min, 4 - max for (int scene_index = ref_index - 1; scene_index >= 0 ; scene_index--) { // to include ref scene photometric calibration quadCLTs[scene_index] = quadCLTs[ref_index].spawnNoModelQuadCLT( Loading Loading @@ -4573,6 +4588,17 @@ public class OpticalFlow { "reliable_ref"); } } double max_z_change = Double.NaN; // only applicable for drone images if (max_zoom_diff > 0) { // ignore if set to double avg_z = quadCLTs[ref_index].getAverageZ(true); // use lma max_z_change = avg_z * max_zoom_diff; if (debugLevel > -3) { System.out.println("Setting maximal Z-direction movement to "+ max_z_change+" m."); } } double [][][] scenes_xyzatr = new double [quadCLTs.length][][]; // previous scene relative to the next one scenes_xyzatr[ref_index] = new double[2][3]; // all zeros boolean after_spiral = false; Loading Loading @@ -4684,15 +4710,24 @@ public class OpticalFlow { clt_parameters.imp.debug_level); // 1); // -1); // int debug_level); boolean adjust_OK = scenes_xyzatr[scene_index] != null; if (adjust_OK && (Math.abs(scenes_xyzatr[scene_index][1][2]) > max_roll)) { if (adjust_OK) { // check only for initial orientation, do not check on readjustments if (Math.abs(scenes_xyzatr[scene_index][1][2]) > max_roll) { fail_reason[0] = FAIL_REASON_ROLL; adjust_OK = false; } if (max_zoom_diff > 0) { // ignore if set to if (Math.abs(scenes_xyzatr[scene_index][0][2]) > max_z_change) { fail_reason[0] = FAIL_REASON_ZOOM; adjust_OK = false; } } } // FAIL_REASON_ROLL handle_failure: { if (!adjust_OK) { // boolean OK = false; System.out.println("LMA failed at nscene = "+scene_index+". Reason = "+fail_reason[0]); System.out.println("LMA failed at nscene = "+scene_index+". Reason = "+fail_reason[0]+ " ("+getFailReason(fail_reason[0])+")"); if ((fail_reason[0]==FAIL_REASON_MIN) || ((fail_reason[0]==FAIL_REASON_LMA) && !got_spiral)) { if (fpn_skip) { System.out.println("fpn_skip is set, just using initial pose"); Loading @@ -4708,7 +4743,8 @@ public class OpticalFlow { if (debugLevel > -4) { System.out.println("Pass multi scene "+scene_index+" (of "+ quadCLTs.length+") "+ quadCLTs[ref_index].getImageName() + "/" + scene_QuadClt.getImageName()+ " FAILED. Setting earliest_scene to "+earliest_scene + " Failure reason: " + fail_reason[0]); " FAILED. Setting earliest_scene to "+earliest_scene + " Failure reason: " + fail_reason[0]+ " ("+getFailReason(fail_reason[0])+")"); } // set this and all previous to null for (; scene_index >= 0 ; scene_index--) { Loading Loading @@ -12841,7 +12877,7 @@ public class OpticalFlow { for (int i = 0; i < scene_disparity_strength[0].length; i++) { // scene_disparity_strength[0][i] = (scene_disparity_strength[0][i] - average_disparity) / average_absolute_disparity; scene_disparity_strength[0][i] = (scene_disparity_strength[0][i] - average_disparity) /magic_scale; scene_disparity_strength[0][i] = 1.0 / average_absolute_disparity; scene_disparity_strength[1][i] = 1.0 / average_absolute_disparity; } } } Loading Loading @@ -14144,6 +14180,7 @@ public class OpticalFlow { int debugLevel) { System.out.println("reAdjustPairsLMAInterscene(): using mb_max_gain="+mb_max_gain); boolean fail_on_zoom_roll=false; // it should fail on initial adjustment int avg_len = clt_parameters.imp.avg_len; // boolean test_motion_blur = true;//false // Set up velocities from known coordinates, use averaging Loading Loading @@ -14183,7 +14220,8 @@ public class OpticalFlow { int tile_size = quadCLTs[ref_index].getTileProcessor().getTileSize(); double min_offset = clt_parameters.imp.min_offset; double max_offset = second_margin*clt_parameters.imp.max_rel_offset * tilesX * tile_size; double max_roll = clt_parameters.imp.max_roll_deg*Math.PI/180.0; double max_roll = second_margin*clt_parameters.imp.max_roll_deg*Math.PI/180.0; double max_zoom_diff = second_margin*clt_parameters.imp.max_zoom_diff; boolean fpn_skip = clt_parameters.imp.fpn_skip; // if false - fail as before boolean fpn_rematch = clt_parameters.imp.fpn_rematch; // if false - keep previous double [] min_max = {min_offset, max_offset, 0.0} ; // {min, max, actual rms) Loading Loading @@ -14297,6 +14335,17 @@ public class OpticalFlow { } System.out.println(); } double max_z_change = Double.NaN; // only applicable for drone images if (max_zoom_diff > 0) { // ignore if set to double avg_z = quadCLTs[ref_index].getAverageZ(true); // use lma max_z_change = avg_z * max_zoom_diff; if (fail_on_zoom_roll) { if (debugLevel > -3) { System.out.println("Setting maximal Z-direction movement to "+ max_z_change+" m."); } } } boolean [] failed_scenes = new boolean[quadCLTs.length]; int num_failed =0; for (int nscene = ref_index; nscene >= earliest_scene; nscene--) { Loading Loading @@ -14517,15 +14566,29 @@ public class OpticalFlow { mb_vectors, // double [][] mb_vectors, // now [2][ntiles]; clt_parameters.imp.debug_level); // 1); // -1); // int debug_level); boolean adjust_OK = scenes_xyzatr[nscene] != null; if (adjust_OK && (Math.abs(scenes_xyzatr[nscene][1][2]) > max_roll)) { // if (adjust_OK && (Math.abs(scenes_xyzatr[nscene][1][2]) > max_roll)) { // fail_reason[0] = FAIL_REASON_ROLL; // adjust_OK = false; // } if (adjust_OK && fail_on_zoom_roll) { // check only for initial orientation, do not check on readjustments if (Math.abs(scenes_xyzatr[nscene][1][2]) > max_roll) { fail_reason[0] = FAIL_REASON_ROLL; adjust_OK = false; } if (max_zoom_diff > 0) { // ignore if set to if (Math.abs(scenes_xyzatr[nscene][0][2]) > max_z_change) { // NaN OK - will not fail fail_reason[0] = FAIL_REASON_ZOOM; adjust_OK = false; } } } // FAIL_REASON_ROLL handle_failure: { if (!adjust_OK) { boolean OK = false; System.out.println("LMA failed at nscene = "+nscene+". Reason = "+fail_reason[0]); System.out.println("LMA failed at nscene = "+nscene+". Reason = "+fail_reason[0]+ " ("+getFailReason(fail_reason[0])+")"); if ((fail_reason[0]==FAIL_REASON_MIN) || ((fail_reason[0]==FAIL_REASON_LMA))) { if (fpn_skip) { System.out.println("fpn_skip is set, just skipping this scene"); Loading @@ -14547,7 +14610,8 @@ public class OpticalFlow { if (debugLevel > -4) { System.out.println("reAdjustPairsLMAInterscene "+nscene+" (of "+ quadCLTs.length+") "+ quadCLTs[ref_index].getImageName() + "/" + ts+ " FAILED. Setting earliest_scene to "+earliest_scene + " Failure reason: " + fail_reason[0]); " FAILED. Setting earliest_scene to "+earliest_scene + " Failure reason: " + fail_reason[0]+ " ("+getFailReason(fail_reason[0])+")"); } // set this and all previous to null for (; nscene >= 0 ; nscene--) {
src/main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java +93 −0 Original line number Diff line number Diff line Loading @@ -203,6 +203,21 @@ public class QuadCLTCPU { } public double getAverageZ(boolean use_lma) { double [][] dls = getDLS(); if (dls==null) { return Double.NaN; } double [][] ds = new double [][] {dls[use_lma?1:0], dls[2]}; double sw=0, swd=0; for (int i = 0; i < ds[0].length; i++) if (!Double.isNaN(ds[0][i])){ sw += ds[1][i]; swd += ds[0][i] * ds[1][i]; } double disp_avg = swd/sw; double z_avg = getGeometryCorrection().getZFromDisparity(disp_avg); return z_avg; } public double [][] getDLS(){ // get disparity, disparity_lma, strength if (dsi == null) { Loading Loading @@ -2205,6 +2220,25 @@ public class QuadCLTCPU { return imp; } public ImagePlus saveDoubleArrayInModelDirectory( String suffix, double [] data, int width, int height) { double [][] data2= new double[][] {data}; String x3d_path = getX3dDirectory(); String file_name = image_name + suffix; String file_path = x3d_path + Prefs.getFileSeparator() + file_name + ".tiff"; ImageStack imageStack = ShowDoubleFloatArrays.makeStack(data2, width, height, null); ImagePlus imp = new ImagePlus( file_name, imageStack); FileSaver fs=new FileSaver(imp); fs.saveAsTiff(file_path); System.out.println("saveDoubleArrayInModelDirectory(): saved "+file_path); return imp; } public String saveImagePlusInModelDirectory( String suffix, // null - use title from the imp ImagePlus imp) Loading Loading @@ -15115,6 +15149,65 @@ public class QuadCLTCPU { return true; } public boolean writeLwirPreview( final CLTParameters clt_parameters, double [] data, QuadCLT scene, int tex_palette, String suffix, int debugLevel) { if (scene == null) { scene = (QuadCLT) this; } double [][] rendered_texture = new double[][] {data, new double[data.length]}; for (int i = 0; i < rendered_texture[0].length; i++) { rendered_texture[1][i] = Double.isNaN(rendered_texture[0][i])? 0.0: 1.0; } double [] minmax = scene.getColdHot(); // used in linearStackToColor (from this current scene) int width = getTileProcessor().getTilesX() *getTileProcessor().getTileSize(); int height = data.length/width; String set_name = getImageName(); if (set_name == null ) { QuadCLTCPU.SetChannels [] set_channels = setChannels(debugLevel); set_name = set_channels[0].set_name; } String model_dir= correctionsParameters.selectX3dDirectory( set_name, // quad timestamp. Will be ignored if correctionsParameters.use_x3d_subdirs is false null, true, // smart, true); //newAllowed, // save\ String title = getImageName()+suffix+"-preview"; ImagePlus imp = QuadCLTCPU.linearStackToColorLWIR( clt_parameters, // CLTParameters clt_parameters, tex_palette, // int lwir_palette, // <0 - do not convert minmax, // double [] minmax, title, // String name, "", // String suffix, // such as disparity=... true, // boolean toRGB, rendered_texture, // faded_textures[nslice], // double [][] texture_data, width, // int width, // int tilesX, height, // int height, // int tilesY, debugLevel); // int debugLevel ) String preview_path = model_dir + Prefs.getFileSeparator() + title+".jpeg"; if (new File(preview_path).exists() && !correctionsParameters.thumb_overwrite) { System.out.println("file "+preview_path+" exists, skipping preview generation"); return false; } if (debugLevel > -2) { System.out.println("Saving preview image to "+preview_path); } EyesisCorrections.saveAndShow( imp, model_dir, false, false, correctionsParameters.JPEG_quality, // jpegQuality); // jpegQuality){// <0 - keep current, 0 - force Tiff, >0 use for JPEG (debugLevel > -2) ? debugLevel : 1); // int debugLevel (print what it saves) return true; } public boolean writeRatingFile( // USED in lwir int debugLevel )