Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
imagej-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
3
Issues
3
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Elphel
imagej-elphel
Commits
cfbcc5e2
Commit
cfbcc5e2
authored
Dec 24, 2025
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Per-scene reliable_ref filtering to mitigate "folding" using
reliable_scene masks.
parent
f7241809
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
703 additions
and
38 deletions
+703
-38
ErsCorrection.java
...n/java/com/elphel/imagej/tileprocessor/ErsCorrection.java
+2
-0
Interscene.java
...main/java/com/elphel/imagej/tileprocessor/Interscene.java
+602
-33
IntersceneMatchParameters.java
...lphel/imagej/tileprocessor/IntersceneMatchParameters.java
+9
-1
OpticalFlow.java
...ain/java/com/elphel/imagej/tileprocessor/OpticalFlow.java
+2
-0
QuadCLTCPU.java
...main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java
+88
-4
No files found.
src/main/java/com/elphel/imagej/tileprocessor/ErsCorrection.java
View file @
cfbcc5e2
...
...
@@ -1929,6 +1929,8 @@ public class ErsCorrection extends GeometryCorrection {
public
static
double
[][]
combineXYZATR
(
double
[][]
reference_xyzatr
,
double
[][]
scene_xyzatr
){
if
(
reference_xyzatr
==
null
)
return
scene_xyzatr
;
if
(
scene_xyzatr
==
null
)
return
reference_xyzatr
;
return
combineXYZATR
(
reference_xyzatr
[
0
],
reference_xyzatr
[
1
],
...
...
src/main/java/com/elphel/imagej/tileprocessor/Interscene.java
View file @
cfbcc5e2
...
...
@@ -420,11 +420,14 @@ public class Interscene {
cent_index
+
", last_index="
+
". readjust="
+
readjust
+
"\n"
);
}
boolean
ims_orient
=
clt_parameters
.
imp
.
air_mode_en
;
// true; // set for the airplane mode for now to keep old functionality?
int
n_unresolved
=
invertInitialOrientation
(
clt_parameters
,
// final CLTParameters clt_parameters,
batch_mode
,
// final boolean batch_mode,
compensate_ims_rotation
,
// final boolean compensate_ims_rotation,
inertial_only
,
// final boolean inertial_only,
readjust
,
// final boolean readjust,
ims_orient
,
// final boolean ims_orient, // recalculate and use IMS orientations with quat_corr
false
,
// final int set_self, // set record for the new reference to new reference
quadCLTs
,
// final QuadCLT[] quadCLTs, //
ref_index
,
// final int last_index, // last to process (normally old reference)
...
...
@@ -454,7 +457,7 @@ public class Interscene {
}
if
(
n_unresolved
!=
0
)
{
earliest_scene2
=
-
1
;
System
.
out
.
println
(
"
invertInitialOrientation
(). Consider more graceful bail out."
);
System
.
out
.
println
(
"
setInitialOrientationsCenterIms
(). Consider more graceful bail out."
);
start_ref_pointers
[
0
]
=
start_ref_pointers1
[
0
];
return
earliest_scene2
;
// cent_index;
}
...
...
@@ -465,6 +468,9 @@ public class Interscene {
quadCLTs
[
ref_index
].
setRefPointer
(
cent_ts
);
// write pointer to center scene to reference scene
quadCLTs
[
cent_index
].
setFirstLastPointers
(
quadCLTs
[
earliest_scene2
],
quadCLTs
[
ref_index
]);
// set first/last to center scene
// set quadCLTs[ref_index].set_orient(0); // ? as it has only half?
if
(
debugLevel
>
-
3
)
{
System
.
out
.
println
(
"setInitialOrientationsCenterIms(): saving properies of the old ref (now last) to provide a reference to a new reference."
);
}
quadCLTs
[
ref_index
].
saveInterProperties
(
// save properties for interscene processing (extrinsics, ers, ...) // null pointer
null
,
// String path, // full name with extension or w/o path to use x3d directory
...
...
@@ -473,6 +479,9 @@ public class Interscene {
quadCLTs
[
cent_index
].
set_orient
(
1
);
// first orientation
quadCLTs
[
cent_index
].
set_accum
(
0
);
// reset accumulations ("build_interscene") number
if
(
debugLevel
>
-
3
)
{
System
.
out
.
println
(
"setInitialOrientationsCenterIms(): saving properies of the new reference scene with data for both earlier and later scenes."
);
}
quadCLTs
[
cent_index
].
saveInterProperties
(
// save properties for interscene processing (extrinsics, ers, ...) // null pointer
null
,
// String path, // full name with extension or w/o path to use x3d directory
debugLevel
+
1
);
...
...
@@ -483,8 +492,485 @@ public class Interscene {
}
// Will now use quat_corr from the center scene (ref_index) that is different from the previously adjusted data
public
static
int
invertInitialOrientation
(
final
CLTParameters
clt_parameters
,
final
boolean
batch_mode
,
final
boolean
compensate_ims_rotation
,
final
boolean
inertial_only
,
final
boolean
readjust
,
final
boolean
ims_orient
,
// recalculate and use IMS orientations with quat_corr
final
boolean
set_self
,
// set record for the new reference to new reference ==false
final
QuadCLT
[]
quadCLTs
,
//
final
int
last_index
,
// original ref_index (last)
final
int
ref_index
,
// new reference index (center)
final
int
ref_old
,
// original ref_index (normally == last_index)
final
int
earliest_index
,
// only used with readjust
final
int
debugLevel
)
{
boolean
save_reliables
=
clt_parameters
.
imp
.
save_reliables
;
boolean
[][]
reliables
=
save_reliables
?
(
new
boolean
[
quadCLTs
.
length
][])
:
null
;
//Readjust may be needed similar to compensateDSI() - top DSI was calculated for wider scene
// range and be offset from the single-scene DSI
if
(
debugLevel
>
-
3
)
{
System
.
out
.
println
(
"\ninvertInitialOrientation(): earliest_index "
+
earliest_index
+
", ref_index="
+
ref_index
+
", last_index="
+
last_index
+
". readjust="
+
readjust
+
"\n"
);
}
ErsCorrection
ers_old_reference
=
quadCLTs
[
ref_old
].
getErsCorrection
();
int
offs
=
set_self
?
0
:
1
;
ErsCorrection
ers_reference
=
quadCLTs
[
ref_index
].
getErsCorrection
();
String
cent_ts
=
quadCLTs
[
ref_index
].
getImageName
();
// center scene relative to the old reference
double
[][]
center_xyzatr
=
new
double
[][]
{
ers_old_reference
.
getSceneXYZ
(
cent_ts
),
ers_old_reference
.
getSceneATR
(
cent_ts
)};
// old reference relative to the new one
double
[][]
inv_cent_xyzatr
=
ErsCorrection
.
invertXYZATR
(
center_xyzatr
);
double
[][][]
predicted_scene_xyzatr
=
new
double
[
last_index
+
1
][][];
double
[][][]
predicted_dxyzatr_dt
=
new
double
[
last_index
+
1
][][];
for
(
int
scene_index
=
ref_index
+
offs
;
scene_index
<=
last_index
;
scene_index
++)
{
// include cent_index itself to the map
if
(
scene_index
==
ref_old
)
{
predicted_scene_xyzatr
[
scene_index
]
=
new
double
[
2
][
3
];
predicted_dxyzatr_dt
[
scene_index
]
=
ers_old_reference
.
getErsXYZATR_dt
();
}
else
{
String
ts
=
quadCLTs
[
scene_index
].
getImageName
();
predicted_scene_xyzatr
[
scene_index
]
=
ers_old_reference
.
getSceneXYZATR
(
ts
);
predicted_dxyzatr_dt
[
scene_index
]
=
ers_old_reference
.
getSceneErsXYZATR_dt
(
ts
);
}
predicted_scene_xyzatr
[
scene_index
]
=
ErsCorrection
.
combineXYZATR
(
predicted_scene_xyzatr
[
scene_index
],
inv_cent_xyzatr
);
}
if
(!
readjust
)
{
// Invert half-sequence to reference cent_index
for
(
int
scene_index
=
ref_index
+
offs
;
scene_index
<=
last_index
;
scene_index
++)
{
// include cent_index itself to the map
ers_reference
.
addScene
(
quadCLTs
[
scene_index
].
getImageName
(),
predicted_scene_xyzatr
[
scene_index
],
predicted_dxyzatr_dt
[
scene_index
]);
// ers_scene.getErsXYZATR_dt(),
}
return
0
;
}
else
{
// if (readjust) {
boolean
lma_use_Z
=
clt_parameters
.
imp
.
lma_use_Z
;
// true; // lpf x and y, re-adjust X,Y,Z,A,T,R with pull for X,Y. Disables
boolean
lma_use_R
=
clt_parameters
.
imp
.
lma_use_R
;
// true; // lpf x and y, re-adjust X,Y,Z,A,T,R with pull for X,Y. Disables
System
.
out
.
println
(
"invertInitialOrientation(): "
+
", lma_use_Z="
+
lma_use_Z
+
", lma_use_R="
+
lma_use_R
);
boolean
[]
param_select
=
ErsCorrection
.
getParamSelect
(
// ZR - always
lma_use_Z
,
// boolean use_Z,
lma_use_R
,
// boolean use_R,
true
,
// boolean use_XY
false
,
// boolean use_AT,
false
,
// boolean use_ERS);//clt_parameters.ilp.ilma_lma_select;
false
,
// boolean use_ERS_tilt);
false
);
// boolean use_ERS_roll);
System
.
out
.
print
(
"param_select=["
);
for
(
int
i
=
0
;
i
<
param_select
.
length
;
i
++)
{
System
.
out
.
print
(
param_select
[
i
]?
"+"
:
"-"
);
}
System
.
out
.
println
(
"]"
);
RMSEStats
rmse_stats
=
new
RMSEStats
();
RMSEStats
rmse_stats_metric
=
clt_parameters
.
imp
.
eig_use
?
(
new
RMSEStats
()):
null
;
double
[][][]
scenes_xyzatr
=
new
double
[
last_index
+
1
][][];
double
[][][]
dxyzatr_dt
=
new
double
[
last_index
+
1
][][];
for
(
int
nscene
=
earliest_index
;
nscene
<=
ref_index
;
nscene
++)
{
String
ts
=
quadCLTs
[
nscene
].
getImageName
();
scenes_xyzatr
[
nscene
]
=
ers_reference
.
getSceneXYZATR
(
ts
);
dxyzatr_dt
[
nscene
]
=
ers_reference
.
getSceneErsXYZATR_dt
(
quadCLTs
[
nscene
].
getImageName
());
}
int
tilesX
=
quadCLTs
[
ref_index
].
getTileProcessor
().
getTilesX
();
int
tilesY
=
quadCLTs
[
ref_index
].
getTileProcessor
().
getTilesY
();
int
tile_size
=
quadCLTs
[
ref_index
].
getTileProcessor
().
getTileSize
();
double
min_offset
=
clt_parameters
.
imp
.
min_offset
;
// 0.0; //
double
max_offset
=
clt_parameters
.
imp
.
max_rel_offset
*
tilesX
*
tile_size
;
double
[]
min_max
=
{
min_offset
,
2
*
max_offset
,
0.0
}
;
// {min, max, actual rms)
// set reference
double
min_ref_str
=
clt_parameters
.
imp
.
min_ref_str
;
boolean
ref_need_lma
=
clt_parameters
.
imp
.
ref_need_lma
;
double
min_ref_frac
=
clt_parameters
.
imp
.
min_ref_frac
;
boolean
ref_smooth
=
clt_parameters
.
imp
.
ref_smooth
;
//true; // use SfM filtering if available
boolean
sfm_filter
=
clt_parameters
.
imp
.
sfm_filter
;
//true; // use SfM filtering if available
double
sfm_minmax
=
clt_parameters
.
imp
.
sfm_minmax
;
//10.0; // minimal value of the SfM gain maximum to consider available
double
sfm_fracmax
=
clt_parameters
.
imp
.
sfm_fracmax
;
// 0.75; // minimal fraction of the SfM maximal gain
double
sfm_fracall
=
clt_parameters
.
imp
.
sfm_fracall
;
// 0.3; // minimal relative area of the SfM-e
boolean
fmg_initial_en
=
clt_parameters
.
imp
.
fmg_initial_en
;
// enable IMS-based FPN mitigation for initial orientation
double
fmg_distance
=
clt_parameters
.
imp
.
fmg_distance
;
// try to find other reference scene not closer than this pixels
// TODO: improve to use "preferred" distance
if
(
fmg_distance
<
(
min_offset
+
2
))
{
fmg_distance
=
min_offset
+
2
;
}
double
fmg_max_quad
=
clt_parameters
.
imp
.
fmg_max_quad
;
// estimate offset by 4 points (rooll-aware, 25% from center) if center
// offset is too small
boolean
fmg_rectilinear
=
clt_parameters
.
imp
.
fmg_rectilinear
;
// use rectilinear model for scene offset estimation
boolean
debug2
=
!
batch_mode
;
// false; // true;
boolean
[]
reliable_ref
=
null
;
boolean
use_lma_dsi
=
clt_parameters
.
imp
.
use_lma_dsi
;
double
[]
reduced_strength
=
new
double
[
1
];
double
avg_z
=
quadCLTs
[
ref_index
].
getAverageZ
(
true
);
// use lma
double
[]
lma_rms
=
new
double
[
clt_parameters
.
imp
.
eig_use
?
6
:
4
];
// [2];
double
[][][]
ims_xyzatr
=
null
;
double
[]
quat_corr
=
compensate_ims_rotation
?
quadCLTs
[
ref_index
].
getQuatCorr
()
:
null
;
//
double
[]
enu_corr_metric
=
quadCLTs
[
ref_index
].
getENUCorrMetric
();
// not used?
if
(
ims_orient
)
{
if
(
inertial_only
)
{
ims_xyzatr
=
QuadCLT
.
integratePIMU
(
// does nor use quat_corr
clt_parameters
,
// final CLTParameters clt_parameters,
quadCLTs
,
// final QuadCLT[] quadCLTs,
quat_corr
,
// double [] quat_corr,
ref_index
,
// final int ref_index,
null
,
// double [][][] dxyzatr,
0
,
// final int early_index,
(
quadCLTs
.
length
-
1
),
// int last_index,
debugLevel
// final int debugLevel
);
}
else
{
ims_xyzatr
=
quadCLTs
[
ref_index
].
getXyzatrIms
(
clt_parameters
,
// CLTParameters clt_parameters,
quadCLTs
,
// QuadCLT[] quadCLTs,
quat_corr
,
// double [] quat_corr, // only applies to rotations - verify!
debugLevel
)
;
// int debugLevel)
}
}
// use combo if second pass?
if
(
min_ref_str
>
0.0
)
{
// can reuse that for the center scene (pass with the quadCLTs[ref_index]?
reliable_ref
=
quadCLTs
[
ref_index
].
getReliableTiles
(
// will be null if does not exist.
false
,
// boolean use_combo,
min_ref_str
,
// double min_strength,
min_ref_frac
,
// double min_ref_frac,
ref_need_lma
,
// boolean needs_lma);
true
,
// ref_need_lma_combo, // boolean needs_lma_combo);
sfm_filter
,
// boolean sfm_filter, // use SfM filtering if available
sfm_minmax
,
// double sfm_minmax, // minimal value of the SfM gain maximum to consider available
sfm_fracmax
,
// double sfm_fracmax,// minimal fraction of the SfM maximal gain
sfm_fracall
,
// double sfm_fracall,// minimal relative area of the SfM-enabled tiles (do not apply filter if less)
reduced_strength
,
// if not null will return >0 if had to reduce strength (no change if did not reduce)
debugLevel
);
// int debugLevel)
if
(
reduced_strength
[
0
]
>
0
)
{
use_lma_dsi
=
false
;
// too few points
}
if
(
debug2
)
{
double
[]
dbg_img
=
new
double
[
reliable_ref
.
length
];
for
(
int
i
=
0
;
i
<
dbg_img
.
length
;
i
++)
{
dbg_img
[
i
]
=
reliable_ref
[
i
]?
1
:
0
;
}
ShowDoubleFloatArrays
.
showArrays
(
dbg_img
,
quadCLTs
[
ref_index
].
getTileProcessor
().
getTilesX
(),
quadCLTs
[
ref_index
].
getTileProcessor
().
getTilesY
(),
"reliable_ref"
);
}
}
// Trying new version with motion blur and single-setting of the reference frame
boolean
mb_en
=
clt_parameters
.
imp
.
mb_en
;
double
mb_tau
=
clt_parameters
.
imp
.
mb_tau
;
// 0.008; // time constant, sec
double
mb_max_gain
=
clt_parameters
.
imp
.
mb_max_gain_inter
;
// 5.0; // motion blur maximal gain (if more - move second point more than a pixel
TpTask
[][]
tp_tasks_ref
=
new
TpTask
[
2
][];
double
[][]
pXpYD_ref
=
new
double
[
tilesX
*
tilesY
][];
ArrayList
<
Integer
>
fpn_list
=
new
ArrayList
<
Integer
>();
double
[]
reg_weights
=
clt_parameters
.
ilp
.
ilma_regularization_weights
;
int
[]
fail_reason
=
new
int
[
1
];
// null or int[1]: 0 - OK, 2 - LMA, 3 - min, 4 - max
if
(
reliables
!=
null
)
{
reliables
[
ref_index
]=
reliable_ref
;
}
// boolean fpn_skip = true;
double
[][]
last_corr_xyzatr
=
{
ZERO3
,
ZERO3
};
int
prev_adjusted_index
=
ref_index
;
// last successfully adjusted index (skipping FAIL_REASON_MIN) that were too close to try adjustment
for
(
int
scene_index
=
ref_index
+
offs
;
scene_index
<=
last_index
;
scene_index
++)
{
// include cent_index itself to the map offs==1, ref is already set
double
[][]
scene_xyzatr_old
;
// ,dxyzatr_dt;
if
(
scene_index
==
last_index
)
{
scene_xyzatr_old
=
new
double
[
2
][
3
];
dxyzatr_dt
[
scene_index
]
=
ers_old_reference
.
getErsXYZATR_dt
();
}
else
{
String
ts
=
quadCLTs
[
scene_index
].
getImageName
();
scene_xyzatr_old
=
ers_old_reference
.
getSceneXYZATR
(
ts
);
dxyzatr_dt
[
scene_index
]
=
ers_old_reference
.
getSceneErsXYZATR_dt
(
ts
);
}
double
[][]
initial_pose
;
if
(
ims_xyzatr
!=
null
)
{
// use new recalculated orientation from IMS, accounting for different quat_corr of the center scene from last_scene
// Calculate difference of the new IMS-derived pose and the one for the last adjusted scene
double
[][]
last_prediction
=
ims_xyzatr
[
prev_adjusted_index
];
double
[][]
last_prediction_inv
=
ErsCorrection
.
invertXYZATR
(
last_prediction
);
// prediction increment from the last fitted scene to this one.
double
[][]
prediction_inc
=
ErsCorrection
.
combineXYZATR
(
ims_xyzatr
[
scene_index
],
// current prediction
last_prediction_inv
);
// previous prediction inverted
// when starting from the reference scene as [[0,0,0],[0,0,0]], and not adjusting orientations, the sum of prediction_inc
// will lead to the IMS orientations, and position may gradually diverge.
// When debugging, make sure that predicted orientation is the same as IMS.
// In LMA allow X,Y (and optionally Z), keep A,T frozen. What about roll? If enabled it will just gradually diverge as X,Y (and Z?) do.
String
ts_prev
=
quadCLTs
[
prev_adjusted_index
].
getImageName
();
double
[][]
scene_xyzatr_prev
=
ers_reference
.
getSceneXYZATR
(
ts_prev
);
initial_pose
=
ErsCorrection
.
combineXYZATR
(
prediction_inc
,
scene_xyzatr_prev
);
}
else
{
// old adjustment for this scene relative to the new reference (center)
initial_pose
=
ErsCorrection
.
combineXYZATR
(
scene_xyzatr_old
,
inv_cent_xyzatr
);
// add same correction (from initial to final/LMA) as was for the previous scene
initial_pose
=
ErsCorrection
.
combineXYZATR
(
last_corr_xyzatr
,
// current correction
initial_pose
);
// previously known pose
}
// Will be used in prepareLMA()
quadCLTs
[
scene_index
].
getErsCorrection
().
setErsDt
(
// set for ref also (should be set before non-ref!)
QuadCLTCPU
.
scaleDtToErs
(
clt_parameters
,
dxyzatr_dt
[
scene_index
]));
// cam_dxyzatr));
// Trying new version with motion blur and single-setting of the reference frame
double
est_shift
=
quadCLTs
[
ref_index
].
estimateAverageShift
(
new
double
[
2
][
3
],
// scenes_xyzatr[ref_index], // double [][] xyzatr0,
initial_pose
,
// double [][] xyzatr1,
avg_z
,
// double average_z,
false
,
// boolean use_rot,
fmg_rectilinear
);
// boolean fmg_rectilinear)
if
(
est_shift
<
fmg_max_quad
)
{
est_shift
=
quadCLTs
[
ref_index
].
estimateAverageShift
(
new
double
[
2
][
3
],
// scenes_xyzatr[ref_index], // double [][] xyzatr0,
initial_pose
,
// double [][] xyzatr1,
avg_z
,
// double average_z,
true
,
// boolean use_rot,
fmg_rectilinear
);
// boolean rectilinear)
}
double
[]
center_offset_xy
=
quadCLTs
[
ref_index
].
estimateCenterShiftXY
(
new
double
[
2
][
3
],
// scenes_xyzatr[ref_index], // double [][] xyzatr0,
initial_pose
,
// double [][] xyzatr1,
avg_z
,
// double average_z,
fmg_rectilinear
);
// boolean fmg_rectilinear)
boolean
[]
reliable_scene
=
quadCLTs
[
ref_index
].
maskByOverlap
(
reliable_ref
,
// boolean [] reliable_ref_tiles,
center_offset_xy
);
// double [] offset)
if
(
reliables
!=
null
)
{
reliables
[
scene_index
]=
reliable_scene
;
}
//reliable_ref
if
(
debugLevel
>
-
4
)
{
System
.
out
.
println
(
"nscene="
+
scene_index
+
": est offset "
+
est_shift
+
"pix (dx="
+
center_offset_xy
[
0
]+
", dy="
+
center_offset_xy
[
1
]+
")"
);
}
// double [][]scene_xyzatr = new double[][] {initial_pose[0].clone(),initial_pose[1].clone()};
boolean
adjust_OK
=
false
;
if
(
est_shift
<
min_max
[
0
])
{
fail_reason
[
0
]=
FAIL_REASON_MIN
;
}
else
{
// Trying new version with motion blur and single-setting of the reference frame
final
double
max_rms
=
LOOSEN_MAX_RMS
*
(
clt_parameters
.
imp
.
eig_use
?
clt_parameters
.
imp
.
eig_max_rms
:
clt_parameters
.
imp
.
max_rms
);
scenes_xyzatr
[
scene_index
]
=
adjustDiffPairsLMAInterscene
(
// compare two scenes, first may be reference, use motion blur
clt_parameters
,
// CLTParameters clt_parameters,
use_lma_dsi
,
// clt_parameters.imp.use_lma_dsi,
false
,
// boolean fpn_disable, // disable fpn filter if images are known to be too close
true
,
// boolean disable_ers,
min_max
,
// double [] min_max, // null or pair of minimal and maximal offsets
fail_reason
,
// int [] fail_reason, // null or int[1]: 0 - OK, 1 - LMA, 2 - min, 3 - max
quadCLTs
,
// QuadCLT [] quadCLTs,
ref_index
,
// int ref_index,
tp_tasks_ref
,
// TpTask[][] tp_tasks_ref, // Should be TpTask[2][*]. If tp_tasks_ref[0] == null will calculate
// at set first scene to the GPU
pXpYD_ref
,
// double [][] pXpYD_ref, // should be set or at least double [num_tiles][] if tp_tasks_ref[0] == null
ref_index
,
// int nscene0, // may be == ref_index
scene_index
,
// int nscene1, // compares to nscene0
null
,
// double [] ref_disparity, // null or alternative reference disparity
reliable_scene
,
// reliable_ref, // boolean [] reliable_ref, // null or bitmask of reliable reference tiles
ref_smooth
,
// boolean smooth_disparity, // smooth disparity (according to clt_parameters)+update reliable_ref if true
scenes_xyzatr
[
ref_index
],
// double [][] scene0_xyzatr,,
initial_pose
,
// double [][] scene1_xyzatr,
Double
.
NaN
,
// double average_z,
initial_pose
,
// double [] scene1_xyzatr_pull, // if both are not null, specify target values to pull to
param_select
,
// clt_parameters.ilp.ilma_lma_select, // boolean[] param_select,
reg_weights
,
// double [] param_regweights,
lma_rms
,
// double [] rms_out, // null or double [2]
max_rms
,
// double max_rms,
mb_en
,
// boolean mb_en,
mb_tau
,
// double mb_tau, // 0.008; // time constant, sec
mb_max_gain
,
// double mb_max_gain, // 5.0; // motion blur maximal gain (if more - move second point more than a pixel
clt_parameters
.
imp
.
debug_level
);
// int debugLevel);
adjust_OK
=
scenes_xyzatr
[
scene_index
]
!=
null
;
}
if
(!
adjust_OK
)
{
System
.
out
.
println
(
"LMA failed at nscene = "
+
scene_index
+
". Reason = "
+
fail_reason
[
0
]+
" ("
+
getFailReason
(
fail_reason
[
0
])+
")"
);
fpn_list
.
add
(
scene_index
);
scenes_xyzatr
[
scene_index
]
=
initial_pose
;
// should not be modified for initial adjust, but just in case
quadCLTs
[
scene_index
].
getErsCorrection
().
setErsDt
(
// set for ref also (should be set before non-ref!)
QuadCLTCPU
.
scaleDtToErs
(
clt_parameters
,
dxyzatr_dt
[
scene_index
]));
continue
;
}
// update last_corr_xyzatr, // current correction
double
[][]
corr_diff
=
ErsCorrection
.
combineXYZATR
(
scenes_xyzatr
[
scene_index
],
// new
ErsCorrection
.
invertXYZATR
(
initial_pose
));
//old
last_corr_xyzatr
=
ErsCorrection
.
combineXYZATR
(
last_corr_xyzatr
,
corr_diff
);
// not used here with IMS: after_spiral == false
double
[][]
adjusted_xyzatr_dt
=
QuadCLTCPU
.
scaleDtFromErs
(
clt_parameters
,
quadCLTs
[
scene_index
].
getErsCorrection
().
getErsXYZATR_dt
(
));
ers_reference
.
addScene
(
quadCLTs
[
scene_index
].
getImageName
(),
scenes_xyzatr
[
scene_index
][
0
],
scenes_xyzatr
[
scene_index
][
1
],
adjusted_xyzatr_dt
[
0
],
// ZERO3, // ers_scene.getErsXYZ_dt(),
adjusted_xyzatr_dt
[
1
]
// ZERO3 // ers_scene.getErsATR_dt()
);
prev_adjusted_index
=
scene_index
;
rmse_stats
.
add
(
lma_rms
[
0
]);
if
((
rmse_stats_metric
!=
null
)
&&
(
lma_rms
.
length
>=
4
))
{
rmse_stats_metric
.
add
(
lma_rms
[
4
]);
}
if
(
debugLevel
>
-
3
)
{
System
.
out
.
println
(
"invertInitialOrientation(): scene "
+
scene_index
+
" (of "
+
quadCLTs
.
length
+
") "
+
quadCLTs
[
ref_index
].
getImageName
()
+
"/"
+
quadCLTs
[
scene_index
].
getImageName
()+
" Done. Weight = "
+
lma_rms
[
2
]+
", number="
+
lma_rms
[
3
]);
System
.
out
.
print
(
"RMS="
+
lma_rms
[
0
]+
", maximal so far was "
+
rmse_stats
.
getMax
()+
", average was "
+
rmse_stats
.
getAverage
());
if
((
rmse_stats_metric
!=
null
)
&&
(
lma_rms
.
length
>=
6
))
{
System
.
out
.
print
(
". Pixel RMS="
+
lma_rms
[
4
]+
"pix, maximal so far was "
+
rmse_stats_metric
.
getMax
()+
"pix, average was "
+
rmse_stats_metric
.
getAverage
()+
"pix."
);
}
System
.
out
.
println
();
}
}
// for (int scene_index = ref_index; scene_index <= last_index; scene_index++) {
if
(
debugLevel
>
-
4
)
{
System
.
out
.
println
(
"num_fpn_mitigate= "
+
fpn_list
.
size
());
}
if
(
fmg_initial_en
&&
!
fpn_list
.
isEmpty
())
{
// here max_offset is not critical, min_offset can be 0 too
//double [] min_max = {min_offset, max_offset, 0.0} ; // {min, max, actual rms)
if
(
fmg_distance
<
(
min_max
[
0
]
+
2
))
{
fmg_distance
=
min_max
[
0
]
+
2
;
}
int
[][]
fpn_pairs
=
getFPNPairs
(
fpn_list
,
// ArrayList<Integer> fpn_list,
fmg_distance
,
// double fpn_mitigate_dist,
fmg_rectilinear
,
// boolean rectilinear,
quadCLTs
,
// QuadCLT [] quadCLTs,
scenes_xyzatr
,
// double [][][] scenes_xyzatr,
avg_z
,
// double avg_z,
last_index
,
// ref_index, // int ref_index, // >= earliest_scene
earliest_index
);
// int earliest_scene)
if
(
getFPNUnResolved
(
fpn_pairs
)
>
0
)
{
System
.
out
.
println
(
"Unresolved FPN pairs:"
+
getFPNUnResolved
(
fpn_pairs
));
return
getFPNUnResolved
(
fpn_pairs
);
}
double
[]
min_max_fpn
=
{
0
,
min_max
[
1
]};
for
(
int
ipair
=
0
;
ipair
<
fpn_pairs
.
length
;
ipair
++)
if
(
fpn_pairs
[
ipair
][
1
]
>=
0
)
{
if
(
debugLevel
>
-
4
)
{
System
.
out
.
println
(
"Mitigating FPN for scene "
+
fpn_pairs
[
ipair
][
0
]+
" being too close to reference "
+
ref_index
+
", using scene "
+
fpn_pairs
[
ipair
][
1
]+
" as a reference"
);
}
TpTask
[][]
tp_tasks_rel_ref
=
new
TpTask
[
2
][];
final
double
max_rms
=
clt_parameters
.
imp
.
eig_use
?
clt_parameters
.
imp
.
eig_max_rms
:
clt_parameters
.
imp
.
max_rms
;
double
[][]
rel_xyzatr
=
adjustDiffPairsLMAInterscene
(
// compare two scenes, first may be reference, use motion blur
clt_parameters
,
// CLTParameters clt_parameters,
use_lma_dsi
,
// clt_parameters.imp.use_lma_dsi,
false
,
// boolean fpn_disable, // disable fpn filter if images are known to be too close
true
,
// boolean disable_ers,
min_max_fpn
,
// min_max,// double [] min_max, // null or pair of minimal and maximal offsets
fail_reason
,
// int [] fail_reason, // null or int[1]: 0 - OK, 1 - LMA, 2 - min, 3 - max
quadCLTs
,
// QuadCLT [] quadCLTs,
ref_index
,
// int ref_index,
tp_tasks_rel_ref
,
// TpTask[][] tp_tasks_ref, // Should be TpTask[2][*]. If tp_tasks_ref[0] == null will calculate
// at set first scene to the GPU
pXpYD_ref
,
// double [][] pXpYD_ref, // should be set or at least double [num_tiles][] if tp_tasks_ref[0] == null
fpn_pairs
[
ipair
][
1
],
// ref_index, // int nscene0, // may be == ref_index
fpn_pairs
[
ipair
][
0
],
// int nscene1, // compares to nscene0
null
,
// double [] ref_disparity, // null or alternative reference disparity
reliable_ref
,
//boolean [] reliable_ref, // null or bitmask of reliable reference tiles
ref_smooth
,
// boolean smooth_disparity, // smooth disparity (according to clt_parameters)+update reliable_ref if true
scenes_xyzatr
[
fpn_pairs
[
ipair
][
1
]],
// double [][] scene0_xyzatr,,
scenes_xyzatr
[
fpn_pairs
[
ipair
][
0
]],
// initial_pose, // double [][] scene1_xyzatr,
Double
.
NaN
,
// double average_z,
scenes_xyzatr
[
fpn_pairs
[
ipair
][
0
]],
// initial_pose, // double [] scene1_xyzatr_pull, // if both are not null, specify target values to pull to
param_select
,
// clt_parameters.ilp.ilma_lma_select, // boolean[] param_select,
reg_weights
,
// double [] param_regweights,
lma_rms
,
// double [] rms_out, // null or double [2]
2
*
max_rms
,
// double max_rms,
mb_en
,
// boolean mb_en,
mb_tau
,
// double mb_tau, // 0.008; // time constant, sec
mb_max_gain
,
// double mb_max_gain, // 5.0; // motion blur maximal gain (if more - move second point more than a pixel
clt_parameters
.
imp
.
debug_level
);
// int debugLevel);
boolean
adjust_OK
=
rel_xyzatr
!=
null
;
if
(!
adjust_OK
)
{
// should not be modified for initial adjust, but just in case
quadCLTs
[
fpn_pairs
[
ipair
][
0
]].
getErsCorrection
().
setErsDt
(
// set for ref also (should be set before non-ref!)
QuadCLTCPU
.
scaleDtToErs
(
clt_parameters
,
dxyzatr_dt
[
fpn_pairs
[
ipair
][
0
]]));
System
.
out
.
println
(
"LMA failed at scene pair = "
+
fpn_pairs
[
ipair
][
0
]+
" referenced from scene "
+
fpn_pairs
[
ipair
][
1
]+
". Reason = "
+
fail_reason
[
0
]+
" ("
+
getFailReason
(
fail_reason
[
0
])+
")"
);
}
else
{
scenes_xyzatr
[
fpn_pairs
[
ipair
][
0
]]
=
rel_xyzatr
;
// save directly, no need to combine
double
[][]
adjusted_xyzatr_dt
=
QuadCLTCPU
.
scaleDtFromErs
(
clt_parameters
,
quadCLTs
[
fpn_pairs
[
ipair
][
0
]].
getErsCorrection
().
getErsXYZATR_dt
());
ers_reference
.
addScene
(
quadCLTs
[
fpn_pairs
[
ipair
][
0
]].
getImageName
(),
scenes_xyzatr
[
fpn_pairs
[
ipair
][
0
]][
0
],
scenes_xyzatr
[
fpn_pairs
[
ipair
][
0
]][
1
],
adjusted_xyzatr_dt
[
0
],
// ZERO3, // ers_scene.getErsXYZ_dt(),
adjusted_xyzatr_dt
[
1
]);
// ZERO3 // ers_scene.getErsATR_dt()
rmse_stats
.
add
(
lma_rms
[
0
]);
if
((
rmse_stats_metric
!=
null
)
&&
(
lma_rms
.
length
>=
4
))
{
rmse_stats_metric
.
add
(
lma_rms
[
4
]);
}
if
(
debugLevel
>
-
3
)
{
System
.
out
.
println
(
"Pass multi scene "
+
fpn_pairs
[
ipair
][
0
]+
" (of "
+
quadCLTs
.
length
+
") "
+
quadCLTs
[
fpn_pairs
[
ipair
][
1
]].
getImageName
()
+
"/"
+
quadCLTs
[
fpn_pairs
[
ipair
][
0
]].
getImageName
()+
" Done. Weight = "
+
lma_rms
[
2
]+
", number="
+
lma_rms
[
3
]);
System
.
out
.
print
(
"RMS="
+
lma_rms
[
0
]+
", maximal so far was "
+
rmse_stats
.
getMax
()+
", average was "
+
rmse_stats
.
getAverage
());
if
((
rmse_stats_metric
!=
null
)
&&
(
lma_rms
.
length
>=
6
))
{
System
.
out
.
print
(
". RMS="
+
lma_rms
[
4
]+
"pix, maximal so far was "
+
rmse_stats_metric
.
getMax
()+
"pix, average was "
+
rmse_stats_metric
.
getAverage
()+
"pix."
);
}
System
.
out
.
println
();
}
}
}
}
// Add to log
StringBuffer
sb
=
new
StringBuffer
();
sb
.
append
(
new
SimpleDateFormat
(
"yyyy/MM/dd HH:mm:ss"
).
format
(
Calendar
.
getInstance
().
getTime
())+
"\n"
);
sb
.
append
(
"Finished invertInitialOrientation():\n"
);
sb
.
append
(
"getNumOrient()= "
+
quadCLTs
[
ref_index
].
getNumOrient
()+
" of "
+
clt_parameters
.
imp
.
min_num_orient
+
"\n"
);
sb
.
append
(
"getNumAccum()= "
+
quadCLTs
[
ref_index
].
getNumAccum
()+
" of "
+
clt_parameters
.
imp
.
min_num_interscene
+
"\n"
);
sb
.
append
(
"earliest_scene= "
+
earliest_index
+
"\n"
);
sb
.
append
(
"ref_index= "
+
ref_index
+
"\n"
);
sb
.
append
(
"last_index= "
+
last_index
+
"\n"
);
sb
.
append
(
"old_ref_index= "
+
ref_old
+
"\n"
);
sb
.
append
(
"Maximal RMSE= "
+
rmse_stats
.
getMax
()+
"\n"
);
sb
.
append
(
"Average RMSE= "
+
rmse_stats
.
getAverage
()+
"\n"
);
if
(
rmse_stats_metric
!=
null
)
{
sb
.
append
(
"Maximal RMSE= "
+
rmse_stats_metric
.
getMax
()+
"pix\n"
);
sb
.
append
(
"Average RMSE= "
+
rmse_stats_metric
.
getAverage
()+
"pix\n"
);
}
sb
.
append
(
"------------------------\n\n"
);
quadCLTs
[
ref_index
].
appendStringInModelDirectory
(
sb
.
toString
(),
QuadCLT
.
ORIENTATION_LOGS_SUFFIX
);
// String suffix)
}
if
(
reliables
!=
null
)
{
quadCLTs
[
ref_index
].
saveReliables
(
quadCLTs
,
// QuadCLTCPU [] quadCLTs,
reliables
,
// boolean [][] reliables);
"-invert"
);
// String suffix)
}
return
0
;
}
public
static
int
invertInitialOrientation_old
(
final
CLTParameters
clt_parameters
,
final
boolean
batch_mode
,
final
boolean
readjust
,
...
...
@@ -663,9 +1149,19 @@ public class Interscene {
true
,
// boolean use_rot,
fmg_rectilinear
);
// boolean rectilinear)
}
double
[]
center_offset_xy
=
quadCLTs
[
ref_index
].
estimateCenterShiftXY
(
scenes_xyzatr
[
ref_index
],
// double [][] xyzatr0,
initial_pose
,
// double [][] xyzatr1,
avg_z
,
// double average_z,
fmg_rectilinear
);
// boolean fmg_rectilinear)
boolean
[]
reliable_scene
=
quadCLTs
[
ref_index
].
maskByOverlap
(
reliable_ref
,
// boolean [] reliable_ref_tiles,
center_offset_xy
);
// double [] offset)
if
(
debugLevel
>
-
4
)
{
System
.
out
.
println
(
"nscene="
+
scene_index
+
": est offset "
+
est_shift
+
"pix"
);
est_shift
+
"pix
(dx="
+
center_offset_xy
[
0
]+
", dy="
+
center_offset_xy
[
1
]+
")
"
);
}
// double [][]scene_xyzatr = new double[][] {initial_pose[0].clone(),initial_pose[1].clone()};
boolean
adjust_OK
=
false
;
...
...
@@ -689,7 +1185,7 @@ public class Interscene {
ref_index
,
// int nscene0, // may be == ref_index
scene_index
,
// int nscene1, // compares to nscene0
null
,
// double [] ref_disparity, // null or alternative reference disparity
reliable_ref
,
// boolean [] reliable_ref, // null or bitmask of reliable reference tiles
reliable_
scene
,
// reliable_
ref, // boolean [] reliable_ref, // null or bitmask of reliable reference tiles
ref_smooth
,
// boolean smooth_disparity, // smooth disparity (according to clt_parameters)+update reliable_ref if true
scenes_xyzatr
[
ref_index
],
// double [][] scene0_xyzatr,,
initial_pose
,
// double [][] scene1_xyzatr,
...
...
@@ -879,6 +1375,7 @@ public class Interscene {
return
0
;
}
public
static
int
setInitialOrientationsIms
(
final
CLTParameters
clt_parameters
,
final
boolean
compensate_ims_rotation
,
...
...
@@ -905,8 +1402,6 @@ public class Interscene {
double
sfm_fracall
=
clt_parameters
.
imp
.
sfm_fracall
;
// 0.3; // minimal relative area of the SfM-e
boolean
ref_smooth
=
clt_parameters
.
imp
.
ref_smooth
;
//true; // use SfM filtering if available
// double ref_sigma = clt_parameters.imp.ref_sigma; //10.0; // minimal value of the SfM gain maximum to consider available
// double ref_smooth_diff = clt_parameters.imp.ref_smooth_diff; // 0.75; // minimal fraction of the SfM maximal gain
boolean
lock_position
=
clt_parameters
.
imp
.
lock_position
;
boolean
manual_correction
=
clt_parameters
.
imp
.
manual_correction
;
int
max_num_scenes
=
clt_parameters
.
imp
.
max_num_scenes
;
// cut longer series
...
...
@@ -918,6 +1413,9 @@ public class Interscene {
// offset is too small
boolean
fmg_rectilinear
=
clt_parameters
.
imp
.
fmg_rectilinear
;
// use rectilinear model for scene offset estimation
boolean
save_reliables
=
clt_parameters
.
imp
.
save_reliables
;
boolean
[][]
reliables
=
save_reliables
?
(
new
boolean
[
quadCLTs
.
length
][])
:
null
;
double
boost_max_short
=
2.0
;
//
double
boost_zoom_short
=
1.5
;
//
sfm_filter
&=
!
lock_position
;
// no SFM for locked position
...
...
@@ -1014,7 +1512,9 @@ public class Interscene {
quadCLTs
[
ref_index
].
getImageName
()+
"-reliable_ref"
);
}
}
if
(
reliables
!=
null
)
{
reliables
[
ref_index
]=
reliable_ref
;
}
double
max_z_change
=
Double
.
NaN
;
// only applicable for drone images
double
avg_z
=
quadCLTs
[
ref_index
].
getAverageZ
(
true
);
// use lma
if
(!
lock_position
&&
(
max_zoom_diff
>
0
))
{
// ignore if set to
...
...
@@ -1082,22 +1582,12 @@ public class Interscene {
ims_xyzatr
[
i
][
0
][
j
]=
0.0
;
}
}
// boolean man_corr = debugLevel> 100; // <10; //
int
other_scene
=
-
1
;
// 57
if
(
manual_correction
)
{
other_scene
=
57
;
// double [][] xyz_atr_le = {{-0.5183922094898724, 9.154782438090823, 1.9419561092947408},{0,0,0}};
// double [][] xyz_atr_le = {{-0.8268073979557207, 12.435651264663617, 0.43389361433133333},{0,0,0}};
// double [][] xyz_atr_le = {
// {-1.5074533979557208, 5.289806264663618, 0.6908026143313334},
// {-0.015346300027727794,0.16450786973129805,-0.008030574830017914}};
double
[][]
xyz_atr_le
=
{
{-
1.5074533979557208
,
2.401806264663618
,
0.6908026143313334
},
{-
0.015346300027727794
,
0.23050786973129805
,-
0.008030574830017914
}};
// double [][] xyz_atr_le = {
// {0, 0, 0.6908026143313334},
// {0.018641752679327314, 0.2862869959075706, -0.008030574830017914}};
double
[][]
xyz_atr_gt
=
{{
0
,
0
,
0
},
{
0
,
0
,
0
}};
manualIMSCorrection
(
ims_xyzatr
,
// double [][][] xyz_atr,
...
...
@@ -1107,7 +1597,6 @@ public class Interscene {
}
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;
boolean
got_spiral
=
false
;
double
[][]
last_corr_xyzatr
=
{
ZERO3
,
ZERO3
};
ers_reference
.
addScene
(
quadCLTs
[
ref_index
].
getImageName
(),
// add reference scene (itself) too
...
...
@@ -1129,8 +1618,8 @@ public class Interscene {
double
[][]
pXpYD_ref
=
new
double
[
tilesX
*
tilesY
][];
ArrayList
<
Integer
>
fpn_list
=
new
ArrayList
<
Integer
>();
double
[]
reg_weights
=
clt_parameters
.
ilp
.
ilma_regularization_weights
;
// min_max[1] = max_offset;
final
double
max_rms
=
clt_parameters
.
imp
.
eig_use
?
clt_parameters
.
imp
.
eig_max_rms
:
clt_parameters
.
imp
.
max_rms
;
for
(
int
scene_index
=
ref_index
-
1
;
scene_index
>=
earliest_scene
;
scene_index
--)
{
if
(
scene_index
==
other_scene
)
{
last_corr_xyzatr
=
new
double
[][]
{
ZERO3
,
ZERO3
};
// start from scratch
...
...
@@ -1205,9 +1694,23 @@ public class Interscene {
true
,
// boolean use_rot,
fmg_rectilinear
);
// boolean rectilinear)
}
double
[]
center_offset_xy
=
quadCLTs
[
ref_index
].
estimateCenterShiftXY
(
scenes_xyzatr
[
ref_index
],
// double [][] xyzatr0,
scenes_xyzatr
[
scene_index
],
// double [][] xyzatr1,
avg_z
,
// double average_z,
fmg_rectilinear
);
// boolean fmg_rectilinear)
boolean
[]
reliable_scene
=
quadCLTs
[
ref_index
].
maskByOverlap
(
reliable_ref
,
// boolean [] reliable_ref_tiles,
center_offset_xy
);
// double [] offset)
if
(
reliables
!=
null
)
{
reliables
[
scene_index
]=
reliable_scene
;
}
if
(
debugLevel
>
-
4
)
{
System
.
out
.
println
(
"nscene="
+
scene_index
+
": est offset "
+
est_shift
+
"pix"
);
est_shift
+
"pix
(dx="
+
center_offset_xy
[
0
]+
", dy="
+
center_offset_xy
[
1
]+
")
"
);
}
boolean
adjust_OK
=
false
;
if
(
est_shift
<
min_max
[
0
])
{
...
...
@@ -1228,7 +1731,7 @@ public class Interscene {
ref_index
,
// int nscene0, // may be == ref_index
scene_index
,
// int nscene1, // compares to nscene0
null
,
// double [] ref_disparity, // null or alternative reference disparity
reliable_ref
,
// boolean [] reliable_ref, // null or bitmask of reliable reference tiles
reliable_
scene
,
// reliable_
ref, // boolean [] reliable_ref, // null or bitmask of reliable reference tiles
ref_smooth
,
// boolean smooth_disparity, // smooth disparity (according to clt_parameters)+update reliable_ref if true
scenes_xyzatr
[
ref_index
],
// double [][] scene0_xyzatr,,
initial_pose
,
// double [][] scene1_xyzatr,
...
...
@@ -1378,6 +1881,25 @@ public class Interscene {
" being too close to reference "
+
ref_index
+
", using scene "
+
fpn_pairs
[
ipair
][
1
]+
" as a reference"
);
}
double
[]
center_offset_xy0
=
quadCLTs
[
ref_index
].
estimateCenterShiftXY
(
scenes_xyzatr
[
ref_index
],
// double [][] xyzatr0,
scenes_xyzatr
[
fpn_pairs
[
ipair
][
0
]],
// double [][] xyzatr1,
avg_z
,
// double average_z,
fmg_rectilinear
);
// boolean fmg_rectilinear)
boolean
[]
reliable_scene
=
quadCLTs
[
ref_index
].
maskByOverlap
(
reliable_ref
,
// boolean [] reliable_ref_tiles,
center_offset_xy0
);
// double [] offset)
double
[]
center_offset_xy1
=
quadCLTs
[
ref_index
].
estimateCenterShiftXY
(
scenes_xyzatr
[
ref_index
],
// double [][] xyzatr0,
scenes_xyzatr
[
fpn_pairs
[
ipair
][
1
]],
// double [][] xyzatr1,
avg_z
,
// double average_z,
fmg_rectilinear
);
// boolean fmg_rectilinear)
reliable_scene
=
quadCLTs
[
ref_index
].
maskByOverlap
(
reliable_scene
,
// boolean [] reliable_ref_tiles,
center_offset_xy1
);
// double [] offset)
TpTask
[][]
tp_tasks_rel_ref
=
new
TpTask
[
2
][];
double
[][]
rel_xyzatr
=
adjustDiffPairsLMAInterscene
(
// compare two scenes, first may be reference, use motion blur
clt_parameters
,
// CLTParameters clt_parameters,
...
...
@@ -1394,7 +1916,7 @@ public class Interscene {
fpn_pairs
[
ipair
][
1
],
// ref_index, // int nscene0, // may be == ref_index
fpn_pairs
[
ipair
][
0
],
// int nscene1, // compares to nscene0
null
,
// double [] ref_disparity, // null or alternative reference disparity
reliable_ref
,
//boolean [] reliable_ref, // null or bitmask of reliable reference tiles
reliable_
scene
,
// reliable_
ref, //boolean [] reliable_ref, // null or bitmask of reliable reference tiles
ref_smooth
,
// boolean smooth_disparity, // smooth disparity (according to clt_parameters)+update reliable_ref if true
scenes_xyzatr
[
fpn_pairs
[
ipair
][
1
]],
// double [][] scene0_xyzatr,,
scenes_xyzatr
[
fpn_pairs
[
ipair
][
0
]],
// initial_pose, // double [][] scene1_xyzatr,
...
...
@@ -1448,6 +1970,12 @@ public class Interscene {
}
}
}
if
(
reliables
!=
null
)
{
quadCLTs
[
ref_index
].
saveReliables
(
quadCLTs
,
// QuadCLTCPU [] quadCLTs,
reliables
,
// boolean [][] reliables);
"-initial"
);
// String suffix)
}
if
(
earliest_scene
>
0
)
{
System
.
out
.
print
(
"setInitialOrientationsIms(): Not all scenes matched, earliest useful scene = "
+
earliest_scene
+
...
...
@@ -2106,8 +2634,8 @@ public class Interscene {
double
best_dist
=
Double
.
NaN
;
for
(
int
i
=
latest_scene
;
i
>=
earliest_scene
;
i
--)
{
double
fpn_dist
=
quadCLTs
[
latest_scene
].
estimateAverageShift
(
scenes_xyzatr
[
i
],
// double [][] xyzatr0,
scenes_xyzatr
[
fpn_index
],
// double [][] xyzatr1,
scenes_xyzatr
[
i
],
// double [][] xyzatr0,
scenes_xyzatr
[
fpn_index
],
// double [][] xyzatr1,
avg_z
,
// double average_z,
false
,
// boolean use_rot,
rectilinear
);
// boolean rectilinear)
...
...
@@ -2839,11 +3367,13 @@ public class Interscene {
int
ers_mode
,
// 0 - keep, 1 - set from velocity, 2 - set from IMS
boolean
test_motion_blur
,
int
debugLevel
)
{
{
// manually set test_motion_blur here
boolean
save_reliables
=
clt_parameters
.
imp
.
save_reliables
;
boolean
[][]
reliables
=
save_reliables
?
(
new
boolean
[
quadCLTs
.
length
][])
:
null
;
boolean
restore_imu
=
clt_parameters
.
imp
.
restore_imu
;
//false; // restore imu omega-az and omega-tl, freeze ERS, adjust X,Y,Z,Az,Tl,Rl
System
.
out
.
println
(
"reAdjustPairsLMAInterscene(): using mb_max_gain="
+
mb_max_gain
+
", disable_ers="
+
disable_ers
+
", disable_ers_y="
+
disable_ers_y
+
", restore_imu="
+
restore_imu
+
", lma_xyzatr="
+
lma_xyzatr
+
", readjust_xy_ims="
+
readjust_xy_ims
+
", readjust_xy_ims="
+
readjust_xy_ims
+
", lma_xyzatr="
+
lma_xyzatr
+
", readjust_xy_ims="
+
readjust_xy_ims
+
", use_Z="
+
use_Z
+
", use_R="
+
use_R
+
", use_XY"
+
use_XY
+
", use_AT="
+
use_AT
);
boolean
freeze_xy_pull
=
clt_parameters
.
imp
.
freeze_xy_pull
;
// true; // false; // true; // debugging freezing xy to xy_pull
boolean
copy_pull_current
=
clt_parameters
.
imp
.
copy_pull_current
;
//false; // true;
...
...
@@ -3213,6 +3743,10 @@ public class Interscene {
// Main cycle - first goes down from the center, then up, and finally processes "fpn" scenes (close to reference)
double
[][]
precomp_xyzatr
=
new
double
[
2
][
3
];
int
last_processed_scene
=
-
2
;
// none
if
(
reliables
!=
null
)
{
reliables
[
ref_index
]=
reliable_ref
;
}
/*
* There is still a problem with a large mismatch at start position for far off-reference scenes,
* especially those that were not refined after inversion - reversing order of earlier processed "later"
...
...
@@ -3222,7 +3756,6 @@ public class Interscene {
* precomp_xyzatr will be used to store how much LMA corrected from the original estimation and add it
* to the next scene (only when it is the next), similar to the initial orientation.
*/
for
(
int
nscene:
scene_seq
)
{
if
(
nscene
==
debug_scene
)
{
System
.
out
.
println
(
"nscene = "
+
nscene
);
...
...
@@ -3242,9 +3775,21 @@ public class Interscene {
true
,
// boolean use_rot,
fmg_rectilinear
);
// boolean rectilinear)
}
double
[]
center_offset_xy
=
quadCLTs
[
ref_index
].
estimateCenterShiftXY
(
scenes_xyzatr
[
ref_index
],
// double [][] xyzatr0,
scenes_xyzatr
[
nscene
],
// double [][] xyzatr1,
avg_z
,
// double average_z,
fmg_rectilinear
);
// boolean fmg_rectilinear)
boolean
[]
reliable_scene
=
quadCLTs
[
ref_index
].
maskByOverlap
(
reliable_ref
,
// boolean [] reliable_ref_tiles,
center_offset_xy
);
// double [] offset)
if
(
reliables
!=
null
)
{
reliables
[
nscene
]=
reliable_scene
;
}
if
(
debugLevel
>
-
4
)
{
System
.
out
.
println
(
"nscene="
+
nscene
+
": est offset "
+
est_shift
+
"pix"
);
est_shift
+
"pix
(dx="
+
center_offset_xy
[
0
]+
", dy="
+
center_offset_xy
[
1
]+
")
"
);
}
// just checking it is not isolated
if
((
quadCLTs
[
nscene
]
==
null
)
||
...
...
@@ -3322,7 +3867,7 @@ public class Interscene {
ref_index
,
// int nscene0, // may be == ref_index
nscene
,
// int nscene1, // compares to nscene0
interscene_ref_disparity
,
// double [] ref_disparity, // null or alternative reference disparity
reliable_ref
,
// boolean [] reliable_ref, // null or bitmask of reliable reference tiles
reliable_
scene
,
// reliable_
ref, // boolean [] reliable_ref, // null or bitmask of reliable reference tiles
false
,
// boolean smooth_disparity, // smooth disparity (according to clt_parameters)+update reliable_ref if true
scenes_xyzatr
[
ref_index
],
// double [][] scene0_xyzatr,
scenes_xyzatr
[
nscene
],
// double [][] scene1_xyzatr,
...
...
@@ -3488,6 +4033,23 @@ public class Interscene {
" being too close to reference "
+
ref_index
+
", using scene "
+
fpn_pairs
[
ipair
][
1
]+
" as a reference"
);
}
double
[]
center_offset_xy0
=
quadCLTs
[
ref_index
].
estimateCenterShiftXY
(
scenes_xyzatr
[
ref_index
],
// double [][] xyzatr0,
scenes_xyzatr
[
fpn_pairs
[
ipair
][
0
]],
// double [][] xyzatr1,
avg_z
,
// double average_z,
fmg_rectilinear
);
// boolean fmg_rectilinear)
boolean
[]
reliable_scene
=
quadCLTs
[
ref_index
].
maskByOverlap
(
reliable_ref
,
// boolean [] reliable_ref_tiles,
center_offset_xy0
);
// double [] offset)
double
[]
center_offset_xy1
=
quadCLTs
[
ref_index
].
estimateCenterShiftXY
(
scenes_xyzatr
[
ref_index
],
// double [][] xyzatr0,
scenes_xyzatr
[
fpn_pairs
[
ipair
][
1
]],
// double [][] xyzatr1,
avg_z
,
// double average_z,
fmg_rectilinear
);
// boolean fmg_rectilinear)
reliable_scene
=
quadCLTs
[
ref_index
].
maskByOverlap
(
reliable_scene
,
// boolean [] reliable_ref_tiles,
center_offset_xy1
);
// double [] offset)
double
[]
lma_rms
=
new
double
[
clt_parameters
.
imp
.
eig_use
?
6
:
4
];
// [2];
TpTask
[][]
tp_tasks_rel_ref
=
new
TpTask
[
2
][];
double
[][]
rel_xyzatr
=
adjustDiffPairsLMAInterscene
(
// compare two scenes, first may be reference, use motion blur
...
...
@@ -3504,9 +4066,9 @@ public class Interscene {
pXpYD_ref
,
// double [][] pXpYD_ref, // should be se or at least double [num_tiles][] if tp_tasks_ref[0] == null
// will be recalculated when tp_tasks_ref[0] == null, but for reference frame
fpn_pairs
[
ipair
][
1
],
// int nscene0, // may be == ref_index
fpn_pairs
[
ipair
][
0
],
// int nscene1, // compares to nscene0
fpn_pairs
[
ipair
][
0
],
// int nscene1, // compares to nscene0
interscene_ref_disparity
,
// double [] ref_disparity, // null or alternative reference disparity
reliable_ref
,
// boolean [] reliable_ref, // null or bitmask of reliable reference tiles
reliable_
scene
,
// reliable_
ref, // boolean [] reliable_ref, // null or bitmask of reliable reference tiles
false
,
// boolean smooth_disparity, // smooth disparity (according to clt_parameters)+update reliable_ref if true
scenes_xyzatr
[
fpn_pairs
[
ipair
][
1
]],
// double [][] scene0_xyzatr,
scenes_xyzatr
[
fpn_pairs
[
ipair
][
0
]],
// double [][] scene1_xyzatr,
...
...
@@ -3560,6 +4122,13 @@ public class Interscene {
}
}
if
(
reliables
!=
null
)
{
quadCLTs
[
ref_index
].
saveReliables
(
quadCLTs
,
// QuadCLTCPU [] quadCLTs,
reliables
,
// boolean [][] reliables);
"-readjust-"
+
quadCLTs
[
ref_index
].
getNumOrient
());
// String suffix)
}
boolean
test_adjust1
=
debugLevel
>
1000
;
if
(
test_adjust1
)
{
int
[]
test_pair
=
{
0
,
ref_index
};
...
...
@@ -3685,7 +4254,7 @@ public class Interscene {
int
ers_mode
,
// 0 - keep, 1 - set from velocity, 2 - set from IMS
boolean
test_motion_blur
,
int
debugLevel
)
{
{
// manually set test_motion_blur here
// boolean copy_pull_current = clt_parameters.imp.copy_pull_current; //false; // true;
boolean
restore_imu
=
clt_parameters
.
imp
.
restore_imu
;
//false; // restore imu omega-az and omega-tl, freeze ERS, adjust X,Y,Z,Az,Tl,Rl
boolean
lock_position
=
true
;
// clt_parameters.imp.lock_position;
...
...
src/main/java/com/elphel/imagej/tileprocessor/IntersceneMatchParameters.java
View file @
cfbcc5e2
...
...
@@ -599,12 +599,13 @@ min_str_neib_fpn 0.35
// Detect initial match
public
boolean
use_combo_reliable
=
true
;
// use combo dsi if available for rel
ai
ble tiles
public
boolean
use_combo_reliable
=
true
;
// use combo dsi if available for rel
ia
ble tiles
public
boolean
ref_need_lma
=
true
;
// need LMA output for reliable tiles (no combo available)
public
boolean
ref_need_lma_combo
=
true
;
// need LMA output for reliable tiles (when combo is available)
public
double
min_ref_str
=
0.33
;
// 0.22; // For orientations: use only tiles of the reference scene DSI_MAIN is stronger
public
double
min_ref_str_lma
=
0.8
;
// 0.22; // For orientations: use only tiles of the reference scene DSI_MAIN is stronger
public
double
min_ref_frac
=
0.2
;
// 0.22; if fraction number of reliable tiles is less than this, use best possible
public
boolean
save_reliables
=
true
;
// save reliable tiles as a multi-slice image
// was overwritten in code to always be true ****
public
boolean
ref_smooth
=
true
;
// false; // smooth reference disparity for initial matching
...
...
@@ -2226,6 +2227,8 @@ min_str_neib_fpn 0.35
"Match only tiles where INTER-INTRA-LMA is stronger than that (and has LMA)."
);
gd
.
addNumericField
(
"DSI_MAIN minimal fraction"
,
this
.
min_ref_frac
,
5
,
7
,
""
,
"If relative number of the reliable tiles is less than this - use this best fraction."
);
gd
.
addCheckbox
(
"Save reliable tiles as a multi-slice image"
,
this
.
save_reliables
,
"Debug feature - which tiles where used for each scene"
);
gd
.
addMessage
(
"Smooth reference disparity for initial matching"
);
gd
.
addCheckbox
(
"Smooth reference disparity"
,
this
.
ref_smooth
,
...
...
@@ -3865,6 +3868,8 @@ min_str_neib_fpn 0.35
this
.
min_ref_str
=
gd
.
getNextNumber
();
this
.
min_ref_str_lma
=
gd
.
getNextNumber
();
this
.
min_ref_frac
=
gd
.
getNextNumber
();
this
.
save_reliables
=
gd
.
getNextBoolean
();
this
.
ref_smooth
=
gd
.
getNextBoolean
();
ref_smooth_always
=
gd
.
getNextBoolean
();
this
.
ref_sigma
=
gd
.
getNextNumber
();
...
...
@@ -5065,6 +5070,7 @@ min_str_neib_fpn 0.35
properties
.
setProperty
(
prefix
+
"min_ref_str"
,
this
.
min_ref_str
+
""
);
// double
properties
.
setProperty
(
prefix
+
"min_ref_str_lma"
,
this
.
min_ref_str_lma
+
""
);
// double
properties
.
setProperty
(
prefix
+
"min_ref_frac"
,
this
.
min_ref_frac
+
""
);
// double
properties
.
setProperty
(
prefix
+
"save_reliables"
,
this
.
save_reliables
+
""
);
// boolean
properties
.
setProperty
(
prefix
+
"ref_smooth"
,
this
.
ref_smooth
+
""
);
// boolean
properties
.
setProperty
(
prefix
+
"ref_smooth_always"
,
this
.
ref_smooth_always
+
""
);
// boolean
...
...
@@ -6205,6 +6211,7 @@ min_str_neib_fpn 0.35
if
(
properties
.
getProperty
(
prefix
+
"min_ref_str"
)!=
null
)
this
.
min_ref_str
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"min_ref_str"
));
if
(
properties
.
getProperty
(
prefix
+
"min_ref_str_lma"
)!=
null
)
this
.
min_ref_str_lma
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"min_ref_str_lma"
));
if
(
properties
.
getProperty
(
prefix
+
"min_ref_frac"
)!=
null
)
this
.
min_ref_frac
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"min_ref_frac"
));
if
(
properties
.
getProperty
(
prefix
+
"save_reliables"
)!=
null
)
this
.
save_reliables
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"save_reliables"
));
if
(
properties
.
getProperty
(
prefix
+
"ref_smooth"
)!=
null
)
this
.
ref_smooth
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"ref_smooth"
));
if
(
properties
.
getProperty
(
prefix
+
"ref_smooth_always"
)!=
null
)
this
.
ref_smooth_always
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"ref_smooth_always"
));
...
...
@@ -7358,6 +7365,7 @@ min_str_neib_fpn 0.35
imp
.
min_ref_str
=
this
.
min_ref_str
;
imp
.
min_ref_str_lma
=
this
.
min_ref_str_lma
;
imp
.
min_ref_frac
=
this
.
min_ref_frac
;
imp
.
save_reliables
=
this
.
save_reliables
;
imp
.
ref_smooth
=
this
.
ref_smooth
;
imp
.
ref_smooth_always
=
this
.
ref_smooth_always
;
...
...
src/main/java/com/elphel/imagej/tileprocessor/OpticalFlow.java
View file @
cfbcc5e2
...
...
@@ -5806,6 +5806,7 @@ public class OpticalFlow {
boolean
lma_use_Z
=
clt_parameters
.
imp
.
lma_use_Z
;
// true; // lpf x and y, re-adjust X,Y,Z,A,T,R with pull for X,Y. Disables
boolean
lma_use_R
=
clt_parameters
.
imp
.
lma_use_R
;
// true; // lpf x and y, re-adjust X,Y,Z,A,T,R with pull for X,Y. Disables
boolean
ers_from_ims
=
true
;
// false; // change later
int
ers_mode
=
0
;
// keep
// with IMS it is already set during initial orientation. In non-IMS mode
if
(!
ers_from_ims
&&
(
master_CLT
.
getNumOrient
()
<
2
))
{
...
...
@@ -5849,6 +5850,7 @@ public class OpticalFlow {
boolean
lma_use_AT
=
(
readjust_xy_ims
||
lpf_xy
);
if
(
clt_parameters
.
imp
.
air_mode_en
)
{
readjust_xy_ims
=
false
;
int
min_adjust_atr
=
2
;
if
(
master_CLT
.
getNumOrient
()
<
min_adjust_atr
)
{
disable_ers
=
true
;
...
...
src/main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java
View file @
cfbcc5e2
...
...
@@ -144,6 +144,8 @@ public class QuadCLTCPU {
public
static
final
String
CENTER_FPN_SUFFIX
=
"-FPN"
;
public
static
final
String
CENTER_ROWCOL_SUFFIX
=
"-ROWCOL"
;
// Scale estimated overlap before masking out folded pixels to account for rotations and distortions
public
static
final
double
RELIABLE_SCALE
=
1.2
;
// public GPUTileProcessor.GpuQuad gpuQuad = null;
...
...
@@ -2056,8 +2058,69 @@ public class QuadCLTCPU {
return
offs_avg
;
}
public
double
[]
estimateCenterShiftXY
(
double
[][]
xyzatr0
,
double
[][]
xyzatr1
,
double
average_z
,
boolean
rectilinear
)
{
double
[][]
xyzatr0_a
=
new
double
[][]
{
xyzatr0
[
0
].
clone
(),
xyzatr0
[
1
].
clone
()};
// debugging
double
[][]
xyzatr1_a
=
new
double
[][]
{
xyzatr1
[
0
].
clone
(),
xyzatr1
[
1
].
clone
()};
ErsCorrection
ers
=
getErsCorrection
();
double
disp_avg
=
ers
.
getDisparityFromZ
(
average_z
);
int
[]
wh
=
ers
.
getSensorWH
();
double
[]
xy
=
{
0.5
*
wh
[
0
],
0.5
*
wh
[
1
]};
double
[]
pXpYD
=
ers
.
getImageCoordinatesERS
(
null
,
// QuadCLT cameraQuadCLT, // camera station that got image to be to be matched
xy
[
0
],
// double px, // pixel coordinate X in the reference view
xy
[
1
],
// double py, // pixel coordinate Y in the reference view
disp_avg
,
// double disparity, // this reference disparity
!
rectilinear
,
// boolean distortedView, // This camera view is distorted (diff.rect), false - rectilinear
xyzatr0_a
[
0
],
// double [] reference_xyz, // this view position in world coordinates (typically zero3)
xyzatr0_a
[
1
],
// double [] reference_atr, // this view orientation relative to world frame (typically zero3)
!
rectilinear
,
// boolean distortedCamera, // camera view is distorted (false - rectilinear)
xyzatr1_a
[
0
],
// double [] camera_xyz, // camera center in world coordinates
xyzatr1_a
[
1
],
// double [] camera_atr, // camera orientation relative to world frame
OpticalFlow
.
LINE_ERR
);
// double line_err); // threshold error in scan lines (1.0)
if
(
pXpYD
==
null
)
{
return
null
;
}
else
{
// return new double [] {pXpYD[0]-xy[0],pXpYD[1]-xy[1]};
return
new
double
[]
{
xy
[
0
]-
pXpYD
[
0
],
xy
[
1
]-
pXpYD
[
1
]};
}
}
public
boolean
[]
maskByOverlap
(
boolean
[]
reliable_ref_tiles
,
double
[]
offset
)
{
boolean
[]
relable_scene_tiles
=
reliable_ref_tiles
.
clone
();
int
tile_size
=
getTileSize
();
int
tilesX
=
getTilesX
();
int
tilesY
=
getTilesY
();
int
width
=
getWidth
();
int
height
=
getHeight
();
double
s
=
0.5
*(
RELIABLE_SCALE
-
1
);
// > 0
int
xl
=
(
int
)
Math
.
round
((
offset
[
0
]
-
s
*
width
)/
tile_size
);
int
xr
=
(
int
)
Math
.
round
((
offset
[
0
]
+
(
s
+
1
)*
width
)/
tile_size
);
int
yt
=
(
int
)
Math
.
round
((
offset
[
1
]
-
s
*
height
)/
tile_size
);
int
yb
=
(
int
)
Math
.
round
((
offset
[
1
]
+
(
s
+
1
)*
height
)/
tile_size
);
if
(
yt
>
0
)
{
Arrays
.
fill
(
relable_scene_tiles
,
0
,
tilesX
*
yt
,
false
);
}
if
(
yb
<
tilesY
)
{
Arrays
.
fill
(
relable_scene_tiles
,
tilesX
*
yb
,
relable_scene_tiles
.
length
,
false
);
}
if
(
xl
>
0
)
{
for
(
int
i
=
0
;
i
<
tilesY
;
i
++)
{
Arrays
.
fill
(
relable_scene_tiles
,
tilesX
*
i
,
tilesX
*
i
+
xl
,
false
);
}
}
if
(
xr
<
tilesX
)
{
for
(
int
i
=
0
;
i
<
tilesY
;
i
++)
{
Arrays
.
fill
(
relable_scene_tiles
,
tilesX
*
i
+
xr
,
tilesX
*
(
i
+
1
),
false
);
//java.lang.IllegalArgumentException: fromIndex(9) > toIndex(0)
}
}
return
relable_scene_tiles
;
}
public
double
[][]
getGround
(
CLTParameters
clt_parameters
,
...
...
@@ -4412,9 +4475,9 @@ public class QuadCLTCPU {
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
);
return
;
}
public
double
[][]
readComboDSI
(
boolean
silent
)
{
double
[][]
combo_dsi
=
new
double
[
OpticalFlow
.
COMBO_DSN_TITLES
.
length
][];
for
(
int
indx:
new
int
[]{
INDEX_INTER_LMA
,
INDEX_INTER
})
{
...
...
@@ -4834,7 +4897,28 @@ public class QuadCLTCPU {
return
num_slices_read
;
}
public
void
saveReliables
(
QuadCLTCPU
[]
quadCLTs
,
boolean
[][]
reliables
,
String
suffix
)
{
String
[]
titles
=
new
String
[
quadCLTs
.
length
];
double
[][]
dreliables
=
new
double
[
reliables
.
length
][];
for
(
int
nscene
=
0
;
nscene
<
quadCLTs
.
length
;
nscene
++)
if
(
quadCLTs
[
nscene
]
!=
null
){
titles
[
nscene
]
=
quadCLTs
[
nscene
].
getImageName
();
if
(
reliables
[
nscene
]
!=
null
)
{
dreliables
[
nscene
]
=
new
double
[
reliables
[
nscene
].
length
];
for
(
int
i
=
0
;
i
<
reliables
[
nscene
].
length
;
i
++)
{
dreliables
[
nscene
][
i
]
=
reliables
[
nscene
][
i
]
?
1.0
:
0.0
;
}
}
}
saveDoubleArrayInModelDirectory
(
"-RELIABLE_TILES"
+
suffix
,
// String suffix,
titles
,
// String [] labels, // or null
dreliables
,
// double [][] data,
getTilesX
(),
// int width,
getTilesY
());
//int height)
}
public
void
saveInterProperties
(
// save properties for interscene processing (extrinsics, ers, ...)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment