Commit dd7e6ced authored by Andrey Filippov's avatar Andrey Filippov

Implemented multiple-reference (center and 1/4 and 3/4) global LMA pose

refining.
parent 6da5747a
......@@ -26,6 +26,8 @@ public class IntersceneGlobalLmaParameters {
public boolean glob_en;
public boolean glob_exit_after_test; // exit OpticalFlow.buildSeries() immediately after running, do not increment num_orient
public boolean glob_recalculate_quarter_refs; // force regeneration of quarter-reference DSI/INTER-INTRA-LMA files
public boolean glob_quarter_refs_sfm_only; // generate quarter-reference INTER-INTRA-LMA using SfM-only (no pose LMA updates)
public int glob_solver_mode; // 0 - current sparse global refine, 1 - classic LMA-structure implementation
public boolean [] param_sel;
public double [] param_regweights;
......@@ -53,9 +55,11 @@ public class IntersceneGlobalLmaParameters {
public int glob_center_pair_weight_mode;
public IntersceneGlobalLmaParameters() {
glob_en = true;
glob_exit_after_test = true; // TODO: change default to false when debugging is over
glob_solver_mode = GLOB_SOLVER_SPARSE_BANDED;
glob_en = true;
glob_exit_after_test = true; // TODO: change default to false when debugging is over
glob_recalculate_quarter_refs = false;
glob_quarter_refs_sfm_only = true;
glob_solver_mode = GLOB_SOLVER_SPARSE_BANDED;
param_sel = new boolean [ErsCorrection.DP_XYZATR.length];
param_regweights = new double [ErsCorrection.DP_XYZATR.length];
param_lpf = new double [ErsCorrection.DP_XYZATR.length];
......@@ -93,6 +97,10 @@ public class IntersceneGlobalLmaParameters {
"Use global LMA for adjusting scenes poses." );
gd.addCheckbox("Exit after Global LMA (debug mode)", this.glob_exit_after_test,
"exit OpticalFlow.buildSeries() immediately after running, do not increment num_orient enabling re-running next time");
gd.addCheckbox("Recalculate quarter refs each run (debug)", this.glob_recalculate_quarter_refs,
"Force regeneration of quarter-reference -DSI_MAIN and -INTER-INTRA-LMA before Global LMA.");
gd.addCheckbox("Quarter refs use SfM-only generation", this.glob_quarter_refs_sfm_only,
"For quarter references, run scanSfmIMS disparity refinement without per-scene pose LMA adjustment.");
gd.addNumericField("Global LMA solver mode (0/1)", this.glob_solver_mode, 0,3,"",
"0: current sparse/banded global solver, 1: classic LMA-structure global solver.");
gd.addStringField ("Select XYZATR parameters to fit", IntersceneMatchParameters.booleansToString(this.param_sel,2), 40,
......@@ -142,13 +150,15 @@ public class IntersceneGlobalLmaParameters {
"Display debug hyperstack in ImageJ UI.");
gd.addCheckbox("Save only initial+final CSV", this.glob_save_initial_final_only,
"Do not save intermediate outer-loop TIFF/CSV, save only combined initial+final CSV.");
gd.addNumericField("Center pair weight mode (0/1/2)", this.glob_center_pair_weight_mode, 0,3,"",
"0: all pairs enabled, 1: disable center +/-1 pairs, 2: disable center +/-1,+/-2 pairs.");
gd.addNumericField("Center pair weight mode (>=0)", this.glob_center_pair_weight_mode, 0,3,"",
"0: all pairs enabled, N>0: disable center-reference pairs with |scene-center| <= N.");
}
public void dialogAnswers(GenericJTabbedDialog gd) {
this.glob_en = gd.getNextBoolean();
this.glob_exit_after_test = gd.getNextBoolean();
this.glob_solver_mode = clampSolverMode((int) gd.getNextNumber());
this.glob_en = gd.getNextBoolean();
this.glob_exit_after_test = gd.getNextBoolean();
this.glob_recalculate_quarter_refs = gd.getNextBoolean();
this.glob_quarter_refs_sfm_only = gd.getNextBoolean();
this.glob_solver_mode = clampSolverMode((int) gd.getNextNumber());
this.param_sel = IntersceneMatchParameters.StringToBooleans(gd.getNextString(), this.param_sel);
this.param_regweights = IntersceneMatchParameters.StringToDoubles(gd.getNextString(), this.param_regweights);
this.param_lpf = IntersceneMatchParameters.StringToDoubles(gd.getNextString(), this.param_lpf);
......@@ -179,14 +189,13 @@ public class IntersceneGlobalLmaParameters {
if (this.glob_center_pair_weight_mode < 0) {
this.glob_center_pair_weight_mode = 0;
}
if (this.glob_center_pair_weight_mode > 2) {
this.glob_center_pair_weight_mode = 2;
}
}
public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"glob_en", this.glob_en+"");
properties.setProperty(prefix+"glob_exit_after_test", this.glob_exit_after_test+"");
properties.setProperty(prefix+"glob_recalculate_quarter_refs", this.glob_recalculate_quarter_refs+"");
properties.setProperty(prefix+"glob_quarter_refs_sfm_only", this.glob_quarter_refs_sfm_only+"");
properties.setProperty(prefix+"glob_solver_mode", this.glob_solver_mode+"");
properties.setProperty(prefix+"param_sel", IntersceneMatchParameters.booleansToString(this.param_sel,2));
properties.setProperty(prefix+"param_regweights",IntersceneMatchParameters.doublesToString(this.param_regweights));
......@@ -218,6 +227,8 @@ public class IntersceneGlobalLmaParameters {
public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"glob_en")!=null) this.glob_en=Boolean.parseBoolean(properties.getProperty(prefix+"glob_en"));
if (properties.getProperty(prefix+"glob_exit_after_test")!=null) this.glob_exit_after_test=Boolean.parseBoolean(properties.getProperty(prefix+"glob_exit_after_test"));
if (properties.getProperty(prefix+"glob_recalculate_quarter_refs")!=null) this.glob_recalculate_quarter_refs=Boolean.parseBoolean(properties.getProperty(prefix+"glob_recalculate_quarter_refs"));
if (properties.getProperty(prefix+"glob_quarter_refs_sfm_only")!=null) this.glob_quarter_refs_sfm_only=Boolean.parseBoolean(properties.getProperty(prefix+"glob_quarter_refs_sfm_only"));
if (properties.getProperty(prefix+"glob_solver_mode")!=null) this.glob_solver_mode=Integer.parseInt(properties.getProperty(prefix+"glob_solver_mode"));
this.glob_solver_mode = clampSolverMode(this.glob_solver_mode);
if (properties.getProperty(prefix+"param_sel")!=null) this.param_sel= IntersceneMatchParameters.StringToBooleans(properties.getProperty(prefix+"param_sel"),this.param_sel);
......@@ -246,7 +257,6 @@ public class IntersceneGlobalLmaParameters {
if (properties.getProperty(prefix+"glob_save_initial_final_only")!=null) this.glob_save_initial_final_only=Boolean.parseBoolean(properties.getProperty(prefix+"glob_save_initial_final_only"));
if (properties.getProperty(prefix+"glob_center_pair_weight_mode")!=null) this.glob_center_pair_weight_mode=Integer.parseInt(properties.getProperty(prefix+"glob_center_pair_weight_mode"));
if (this.glob_center_pair_weight_mode < 0) this.glob_center_pair_weight_mode = 0;
if (this.glob_center_pair_weight_mode > 2) this.glob_center_pair_weight_mode = 2;
}
@Override
......@@ -254,6 +264,8 @@ public class IntersceneGlobalLmaParameters {
IntersceneGlobalLmaParameters iglp = new IntersceneGlobalLmaParameters();
iglp.glob_en = this.glob_en;
iglp.glob_exit_after_test = this.glob_exit_after_test;
iglp.glob_recalculate_quarter_refs = this.glob_recalculate_quarter_refs;
iglp.glob_quarter_refs_sfm_only = this.glob_quarter_refs_sfm_only;
iglp.glob_solver_mode = this.glob_solver_mode;
iglp.param_sel = this.param_sel.clone();
iglp.param_regweights = this.param_regweights.clone();
......
......@@ -2,41 +2,165 @@ package com.elphel.imagej.tileprocessor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicInteger;
import com.elphel.imagej.cameras.CLTParameters;
import com.elphel.imagej.gpu.TpTask;
import Jama.Matrix;
/**
* Classic-LMA structured global refinement path.
*
* <p>Phase-1 keeps numeric behavior stable by delegating the actual solve to
* {@link IntersceneGlobalRefine}, while this class owns the classic LMA structure
* ({@code prepareLMA/getFxDerivs/getYminusFxWeighted/lmaStep/runLma}) for incremental migration.
* <p>This class keeps explicit LMA structure
* ({@code prepareLMA/getFxDerivs/getYminusFxWeighted/getWJtJlambda/lmaStep/runLma})
* and assembles one combined residual/Jacobian consisting of correlation, LPF and pull terms.
*/
public class IntersceneGlobalLmaRefine {
private static final int[] SCENE_POSE_PARAM_ORDER = ErsCorrection.DP_XYZATR.clone();
private static final int[] SCENE_RATE_ANG_PAR_INDICES = {
ErsCorrection.DP_DSVAZ,
ErsCorrection.DP_DSVTL,
ErsCorrection.DP_DSVRL};
private static final int[] SCENE_RATE_LIN_PAR_INDICES = {
ErsCorrection.DP_DSVX,
ErsCorrection.DP_DSVY,
ErsCorrection.DP_DSVZ};
private static final int[] REF_RATE_ANG_PAR_INDICES = {
ErsCorrection.DP_DVAZ,
ErsCorrection.DP_DVTL,
ErsCorrection.DP_DVRL};
private static final int[] REF_RATE_LIN_PAR_INDICES = {
ErsCorrection.DP_DVX,
ErsCorrection.DP_DVY,
ErsCorrection.DP_DVZ};
private static final double MIN_DIAG = 1.0e-12;
private static final double DEFAULT_PULL_WEIGHT = 1.0e-6;
private static final double DEFAULT_DT = 1.0 / 60.0;
private static final class PairFactor {
int sceneIndex;
int refSceneIndex;
double pairWeight;
PairFactor(
final int sceneIndex,
final int refSceneIndex,
final double pairWeight) {
this.sceneIndex = sceneIndex;
this.refSceneIndex = refSceneIndex;
this.pairWeight = pairWeight;
}
}
private static final class PairObservation {
int sceneIndex;
int refSceneIndex;
double pairWeight = 1.0;
double[][] centers = null;
double[][] eigen = null;
double[][] vectorXys = null;
boolean[] reliableRef = null;
int yBase = 0;
int wBase = 0;
}
private static final class ObservationCache {
ArrayList<PairObservation> observations = new ArrayList<PairObservation>();
double[] yVector = null;
double[] wVector = null;
int tilesPerPair = 0;
int solvedPairs = 0;
int failedPairs = 0;
}
private static final class RefGpuData {
int refSceneIndex = -1;
double[][] pXpYD = null;
TpTask[] tasks = null;
boolean[] reliableMask = null;
}
private static final class RateTerm {
int sceneIndex;
double coeff;
RateTerm(
final int sceneIndex,
final double coeff) {
this.sceneIndex = sceneIndex;
this.coeff = coeff;
}
}
private static final class VectorTerm {
int vectorIndex;
double coeff;
VectorTerm(
final int vectorIndex,
final double coeff) {
this.vectorIndex = vectorIndex;
this.coeff = coeff;
}
}
private static final class CorrelationPairContext {
PairObservation obs;
int[] localParamIndices = new int[0];
ArrayList<VectorTerm>[] vectorTerms = null;
int[] validTiles = new int[0];
double[][][] eigTrans = null;
double[] yRows = new double[0];
double[] rawWeights = new double[0];
int rowBase = 0;
}
private static final class ClassicState {
int[] activePoseParams = new int[0];
int[] vectorSceneIndices = new int[0];
int[] vectorParamIndices = new int[0];
HashMap<Long, Integer> vectorIndexBySceneParam = new HashMap<Long, Integer>();
double[] parameterVector = new double[0];
double[] parameterInitial = new double[0];
double[] parameterPull = new double[0];
int correlationRows = 0;
int pullBase = 0;
int pullRows = 0;
int lpfBase = 0;
int[] lpfVar = new int[0];
int[] lpfPrevVar = new int[0];
int[] lpfNextVar = new int[0];
double[] lpfPrevFixed = new double[0];
double[] lpfNextFixed = new double[0];
ArrayList<CorrelationPairContext> correlationPairs = new ArrayList<CorrelationPairContext>();
double[][][] rateSourceScenes = null;
boolean includeRateChain = true;
double[] yVector = new double[0];
double[] weights = new double[0];
double[][] lastJt = null;
double[] lastYminusFx = null;
double[] lastRms = null;
double[] initialRms = null;
double lastMaxDelta = Double.NaN;
int acceptedSteps = 0;
int attemptedSteps = 0;
void clearLinearization() {
lastJt = null;
lastYminusFx = null;
lastRms = null;
initialRms = null;
lastMaxDelta = Double.NaN;
acceptedSteps = 0;
attemptedSteps = 0;
}
}
......@@ -58,6 +182,10 @@ public class IntersceneGlobalLmaRefine {
private final IntersceneGlobalRefine.Options options;
private final ClassicState classicState = new ClassicState();
private double[] refDisparity = null;
private double[][] pXpYDCenter = null;
private double[] sceneTimes = null;
private IntersceneGlobalLmaRefine(
final CLTParameters cltParameters,
final QuadCLT[] quadCLTs,
......@@ -163,7 +291,6 @@ public class IntersceneGlobalLmaRefine {
}
}
@SuppressWarnings("unused")
private static void setScenePoseParameter(
final double[][] scenePose,
final int dpIndex,
......@@ -208,6 +335,32 @@ public class IntersceneGlobalLmaRefine {
return values[index];
}
private static long getSceneParamKey(
final int sceneIndex,
final int dpIndex) {
return (((long) sceneIndex) << 32) ^ (dpIndex & 0xffffffffL);
}
private static int[] getParameterIndices(final boolean[] mask) {
if (mask == null) {
return new int[0];
}
int n = 0;
for (int i = 0; i < mask.length; i++) {
if (mask[i]) {
n++;
}
}
final int[] out = new int[n];
int indx = 0;
for (int i = 0; i < mask.length; i++) {
if (mask[i]) {
out[indx++] = i;
}
}
return out;
}
private int[] buildActivePoseParameters() {
final ArrayList<Integer> active = new ArrayList<Integer>();
for (final int dpIndex : SCENE_POSE_PARAM_ORDER) {
......@@ -247,6 +400,99 @@ public class IntersceneGlobalLmaRefine {
return out;
}
private static double[][][] cloneScenePoses(final double[][][] scenes_xyzatr) {
if (scenes_xyzatr == null) {
return null;
}
final double[][][] copy = new double[scenes_xyzatr.length][][];
for (int i = 0; i < scenes_xyzatr.length; i++) {
if (scenes_xyzatr[i] == null) {
continue;
}
copy[i] = new double[scenes_xyzatr[i].length][];
for (int j = 0; j < scenes_xyzatr[i].length; j++) {
if (scenes_xyzatr[i][j] != null) {
copy[i][j] = scenes_xyzatr[i][j].clone();
}
}
}
return copy;
}
private void buildLpfRows() {
final int nvars = classicState.parameterVector.length;
final ArrayList<Integer> lpfVar = new ArrayList<Integer>();
final ArrayList<Integer> lpfPrevVar = new ArrayList<Integer>();
final ArrayList<Integer> lpfNextVar = new ArrayList<Integer>();
final ArrayList<Double> lpfPrevFixed = new ArrayList<Double>();
final ArrayList<Double> lpfNextFixed = new ArrayList<Double>();
for (int i = 0; i < nvars; i++) {
final int scene = classicState.vectorSceneIndices[i];
final int dpIndex = classicState.vectorParamIndices[i];
final double lpfControl = getArrayValue(paramLpf, dpIndex);
if (!(lpfControl > 0.0)) {
continue;
}
final int prevScene = scene - 1;
final int nextScene = scene + 1;
if ((prevScene < earliestScene) || (nextScene > lastScene)) {
continue;
}
int prevVar = -1;
int nextVar = -1;
double prevFixed = 0.0;
double nextFixed = 0.0;
final Integer prevIdx = classicState.vectorIndexBySceneParam.get(getSceneParamKey(
prevScene,
dpIndex));
if (prevIdx != null) {
prevVar = prevIdx.intValue();
} else if ((prevScene >= 0) && (prevScene < scenesXyzatr.length) && isPoseValid(scenesXyzatr[prevScene])) {
prevFixed = normalizeValue(getScenePoseParameter(
scenesXyzatr[prevScene],
dpIndex));
} else {
continue;
}
final Integer nextIdx = classicState.vectorIndexBySceneParam.get(getSceneParamKey(
nextScene,
dpIndex));
if (nextIdx != null) {
nextVar = nextIdx.intValue();
} else if ((nextScene >= 0) && (nextScene < scenesXyzatr.length) && isPoseValid(scenesXyzatr[nextScene])) {
nextFixed = normalizeValue(getScenePoseParameter(
scenesXyzatr[nextScene],
dpIndex));
} else {
continue;
}
lpfVar.add(Integer.valueOf(i));
lpfPrevVar.add(Integer.valueOf(prevVar));
lpfNextVar.add(Integer.valueOf(nextVar));
lpfPrevFixed.add(Double.valueOf(prevFixed));
lpfNextFixed.add(Double.valueOf(nextFixed));
}
classicState.pullRows = nvars;
classicState.lpfVar = new int[lpfVar.size()];
classicState.lpfPrevVar = new int[lpfVar.size()];
classicState.lpfNextVar = new int[lpfVar.size()];
classicState.lpfPrevFixed = new double[lpfVar.size()];
classicState.lpfNextFixed = new double[lpfVar.size()];
for (int i = 0; i < lpfVar.size(); i++) {
classicState.lpfVar[i] = lpfVar.get(i).intValue();
classicState.lpfPrevVar[i] = lpfPrevVar.get(i).intValue();
classicState.lpfNextVar[i] = lpfNextVar.get(i).intValue();
classicState.lpfPrevFixed[i] = lpfPrevFixed.get(i).doubleValue();
classicState.lpfNextFixed[i] = lpfNextFixed.get(i).doubleValue();
}
}
private void buildStateVector() {
classicState.activePoseParams = buildActivePoseParameters();
if (scenesXyzatr == null) {
......@@ -255,6 +501,17 @@ public class IntersceneGlobalLmaRefine {
classicState.parameterVector = new double[0];
classicState.parameterInitial = new double[0];
classicState.parameterPull = new double[0];
classicState.vectorIndexBySceneParam.clear();
classicState.pullRows = 0;
classicState.lpfVar = new int[0];
classicState.lpfPrevVar = new int[0];
classicState.lpfNextVar = new int[0];
classicState.lpfPrevFixed = new double[0];
classicState.lpfNextFixed = new double[0];
classicState.correlationRows = 0;
classicState.pullBase = 0;
classicState.lpfBase = 0;
classicState.correlationPairs.clear();
classicState.yVector = new double[0];
classicState.weights = new double[0];
classicState.clearLinearization();
......@@ -282,14 +539,14 @@ public class IntersceneGlobalLmaRefine {
classicState.parameterVector = new double[n];
classicState.parameterInitial = new double[n];
classicState.parameterPull = new double[n];
classicState.yVector = new double[n];
classicState.weights = new double[n];
classicState.vectorIndexBySceneParam.clear();
for (int i = 0; i < n; i++) {
final int scene = vectorSceneIndices.get(i);
final int dpIndex = vectorParamIndices.get(i);
classicState.vectorSceneIndices[i] = scene;
classicState.vectorParamIndices[i] = dpIndex;
classicState.vectorIndexBySceneParam.put(getSceneParamKey(scene, dpIndex), i);
final double current = normalizeValue(getScenePoseParameter(scenesXyzatr[scene], dpIndex));
double pull = current;
......@@ -298,17 +555,12 @@ public class IntersceneGlobalLmaRefine {
isPoseValid(scenesXyzatrPull[scene])) {
pull = normalizeValue(getScenePoseParameter(scenesXyzatrPull[scene], dpIndex));
}
final double regWeight = getArrayValue(paramRegweights, dpIndex);
final double lpfWeight = getArrayValue(paramLpf, dpIndex);
final double rawWeight = (regWeight > 0.0) ? regWeight : ((lpfWeight > 0.0) ? lpfWeight : 1.0);
classicState.parameterVector[i] = current;
classicState.parameterInitial[i] = current;
classicState.parameterPull[i] = pull;
classicState.yVector[i] = 0.0;
classicState.weights[i] = rawWeight;
}
classicState.weights = normalizeWeights(classicState.weights);
buildLpfRows();
classicState.clearLinearization();
}
......@@ -325,15 +577,339 @@ public class IntersceneGlobalLmaRefine {
}
}
private void applyVectorToScenes(final double[] vector) {
if (scenesXyzatr == null) {
return;
}
for (int i = 0; i < vector.length; i++) {
final int scene = classicState.vectorSceneIndices[i];
final int dpIndex = classicState.vectorParamIndices[i];
if ((scene < 0) || (scene >= scenesXyzatr.length) || !isPoseValid(scenesXyzatr[scene])) {
continue;
}
setScenePoseParameter(
scenesXyzatr[scene],
dpIndex,
normalizeValue(vector[i]));
}
}
private static double[][][] setEigenTransform(
final double eigMaxSqrt,
final double eigMinSqrt,
final double[][] eigen) {
if (eigen == null) {
return null;
}
final double[][][] transform = new double[eigen.length][][];
final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
final AtomicInteger ai = new AtomicInteger(0);
final double k0 = 1.0 / eigMaxSqrt;
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int iTile = ai.getAndIncrement(); iTile < eigen.length; iTile = ai.getAndIncrement()) {
if (eigen[iTile] == null) {
continue;
}
final double[][] am = {{eigen[iTile][0], eigen[iTile][1]}, {eigen[iTile][1], -eigen[iTile][0]}};
if (!Double.isNaN(am[0][0]) && !Double.isNaN(am[0][1])) {
transform[iTile] = new double[2][2];
for (int i = 0; i < 2; i++) {
final double k = Math.max(0, 1 / Math.max(eigMinSqrt, Math.sqrt(eigen[iTile][2 + i])) - k0);
for (int j = 0; j < 2; j++) {
transform[iTile][i][j] = k * am[i][j];
}
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
return transform;
}
private void buildCombinedRows(
final ObservationCache obsCache,
final int firstScene,
final int endScene,
final boolean[] activePoseScene,
final int debugLevel) {
classicState.correlationPairs.clear();
final ArrayList<Double> corrY = new ArrayList<Double>();
final ArrayList<Double> corrW = new ArrayList<Double>();
int corrRows = 0;
for (int iobs = 0; iobs < obsCache.observations.size(); iobs++) {
final PairObservation obs = obsCache.observations.get(iobs);
if (!(obs.pairWeight > 0.0) || (obs.vectorXys == null) || (obs.centers == null)) {
continue;
}
final int ivar = obs.sceneIndex - firstScene;
if ((ivar < 0) || (ivar >= activePoseScene.length) || !activePoseScene[ivar]) {
continue;
}
final boolean[] localMask = getLocalParamMaskForPair(
paramSelect,
obs.sceneIndex,
obs.refSceneIndex,
centerIndex,
disableErs);
final int[] localParamIndices = getParameterIndices(localMask);
if (localParamIndices.length == 0) {
continue;
}
@SuppressWarnings("unchecked")
final ArrayList<VectorTerm>[] vectorTerms = new ArrayList[localParamIndices.length];
for (int ilp = 0; ilp < localParamIndices.length; ilp++) {
vectorTerms[ilp] = mapLocalParameterToVectorTerms(
localParamIndices[ilp],
obs.sceneIndex,
obs.refSceneIndex,
centerIndex,
firstScene,
endScene,
activePoseScene,
classicState.rateSourceScenes,
classicState.includeRateChain);
}
final double[][][] eigTrans = setEigenTransform(
cltParameters.imp.eig_max_sqrt,
cltParameters.imp.eig_min_sqrt,
obs.eigen);
final ArrayList<Integer> validTileList = new ArrayList<Integer>();
final ArrayList<Double> yRows = new ArrayList<Double>();
final ArrayList<Double> wRows = new ArrayList<Double>();
final int nt = Math.min(obs.vectorXys.length, obs.centers.length);
for (int itile = 0; itile < nt; itile++) {
final double[] v = obs.vectorXys[itile];
final double[] center = obs.centers[itile];
if ((v == null) || (v.length < 3) || (center == null) || (center.length < 3)) {
continue;
}
final double w = v[2];
if (!(w > 0.0) || !Double.isFinite(w)) {
continue;
}
final double[][] tr = (eigTrans == null) ? null : eigTrans[itile];
if ((eigTrans != null) && (tr == null)) {
continue;
}
double y0 = v[0];
double y1 = v[1];
if (tr != null) {
final double ty0 = tr[0][0] * y0 + tr[0][1] * y1;
final double ty1 = tr[1][0] * y0 + tr[1][1] * y1;
y0 = ty0;
y1 = ty1;
}
validTileList.add(Integer.valueOf(itile));
yRows.add(Double.valueOf(y0));
yRows.add(Double.valueOf(y1));
wRows.add(Double.valueOf(w));
wRows.add(Double.valueOf(w));
}
if (validTileList.isEmpty()) {
continue;
}
final CorrelationPairContext cpc = new CorrelationPairContext();
cpc.obs = obs;
cpc.localParamIndices = localParamIndices;
cpc.vectorTerms = vectorTerms;
cpc.validTiles = new int[validTileList.size()];
for (int i = 0; i < cpc.validTiles.length; i++) {
cpc.validTiles[i] = validTileList.get(i).intValue();
}
cpc.eigTrans = eigTrans;
cpc.yRows = new double[yRows.size()];
for (int i = 0; i < cpc.yRows.length; i++) {
cpc.yRows[i] = yRows.get(i).doubleValue();
}
cpc.rawWeights = new double[wRows.size()];
for (int i = 0; i < cpc.rawWeights.length; i++) {
cpc.rawWeights[i] = wRows.get(i).doubleValue();
}
cpc.rowBase = corrRows;
corrRows += cpc.yRows.length;
classicState.correlationPairs.add(cpc);
for (int i = 0; i < cpc.yRows.length; i++) {
corrY.add(Double.valueOf(cpc.yRows[i]));
corrW.add(Double.valueOf(cpc.rawWeights[i]));
}
}
classicState.correlationRows = corrRows;
classicState.pullBase = corrRows;
classicState.lpfBase = classicState.pullBase + classicState.pullRows;
final int rows = classicState.lpfBase + classicState.lpfVar.length;
classicState.yVector = new double[rows];
final double[] rawWeights = new double[rows];
for (int i = 0; i < corrRows; i++) {
classicState.yVector[i] = corrY.get(i).doubleValue();
rawWeights[i] = corrW.get(i).doubleValue();
}
for (int i = 0; i < classicState.pullRows; i++) {
final int row = classicState.pullBase + i;
classicState.yVector[row] = 0.0;
final int dpIndex = classicState.vectorParamIndices[i];
final double regWeight = getArrayValue(paramRegweights, dpIndex);
rawWeights[row] = (regWeight > 0.0) ? (regWeight * regWeight) : DEFAULT_PULL_WEIGHT;
}
for (int i = 0; i < classicState.lpfVar.length; i++) {
final int row = classicState.lpfBase + i;
classicState.yVector[row] = 0.0;
final int iv = classicState.lpfVar[i];
final int dpIndex = classicState.vectorParamIndices[iv];
final double lpfControl = getArrayValue(paramLpf, dpIndex);
rawWeights[row] = (lpfControl > 0.0) ? (lpfControl * lpfControl) : 0.0;
}
classicState.weights = normalizeWeights(rawWeights);
if (debugLevel > -3) {
System.out.println(
"IntersceneGlobalLmaRefine: combined rows built, corrPairs=" + classicState.correlationPairs.size() +
", corrRows=" + classicState.correlationRows +
", pullRows=" + classicState.pullRows +
", lpfRows=" + classicState.lpfVar.length +
", totalRows=" + rows);
}
}
private boolean rebuildObservationRowsForOuter(final int debugLevel) {
if ((classicState.parameterVector == null) || (classicState.parameterVector.length == 0)) {
classicState.correlationPairs.clear();
classicState.correlationRows = 0;
classicState.pullBase = 0;
classicState.lpfBase = classicState.pullRows;
final int rows = classicState.pullRows + classicState.lpfVar.length;
classicState.yVector = new double[rows];
final double[] rawWeights = new double[rows];
for (int i = 0; i < classicState.pullRows; i++) {
final int dpIndex = classicState.vectorParamIndices[i];
final double regWeight = getArrayValue(paramRegweights, dpIndex);
rawWeights[i] = (regWeight > 0.0) ? (regWeight * regWeight) : DEFAULT_PULL_WEIGHT;
}
for (int i = 0; i < classicState.lpfVar.length; i++) {
final int iv = classicState.lpfVar[i];
final int dpIndex = classicState.vectorParamIndices[iv];
final double lpfControl = getArrayValue(paramLpf, dpIndex);
rawWeights[classicState.pullRows + i] = (lpfControl > 0.0) ? (lpfControl * lpfControl) : 0.0;
}
classicState.weights = normalizeWeights(rawWeights);
return true;
}
final int firstScene = Math.max(0, earliestScene);
final int endScene = Math.min(lastScene, quadCLTs.length - 1);
final int nvars = endScene - firstScene + 1;
final boolean[] activePoseScene = new boolean[nvars];
for (int nscene = firstScene; nscene <= endScene; nscene++) {
final int ivar = nscene - firstScene;
activePoseScene[ivar] = (nscene != centerIndex) &&
(quadCLTs[nscene] != null) &&
(scenesXyzatr[nscene] != null);
}
classicState.rateSourceScenes = options.freezeRateChainInInner ? cloneScenePoses(scenesXyzatr) : scenesXyzatr;
classicState.includeRateChain = !options.freezeRateChainInInner;
final ArrayList<PairFactor> pairFactors = buildPairFactors(
cltParameters,
quadCLTs,
scenesXyzatr,
activePoseScene,
firstScene,
endScene,
centerIndex,
options.minOffset,
debugLevel);
applyPairWeights(
pairFactors,
centerIndex,
options.centerPairWeightMode,
debugLevel);
final RefGpuData[] refGpuCache = new RefGpuData[nvars];
final double[] minMax = {options.minOffset, options.maxOffset, Double.NaN};
final ObservationCache obsCache = buildObservationCache(
cltParameters,
quadCLTs,
centerCLT,
centerIndex,
firstScene,
endScene,
scenesXyzatr,
sceneTimes,
pairFactors,
refDisparity,
pXpYDCenter,
reliableRef,
mbMaxGain,
minMax,
refGpuCache,
debugLevel);
if (obsCache.observations.isEmpty()) {
classicState.correlationPairs.clear();
classicState.correlationRows = 0;
classicState.pullBase = 0;
classicState.lpfBase = classicState.pullRows;
final int rows = classicState.pullRows + classicState.lpfVar.length;
classicState.yVector = new double[rows];
final double[] rawWeights = new double[rows];
for (int i = 0; i < classicState.pullRows; i++) {
final int dpIndex = classicState.vectorParamIndices[i];
final double regWeight = getArrayValue(paramRegweights, dpIndex);
rawWeights[i] = (regWeight > 0.0) ? (regWeight * regWeight) : DEFAULT_PULL_WEIGHT;
}
for (int i = 0; i < classicState.lpfVar.length; i++) {
final int iv = classicState.lpfVar[i];
final int dpIndex = classicState.vectorParamIndices[iv];
final double lpfControl = getArrayValue(paramLpf, dpIndex);
rawWeights[classicState.pullRows + i] = (lpfControl > 0.0) ? (lpfControl * lpfControl) : 0.0;
}
classicState.weights = normalizeWeights(rawWeights);
return false;
}
buildCombinedRows(
obsCache,
firstScene,
endScene,
activePoseScene,
debugLevel);
return true;
}
private void prepareLMA(final int debugLevel) {
buildStateVector();
applyVectorToScenes(classicState.parameterVector);
final int firstScene = Math.max(0, earliestScene);
final int endScene = Math.min(lastScene, quadCLTs.length - 1);
if ((endScene >= firstScene) && (centerCLT != null)) {
refDisparity = (centerDisparity != null) ? centerDisparity :
centerCLT.getDLS()[cltParameters.imp.use_lma_dsi ? 1 : 0];
pXpYDCenter = OpticalFlow.transformToScenePxPyD(
null,
refDisparity,
Interscene.ZERO3,
Interscene.ZERO3,
centerCLT,
centerCLT);
sceneTimes = getSceneTimes(
quadCLTs,
firstScene,
endScene);
}
rebuildObservationRowsForOuter(debugLevel);
if (debugLevel > -4) {
System.out.println(
"IntersceneGlobalLmaRefine: prepareLMA() classic scaffold active; " +
"IntersceneGlobalLmaRefine: prepareLMA() classic LMA active; " +
"unknowns=" + classicState.parameterVector.length +
", rows=" + classicState.yVector.length +
", corrRows=" + classicState.correlationRows +
", pullRows=" + classicState.pullRows +
", lpfRows=" + classicState.lpfVar.length +
", activePoseParams=" + Arrays.toString(classicState.activePoseParams) +
", center=" + centerIndex +
", range=[" + earliestScene + "," + lastScene + "]");
", range=[" + earliestScene + "," + lastScene + "]" +
", includeRateChain=" + classicState.includeRateChain);
}
}
......@@ -341,25 +917,202 @@ public class IntersceneGlobalLmaRefine {
final double[] vector,
final double[][] jt,
final int debugLevel) {
final int n = vector.length;
final double[] fx = new double[n];
applyVectorToScenes(vector);
final int nvars = vector.length;
final int nrows = classicState.yVector.length;
final double[] fx = new double[nrows];
if (jt != null) {
for (int p = 0; p < n; p++) {
if ((jt[p] == null) || (jt[p].length != n)) {
jt[p] = new double[n];
for (int p = 0; p < nvars; p++) {
if ((jt[p] == null) || (jt[p].length != nrows)) {
jt[p] = new double[nrows];
}
Arrays.fill(jt[p], 0.0);
}
}
for (int i = 0; i < n; i++) {
final double pull = classicState.parameterPull[i];
fx[i] = vector[i] - pull;
// Correlation block: one multithreaded tile loop per pair.
for (int ipair = 0; ipair < classicState.correlationPairs.size(); ipair++) {
final CorrelationPairContext cpc = classicState.correlationPairs.get(ipair);
final PairObservation obs = cpc.obs;
if ((obs == null) || (obs.centers == null) || (cpc.validTiles.length == 0)) {
continue;
}
final int nscene = obs.sceneIndex;
final int refScene = obs.refSceneIndex;
if ((nscene < 0) || (nscene >= quadCLTs.length) || (quadCLTs[nscene] == null) ||
(refScene < 0) || (refScene >= quadCLTs.length) || (quadCLTs[refScene] == null)) {
continue;
}
final double[][] poseNow = getScenePose(
scenesXyzatr,
nscene,
centerIndex);
final double[][] refPose = getScenePose(
scenesXyzatr,
refScene,
centerIndex);
final double[][] sceneRates = getSceneRates(
nscene,
classicState.rateSourceScenes,
quadCLTs,
sceneTimes,
Math.max(0, earliestScene),
Math.min(lastScene, quadCLTs.length - 1),
centerIndex);
final double[][] refRates = getSceneRates(
refScene,
classicState.rateSourceScenes,
quadCLTs,
sceneTimes,
Math.max(0, earliestScene),
Math.min(lastScene, quadCLTs.length - 1),
centerIndex);
final ErsCorrection ersRef = quadCLTs[refScene].getErsCorrection();
final ErsCorrection ersScene = quadCLTs[nscene].getErsCorrection();
final double[] refWatrBak = ersRef.ers_watr_center_dt.clone();
final double[] refWxyzBak = ersRef.ers_wxyz_center_dt.clone();
final double[] sceneWatrBak = ersScene.ers_watr_center_dt.clone();
final double[] sceneWxyzBak = ersScene.ers_wxyz_center_dt.clone();
try {
ersRef.ers_watr_center_dt = refRates[1].clone();
ersRef.ers_wxyz_center_dt = refRates[0].clone();
ersScene.ers_watr_center_dt = sceneRates[1].clone();
ersScene.ers_wxyz_center_dt = sceneRates[0].clone();
ersScene.setupERS();
ersRef.setupERS();
final Matrix[] referenceMatricesInverse = ErsCorrection.getInterRotDeriveMatrices(
refPose[1],
true);
final Matrix[] sceneMatricesInverse = ErsCorrection.getInterRotDeriveMatrices(
poseNow[1],
true);
final Matrix sceneRotMatrix = ErsCorrection.getInterRotDeriveMatrices(
poseNow[1],
false)[0];
final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
final AtomicInteger ai = new AtomicInteger(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int ilocal = ai.getAndIncrement(); ilocal < cpc.validTiles.length; ilocal = ai.getAndIncrement()) {
final int itile = cpc.validTiles[ilocal];
if ((itile < 0) || (itile >= obs.centers.length) || (obs.centers[itile] == null) || (obs.centers[itile].length < 3)) {
continue;
}
final double[] center = obs.centers[itile];
final boolean isInfinity = center[2] < 0.0;
final double[][] derivParams = ersRef.getDPxSceneDParameters(
ersScene,
true,
isInfinity,
center,
refPose[0],
poseNow[0],
referenceMatricesInverse,
sceneMatricesInverse,
sceneRotMatrix,
debugLevel);
if ((derivParams == null) || (derivParams.length == 0) || (derivParams[0] == null) || (derivParams[0].length < 2)) {
continue;
}
double fx0 = derivParams[0][0];
double fx1 = derivParams[0][1];
final double[][] tr = (cpc.eigTrans == null) ? null : cpc.eigTrans[itile];
if (tr != null) {
final double t0 = tr[0][0] * fx0 + tr[0][1] * fx1;
final double t1 = tr[1][0] * fx0 + tr[1][1] * fx1;
fx0 = t0;
fx1 = t1;
}
final int row0 = cpc.rowBase + 2 * ilocal;
final int row1 = row0 + 1;
fx[row0] = fx0;
fx[row1] = fx1;
if (jt != null) {
for (int ip = 0; ip < cpc.localParamIndices.length; ip++) {
final int parIndex = cpc.localParamIndices[ip];
final int dindx = parIndex + 1;
if ((dindx < 0) || (dindx >= derivParams.length) || (derivParams[dindx] == null) || (derivParams[dindx].length < 2)) {
continue;
}
double j0 = derivParams[dindx][0];
double j1 = derivParams[dindx][1];
if (tr != null) {
final double tj0 = tr[0][0] * j0 + tr[0][1] * j1;
final double tj1 = tr[1][0] * j0 + tr[1][1] * j1;
j0 = tj0;
j1 = tj1;
}
final ArrayList<VectorTerm> vt = cpc.vectorTerms[ip];
for (int it = 0; it < vt.size(); it++) {
final VectorTerm term = vt.get(it);
jt[term.vectorIndex][row0] += term.coeff * j0;
jt[term.vectorIndex][row1] += term.coeff * j1;
}
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
} finally {
ersRef.ers_watr_center_dt = refWatrBak;
ersRef.ers_wxyz_center_dt = refWxyzBak;
ersScene.ers_watr_center_dt = sceneWatrBak;
ersScene.ers_wxyz_center_dt = sceneWxyzBak;
}
}
// Pull block: one equation per unknown.
for (int i = 0; i < classicState.pullRows; i++) {
final int row = classicState.pullBase + i;
fx[row] = vector[i] - classicState.parameterPull[i];
if (jt != null) {
jt[i][i] = 1.0;
jt[i][row] = 1.0;
}
}
if ((debugLevel > 2) && (n > 0)) {
System.out.println("IntersceneGlobalLmaRefine: getFxDerivs() placeholder residual blocks active, samples=" + n);
// LPF block: x_i - 0.5*(x_{i-1}+x_{i+1}) for each valid row.
for (int i = 0; i < classicState.lpfVar.length; i++) {
final int row = classicState.lpfBase + i;
final int iv = classicState.lpfVar[i];
double v = vector[iv];
final int prevVar = classicState.lpfPrevVar[i];
if (prevVar >= 0) {
v -= 0.5 * vector[prevVar];
if (jt != null) {
jt[prevVar][row] -= 0.5;
}
} else {
v -= 0.5 * classicState.lpfPrevFixed[i];
}
final int nextVar = classicState.lpfNextVar[i];
if (nextVar >= 0) {
v -= 0.5 * vector[nextVar];
if (jt != null) {
jt[nextVar][row] -= 0.5;
}
} else {
v -= 0.5 * classicState.lpfNextFixed[i];
}
fx[row] = v;
if (jt != null) {
jt[iv][row] += 1.0;
}
}
if ((debugLevel > 2) && (nrows > 0)) {
System.out.println("IntersceneGlobalLmaRefine: getFxDerivs() rows=" + nrows +
", corrRows=" + classicState.correlationRows +
", pullRows=" + classicState.pullRows +
", lpfRows=" + classicState.lpfVar.length +
", unknowns=" + nvars);
}
return fx;
}
......@@ -370,6 +1123,7 @@ public class IntersceneGlobalLmaRefine {
final boolean noNaNs) {
final double[] weighted = new double[fx.length];
double sum = 0.0;
double sumPure = 0.0;
for (int i = 0; i < fx.length; i++) {
double d = classicState.yVector[i] - fx[i];
double wd = d * classicState.weights[i];
......@@ -385,12 +1139,13 @@ public class IntersceneGlobalLmaRefine {
wd = 0.0;
}
weighted[i] = wd;
sum += d * wd;
final double dwd = d * wd;
sum += dwd;
sumPure += d * d;
}
if ((rms != null) && (rms.length >= 2)) {
final double v = Math.sqrt(sum);
rms[0] = v;
rms[1] = v;
rms[0] = Math.sqrt(Math.max(0.0, sum));
rms[1] = Math.sqrt(Math.max(0.0, sumPure / Math.max(1, Math.max(1, classicState.correlationRows))));
}
return weighted;
}
......@@ -408,7 +1163,7 @@ public class IntersceneGlobalLmaRefine {
}
wjtjl[i][j] = d;
if (i == j) {
wjtjl[i][i] += d * lambda;
wjtjl[i][i] += Math.max(MIN_DIAG, d) * lambda;
} else {
wjtjl[j][i] = d;
}
......@@ -428,7 +1183,6 @@ public class IntersceneGlobalLmaRefine {
return max;
}
@SuppressWarnings("unused")
private boolean[] lmaStep(
final double lambda,
final double rmsDiffStop,
......@@ -438,6 +1192,7 @@ public class IntersceneGlobalLmaRefine {
if (n == 0) {
return new boolean[] {true, true};
}
classicState.attemptedSteps++;
if ((classicState.lastJt == null) || (classicState.lastJt.length != n)) {
classicState.lastJt = new double[n][];
}
......@@ -469,6 +1224,7 @@ public class IntersceneGlobalLmaRefine {
final double[] delta = deltaVector.getColumnPackedCopy();
final double maxDelta = getMaxAbs(delta);
classicState.lastMaxDelta = maxDelta;
final double[] oldVector = classicState.parameterVector.clone();
final double[] oldRms = classicState.lastRms.clone();
final double[] newVector = oldVector.clone();
......@@ -489,6 +1245,8 @@ public class IntersceneGlobalLmaRefine {
classicState.parameterVector = newVector;
classicState.lastRms = rms;
classicState.lastYminusFx = yMinusFxNew;
classicState.acceptedSteps++;
applyVectorToScenes(newVector);
final boolean convergedByRms = rms[0] >= (oldRms[0] * (1.0 - rmsDiffStop));
final boolean convergedByDelta = maxDelta <= deltaStop;
return new boolean[] {true, convergedByRms || convergedByDelta};
......@@ -503,33 +1261,1071 @@ public class IntersceneGlobalLmaRefine {
classicState.lastRms,
true);
classicState.parameterVector = oldVector;
applyVectorToScenes(oldVector);
return new boolean[] {false, false};
}
private IntersceneGlobalRefine.Result runLma(final int debugLevel) {
final IntersceneGlobalRefine.Result result = new IntersceneGlobalRefine.Result();
final int unknowns = classicState.parameterVector.length;
if (unknowns == 0) {
return result;
}
double lambda = (options != null) ? options.lambdaDiag : 0.1;
if (!(lambda > 0.0)) {
lambda = 0.1;
}
final double lambdaScaleGood = ((options != null) && (options.lambdaScaleGood > 0.0)) ? options.lambdaScaleGood : 0.5;
final double lambdaScaleBad = ((options != null) && (options.lambdaScaleBad > 1.0)) ? options.lambdaScaleBad : 8.0;
final double lambdaMax = ((options != null) && (options.lambdaMax > 0.0)) ? options.lambdaMax : 100.0;
final double rmsDiffStop = ((options != null) && (options.rmsDiffStop >= 0.0)) ? options.rmsDiffStop : 0.001;
final double deltaStop = ((options != null) && (options.deltaStop > 0.0)) ? options.deltaStop : 1.0e-5;
final int outerIterations = ((options != null) && (options.outerIterations > 0)) ? options.outerIterations : 1;
final int innerIterations = ((options != null) && (options.innerIterations > 0)) ? options.innerIterations : 1;
boolean converged = false;
int outerDone = 0;
int innerDone = 0;
for (int outer = 0; outer < outerIterations; outer++) {
final boolean haveObs = rebuildObservationRowsForOuter(debugLevel);
if (!haveObs && (classicState.correlationRows == 0)) {
if (debugLevel > -2) {
System.out.println("IntersceneGlobalLmaRefine: no valid correlation rows for outer=" + outer + ", stopping.");
}
break;
}
classicState.lastJt = null;
classicState.lastYminusFx = null;
classicState.lastRms = null;
classicState.initialRms = null;
for (int inner = 0; inner < innerIterations; inner++) {
final boolean[] step = lmaStep(
lambda,
rmsDiffStop,
deltaStop,
debugLevel);
if (step == null) {
converged = true;
break;
}
final boolean improved = step[0];
final boolean stop = step[1];
if (improved) {
lambda *= lambdaScaleGood;
} else {
lambda *= lambdaScaleBad;
}
if (lambda > lambdaMax) {
converged = true;
}
innerDone = inner + 1;
outerDone = outer + 1;
if (debugLevel > -3 && (classicState.lastRms != null)) {
System.out.println(
"IntersceneGlobalLmaRefine: outer=" + outer +
" inner=" + inner +
" improved=" + improved +
" stop=" + stop +
" avgPairRms=" + classicState.lastRms[0] +
" avgPairRmsPure=" + classicState.lastRms[1] +
" maxDelta=" + classicState.lastMaxDelta +
" lambda=" + lambda);
}
if (stop || converged) {
converged = true;
break;
}
}
if (converged) {
break;
}
}
captureCurrentVectorFromScenes();
final HashSet<Integer> solved = new HashSet<Integer>();
for (final int scene : classicState.vectorSceneIndices) {
solved.add(Integer.valueOf(scene));
}
result.solvedScenes = solved.size();
result.failedScenes = 0;
result.outerDone = outerDone;
result.maxDelta = classicState.lastMaxDelta;
result.pcgIterationsLast = Math.max(innerDone, classicState.attemptedSteps);
if (classicState.lastRms != null) {
result.avgPairRms = classicState.lastRms[0];
result.avgPairRmsPure = classicState.lastRms[1];
}
if (debugLevel > -4) {
System.out.println(
"IntersceneGlobalLmaRefine: runLma() phase-1 delegating numeric solve to IntersceneGlobalRefine");
"IntersceneGlobalLmaRefine: finished, outerDone=" + result.outerDone +
", solvedScenes=" + result.solvedScenes +
", avgPairRms=" + result.avgPairRms +
", avgPairRmsPure=" + result.avgPairRmsPure +
", acceptedSteps=" + classicState.acceptedSteps +
", attemptedSteps=" + classicState.attemptedSteps);
}
final IntersceneGlobalRefine.Result result = IntersceneGlobalRefine.refineAllToReference(
cltParameters,
return result;
}
private static ArrayList<PairFactor> buildPairFactors(
final CLTParameters cltParameters,
final QuadCLT[] quadCLTs,
final double[][][] scenes_xyzatr,
final boolean[] activePoseScene,
final int firstScene,
final int lastScene,
final int centerIndex,
final double minOffset,
final int debugLevel) {
final ArrayList<PairFactor> factors = new ArrayList<PairFactor>();
final HashSet<Long> used = new HashSet<Long>();
for (int nscene = firstScene; nscene <= lastScene; nscene++) {
final int ivar = nscene - firstScene;
if ((ivar >= 0) && (ivar < activePoseScene.length) && activePoseScene[ivar]) {
final long key = (((long) nscene) << 32) | (centerIndex & 0xffffffffL);
if (used.add(key)) {
factors.add(new PairFactor(
nscene,
centerIndex,
1.0));
}
}
}
if (!cltParameters.imp.fmg_initial_en) {
return factors;
}
final double avgZ = getAverageAbsZ(
scenes_xyzatr,
activePoseScene,
firstScene);
final ArrayList<Integer> fpnList = new ArrayList<Integer>();
for (int nscene = firstScene; nscene <= lastScene; nscene++) {
final int ivar = nscene - firstScene;
if ((ivar < 0) || (ivar >= activePoseScene.length) || !activePoseScene[ivar]) {
continue;
}
double estShift = quadCLTs[centerIndex].estimateAverageShift(
getScenePose(scenes_xyzatr, centerIndex, centerIndex),
getScenePose(scenes_xyzatr, nscene, centerIndex),
avgZ,
false,
cltParameters.imp.fmg_rectilinear);
if (estShift < minOffset) {
estShift = quadCLTs[centerIndex].estimateAverageShift(
getScenePose(scenes_xyzatr, centerIndex, centerIndex),
getScenePose(scenes_xyzatr, nscene, centerIndex),
avgZ,
true,
cltParameters.imp.fmg_rectilinear);
}
if (estShift < minOffset) {
fpnList.add(nscene);
}
}
if (fpnList.isEmpty()) {
return factors;
}
double fmgDistance = cltParameters.imp.fmg_distance;
if (fmgDistance < (minOffset + 2.0)) {
fmgDistance = minOffset + 2.0;
}
final int[][] fpnPairs = Interscene.getFPNPairs(
fpnList,
fmgDistance,
cltParameters.imp.fmg_rectilinear,
quadCLTs,
centerCLT,
scenes_xyzatr,
avgZ,
centerIndex,
earliestScene,
firstScene);
for (int i = 0; i < fpnPairs.length; i++) {
final int scene = fpnPairs[i][0];
final int ref = fpnPairs[i][1];
if ((scene < firstScene) || (scene > lastScene) || (ref < firstScene) || (ref > lastScene)) {
continue;
}
if ((scene == ref) || (ref == centerIndex)) {
continue;
}
final int ivarScene = scene - firstScene;
final int ivarRef = ref - firstScene;
if ((ivarScene < 0) || (ivarScene >= activePoseScene.length) || !activePoseScene[ivarScene]) {
continue;
}
if ((ivarRef < 0) || (ivarRef >= activePoseScene.length) || !activePoseScene[ivarRef]) {
continue;
}
if ((quadCLTs[ref] == null) || (scenes_xyzatr[ref] == null)) {
continue;
}
final long key = (((long) scene) << 32) | (ref & 0xffffffffL);
if (used.add(key)) {
factors.add(new PairFactor(
scene,
ref,
1.0));
}
}
if (debugLevel > -3) {
System.out.println("IntersceneGlobalLmaRefine: pair factors total=" + factors.size());
}
return factors;
}
private static void applyPairWeights(
final ArrayList<PairFactor> pairFactors,
final int centerIndex,
final int centerPairWeightMode,
final int debugLevel) {
if ((pairFactors == null) || pairFactors.isEmpty()) {
return;
}
final int mode = Math.max(0, centerPairWeightMode);
int numZero = 0;
for (PairFactor pf : pairFactors) {
double w = 1.0;
if ((mode > 0) && (pf.refSceneIndex == centerIndex)) {
final int d = Math.abs(pf.sceneIndex - centerIndex);
if ((d > 0) && (d <= mode)) {
w = 0.0;
}
}
pf.pairWeight = w;
if (!(w > 0.0)) {
numZero++;
}
}
if (debugLevel > -3) {
System.out.println(
"IntersceneGlobalLmaRefine: pair weights applied, mode=" + mode +
", zeroWeightedPairs=" + numZero + "/" + pairFactors.size());
}
}
private static double getAverageAbsZ(
final double[][][] scenes_xyzatr,
final boolean[] activePoseScene,
final int firstScene) {
double sum = 0.0;
int n = 0;
for (int ivar = 0; ivar < activePoseScene.length; ivar++) {
if (!activePoseScene[ivar]) {
continue;
}
final int nscene = firstScene + ivar;
if ((nscene >= 0) && (nscene < scenes_xyzatr.length) && (scenes_xyzatr[nscene] != null)) {
sum += Math.abs(scenes_xyzatr[nscene][0][2]);
n++;
}
}
return (n > 0) ? Math.max(1.0, sum / n) : 1.0;
}
private static RefGpuData getReferenceGpuData(
final CLTParameters clt_parameters,
final QuadCLT[] quadCLTs,
final double[][][] scenes_xyzatr,
final double[] sceneTimes,
final int firstScene,
final int lastScene,
final int centerIndex,
final int refScene,
final double[] refDisparity,
final double[][] pXpYDCenter,
final boolean[] reliableRefCenter,
final double mb_max_gain,
final RefGpuData[] cache,
final int debugLevel) {
final int ivar = refScene - firstScene;
if ((ivar >= 0) && (ivar < cache.length) && (cache[ivar] != null) &&
(cache[ivar].refSceneIndex == refScene) && (cache[ivar].tasks != null) &&
(cache[ivar].pXpYD != null)) {
return cache[ivar];
}
if ((refScene < 0) || (refScene >= quadCLTs.length) || (quadCLTs[refScene] == null)) {
return null;
}
final RefGpuData rslt = new RefGpuData();
rslt.refSceneIndex = refScene;
final double[][] refPose = getScenePose(
scenes_xyzatr,
refScene,
centerIndex);
final double[][] refRates = getSceneRates(
refScene,
scenes_xyzatr,
quadCLTs,
sceneTimes,
firstScene,
lastScene,
scenesXyzatr,
scenesXyzatrPull,
paramSelect,
paramRegweights,
paramLpf,
centerDisparity,
centerIndex);
rslt.pXpYD = (refScene == centerIndex) ? pXpYDCenter : OpticalFlow.transformToScenePxPyD(
null,
refDisparity,
refPose[0],
refPose[1],
quadCLTs[refScene],
quadCLTs[centerIndex]);
rslt.reliableMask = (refScene == centerIndex) ? reliableRefCenter : buildPairReliableMask(
clt_parameters,
quadCLTs,
centerIndex,
refScene,
centerIndex,
scenes_xyzatr,
reliableRefCenter,
debugLevel);
double[][] mbVectorsRef = null;
if (clt_parameters.imp.mb_en) {
final double[][] refDt = QuadCLTCPU.scaleDtFromErs(
clt_parameters,
new double[][] {
refRates[0].clone(),
refRates[1].clone()});
mbVectorsRef = OpticalFlow.getMotionBlur(
quadCLTs[centerIndex],
quadCLTs[refScene],
pXpYDCenter,
refPose[0],
refPose[1],
refDt[0],
refDt[1],
0,
debugLevel);
}
final TpTask[][] tasks = Interscene.setReferenceGPU(
clt_parameters,
quadCLTs[refScene],
refDisparity,
rslt.pXpYD,
null,
rslt.reliableMask,
0,
clt_parameters.imp.mb_tau,
mb_max_gain,
mbVectorsRef,
debugLevel);
if ((tasks == null) || (tasks.length == 0) || (tasks[0] == null)) {
return null;
}
rslt.tasks = tasks[0];
if ((ivar >= 0) && (ivar < cache.length)) {
cache[ivar] = rslt;
}
return rslt;
}
private static ObservationCache buildObservationCache(
final CLTParameters clt_parameters,
final QuadCLT[] quadCLTs,
final QuadCLT centerCLT,
final int centerIndex,
final int firstScene,
final int lastScene,
final double[][][] scenes_xyzatr,
final double[] sceneTimes,
final ArrayList<PairFactor> pairFactors,
final double[] refDisparity,
final double[][] pXpYDCenter,
final boolean[] reliableRef,
final double mb_max_gain,
final double[] minMax,
final RefGpuData[] refGpuCache,
final int debugLevel) {
final ObservationCache cache = new ObservationCache();
if ((pairFactors == null) || pairFactors.isEmpty()) {
return cache;
}
final int tilesX = centerCLT.getTileProcessor().getTilesX();
final int tilesY = centerCLT.getTileProcessor().getTilesY();
cache.tilesPerPair = tilesX * tilesY;
cache.yVector = new double[2 * cache.tilesPerPair * pairFactors.size()];
cache.wVector = new double[cache.tilesPerPair * pairFactors.size()];
for (int ifactor = 0; ifactor < pairFactors.size(); ifactor++) {
final PairFactor pf = pairFactors.get(ifactor);
final RefGpuData refGpu = getReferenceGpuData(
clt_parameters,
quadCLTs,
scenes_xyzatr,
sceneTimes,
firstScene,
lastScene,
centerIndex,
pf.refSceneIndex,
refDisparity,
pXpYDCenter,
reliableRef,
mb_max_gain,
refGpuCache,
debugLevel);
if (refGpu == null) {
cache.failedPairs++;
continue;
}
final PairObservation obs = buildPairObservation(
clt_parameters,
quadCLTs,
centerCLT,
centerIndex,
pf.sceneIndex,
pf.refSceneIndex,
firstScene,
lastScene,
scenes_xyzatr,
sceneTimes,
refGpu.pXpYD,
refGpu.tasks,
refGpu.reliableMask,
refDisparity,
minMax,
mb_max_gain,
pf.pairWeight,
ifactor,
cache,
debugLevel);
if (obs == null) {
cache.failedPairs++;
continue;
}
cache.observations.add(obs);
cache.solvedPairs++;
}
return cache;
}
private static PairObservation buildPairObservation(
final CLTParameters clt_parameters,
final QuadCLT[] quadCLTs,
final QuadCLT centerCLT,
final int centerIndex,
final int nscene,
final int refScene,
final int earliestScene,
final int lastScene,
final double[][][] scenes_xyzatr,
final double[] sceneTimes,
final double[][] pXpYDRef,
final TpTask[] tpTaskRef,
final boolean[] reliableRef,
final double[] refDisparity,
final double[] minMax,
final double mb_max_gain,
final double pairWeight,
final int pairOrdinal,
final ObservationCache cache,
final int debugLevel) {
if ((quadCLTs[nscene] == null) || (scenes_xyzatr[nscene] == null)) {
return null;
}
final boolean[] reliablePair = buildPairReliableMask(
clt_parameters,
quadCLTs,
centerIndex,
nscene,
refScene,
scenes_xyzatr,
reliableRef,
disableErs,
mbMaxGain,
options,
debugLevel);
captureCurrentVectorFromScenes();
return result;
final double[][] poseNow = getScenePose(
scenes_xyzatr,
nscene,
centerIndex);
final double[][] sceneRates = getSceneRates(
nscene,
scenes_xyzatr,
quadCLTs,
sceneTimes,
earliestScene,
lastScene,
centerIndex);
double[][] mbVectorsScene = null;
if (clt_parameters.imp.mb_en) {
final double[][] sceneDt = QuadCLTCPU.scaleDtFromErs(
clt_parameters,
new double[][] {
sceneRates[0].clone(),
sceneRates[1].clone()});
mbVectorsScene = OpticalFlow.getMotionBlur(
centerCLT,
quadCLTs[nscene],
pXpYDRef,
poseNow[0],
poseNow[1],
sceneDt[0],
sceneDt[1],
0,
debugLevel);
}
final int[] failReason = {0};
final double[][][] coordMotion = Interscene.interCorrPair(
clt_parameters,
false,
false,
mb_max_gain,
minMax,
failReason,
centerCLT,
refDisparity,
quadCLTs[refScene],
pXpYDRef,
tpTaskRef,
quadCLTs[nscene],
poseNow[0],
poseNow[1],
reliablePair,
clt_parameters.imp.margin,
clt_parameters.imp.sensor_mask_inter,
null,
null,
false,
false,
true,
mbVectorsScene,
-1,
false,
clt_parameters.imp.debug_level,
debugLevel);
if ((coordMotion == null) || (coordMotion.length < 2) || (coordMotion[0] == null) || (coordMotion[1] == null)) {
return null;
}
final PairObservation obs = new PairObservation();
obs.sceneIndex = nscene;
obs.refSceneIndex = refScene;
obs.pairWeight = pairWeight;
obs.centers = coordMotion[0];
obs.eigen = (coordMotion.length > 2) ? coordMotion[2] : null;
obs.reliableRef = reliablePair;
obs.yBase = pairOrdinal * 2 * cache.tilesPerPair;
obs.wBase = pairOrdinal * cache.tilesPerPair;
final int pairTiles = obs.centers.length;
final int ntiles = Math.min(
Math.min(cache.tilesPerPair, pairTiles),
coordMotion[1].length);
for (int itile = 0; itile < ntiles; itile++) {
final double[] v = coordMotion[1][itile];
if ((v == null) || (v.length < 3)) {
continue;
}
final boolean reliable = (reliablePair == null) || ((itile < reliablePair.length) && reliablePair[itile]);
final double w = (pairWeight > 0.0) ? ((reliable ? v[2] : 0.0) * pairWeight) : 0.0;
cache.yVector[obs.yBase + 2 * itile + 0] = v[0];
cache.yVector[obs.yBase + 2 * itile + 1] = v[1];
cache.wVector[obs.wBase + itile] = w;
}
obs.vectorXys = new double[pairTiles][];
for (int itile = 0; itile < pairTiles; itile++) {
if (itile >= cache.tilesPerPair) {
obs.vectorXys[itile] = null;
continue;
}
final double w = cache.wVector[obs.wBase + itile];
if (w <= 0.0) {
obs.vectorXys[itile] = null;
} else {
obs.vectorXys[itile] = new double[] {
cache.yVector[obs.yBase + 2 * itile + 0],
cache.yVector[obs.yBase + 2 * itile + 1],
w};
}
}
return obs;
}
private static boolean[] buildPairReliableMask(
final CLTParameters clt_parameters,
final QuadCLT[] quadCLTs,
final int centerIndex,
final int sceneIndex,
final int refSceneIndex,
final double[][][] scenes_xyzatr,
final boolean[] reliableBase,
final int debugLevel) {
if ((centerIndex < 0) || (centerIndex >= quadCLTs.length) || (quadCLTs[centerIndex] == null)) {
return reliableBase;
}
final QuadCLT centerCLT = quadCLTs[centerIndex];
final int tilesX = centerCLT.getTileProcessor().getTilesX();
final int tilesY = centerCLT.getTileProcessor().getTilesY();
boolean[] reliable = reliableBase;
if (reliable == null) {
reliable = new boolean[tilesX * tilesY];
Arrays.fill(reliable, true);
}
final double[][] centerPose = getScenePose(
scenes_xyzatr,
centerIndex,
centerIndex);
final double[][] scenePose = getScenePose(
scenes_xyzatr,
sceneIndex,
centerIndex);
final double avgZ = centerCLT.getAverageZ(true);
final boolean fmgRectilinear = clt_parameters.imp.fmg_rectilinear;
final double[] centerToSceneOffset = centerCLT.estimateCenterShiftXY(
centerPose,
scenePose,
avgZ,
fmgRectilinear);
if (centerToSceneOffset != null) {
reliable = centerCLT.maskByOverlap(
reliable,
centerToSceneOffset);
}
if (refSceneIndex != centerIndex) {
final double[][] refPose = getScenePose(
scenes_xyzatr,
refSceneIndex,
centerIndex);
final double[] centerToRefOffset = centerCLT.estimateCenterShiftXY(
centerPose,
refPose,
avgZ,
fmgRectilinear);
if (centerToRefOffset != null) {
reliable = centerCLT.maskByOverlap(
reliable,
centerToRefOffset);
}
}
if (debugLevel > 1) {
int selected = 0;
for (int i = 0; i < reliable.length; i++) {
if (reliable[i]) {
selected++;
}
}
System.out.println(
"IntersceneGlobalLmaRefine: overlap mask scene=" + sceneIndex +
", ref=" + refSceneIndex +
", selected=" + selected + "/" + reliable.length);
}
return reliable;
}
private static double parseSceneTimestamp(final String ts) {
if (ts == null) {
return Double.NaN;
}
final String[] parts = ts.trim().split("_");
if (parts.length != 2) {
return Double.NaN;
}
try {
final long sec = Long.parseLong(parts[0]);
final long usec = Long.parseLong(parts[1]);
return sec + (usec * 1.0e-6);
} catch (NumberFormatException nfe) {
return Double.NaN;
}
}
private static double[] getSceneTimes(
final QuadCLT[] quadCLTs,
final int firstScene,
final int lastScene) {
final double[] out = new double[quadCLTs.length];
Arrays.fill(out, Double.NaN);
for (int nscene = firstScene; nscene <= lastScene; nscene++) {
if (quadCLTs[nscene] == null) {
continue;
}
out[nscene] = parseSceneTimestamp(quadCLTs[nscene].getImageName());
}
double t = 0.0;
for (int nscene = firstScene; nscene <= lastScene; nscene++) {
if (Double.isNaN(out[nscene])) {
out[nscene] = t;
}
t = out[nscene] + DEFAULT_DT;
}
return out;
}
private static int findPrevScene(
final int sceneIndex,
final int firstScene,
final QuadCLT[] quadCLTs,
final double[][][] scenes_xyzatr) {
for (int i = sceneIndex - 1; i >= firstScene; i--) {
if ((quadCLTs[i] != null) && (scenes_xyzatr[i] != null)) {
return i;
}
}
return -1;
}
private static int findNextScene(
final int sceneIndex,
final int lastScene,
final QuadCLT[] quadCLTs,
final double[][][] scenes_xyzatr) {
for (int i = sceneIndex + 1; i <= lastScene; i++) {
if ((quadCLTs[i] != null) && (scenes_xyzatr[i] != null)) {
return i;
}
}
return -1;
}
private static double safeDt(
final int i0,
final int i1,
final double[] sceneTimes) {
if ((sceneTimes == null) ||
(i0 < 0) || (i1 < 0) ||
(i0 >= sceneTimes.length) || (i1 >= sceneTimes.length)) {
return DEFAULT_DT;
}
final double dt = Math.abs(sceneTimes[i1] - sceneTimes[i0]);
return (dt > MIN_DIAG) ? dt : DEFAULT_DT;
}
private static double wrapPi(double a) {
while (a > Math.PI) {
a -= (2.0 * Math.PI);
}
while (a < -Math.PI) {
a += (2.0 * Math.PI);
}
return a;
}
private static double getPoseComponent(
final double[][][] scenes_xyzatr,
final int sceneIndex,
final int centerIndex,
final boolean angular,
final int comp) {
if (sceneIndex == centerIndex) {
return 0.0;
}
if ((sceneIndex < 0) || (sceneIndex >= scenes_xyzatr.length) || (scenes_xyzatr[sceneIndex] == null)) {
return 0.0;
}
return angular ? scenes_xyzatr[sceneIndex][1][comp] : scenes_xyzatr[sceneIndex][0][comp];
}
private static ArrayList<RateTerm> getRateTerms(
final int sceneIndex,
final int firstScene,
final int lastScene,
final QuadCLT[] quadCLTs,
final double[][][] scenes_xyzatr,
final double[] sceneTimes) {
final int prev = findPrevScene(
sceneIndex,
firstScene,
quadCLTs,
scenes_xyzatr);
final int next = findNextScene(
sceneIndex,
lastScene,
quadCLTs,
scenes_xyzatr);
final ArrayList<RateTerm> terms = new ArrayList<RateTerm>(2);
if ((prev < 0) && (next < 0)) {
return terms;
}
if (prev < 0) {
final double dt = safeDt(sceneIndex, next, sceneTimes);
terms.add(new RateTerm(sceneIndex, -1.0 / dt));
terms.add(new RateTerm(next, 1.0 / dt));
return terms;
}
if (next < 0) {
final double dt = safeDt(prev, sceneIndex, sceneTimes);
terms.add(new RateTerm(prev, -1.0 / dt));
terms.add(new RateTerm(sceneIndex, 1.0 / dt));
return terms;
}
final double dt = safeDt(prev, next, sceneTimes);
terms.add(new RateTerm(prev, -1.0 / dt));
terms.add(new RateTerm(next, 1.0 / dt));
return terms;
}
private static double getRateValue(
final int sceneIndex,
final boolean angular,
final int comp,
final int firstScene,
final int lastScene,
final int centerIndex,
final double[][][] scenes_xyzatr,
final QuadCLT[] quadCLTs,
final double[] sceneTimes) {
final int prev = findPrevScene(
sceneIndex,
firstScene,
quadCLTs,
scenes_xyzatr);
final int next = findNextScene(
sceneIndex,
lastScene,
quadCLTs,
scenes_xyzatr);
if ((prev < 0) && (next < 0)) {
return 0.0;
}
if (prev < 0) {
final double dt = safeDt(sceneIndex, next, sceneTimes);
final double d = getPoseComponent(scenes_xyzatr, next, centerIndex, angular, comp) -
getPoseComponent(scenes_xyzatr, sceneIndex, centerIndex, angular, comp);
return (angular ? wrapPi(d) : d) / dt;
}
if (next < 0) {
final double dt = safeDt(prev, sceneIndex, sceneTimes);
final double d = getPoseComponent(scenes_xyzatr, sceneIndex, centerIndex, angular, comp) -
getPoseComponent(scenes_xyzatr, prev, centerIndex, angular, comp);
return (angular ? wrapPi(d) : d) / dt;
}
final double dt = safeDt(prev, next, sceneTimes);
final double d = getPoseComponent(scenes_xyzatr, next, centerIndex, angular, comp) -
getPoseComponent(scenes_xyzatr, prev, centerIndex, angular, comp);
return (angular ? wrapPi(d) : d) / dt;
}
private static double[][] getSceneRates(
final int sceneIndex,
final double[][][] scenes_xyzatr,
final QuadCLT[] quadCLTs,
final double[] sceneTimes,
final int firstScene,
final int lastScene,
final int centerIndex) {
final double[][] rates = new double[2][3];
for (int i = 0; i < 3; i++) {
rates[0][i] = getRateValue(
sceneIndex,
false,
i,
firstScene,
lastScene,
centerIndex,
scenes_xyzatr,
quadCLTs,
sceneTimes);
rates[1][i] = getRateValue(
sceneIndex,
true,
i,
firstScene,
lastScene,
centerIndex,
scenes_xyzatr,
quadCLTs,
sceneTimes);
}
return rates;
}
private static double[][] getScenePose(
final double[][][] scenes_xyzatr,
final int sceneIndex,
final int centerIndex) {
if (sceneIndex == centerIndex) {
return new double[][] {
Interscene.ZERO3.clone(),
Interscene.ZERO3.clone()};
}
if ((sceneIndex < 0) || (sceneIndex >= scenes_xyzatr.length) || (scenes_xyzatr[sceneIndex] == null)) {
return new double[][] {
Interscene.ZERO3.clone(),
Interscene.ZERO3.clone()};
}
return new double[][] {
scenes_xyzatr[sceneIndex][0].clone(),
scenes_xyzatr[sceneIndex][1].clone()};
}
private static boolean[] getLocalParamMaskForPair(
final boolean[] paramSelect,
final int sceneIndex,
final int refSceneIndex,
final int centerIndex,
final boolean disableErs) {
final boolean[] mask = new boolean[ErsCorrection.DP_NUM_PARS];
if (paramSelect != null) {
for (int i = 0; i < SCENE_POSE_PARAM_ORDER.length; i++) {
final int pi = SCENE_POSE_PARAM_ORDER[i];
if (pi < paramSelect.length) {
mask[pi] = paramSelect[pi];
}
}
} else {
for (int i = 0; i < SCENE_POSE_PARAM_ORDER.length; i++) {
mask[SCENE_POSE_PARAM_ORDER[i]] = true;
}
}
if (sceneIndex == centerIndex) {
for (int i = 0; i < SCENE_POSE_PARAM_ORDER.length; i++) {
mask[SCENE_POSE_PARAM_ORDER[i]] = false;
}
}
for (int i = 0; i < REF_RATE_ANG_PAR_INDICES.length; i++) {
mask[REF_RATE_ANG_PAR_INDICES[i]] = !disableErs;
mask[SCENE_RATE_ANG_PAR_INDICES[i]] = !disableErs;
mask[REF_RATE_LIN_PAR_INDICES[i]] = true;
mask[SCENE_RATE_LIN_PAR_INDICES[i]] = true;
}
return mask;
}
private ArrayList<VectorTerm> mapLocalParameterToVectorTerms(
final int parIndex,
final int sceneIndex,
final int refSceneIndex,
final int centerIndex,
final int firstScene,
final int lastScene,
final boolean[] activePoseScene,
final double[][][] scenesRatesSource,
final boolean includeRateChain) {
final ArrayList<VectorTerm> rslt = new ArrayList<VectorTerm>(2);
switch (parIndex) {
case ErsCorrection.DP_DSAZ:
case ErsCorrection.DP_DSTL:
case ErsCorrection.DP_DSRL:
case ErsCorrection.DP_DSX:
case ErsCorrection.DP_DSY:
case ErsCorrection.DP_DSZ:
{
final Integer vidx = classicState.vectorIndexBySceneParam.get(getSceneParamKey(sceneIndex, parIndex));
if (vidx != null) {
rslt.add(new VectorTerm(vidx.intValue(), 1.0));
}
break;
}
case ErsCorrection.DP_DSVAZ:
case ErsCorrection.DP_DSVTL:
case ErsCorrection.DP_DSVRL:
{
if (!includeRateChain) {
break;
}
final int comp = parIndex - ErsCorrection.DP_DSVAZ;
final int posePar = ErsCorrection.DP_DSAZ + comp;
final ArrayList<RateTerm> rts = getRateTerms(
sceneIndex,
firstScene,
lastScene,
quadCLTs,
scenesRatesSource,
sceneTimes);
for (int i = 0; i < rts.size(); i++) {
final RateTerm rt = rts.get(i);
if (rt.sceneIndex == centerIndex) {
continue;
}
final int ivar = rt.sceneIndex - firstScene;
if ((ivar < 0) || (ivar >= activePoseScene.length) || !activePoseScene[ivar]) {
continue;
}
final Integer vidx = classicState.vectorIndexBySceneParam.get(getSceneParamKey(rt.sceneIndex, posePar));
if (vidx != null) {
rslt.add(new VectorTerm(vidx.intValue(), rt.coeff));
}
}
break;
}
case ErsCorrection.DP_DSVX:
case ErsCorrection.DP_DSVY:
case ErsCorrection.DP_DSVZ:
{
if (!includeRateChain) {
break;
}
final int comp = parIndex - ErsCorrection.DP_DSVX;
final int posePar = ErsCorrection.DP_DSX + comp;
final ArrayList<RateTerm> rts = getRateTerms(
sceneIndex,
firstScene,
lastScene,
quadCLTs,
scenesRatesSource,
sceneTimes);
for (int i = 0; i < rts.size(); i++) {
final RateTerm rt = rts.get(i);
if (rt.sceneIndex == centerIndex) {
continue;
}
final int ivar = rt.sceneIndex - firstScene;
if ((ivar < 0) || (ivar >= activePoseScene.length) || !activePoseScene[ivar]) {
continue;
}
final Integer vidx = classicState.vectorIndexBySceneParam.get(getSceneParamKey(rt.sceneIndex, posePar));
if (vidx != null) {
rslt.add(new VectorTerm(vidx.intValue(), rt.coeff));
}
}
break;
}
case ErsCorrection.DP_DVAZ:
case ErsCorrection.DP_DVTL:
case ErsCorrection.DP_DVRL:
{
if (!includeRateChain) {
break;
}
final int comp = parIndex - ErsCorrection.DP_DVAZ;
final int posePar = ErsCorrection.DP_DSAZ + comp;
final ArrayList<RateTerm> rts = getRateTerms(
refSceneIndex,
firstScene,
lastScene,
quadCLTs,
scenesRatesSource,
sceneTimes);
for (int i = 0; i < rts.size(); i++) {
final RateTerm rt = rts.get(i);
if (rt.sceneIndex == centerIndex) {
continue;
}
final int ivar = rt.sceneIndex - firstScene;
if ((ivar < 0) || (ivar >= activePoseScene.length) || !activePoseScene[ivar]) {
continue;
}
final Integer vidx = classicState.vectorIndexBySceneParam.get(getSceneParamKey(rt.sceneIndex, posePar));
if (vidx != null) {
rslt.add(new VectorTerm(vidx.intValue(), rt.coeff));
}
}
break;
}
case ErsCorrection.DP_DVX:
case ErsCorrection.DP_DVY:
case ErsCorrection.DP_DVZ:
{
if (!includeRateChain) {
break;
}
final int comp = parIndex - ErsCorrection.DP_DVX;
final int posePar = ErsCorrection.DP_DSX + comp;
final ArrayList<RateTerm> rts = getRateTerms(
refSceneIndex,
firstScene,
lastScene,
quadCLTs,
scenesRatesSource,
sceneTimes);
for (int i = 0; i < rts.size(); i++) {
final RateTerm rt = rts.get(i);
if (rt.sceneIndex == centerIndex) {
continue;
}
final int ivar = rt.sceneIndex - firstScene;
if ((ivar < 0) || (ivar >= activePoseScene.length) || !activePoseScene[ivar]) {
continue;
}
final Integer vidx = classicState.vectorIndexBySceneParam.get(getSceneParamKey(rt.sceneIndex, posePar));
if (vidx != null) {
rslt.add(new VectorTerm(vidx.intValue(), rt.coeff));
}
}
break;
}
default:
}
return rslt;
}
}
......@@ -1998,8 +1998,12 @@ public class IntersceneGlobalRefine {
}
/**
* Dump one combined CSV with initial and final states:
* plain columns are initial, apostrophe-suffixed columns are final.
* Dump initial/final CSV snapshots in two complementary layouts:
* one pair-centric (including legacy filename for compatibility) and one scene-centric.
*
* <p>Pair-centric rows preserve per-pair RMS and weight visibility when scene-to-reference
* mapping is no longer one-to-one. Scene-centric rows keep one row per scene and aggregate
* pair RMS statistics by role ({@code as-scene}, {@code as-reference}, {@code all}).
*/
private static void dumpObservationCsvInitialFinal(
final ObservationCache initialCache,
......@@ -2052,21 +2056,27 @@ public class IntersceneGlobalRefine {
return Integer.compare(pairRef(a.longValue()), pairRef(b.longValue()));
});
final StringBuilder sb = new StringBuilder();
sb.append("index,scene,reference,weight")
final HashMap<Integer, ScenePairStats> statsInitial = new HashMap<Integer, ScenePairStats>();
final HashMap<Integer, ScenePairStats> statsFinal = new HashMap<Integer, ScenePairStats>();
final StringBuilder pairSb = new StringBuilder();
pairSb.append("index,scene,reference,weight")
.append(",X,Y,Z,A,T,R,CURV_X,CURV_Y,CURV_Z,CURV_A,CURV_T,CURV_R,RMS")
.append(",X',Y',Z',A',T',R',CURV_X',CURV_Y',CURV_Z',CURV_A',CURV_T',CURV_R',RMS'")
.append(",pair,scene_index,reference_index,weight'")
.append('\n');
int pairOrdinal = 0;
for (Long keyObj : keys) {
final long key = keyObj.longValue();
final int sceneIndex = pairScene(key);
final int refIndex = pairRef(key);
final String sceneTs = ((sceneIndex >= 0) && (sceneIndex < quadCLTs.length) && (quadCLTs[sceneIndex] != null)) ?
quadCLTs[sceneIndex].getImageName() :
("scene#" + sceneIndex);
final String refTs = ((refIndex >= 0) && (refIndex < quadCLTs.length) && (quadCLTs[refIndex] != null)) ?
quadCLTs[refIndex].getImageName() :
("ref#" + refIndex);
final String sceneTs = getSceneTimestamp(
quadCLTs,
sceneIndex,
"scene");
final String refTs = getSceneTimestamp(
quadCLTs,
refIndex,
"ref");
final double[][] pose0 = getScenePose(
scenesInitial,
sceneIndex,
......@@ -2089,21 +2099,39 @@ public class IntersceneGlobalRefine {
scenesFinal);
double rms0 = Double.NaN;
double rms1 = Double.NaN;
double pairWeight = 1.0;
double pairWeight0 = Double.NaN;
double pairWeight1 = Double.NaN;
final Integer i0 = initialMap.get(keyObj);
if ((i0 != null) && (initialPairRms != null) && (i0.intValue() >= 0) && (i0.intValue() < initialPairRms.length)) {
rms0 = initialPairRms[i0.intValue()];
}
if ((i0 != null) && (i0.intValue() >= 0) && (i0.intValue() < initialCache.observations.size())) {
pairWeight = initialCache.observations.get(i0.intValue()).pairWeight;
pairWeight0 = initialCache.observations.get(i0.intValue()).pairWeight;
}
final Integer i1 = finalMap.get(keyObj);
if ((i1 != null) && (finalPairRms != null) && (i1.intValue() >= 0) && (i1.intValue() < finalPairRms.length)) {
rms1 = finalPairRms[i1.intValue()];
}
if ((i1 != null) && (i1.intValue() >= 0) && (i1.intValue() < finalCache.observations.size())) {
pairWeight = finalCache.observations.get(i1.intValue()).pairWeight;
pairWeight1 = finalCache.observations.get(i1.intValue()).pairWeight;
}
if (i0 != null) {
accumulateScenePairStats(
statsInitial,
sceneIndex,
refIndex,
pairWeight0,
rms0);
}
if (i1 != null) {
accumulateScenePairStats(
statsFinal,
sceneIndex,
refIndex,
pairWeight1,
rms1);
}
double pairWeight = !Double.isNaN(pairWeight1) ? pairWeight1 : pairWeight0;
if ((sceneIndex == centerIndex) && (refIndex == centerIndex)) {
if (Double.isNaN(rms0)) {
rms0 = 0.0;
......@@ -2111,9 +2139,15 @@ public class IntersceneGlobalRefine {
if (Double.isNaN(rms1)) {
rms1 = 0.0;
}
if (Double.isNaN(pairWeight0)) {
pairWeight0 = 1.0;
}
if (Double.isNaN(pairWeight1)) {
pairWeight1 = 1.0;
}
pairWeight = 1.0;
}
sb.append(sceneIndex).append(',')
pairSb.append(sceneIndex).append(',')
.append(sceneTs).append(',')
.append(refTs).append(',')
.append(String.format(Locale.US, "%.12g", pairWeight))
......@@ -2143,14 +2177,248 @@ public class IntersceneGlobalRefine {
.append(',').append(String.format(Locale.US, "%.12g", curv1[4]))
.append(',').append(String.format(Locale.US, "%.12g", curv1[5]))
.append(',').append(String.format(Locale.US, "%.12g", rms1))
.append(',').append(pairOrdinal)
.append(',').append(sceneIndex)
.append(',').append(refIndex)
.append(',').append(String.format(Locale.US, "%.12g", pairWeight1))
.append('\n');
pairOrdinal++;
}
final StringBuilder sceneSb = new StringBuilder();
sceneSb.append("index,scene")
.append(",X,Y,Z,A,T,R,CURV_X,CURV_Y,CURV_Z,CURV_A,CURV_T,CURV_R")
.append(",X',Y',Z',A',T',R',CURV_X',CURV_Y',CURV_Z',CURV_A',CURV_T',CURV_R'")
.append(",N_SCENE,NW_SCENE,WS_SCENE,RMS_SCENE,RMS_SCENE_MAX")
.append(",N_REF,NW_REF,WS_REF,RMS_REF,RMS_REF_MAX")
.append(",N_ALL,NW_ALL,WS_ALL,RMS_ALL,RMS_ALL_MAX")
.append(",N_SCENE',NW_SCENE',WS_SCENE',RMS_SCENE',RMS_SCENE_MAX'")
.append(",N_REF',NW_REF',WS_REF',RMS_REF',RMS_REF_MAX'")
.append(",N_ALL',NW_ALL',WS_ALL',RMS_ALL',RMS_ALL_MAX'")
.append('\n');
for (int sceneIndex = firstScene; sceneIndex <= lastScene; sceneIndex++) {
appendSceneInitialFinalRow(
sceneSb,
sceneIndex,
quadCLTs,
scenesInitial,
scenesFinal,
firstScene,
lastScene,
centerIndex,
statsInitial.get(Integer.valueOf(sceneIndex)),
statsFinal.get(Integer.valueOf(sceneIndex)));
}
if ((centerIndex < firstScene) || (centerIndex > lastScene)) {
appendSceneInitialFinalRow(
sceneSb,
centerIndex,
quadCLTs,
scenesInitial,
scenesFinal,
firstScene,
lastScene,
centerIndex,
statsInitial.get(Integer.valueOf(centerIndex)),
statsFinal.get(Integer.valueOf(centerIndex)));
}
centerCLT.saveStringInModelDirectory(
sb.toString(),
sceneSb.toString(),
"-IGR_OBS_INITIAL_FINAL_SCENES.csv",
false);
centerCLT.saveStringInModelDirectory(
pairSb.toString(),
"-IGR_OBS_INITIAL_FINAL_PAIRS.csv",
false);
centerCLT.saveStringInModelDirectory(
pairSb.toString(),
"-IGR_OBS_INITIAL_FINAL.csv",
false);
}
private static class PairAggregate {
int count = 0;
int weightedCount = 0;
double weightSum = 0.0;
double weightedRmsSum = 0.0;
double rmsMax = Double.NaN;
}
private static class ScenePairStats {
final PairAggregate asScene = new PairAggregate();
final PairAggregate asReference = new PairAggregate();
final PairAggregate all = new PairAggregate();
}
private static String getSceneTimestamp(
final QuadCLT[] quadCLTs,
final int sceneIndex,
final String missingPrefix) {
return ((sceneIndex >= 0) && (sceneIndex < quadCLTs.length) && (quadCLTs[sceneIndex] != null)) ?
quadCLTs[sceneIndex].getImageName() :
(missingPrefix + "#" + sceneIndex);
}
private static ScenePairStats getScenePairStats(
final HashMap<Integer, ScenePairStats> statsMap,
final int sceneIndex) {
final Integer key = Integer.valueOf(sceneIndex);
ScenePairStats stats = statsMap.get(key);
if (stats == null) {
stats = new ScenePairStats();
statsMap.put(
key,
stats);
}
return stats;
}
private static void updatePairAggregate(
final PairAggregate acc,
final double pairWeight,
final double rms) {
acc.count++;
if (Double.isNaN(rms) || Double.isNaN(pairWeight) || (pairWeight <= 0.0)) {
return;
}
acc.weightedCount++;
acc.weightSum += pairWeight;
acc.weightedRmsSum += pairWeight * rms;
acc.rmsMax = Double.isNaN(acc.rmsMax) ? rms : Math.max(
acc.rmsMax,
rms);
}
private static void accumulateScenePairStats(
final HashMap<Integer, ScenePairStats> statsMap,
final int sceneIndex,
final int refIndex,
final double pairWeight,
final double rms) {
final ScenePairStats sceneStats = getScenePairStats(
statsMap,
sceneIndex);
updatePairAggregate(
sceneStats.asScene,
pairWeight,
rms);
updatePairAggregate(
sceneStats.all,
pairWeight,
rms);
if (refIndex != sceneIndex) {
final ScenePairStats refStats = getScenePairStats(
statsMap,
refIndex);
updatePairAggregate(
refStats.asReference,
pairWeight,
rms);
updatePairAggregate(
refStats.all,
pairWeight,
rms);
}
}
private static double getWeightedRmsMean(final PairAggregate acc) {
return (acc.weightSum > 0.0) ? (acc.weightedRmsSum / acc.weightSum) : Double.NaN;
}
private static void appendPairAggregate(
final StringBuilder sb,
final PairAggregate acc) {
sb.append(',').append(acc.count)
.append(',').append(acc.weightedCount)
.append(',').append(String.format(Locale.US, "%.12g", acc.weightSum))
.append(',').append(String.format(Locale.US, "%.12g", getWeightedRmsMean(acc)))
.append(',').append(String.format(Locale.US, "%.12g", acc.rmsMax));
}
private static void appendSceneInitialFinalRow(
final StringBuilder sb,
final int sceneIndex,
final QuadCLT[] quadCLTs,
final double[][][] scenesInitial,
final double[][][] scenesFinal,
final int firstScene,
final int lastScene,
final int centerIndex,
final ScenePairStats statsInitial,
final ScenePairStats statsFinal) {
final String sceneTs = getSceneTimestamp(
quadCLTs,
sceneIndex,
"scene");
final double[][] pose0 = getScenePose(
scenesInitial,
sceneIndex,
centerIndex);
final double[] curv0 = getSceneCurvature(
sceneIndex,
firstScene,
lastScene,
centerIndex,
scenesInitial);
final double[][] pose1 = getScenePose(
scenesFinal,
sceneIndex,
centerIndex);
final double[] curv1 = getSceneCurvature(
sceneIndex,
firstScene,
lastScene,
centerIndex,
scenesFinal);
final ScenePairStats s0 = (statsInitial != null) ? statsInitial : new ScenePairStats();
final ScenePairStats s1 = (statsFinal != null) ? statsFinal : new ScenePairStats();
sb.append(sceneIndex).append(',')
.append(sceneTs)
.append(',').append(String.format(Locale.US, "%.12g", pose0[0][0]))
.append(',').append(String.format(Locale.US, "%.12g", pose0[0][1]))
.append(',').append(String.format(Locale.US, "%.12g", pose0[0][2]))
.append(',').append(String.format(Locale.US, "%.12g", pose0[1][0]))
.append(',').append(String.format(Locale.US, "%.12g", pose0[1][1]))
.append(',').append(String.format(Locale.US, "%.12g", pose0[1][2]))
.append(',').append(String.format(Locale.US, "%.12g", curv0[0]))
.append(',').append(String.format(Locale.US, "%.12g", curv0[1]))
.append(',').append(String.format(Locale.US, "%.12g", curv0[2]))
.append(',').append(String.format(Locale.US, "%.12g", curv0[3]))
.append(',').append(String.format(Locale.US, "%.12g", curv0[4]))
.append(',').append(String.format(Locale.US, "%.12g", curv0[5]))
.append(',').append(String.format(Locale.US, "%.12g", pose1[0][0]))
.append(',').append(String.format(Locale.US, "%.12g", pose1[0][1]))
.append(',').append(String.format(Locale.US, "%.12g", pose1[0][2]))
.append(',').append(String.format(Locale.US, "%.12g", pose1[1][0]))
.append(',').append(String.format(Locale.US, "%.12g", pose1[1][1]))
.append(',').append(String.format(Locale.US, "%.12g", pose1[1][2]))
.append(',').append(String.format(Locale.US, "%.12g", curv1[0]))
.append(',').append(String.format(Locale.US, "%.12g", curv1[1]))
.append(',').append(String.format(Locale.US, "%.12g", curv1[2]))
.append(',').append(String.format(Locale.US, "%.12g", curv1[3]))
.append(',').append(String.format(Locale.US, "%.12g", curv1[4]))
.append(',').append(String.format(Locale.US, "%.12g", curv1[5]));
appendPairAggregate(
sb,
s0.asScene);
appendPairAggregate(
sb,
s0.asReference);
appendPairAggregate(
sb,
s0.all);
appendPairAggregate(
sb,
s1.asScene);
appendPairAggregate(
sb,
s1.asReference);
appendPairAggregate(
sb,
s1.all);
sb.append('\n');
}
private static long makePairKey(
final int sceneIndex,
final int refIndex) {
......
......@@ -137,6 +137,189 @@ public class OpticalFlow {
return "unknown scene-matching failure reason="+fr;
}
}
private static int findSceneIndexByTimestamp(
final QuadCLT[] quadCLTs,
final String timestamp) {
if ((quadCLTs == null) || (timestamp == null) || timestamp.isEmpty()) {
return -1;
}
for (int i = 0; i < quadCLTs.length; i++) {
if ((quadCLTs[i] != null) && timestamp.equals(quadCLTs[i].getImageName())) {
return i;
}
}
return -1;
}
private static String getInterIntraLmaPath(
final QuadCLT scene,
final String timestamp) {
if ((scene == null) || (timestamp == null) || timestamp.isEmpty()) {
return null;
}
return scene.getX3dDirectory() + Prefs.getFileSeparator() + timestamp +
QuadCLTCPU.DSI_SUFFIXES[QuadCLTCPU.INDEX_INTER_LMA] + ".tiff";
}
private static String getDsiMainPath(
final QuadCLT scene,
final String timestamp) {
if ((scene == null) || (timestamp == null) || timestamp.isEmpty()) {
return null;
}
return scene.getX3dDirectory() + Prefs.getFileSeparator() + timestamp +
QuadCLTCPU.DSI_SUFFIXES[QuadCLTCPU.INDEX_DSI_MAIN] + ".tiff";
}
private static String resolveQuarterInterIntraPath(
final QuadCLT[] quadCLTs,
final int refIndex,
final int fallbackIndex,
final String timestamp) {
QuadCLT dirScene = ((refIndex >= 0) && (refIndex < quadCLTs.length)) ? quadCLTs[refIndex] : null;
String ts = timestamp;
if ((ts == null) || ts.isEmpty()) {
if ((fallbackIndex >= 0) && (fallbackIndex < quadCLTs.length) && (quadCLTs[fallbackIndex] != null)) {
ts = quadCLTs[fallbackIndex].getImageName();
dirScene = quadCLTs[fallbackIndex];
}
} else {
final int idx = findSceneIndexByTimestamp(quadCLTs, ts);
if ((idx >= 0) && (idx < quadCLTs.length) && (quadCLTs[idx] != null)) {
dirScene = quadCLTs[idx];
}
}
return getInterIntraLmaPath(dirScene, ts);
}
private static int resolveQuarterRefIndex(
final QuadCLT[] quadCLTs,
final int rangeStart,
final int rangeEnd,
final int fallbackIndex,
final String timestamp) {
int idx = findSceneIndexByTimestamp(quadCLTs, timestamp);
if ((idx < rangeStart) || (idx > rangeEnd)) {
idx = fallbackIndex;
}
if (idx < rangeStart) {
idx = rangeStart;
}
if (idx > rangeEnd) {
idx = rangeEnd;
}
return idx;
}
private static boolean ensureQuarterReferenceProducts(
final CLTParameters clt_parameters,
final ColorProcParameters colorProcParameters,
final EyesisCorrectionParameters.RGBParameters rgbParameters,
final QuadCLT quadCLT_main,
final QuadCLT[] quadCLTs,
final SetChannels[] set_channels,
final int centerRefIndex,
final int quarterRefIndex,
final int rangeStart,
final int rangeEnd,
final boolean forceRecalculateQuarterRefs,
final boolean quarterSfmOnly,
final boolean batch_mode,
final int threadsMax,
final boolean updateStatus,
final int debugLevel) {
if ((quadCLTs == null) || (set_channels == null) ||
(centerRefIndex < 0) || (centerRefIndex >= quadCLTs.length) ||
(quarterRefIndex < 0) || (quarterRefIndex >= quadCLTs.length) ||
(rangeStart > rangeEnd)) {
return false;
}
if (quadCLTs[centerRefIndex] == null) {
return false;
}
if (quadCLTs[quarterRefIndex] == null) {
quadCLTs[quarterRefIndex] = quadCLTs[centerRefIndex].spawnNoModelQuadCLT(
set_channels[quarterRefIndex].set_name,
clt_parameters,
colorProcParameters,
threadsMax,
debugLevel - 2);
}
if (quadCLTs[quarterRefIndex] == null) {
return false;
}
if (forceRecalculateQuarterRefs) {
final String quarterTs = quadCLTs[quarterRefIndex].getImageName();
final String quarterInterPath = getInterIntraLmaPath(quadCLTs[quarterRefIndex], quarterTs);
final String quarterDsiMainPath = getDsiMainPath(quadCLTs[quarterRefIndex], quarterTs);
if (debugLevel > -3) {
System.out.println("buildSeries(): forcing quarter-reference regeneration for " + quarterTs);
}
if (quarterInterPath != null) {
final File fInter = new File(quarterInterPath);
if (fInter.exists() && !fInter.delete()) {
System.out.println("buildSeries(): WARNING failed to delete quarter INTER-INTRA-LMA " + quarterInterPath);
}
}
if (quarterDsiMainPath != null) {
final File fDsi = new File(quarterDsiMainPath);
if (fDsi.exists() && !fDsi.delete()) {
System.out.println("buildSeries(): WARNING failed to delete quarter DSI_MAIN " + quarterDsiMainPath);
}
}
quadCLTs[quarterRefIndex].setDSI(null);
}
if (!quadCLTs[quarterRefIndex].dsiExists()) {
if (debugLevel > -3) {
System.out.println("buildSeries(): generating -DSI_MAIN for quarter scene " +
quadCLTs[quarterRefIndex].getImageName());
}
buildRefDSI(
clt_parameters,
false,
false,
colorProcParameters,
rgbParameters,
batch_mode,
set_channels[quarterRefIndex].set_name,
quadCLT_main,
quadCLTs[quarterRefIndex],
threadsMax,
updateStatus,
debugLevel);
}
if (!quadCLTs[quarterRefIndex].dsiExists()) {
return false;
}
final EstimateSceneRange quarterRange = new EstimateSceneRange();
quarterRange.earliest = rangeStart;
quarterRange.latest = rangeEnd;
quarterRange.center = quarterRefIndex;
quarterRange.earliest_prescan = rangeStart;
quarterRange.latest_prescan = rangeEnd;
quarterRange.needs_prescan = false;
if (debugLevel > -3) {
System.out.println("buildSeries(): generating quarter INTER-INTRA-LMA with scanSfmIMS(), center=" +
quarterRefIndex + ", range=[" + rangeStart + "," + rangeEnd + "], sfm_only=" + quarterSfmOnly);
}
final boolean sfmOk = EstimateSceneRange.scanSfmIMS(
clt_parameters,
quarterRange,
quadCLTs,
quadCLT_main,
colorProcParameters,
set_channels,
batch_mode,
updateStatus,
debugLevel,
quarterSfmOnly);
if (!sfmOk) {
return false;
}
return quadCLTs[quarterRefIndex].interDsiExists();
}
public static double [] ZERO3 = {0.0,0.0,0.0};
public static double LINE_ERR = 0.1;
public static int THREADS_MAX = 100; // maximal number of threads to launch
......@@ -6100,6 +6283,163 @@ java.lang.NullPointerException
int [] range = new int [] {earliest_scene, last_index};
if (use_global_lma) {
final QuadCLT centerRefScene = ((ref_index >= 0) && (ref_index < quadCLTs.length)) ? quadCLTs[ref_index] : null;
if (centerRefScene != null) {
final int overlapScenes = Math.max(1, Math.min(4, (range[1] - range[0] + 1) / 20 + 1));
final int q1RangeStart = range[0];
final int q1RangeEnd = Math.min(range[1], ref_index + overlapScenes);
final int q3RangeStart = Math.max(range[0], ref_index - overlapScenes);
final int q3RangeEnd = range[1];
final int q1Guess = Math.max(q1RangeStart, Math.min(ref_index - 1, (q1RangeStart + ref_index) / 2));
final int q3Guess = Math.min(q3RangeEnd, Math.max(ref_index + 1, (q3RangeEnd + ref_index) / 2));
final int q1Index = resolveQuarterRefIndex(
quadCLTs,
q1RangeStart,
q1RangeEnd,
q1Guess,
centerRefScene.timestamp_quarter1);
final int q3Index = resolveQuarterRefIndex(
quadCLTs,
q3RangeStart,
q3RangeEnd,
q3Guess,
centerRefScene.timestamp_quarter3);
String q1Ts = (quadCLTs[q1Index] != null) ?
quadCLTs[q1Index].getImageName() :
set_channels[q1Index].set_name;
String q3Ts = (quadCLTs[q3Index] != null) ?
quadCLTs[q3Index].getImageName() :
set_channels[q3Index].set_name;
boolean tsUpdated = false;
if ((centerRefScene.timestamp_quarter1 == null) || !centerRefScene.timestamp_quarter1.equals(q1Ts)) {
centerRefScene.timestamp_quarter1 = q1Ts;
tsUpdated = true;
}
if ((centerRefScene.timestamp_quarter3 == null) || !centerRefScene.timestamp_quarter3.equals(q3Ts)) {
centerRefScene.timestamp_quarter3 = q3Ts;
tsUpdated = true;
}
if (tsUpdated) {
centerRefScene.saveInterProperties(
null,
debugLevel + 1);
}
String q1Path = resolveQuarterInterIntraPath(
quadCLTs,
q1Index,
q1Index,
centerRefScene.timestamp_quarter1);
String q3Path = resolveQuarterInterIntraPath(
quadCLTs,
q3Index,
q3Index,
centerRefScene.timestamp_quarter3);
final String q1MsgPath = (q1Path != null) ? q1Path :
(centerRefScene.getX3dDirectory() + Prefs.getFileSeparator() + q1Ts +
QuadCLTCPU.DSI_SUFFIXES[QuadCLTCPU.INDEX_INTER_LMA] + ".tiff");
final String q3MsgPath = (q3Path != null) ? q3Path :
(centerRefScene.getX3dDirectory() + Prefs.getFileSeparator() + q3Ts +
QuadCLTCPU.DSI_SUFFIXES[QuadCLTCPU.INDEX_INTER_LMA] + ".tiff");
final boolean forceQuarterRecalc = clt_parameters.iglp.glob_recalculate_quarter_refs;
final boolean q1Exists = (q1Path != null) && (new File(q1Path).exists());
final boolean q3Exists = (q3Path != null) && (new File(q3Path).exists());
final boolean q1Missing = !q1Exists || forceQuarterRecalc;
final boolean q3Missing = !q3Exists || forceQuarterRecalc;
if (debugLevel > -3) {
System.out.println("buildSeries(): quarter refs selected: q1 ts=" + q1Ts +
", idx=" + q1Index + ", range=[" + q1RangeStart + "," + q1RangeEnd +
"], path=" + q1MsgPath + ", exists=" + q1Exists);
System.out.println("buildSeries(): quarter refs selected: q3 ts=" + q3Ts +
", idx=" + q3Index + ", range=[" + q3RangeStart + "," + q3RangeEnd +
"], path=" + q3MsgPath + ", exists=" + q3Exists);
if (forceQuarterRecalc) {
System.out.println("buildSeries(): quarter-reference force regeneration is enabled");
}
}
if (q1Missing) {
if (q1Exists && forceQuarterRecalc) {
System.out.println("buildSeries(): quarter1 INTER-INTRA-LMA exists, but force regeneration is enabled, will regenerate " + q1MsgPath);
} else {
System.out.println("buildSeries(): quarter1 INTER-INTRA-LMA missing, will generate " + q1MsgPath);
}
} else if (debugLevel > -3) {
System.out.println("buildSeries(): quarter1 INTER-INTRA-LMA present, using " + q1MsgPath);
}
if (q3Missing) {
if (q3Exists && forceQuarterRecalc) {
System.out.println("buildSeries(): quarter3 INTER-INTRA-LMA exists, but force regeneration is enabled, will regenerate " + q3MsgPath);
} else {
System.out.println("buildSeries(): quarter3 INTER-INTRA-LMA missing, will generate " + q3MsgPath);
}
} else if (debugLevel > -3) {
System.out.println("buildSeries(): quarter3 INTER-INTRA-LMA present, using " + q3MsgPath);
}
if (q1Missing || q3Missing) {
System.out.println("buildSeries(): quarter reference prerequisites missing, generating before Global LMA");
boolean q1Ok = true;
boolean q3Ok = true;
if (q1Missing) {
q1Ok = ensureQuarterReferenceProducts(
clt_parameters,
colorProcParameters,
rgbParameters,
quadCLT_main,
quadCLTs,
set_channels,
ref_index,
q1Index,
q1RangeStart,
q1RangeEnd,
forceQuarterRecalc,
clt_parameters.iglp.glob_quarter_refs_sfm_only,
batch_mode,
threadsMax,
updateStatus,
debugLevel);
}
if (q3Missing) {
q3Ok = ensureQuarterReferenceProducts(
clt_parameters,
colorProcParameters,
rgbParameters,
quadCLT_main,
quadCLTs,
set_channels,
ref_index,
q3Index,
q3RangeStart,
q3RangeEnd,
forceQuarterRecalc,
clt_parameters.iglp.glob_quarter_refs_sfm_only,
batch_mode,
threadsMax,
updateStatus,
debugLevel);
}
q1Path = resolveQuarterInterIntraPath(
quadCLTs,
q1Index,
q1Index,
centerRefScene.timestamp_quarter1);
q3Path = resolveQuarterInterIntraPath(
quadCLTs,
q3Index,
q3Index,
centerRefScene.timestamp_quarter3);
if (!q1Ok || (q1Path == null) || !(new File(q1Path).exists())) {
System.out.println("buildSeries(): WARNING quarter1 generation failed or output missing: " + q1MsgPath);
}
if (!q3Ok || (q3Path == null) || !(new File(q3Path).exists())) {
System.out.println("buildSeries(): WARNING quarter3 generation failed or output missing: " + q3MsgPath);
}
if ((q1Path != null) && new File(q1Path).exists()) {
System.out.println("buildSeries(): generated quarter1 INTER-INTRA-LMA " + q1Path);
}
if ((q3Path != null) && new File(q3Path).exists()) {
System.out.println("buildSeries(): generated quarter3 INTER-INTRA-LMA " + q3Path);
}
}
}
IntersceneGlobalRefine.Result igr_result = Interscene.reAdjustPairsLMAIntersceneGlobalReference(
clt_parameters, // final CLTParameters clt_parameters,
quadCLTs, // final QuadCLT[] quadCLTs,
......
......@@ -246,6 +246,8 @@ public class QuadCLTCPU {
// only reference scene has a pair of first/last scene in a sequence
public String timestamp_first = null;
public String timestamp_last = null;
public String timestamp_quarter1 = null;
public String timestamp_quarter3 = null;
public String timestamp_index = null; // timestamp of the scene with index of all reference scenes in this sequence
public HashSet<String> ref_scenes = null; // Set of timestamps of the reference scenes in this sequence
// combined clt for center view, only used in cuas mode
......@@ -7755,12 +7757,18 @@ LogTee.clearSceneLog(); // stop per‑scene logging
if (this.timestamp_first != null) {
properties.setProperty(prefix+"timestamp_first", this.timestamp_first);
}
if (this.timestamp_quarter1 != null) {
properties.setProperty(prefix+"timestamp_quarter1", this.timestamp_quarter1);
}
if (this.timestamp_index != null) {
properties.setProperty(prefix+"timestamp_index", this.timestamp_index);
}
if (this.timestamp_last != null) {
properties.setProperty(prefix+"timestamp_last", this.timestamp_last);
}
if (this.timestamp_quarter3 != null) {
properties.setProperty(prefix+"timestamp_quarter3", this.timestamp_quarter3);
}
if (this.quat_corr != null) {
properties.setProperty(prefix+"quat_corr", IntersceneMatchParameters.doublesToString(this.quat_corr));
......@@ -7972,9 +7980,15 @@ LogTee.clearSceneLog(); // stop per‑scene logging
if (properties.getProperty(prefix+"timestamp_first")!=null) {
this.timestamp_first= (String) properties.getProperty(prefix+"timestamp_first");
}
if (properties.getProperty(prefix+"timestamp_quarter1")!=null) {
this.timestamp_quarter1= (String) properties.getProperty(prefix+"timestamp_quarter1");
}
if (properties.getProperty(prefix+"timestamp_last")!=null) {
this.timestamp_last= (String) properties.getProperty(prefix+"timestamp_last");
}
if (properties.getProperty(prefix+"timestamp_quarter3")!=null) {
this.timestamp_quarter3= (String) properties.getProperty(prefix+"timestamp_quarter3");
}
if (properties.getProperty(prefix+"timestamp_index")!=null) {
this.timestamp_index= (String) properties.getProperty(prefix+"timestamp_index");
}
......
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