Commit 2c606e97 authored by Andrey Filippov's avatar Andrey Filippov

Cleanup, improving photometry equalization

parent 603fc517
......@@ -366,11 +366,16 @@ public class CLTParameters {
public double fom_inf_range = 0.8; // 0.5
// Photometric calibration (move elsewhere)?
public boolean photo_en = false; // perform photogrammetric calibration to equalize pixel values
public boolean photo_en = false; // perform photogrammetric calibration to equalize pixel values and update config
public boolean photo_each = true; // perform photogrammetric calibration for each series ref scene and config
public boolean photo_to_main = true; // propagate scene sequence photometrics to the main instance to be applied
// to the next sequence and saved with corr-xml configuration. It is always
// propagated when calibration is run manually with photo_en = true
public int photo_num_full = 3; // Number of full recalibrations with re-processing of the images
public int photo_num_refines = 3; // Calibrate, remove outliers, recalibrate, ...
public double photo_min_strength = 0.0; // maybe add to filter out weak tiles
public double photo_max_diff = 40.0; // To filter mismatches. Normal (adjusted) have RMSE ~9
public int photo_order = 2; // Approximation order: 0 - just offset, 1 - linear, 2 - quadratic
public boolean photo_debug = false; // Generate images and text
......@@ -1355,10 +1360,13 @@ public class CLTParameters {
properties.setProperty(prefix+"fom_inf_range", this.fom_inf_range+"");
properties.setProperty(prefix+"photo_en", this.photo_en+""); // boolean
properties.setProperty(prefix+"photo_each", this.photo_each+""); // boolean
properties.setProperty(prefix+"photo_to_main", this.photo_to_main+""); // boolean
properties.setProperty(prefix+"photo_num_full", this.photo_num_full+""); // int
properties.setProperty(prefix+"photo_num_refines", this.photo_num_refines+""); // int
properties.setProperty(prefix+"photo_min_strength", this.photo_min_strength+""); // double
properties.setProperty(prefix+"photo_max_diff", this.photo_max_diff+""); // double
properties.setProperty(prefix+"photo_order", this.photo_order+""); // int
properties.setProperty(prefix+"photo_debug", this.photo_debug+""); // boolean
properties.setProperty(prefix+"show_textures", this.show_textures+"");
......@@ -2219,10 +2227,13 @@ public class CLTParameters {
if (properties.getProperty(prefix+"fom_inf_range")!=null) this.fom_inf_range=Double.parseDouble(properties.getProperty(prefix+"fom_inf_range"));
if (properties.getProperty(prefix+"photo_en")!=null) this.photo_en=Boolean.parseBoolean(properties.getProperty(prefix+"photo_en"));
if (properties.getProperty(prefix+"photo_each")!=null) this.photo_each=Boolean.parseBoolean(properties.getProperty(prefix+"photo_each"));
if (properties.getProperty(prefix+"photo_to_main")!=null) this.photo_to_main=Boolean.parseBoolean(properties.getProperty(prefix+"photo_to_main"));
if (properties.getProperty(prefix+"photo_num_full")!=null) this.photo_num_full=Integer.parseInt(properties.getProperty(prefix+"photo_num_full"));
if (properties.getProperty(prefix+"photo_num_refines")!=null) this.photo_num_refines=Integer.parseInt(properties.getProperty(prefix+"photo_num_refines"));
if (properties.getProperty(prefix+"photo_min_strength")!=null) this.photo_min_strength=Double.parseDouble(properties.getProperty(prefix+"photo_min_strength"));
if (properties.getProperty(prefix+"photo_max_diff")!=null) this.photo_max_diff=Double.parseDouble(properties.getProperty(prefix+"photo_max_diff"));
if (properties.getProperty(prefix+"photo_order")!=null) this.photo_order=Integer.parseInt(properties.getProperty(prefix+"photo_order"));
if (properties.getProperty(prefix+"photo_debug")!=null) this.photo_debug=Boolean.parseBoolean(properties.getProperty(prefix+"photo_debug"));
if (properties.getProperty(prefix+"show_textures")!=null) this.show_textures=Boolean.parseBoolean(properties.getProperty(prefix+"show_textures"));
......@@ -3218,6 +3229,11 @@ public class CLTParameters {
gd.addMessage ("It is applied when the source files are read.");
gd.addCheckbox ("Enable photometric calibration", this.photo_en,
"Equalize per- sensor gains and offsets. Requires disparity map. Save to reference scene and with current scene (to .corr-zml).");
gd.addCheckbox ("Re-calibrate photometric for each series", this.photo_each,
"Equalize per- sensor gains and offsets for each reference scene. Requires disparity map. Save to reference scene and with current scene (to .corr-xml).");
gd.addCheckbox ("Propagate per-series to main", this.photo_to_main,
"Propagate scene sequence photometrics to the main instance to be applied to the next sequence and saved with corr-xml configuration."+
"\nIt is always propagated when calibration is run manually with photo_en = true.");
gd.addNumericField("Full photometric (re)calibrations", this.photo_num_full, 0,3,"",
"Full recalibratrions include re-importing raw images with updated offsets/gains");
gd.addNumericField("Refines", this.photo_num_refines, 0,3,"",
......@@ -3226,7 +3242,10 @@ public class CLTParameters {
"Do not use weak tiles.");
gd.addNumericField("Maximal channel mismatch", this.photo_max_diff, 5,7,"",
"Detect (and remove outliers). Adjusted images have RMSE ~9 counts.");
gd.addCheckbox ("Debug pphotometric calibration", this.photo_debug,
gd.addNumericField("Approximation polynomial order", this.photo_order, 0,3,"",
"0 - only offset, 1 - linear, 2 - quadratic");
gd.addCheckbox ("Debug photometric calibration", this.photo_debug,
"Generate debug images an text output.");
......@@ -4225,10 +4244,13 @@ public class CLTParameters {
this.fom_inf_range= gd.getNextNumber();
this.photo_en = gd.getNextBoolean();
this.photo_each = gd.getNextBoolean();
this.photo_to_main = gd.getNextBoolean();
this.photo_num_full = (int) gd.getNextNumber();
this.photo_num_refines = (int) gd.getNextNumber();
this.photo_min_strength = gd.getNextNumber();
this.photo_max_diff = gd.getNextNumber();
this.photo_order = (int) gd.getNextNumber();
this.photo_debug = gd.getNextBoolean();
this.show_textures= gd.getNextBoolean();
......
......@@ -502,6 +502,35 @@ public class ImagejJp4Tiff {
return pixels;
}
public static boolean needsFix000E6410C435(ImagePlus imp) {
String prefix = "STD_";
String serial = (String) imp.getProperty(prefix+"Serial_Number");
if ((serial == null) || !serial.equals(FIXCH6_SERIAL)) {
return false; // wrong camera
}
String schannel = ((String) imp.getProperty(prefix+"PageNumber")).substring(0,1);
if ((schannel == null) || (Integer.parseInt(schannel) != FIXCH6_CHANNEL)) {
return false; // wrong channel
}
String sfdate = (String) imp.getProperty(prefix+"DateTime");
sfdate = sfdate.replaceFirst(":", "-");
sfdate = sfdate.replaceFirst(":", "-")+".000";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
try {
Date startDate = dateFormat.parse(FIXCH6_EARLIEST);
Date endDate = dateFormat.parse(FIXCH6_LATEST);
Date fileDate = dateFormat.parse(sfdate);
if (fileDate.before(startDate) || fileDate.after(endDate)) {
return false; // too early or too late
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
// fixing "00:0E:64:10:C4:35" camera
public int fix000E6410C435(
Hashtable<String, Object> meta_hash,
......
......@@ -1060,6 +1060,9 @@ public class CLTPass3d{
}
public int setTileOpDisparity(
double [] disparity) {
if (disparity== null) {
disparity=new double[tileProcessor.getTilesX() * tileProcessor.getTilesY()]; // all defined, infinity
}
boolean [] selection = new boolean [disparity.length];
for (int i = 0; i < disparity.length; i++) {
selection[i] = !Double.isNaN(disparity[i]);
......
......@@ -4039,10 +4039,14 @@ public class OpticalFlow {
//boolean calibrate_photometric = true;
boolean photo_en = clt_parameters.photo_en; // false; // perform photogrammetric calibration to equalize pixel values
boolean photo_each = clt_parameters.photo_each; // true; // perform photogrammetric calibration to equalize pixel values
boolean photo_to_main= clt_parameters.photo_to_main; // maybe it will not be needed, it will apply this calibration to the next scene sequence
int photo_num_full = clt_parameters.photo_num_full; // 1; // Number of full recalibrations with re-processing of the images
int photo_num_refines = clt_parameters.photo_num_refines; // 3; // Calibrate, remove outliers, recalibrate, ...
double photo_min_strength = clt_parameters.photo_min_strength; // 0.0; // maybe add to filter out weak tiles
double photo_max_diff = clt_parameters.photo_max_diff; // 40.0; // To filter mismatches. Normal (adjusted) have RMSE ~9
int photo_order = clt_parameters.photo_order;
boolean photo_debug = clt_parameters.photo_debug; // false; // Generate images and text
boolean show_dsi_image = clt_parameters.imp.show_ranges && !batch_mode;
......@@ -4202,7 +4206,9 @@ public class OpticalFlow {
build_ref_dsi = true;
}
}
if (!build_ref_dsi && (quadCLTs[ref_index] != null)) {
quadCLTs[ref_index].restoreInterProperties(null, false, debugLevel); //null
}
// 1. Reference scene DSI
while ((quadCLTs[ref_index] == null) || (quadCLTs[ref_index].getBlueSky() == null)) { // null
if (build_ref_dsi) {
......@@ -4265,6 +4271,147 @@ public class OpticalFlow {
} else {
dsi[TwoQuadCLT.DSI_STRENGTH_AUX] = aux_last_scan[1];
}
// perform photometric here, after first DSI
if (photo_each && !quadCLTs[ref_index].isPhotometricThis()) {
if (debugLevel > -3) {
System.out.println("**** Running photometric equalization for "+quadCLTs[ref_index].getImageName()+
", current was from scene "+quadCLTs[ref_index].getPhotometricScene()+" ****");
}
// preparing same format as after combo, filling in only needed data
double [][] ds_photo = new double[TwoQuadCLT.DSI_LENGTH][];
ds_photo[OpticalFlow.COMBO_DSN_INDX_DISP] = dsi[TwoQuadCLT.DSI_DISPARITY_AUX_LMA];
ds_photo[OpticalFlow.COMBO_DSN_INDX_DISP_BG_ALL] = dsi[TwoQuadCLT.DSI_DISPARITY_AUX_LMA];
ds_photo[OpticalFlow.COMBO_DSN_INDX_STRENGTH] = dsi[TwoQuadCLT.DSI_STRENGTH_AUX];
boolean photo_each_debug = false; // true; // false;
boolean photo_each_debug2 = false; // true; // false;
for (int nrecalib = 0; nrecalib < photo_num_full; nrecalib++) { // maybe need to correct just offsets?
int poly_order = photo_order;
if ((poly_order > 1) && (nrecalib == 0)) {
poly_order = 1;
}
QuadCLT.calibratePhotometric2(
clt_parameters, // CLTParameters clt_parameters,
quadCLTs[ref_index], // final QuadCLT ref_scene, will set photometric calibration to this scene
photo_min_strength, // final double min_strength,
photo_max_diff, // final double max_diff, // 30.0
poly_order, // final int photo_order, // 0 - offset only, 1 - linear, 2 - quadratic
photo_num_refines, // final int num_refines, // 2
ds_photo, // combo_dsn_final_filtered, // final double [][] combo_dsn_final, // double [][] combo_dsn_final, // dls,
threadsMax, // int threadsMax,
photo_each_debug); //final boolean debug)
// copy offsets to the current to be saved with other properties. Is it correct/needed?
quadCLTs[ref_index].saveInterProperties( // save properties for interscene processing (extrinsics, ers, ...)
null, // String path, // full name with extension or w/o path to use x3d directory
debugLevel+1);
quadCLTs[ref_index].setDSI(dsi); // try to avoid saving, will complain on restoring, but keep
// quadCLTs[ref_index].saveDSIAll ( // will reload during spawnQuadCLT
// "-DSI_MAIN", // String suffix, // "-DSI_MAIN"
// dsi);
// quadCLT_main.setLwirOffsets(quadCLTs[ref_index].getLwirOffsets());
// quadCLT_main.setLwirScales (quadCLTs[ref_index].getLwirScales ());
// quadCLT_main.setLwirScales2(quadCLTs[ref_index].getLwirScales2());
// quadCLT_main.setPhotometricScene(quadCLTs[ref_index].getPhotometricScene());
// Re-read reference and other scenes using new offsets
// quadCLTs[ref_index].saveQuadClt(); // to re-load new set of Bayer images to the GPU (do nothing for CPU) and Geometry
quadCLTs[ref_index].setQuadClt(); // should work even when the data is new for the same scene
quadCLTs[ref_index] = (QuadCLT) quadCLT_main.spawnQuadCLT( // restores dsi from "DSI-MAIN"
set_channels[ref_index].set_name,
clt_parameters,
colorProcParameters, //
threadsMax,
debugLevel);
// Re-measure and update (is it needed?)
CLTPass3d scan = new CLTPass3d(quadCLTs[ref_index].tp);
scan.setTileOpDisparity(dsi[TwoQuadCLT.DSI_DISPARITY_AUX]);
quadCLTs[ref_index].setQuadClt(); // just in case ?
quadCLTs[ref_index].CLTMeas( // perform single pass according to prepared tiles operations and disparity
clt_parameters, // EyesisCorrectionParameters.CLTParameters clt_parameters,
scan, // final CLTPass3d scan,
false, // final boolean save_textures,
false, // final boolean need_diffs, // calculate diffs even if textures are not needed
0, // final int clust_radius,
true, // final boolean save_corr,
true, // false, // final boolean run_lma, // = true;
0.0, // final double max_chn_diff, // filter correlation results by maximum difference between channels
-1.0, // final double mismatch_override, // keep tile with large mismatch if there is LMA with really strong correlation
threadsMax, // final int threadsMax, // maximal number of threads to launch
updateStatus, // final boolean updateStatus,
debugLevel-2); // final int debugLevel);
double [][] aux_new_scan = TileProcessor.getDSLMA(
scan,
false); // boolean force_final);
dsi[TwoQuadCLT.DSI_DISPARITY_AUX] = aux_new_scan[0]; // compare diffs
dsi[TwoQuadCLT.DSI_STRENGTH_AUX] = aux_new_scan[1];
dsi[TwoQuadCLT.DSI_DISPARITY_AUX_LMA] = aux_new_scan[2];
// Re-measure and update from BG spread and average in dsi
CLTPass3d bgscan = new CLTPass3d(quadCLTs[ref_index].tp);
bgscan.setTileOpDisparity(null);
quadCLTs[ref_index].setQuadClt(); // just in case ?
quadCLTs[ref_index].CLTMeas( // perform single pass according to prepared tiles operations and disparity
clt_parameters, // EyesisCorrectionParameters.CLTParameters clt_parameters,
bgscan, // final CLTPass3d scan,
true, // false, // final boolean save_textures,
true, // false, // final boolean need_diffs, // calculate diffs even if textures are not needed
0, // final int clust_radius,
true, // final boolean save_corr, IS IT NEEDED?
false, // final boolean run_lma, // = true;
0.0, // final double max_chn_diff, // filter correlation results by maximum difference between channels
-1.0, // final double mismatch_override, // keep tile with large mismatch if there is LMA with really strong correlation
threadsMax, // final int threadsMax, // maximal number of threads to launch
updateStatus, // final boolean updateStatus,
debugLevel-2); // final int debugLevel);
if (photo_each_debug2) {
quadCLTs[ref_index].tp.showScan(bgscan, quadCLTs[ref_index].getImageName()+"-bgscan-"+nrecalib); // nrecalib
quadCLTs[ref_index].tp.showScan(scan, quadCLTs[ref_index].getImageName()+"-scan-"+nrecalib);
}
dsi[TwoQuadCLT.DSI_SPREAD_AUX] = bgscan.getSecondMax(); // //aux_bg_scan[3];
dsi[TwoQuadCLT.DSI_AVGVAL_AUX] = bgscan.getAvgVal(); //aux_bg_scan[4];
quadCLTs[ref_index].setDSI(dsi); // Restore known dsi
quadCLTs[ref_index].setBlueSky(ref_blue_sky);
quadCLTs[ref_index].setDSRBG(
clt_parameters, // CLTParameters clt_parameters,
threadsMax, // int threadsMax, // maximal number of threads to launch
updateStatus, // boolean updateStatus,
debugLevel); // int debugLevel)
// ers_reference = quadCLTs[ref_index].getErsCorrection();
}
/*
// propagate to other scenes in this sequence HERE THEY ARE NOT YET READ
for (int scene_index = ref_index - 1; scene_index >= earliest_scene ; scene_index--) {
// quadCLTs[scene_index] = (QuadCLT) quadCLT_main.spawnNoModelQuadCLT( // restores image data
// to include ref scene photometric calibration
quadCLTs[scene_index] = quadCLTs[ref_index].spawnNoModelQuadCLT( // restores image data
set_channels[scene_index].set_name,
clt_parameters,
colorProcParameters, //
threadsMax,
debugLevel-2);
}
*/
} else {
System.out.println("(Re)using photometric calibration from this sequence reference "+quadCLTs[ref_index].getPhotometricScene());
quadCLTs[ref_index].setQuadClt(); // just in case ?
}
// int tilesX = quadCLTs[ref_index].getTileProcessor().getTilesX();
boolean retry=false;
while (true) {
......@@ -4321,6 +4468,23 @@ public class OpticalFlow {
quadCLTs[ref_index].set_accum(0); // reset accumulations ("build_interscene") number
earliest_scene = 0; // reset failures, try to use again all scenes
} else {// if (build_ref_dsi) {
// need to read photometric from reference scene -INTERFRAME.corr-xml, and if it exists - set and propagate to main?
if (photo_each && !quadCLTs[ref_index].isPhotometricThis()) {
if (debugLevel > -3) {
System.out.println("Per-sequence photogrammetric calibration is required, but it does not exist");
}
if (photo_to_main) {
quadCLT_main.setLwirOffsets(quadCLTs[ref_index].getLwirOffsets());
quadCLT_main.setLwirScales (quadCLTs[ref_index].getLwirScales ());
quadCLT_main.setLwirScales2(quadCLTs[ref_index].getLwirScales2());
quadCLT_main.setPhotometricScene(quadCLTs[ref_index].getPhotometricScene());
if (debugLevel > -3) {
System.out.println("Propagating per-sequence photogrammetric calibration to main instance, will apply to next sequence and config file");
}
}
} else {
System.out.println("Without building reference DSI: (re)using photometric calibration from this sequence reference "+quadCLTs[ref_index].getPhotometricScene());
}
// read DSI_MAIN
double [][] dsi = quadCLTs[ref_index].readDsiMain();
if (dsi[TwoQuadCLT.DSI_SPREAD_AUX] == null) {
......@@ -4362,6 +4526,7 @@ public class OpticalFlow {
colorProcParameters, //
threadsMax,
debugLevel);
quadCLTs[ref_index].setQuadClt(); // just in case ?
quadCLTs[ref_index].setBlueSky(ref_blue_sky);
quadCLTs[ref_index].setDSRBG(
......@@ -4387,7 +4552,9 @@ public class OpticalFlow {
double [] lma_rms = new double[2];
double [] use_atr = null;
for (int scene_index = ref_index - 1; scene_index >= 0 ; scene_index--) {
quadCLTs[scene_index] = (QuadCLT) quadCLT_main.spawnNoModelQuadCLT(
// quadCLTs[scene_index] = (QuadCLT) quadCLT_main.spawnNoModelQuadCLT(
// to include ref scene photometric calibration
quadCLTs[scene_index] = quadCLTs[ref_index].spawnNoModelQuadCLT(
set_channels[scene_index].set_name,
clt_parameters,
colorProcParameters, //
......@@ -4649,11 +4816,16 @@ public class OpticalFlow {
quadCLTs[ref_index], // QuadCLT scene,
debugLevel); // int debugLevel);// > 0
for (int nrecalib = 0; nrecalib < photo_num_full; nrecalib++) {
int poly_order = photo_order;
if ((poly_order > 1) && (nrecalib == 0)) {
poly_order = 1;
}
QuadCLT.calibratePhotometric2(
clt_parameters, // CLTParameters clt_parameters,
quadCLTs[ref_index], // final QuadCLT ref_scene, // now - may be null - for testing if scene is rotated ref
quadCLTs[ref_index], // final QuadCLT ref_scene, will set photometric calibration to this scene
photo_min_strength, // final double min_strength,
photo_max_diff, // final double max_diff, // 30.0
poly_order, // final int photo_order, // 0 - offset only, 1 - linear, 2 - quadratic
photo_num_refines, // final int num_refines, // 2
combo_dsn_final_filtered, // final double [][] combo_dsn_final, // double [][] combo_dsn_final, // dls,
threadsMax, // int threadsMax,
......@@ -4662,13 +4834,13 @@ public class OpticalFlow {
quadCLTs[ref_index].saveInterProperties( // save properties for interscene processing (extrinsics, ers, ...)
null, // String path, // full name with extension or w/o path to use x3d directory
debugLevel+1);
quadCLT_main.setLwirOffsets(quadCLTs[ref_index].getLwirOffsets());
quadCLT_main.setLwirScales (quadCLTs[ref_index].getLwirScales ());
quadCLT_main.setLwirScales2(quadCLTs[ref_index].getLwirScales2());
quadCLT_main.setPhotometricScene(quadCLTs[ref_index].getPhotometricScene());
// quadCLT_main.setLwirOffsets(quadCLTs[ref_index].getLwirOffsets());
// quadCLT_main.setLwirScales (quadCLTs[ref_index].getLwirScales ());
// quadCLT_main.setLwirScales2(quadCLTs[ref_index].getLwirScales2());
// quadCLT_main.setPhotometricScene(quadCLTs[ref_index].getPhotometricScene());
// Re-read reference and other scenes using new offsets
quadCLTs[ref_index].saveQuadClt(); // to re-load new set of Bayer images to the GPU (do nothing for CPU) and Geometry
quadCLTs[ref_index].setQuadClt(); // to re-load new set of Bayer images to the GPU (do nothing for CPU) and Geometry
quadCLTs[ref_index] = (QuadCLT) quadCLT_main.spawnQuadCLT( // restores dsi from "DSI-MAIN"
set_channels[ref_index].set_name,
clt_parameters,
......@@ -4695,12 +4867,24 @@ public class OpticalFlow {
debugLevel-2);
}
} else {
if (debugLevel> -3) {
System.out.println("Using photometric calibration from scene "+quadCLTs[ref_index].getPhotometricScene());
}
}
// only now copy photometric to main instance
if (!reuse_video) {
quadCLT_main.setLwirOffsets(quadCLTs[ref_index].getLwirOffsets());
quadCLT_main.setLwirScales (quadCLTs[ref_index].getLwirScales ());
quadCLT_main.setLwirScales2(quadCLTs[ref_index].getLwirScales2());
quadCLT_main.setPhotometricScene(quadCLTs[ref_index].getPhotometricScene());
if (debugLevel> -3) {
System.out.println("Applied photometric calibration from scene "+quadCLTs[ref_index].getPhotometricScene()+
" to quadCLT_main, so it will be applied to the next sequences and saved in config file");
}
}
if (test_ers) { // only debug feature
test_ers0 = quadCLTs.length -1; // make it always == reference !
testERS(
clt_parameters, // CLTParameters clt_parameters,
test_ers0, // int indx0, // reference scene in a pair
......@@ -4708,7 +4892,6 @@ public class OpticalFlow {
// double [] ref_disparity,
quadCLTs, // QuadCLT [] quadCLTs,
debugLevel); // int debugLevel)
System.out.println("buildSeries(): ABORTED after test_ers"); //
return quadCLTs[ref_index].getX3dTopDirectory();
}
......
......@@ -2435,7 +2435,7 @@ public class QuadCLT extends QuadCLTCPU {
scales_new[n] = scales_old[n]/scales[n];
offsets_new[n] = offsets_old[n] + offsets[n] / scales_old[n];
}
System.out.println("calibratePhotometric() Updated calibration:");
System.out.println("calibratePhotometric() Final calibration:");
for (int n = 0; n < num_sens; n++) {
System.out.println(String.format("%2d: %8.4f %8.6f %8.6f", n,offsets_new[n],scales_new[n], scales2_new[n]));
}
......@@ -2452,6 +2452,7 @@ public class QuadCLT extends QuadCLTCPU {
final QuadCLT ref_scene, // now - may be null - for testing if scene is rotated ref
final double min_strength,
final double max_diff, // 30.0
final int photo_order, // 0 - offset only, 1 - linear, 2 - quadratic
final int num_refines, // 2
final double [][] combo_dsn_final, // double [][] combo_dsn_final, // dls,
int threadsMax,
......@@ -2484,7 +2485,9 @@ public class QuadCLT extends QuadCLTCPU {
"PHOTOMETRIC", // String suffix,
threadsMax, // int threadsMax,
-2); // final int debugLevel);
if (debug) {
img_ref.show();
}
ImageStack imageStack = img_ref.getStack();
int num_sens=imageStack.getSize();
float [] fpixels;
......@@ -2496,23 +2499,11 @@ public class QuadCLT extends QuadCLTCPU {
dpixels[n][i] = fpixels[i];
}
}
boolean quadratic = true;
// double [][] dpix_orig = new double[num_sens][];
// for (int n = 0; n < num_sens; n++) {
// dpix_orig[n] = dpixels[n].clone();
// }
// boolean quadratic = true;
int width = img_ref.getWidth();
int height = img_ref.getHeight();
int len = width* height;
double [] avg_pix = new double [len];
double [] offsets = new double[dpixels.length];
double [] scales = new double[dpixels.length];
double [] scales2 = new double[dpixels.length];
double s0 = 0.0;
double sx= 0.0;
double sx2 = 0.0;
double [] sy = new double[num_sens];
double [] sxy = new double[num_sens];
boolean [] good_pix = new boolean[len];
double [][] pa_coeff = new double[num_sens][];
double min_abs_a = 1E-9;
......@@ -2539,7 +2530,7 @@ public class QuadCLT extends QuadCLTCPU {
num_good++;
}
}
double [][] pa_data = new double [num_good][2];
double [][][] pa_data = new double [num_sens][num_good][2];
double [][] raw = new double [num_sens][len];
for (int nsens = 0; nsens < num_sens; nsens++) {
Arrays.fill(raw[nsens],Double.NaN); // debug only
......@@ -2557,15 +2548,28 @@ public class QuadCLT extends QuadCLTCPU {
p= (-b + Math.sqrt(b*b - 4 * a * c))/(2 * a);
}
raw[nsens][i] = p;
pa_data[indx][0] = p; // dpixels[nsens][i];
pa_data[indx][1] = avg_pix[i];
pa_data[nsens][indx][0] = p; // dpixels[nsens][i];
pa_data[nsens][indx][1] = avg_pix[i];
indx++;
}
// quadratic
pa_coeff[nsens] =(new PolynomialApproximation(0)).polynomialApproximation1d(pa_data, quadratic ? 2 : 1);
double a = pa_coeff[nsens][2];
double b = pa_coeff[nsens][1];
double c = pa_coeff[nsens][0];
double c, b, a;
int poly_debug = 0;
if (photo_order < 1) { // zero out scales2, keep old scales (even if not normalized)
a = 0;
b = scales_old[nsens];
double s = 0.0;
for (int i = 0; i < num_good; i++) {
s += pa_data[nsens][i][0] - pa_data[nsens][i][1]/b;
}
c = -s/num_good*b;
} else {
// need to balance quadratic so their average is 0
// linear or quadratic
pa_coeff[nsens] =(new PolynomialApproximation(poly_debug)).polynomialApproximation1d(pa_data[nsens], photo_order);
c = pa_coeff[nsens][0];
b = pa_coeff[nsens][1];
a = (pa_coeff[nsens].length > 2) ? pa_coeff[nsens][2] : 0.0;
}
double A = a;
double C = -c/b;
if (Math.abs(a) >= min_abs_a) {
......@@ -2576,17 +2580,48 @@ public class QuadCLT extends QuadCLTCPU {
scales_new [nsens] = B;
offs_new[nsens] = C;
}
if (debug) {
System.out.println("calibratePhotometric() nref="+nref);
/*
System.out.println(String.format("%3s %8s %8s %8s",
"chn"," c "," b ", " 1e6*a "));
for (int n = 0; n < num_sens; n++) {
System.out.println(String.format("%2d: %8.4f %8.6f %8.6f", n,pa_coeff[n][0],pa_coeff[n][1], 1e6*pa_coeff[n][2]));
// Make scales_new to be (geometric) average 1.0 (except photo_order == 0), update pa_data to match
if (photo_order > 0) {
double scales_avg = 1.0;
for (int nsens = 0; nsens < num_sens; nsens++) {
scales_avg *= scales_new [nsens];
}
System.out.println();
*/
scales_avg = Math.pow(scales_avg, 1.0/num_sens);
for (int nsens = 0; nsens < num_sens; nsens++) {
scales_new [nsens] /= scales_avg;
scales2_new [nsens] /= scales_avg;
for (int i = 0; i < num_good; i++) {
pa_data[nsens][i][1] /= scales_avg;
}
}
}
// make scales2 be average zero, re-run scales
if (photo_order > 1) {
double scales2_offset = 0;
for (int nsens = 0; nsens < num_sens; nsens++) {
scales2_offset += scales2_new[nsens];
}
scales2_offset /= num_sens;
for (int nsens = 0; nsens < num_sens; nsens++) {
scales2_new[nsens] -= scales2_offset;
}
// modify pa_data, re-run linear
for (int nsens = 0; nsens < num_sens; nsens++) {
for (int i = 0; i < num_good; i++) {
double poffs = pa_data[nsens][i][0] - offs_new[nsens];
pa_data[nsens][i][1] -=poffs*poffs*scales2_new[nsens];
}
pa_coeff[nsens] =(new PolynomialApproximation(0)).polynomialApproximation1d(
pa_data[nsens], 1);
double c = pa_coeff[nsens][0];
double b = pa_coeff[nsens][1];
scales_new [nsens] = b;
offs_new[nsens] = -c/b;
}
}
if (true) { // debug) { during debug,
System.out.println("DEBUG: calibratePhotometric() nref="+nref);
System.out.println(String.format("%3s %10s %8s %8s %10s %8s %8s",
// "chn"," c "," b ", " 1e6*a "));
"chn"," offs0 ","scale0 ", "scale20"," offs "," scale ", " scale2"));
......@@ -2596,9 +2631,8 @@ public class QuadCLT extends QuadCLTCPU {
offs_new[n],scales_new[n], 1e6*scales2_new[n]));
}
System.out.println();
}
if (debug) {
double [][] diffs = new double [num_sens][len];
for (int n = 0; n < num_sens; n++) {
Arrays.fill(diffs[n], Double.NaN);
......@@ -2746,10 +2780,12 @@ public class QuadCLT extends QuadCLTCPU {
dbg_img[i][nTile] = pXpYD[nTile][i];
}
}
if (mb_vectors!=null) {
for (int i = 0; i <2; i++) {
dbg_img[3 + i][nTile] = mb_tau * mb_vectors[i][nTile];
}
}
}
(new ShowDoubleFloatArrays()).showArrays( // out of boundary 15
dbg_img,
dbg_width,
......
......@@ -1253,10 +1253,11 @@ public class QuadCLTCPU {
if (!isLwir()) { // colorProcParameters.lwir_islwir) {
referenceExposures = eyesisCorrections.calcReferenceExposures(sourceFiles, debugLevel);
}
// move after restoring properties
/*
int [] channelFiles = set_channels[0].fileNumber();
boolean [][] saturation_imp = (clt_parameters.sat_level > 0.0)? new boolean[channelFiles.length][] : null;
double [] scaleExposures = new double[channelFiles.length];
// ImagePlus [] imp_srcs =
conditionImageSet(
clt_parameters, // EyesisCorrectionParameters.CLTParameters clt_parameters,
colorProcParameters, // ColorProcParameters colorProcParameters, //
......@@ -1277,6 +1278,7 @@ public class QuadCLTCPU {
threadsMax,
1); // debugLevel); // final int debug_level)
}
*/
// try to restore DSI generated from interscene if available, if not use single-scene -DSI_MAIN
int dsi_result = -1;
int max_length=OpticalFlow.COMBO_DSN_TITLES.length;
......@@ -1302,11 +1304,35 @@ public class QuadCLTCPU {
if (dsi_result < 0) {
System.out.println("No DSI data for the scene "+this.getImageName()+", setting this.dsi=null");
setDSI(null);
} else {
}
// WAS: resore only if (dsi_result < 0)... else
restoreInterProperties( // restore properties for interscene processing (extrinsics, ers, ...) // get relative poses (98)
null, // String path, // full name with extension or null to use x3d directory
false, // boolean all_properties,// null, // Properties properties, // if null - will only save extrinsics)
debugLevel);
int [] channelFiles = set_channels[0].fileNumber();
boolean [][] saturation_imp = (clt_parameters.sat_level > 0.0)? new boolean[channelFiles.length][] : null;
double [] scaleExposures = new double[channelFiles.length];
conditionImageSet(
clt_parameters, // EyesisCorrectionParameters.CLTParameters clt_parameters,
colorProcParameters, // ColorProcParameters colorProcParameters, //
sourceFiles, // String [] sourceFiles,
this.image_name, // String set_name,
referenceExposures, // double [] referenceExposures,
channelFiles, // int [] channelFiles,
scaleExposures, // output // double [] scaleExposures
saturation_imp, // output // boolean [][] saturation_imp,
threadsMax, // int threadsMax,
debugLevelInner); // int debugLevel);
if (noise_sigma_level != null) {
generateAddNoise(
"-NOISE",
ref_scene, // final QuadCLTCPU ref_scene, // may be null if scale_fpn <= 0
noise_sigma_level,
noise_variant, //final int noise_variant, // <0 - no-variants, compatible with old code
threadsMax,
1); // debugLevel); // final int debug_level)
}
return this; // can only be QuadCLT instance
}
......@@ -1933,6 +1959,14 @@ public class QuadCLTCPU {
setPhotometricScene(getImageName());
}
public boolean isPhotometricThis() {
if (this.photometric_scene == null) {
return false;
}
return this.photometric_scene.equals(getImageName());
}
public void setLwirScales(double [] scales) {
lwir_scales = scales; // will need to update properties!
// this.photometric_scene = getImageName();
......@@ -2253,7 +2287,7 @@ public class QuadCLTCPU {
for (int d = 0; d < fine_corr[n].length; d++){
for (int i = 0; i < fine_corr[n][d].length; i++){
String name = prefix+"fine_corr_"+n+fine_corr_dir_names[d]+fine_corr_coeff_names[i];
if (properties.getProperty(name)!=null) this.fine_corr[n][d][i]=Double.parseDouble(properties.getProperty(name));
if (properties.getProperty(name)!=null) this.fine_corr[n][d][i]=Double.parseDouble(properties.getProperty(name));// null
}
}
}
......@@ -5728,6 +5762,37 @@ public class QuadCLTCPU {
double [] offsets = getLwirOffsets();
double [] scales = getLwirScales();
double [] scales2 = getLwirScales2();
int needs_fix = -1;
for (int i = 0; i < imp_srcs.length; i++) {
if (ImagejJp4Tiff.needsFix000E6410C435(imp_srcs[i])) {
needs_fix = i;
break; // only one, and always 6
}
}
if (needs_fix >= 0) {
double [] fix_offsets = channelLwirEqualize( // now only calculates offsets, does not apply
channelFiles,
imp_srcs,
lwir_subtract_dc, // boolean remove_dc,
set_name, // just for debug messages == setNames.get(nSet)
threadsMax,
debugLevel);
double avg_offs = 0.0;
for (int i = 0; i < fix_offsets.length; i++) if (i != needs_fix) {
avg_offs += fix_offsets[i];
}
avg_offs /= (fix_offsets.length - 1);
int icorr = (int) Math.round((avg_offs - fix_offsets[needs_fix])/4096);
if (icorr != 0) {
float fcorr = icorr*4096;
System.out.println("Correcting "+imp_srcs[needs_fix].getTitle()+" by "+fcorr);
float [] pixels = (float []) imp_srcs[needs_fix].getProcessor().getPixels();
for (int i = 0; i < pixels.length; i++) {
pixels[i] += fcorr;
}
}
}
channelLwirApplyEqualize( // now apply (was part of channelLwirEqualize() )
channelFiles, // int [] channelFiles,
imp_srcs, // ImagePlus [] imp_srcs,
......@@ -6295,16 +6360,10 @@ public class QuadCLTCPU {
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
// for (int srcChannel=0; srcChannel < channelFiles.length; srcChannel++){
for (int srcChannel = ai.getAndIncrement(); srcChannel < channelFiles.length; srcChannel = ai.getAndIncrement()) {
int nFile=channelFiles[srcChannel];
if (nFile >=0) {
offsets[srcChannel]= avr_pix[srcChannel][0];
// float fd = (float)offsets[srcChannel];
// float [] pixels = (float []) imp_srcs[srcChannel].getProcessor().getPixels();
// for (int i = 0; i < pixels.length; i++) {
// pixels[i] -= fd;
// }
}
}
}
......
......@@ -84,6 +84,7 @@ public class TwoQuadCLT {
public static int DSI_SPREAD_AUX = 10;
public static int DSI_AVGVAL_MAIN = 11;
public static int DSI_AVGVAL_AUX = 12;
public static int DSI_LENGTH = DSI_AVGVAL_AUX+1;
public static String DSI_COMBO_SUFFIX = "-DSI_COMBO";
public static String DSI_MAIN_SUFFIX = "-DSI_MAIN";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment