Commit 1671728b authored by Andrey Filippov's avatar Andrey Filippov

Equalizing intensities

parent c4df622d
package com.elphel.imagej.common; package com.elphel.imagej.common;
import java.util.concurrent.atomic.AtomicInteger;
import com.elphel.imagej.tileprocessor.ImageDtt;
import com.elphel.imagej.tileprocessor.QuadCLT;
import Jama.LUDecomposition; import Jama.LUDecomposition;
import Jama.Matrix; import Jama.Matrix;
public class PolynomialApproximation { public class PolynomialApproximation {
public int debugLevel=1; public int debugLevel=1;
// TODO Move other methods here // TODO Move other methods here
public PolynomialApproximation(){} public PolynomialApproximation(){}
public PolynomialApproximation(int debugLevel){ public PolynomialApproximation(int debugLevel){
this.debugLevel=debugLevel; this.debugLevel=debugLevel;
...@@ -53,7 +58,7 @@ public class PolynomialApproximation { ...@@ -53,7 +58,7 @@ public class PolynomialApproximation {
System.out.println("polynomialApproximation1d() B:"); System.out.println("polynomialApproximation1d() B:");
B.print(10, 5); B.print(10, 5);
} }
// while (!(new LUDecomposition(M)).isNonsingular() && (N1>0)){ // while (!(new LUDecomposition(M)).isNonsingular() && (N1>0)){
while (!(new LUDecomposition(M)).isNonsingular() && (N1>=0)){ // make N=0 legal ? while (!(new LUDecomposition(M)).isNonsingular() && (N1>=0)){ // make N=0 legal ?
aM=new double [N1][N1]; aM=new double [N1][N1];
aB=new double [N1][1]; aB=new double [N1][1];
...@@ -81,14 +86,14 @@ public class PolynomialApproximation { ...@@ -81,14 +86,14 @@ public class PolynomialApproximation {
for (int i=0;i<=N;i++) result[i]=(i<=N1)?aR[i][0]:0.0; for (int i=0;i<=N;i++) result[i]=(i<=N1)?aR[i][0]:0.0;
return result; return result;
} }
/** /**
* Linear approximates each of 3 functions of 3 variables and finds where they are all zero * Linear approximates each of 3 functions of 3 variables and finds where they are all zero
* @param data: for each sample (1-st index): * @param data: for each sample (1-st index):
* 0 - {x,y,z} * 0 - {x,y,z}
* 1 - {f1, f2, f3}, * 1 - {f1, f2, f3},
* 2 - {weight} * 2 - {weight}
* @return {x0, y0, z0} where A1*x0+B1*y0+C1*z0+D1=0, A2*x0+B2*y0+C2*z0+D2=0, A3*x0+B3*y0+C3*z0+D3=0 * @return {x0, y0, z0} where A1*x0+B1*y0+C1*z0+D1=0, A2*x0+B2*y0+C2*z0+D2=0, A3*x0+B3*y0+C3*z0+D3=0
*/ */
public double [] linear3d(double [][][] data){ public double [] linear3d(double [][][] data){
/* /*
* Approximating each of the 3 measured parameters (Far/near, tilt x and tilt y) with linear approximation in the vicinity of the last position * Approximating each of the 3 measured parameters (Far/near, tilt x and tilt y) with linear approximation in the vicinity of the last position
...@@ -102,10 +107,10 @@ public class PolynomialApproximation { ...@@ -102,10 +107,10 @@ public class PolynomialApproximation {
if (this.debugLevel>3){ if (this.debugLevel>3){
System.out.println( System.out.println(
parNum+","+data[nSample][0][0]+","+data[nSample][0][1]+","+data[nSample][0][2]+","+ parNum+","+data[nSample][0][0]+","+data[nSample][0][1]+","+data[nSample][0][2]+","+
data[nSample][1][0]+","+data[nSample][1][1]+","+data[nSample][1][2]+","+data[nSample][2][0]); data[nSample][1][0]+","+data[nSample][1][1]+","+data[nSample][1][2]+","+data[nSample][2][0]);
} }
//TODO replace with PolynomialApproximation class //TODO replace with PolynomialApproximation class
double w=(data[nSample].length>2)?data[nSample][2][0]:1.0; double w=(data[nSample].length>2)?data[nSample][2][0]:1.0;
double [] xyz=data[nSample][0]; double [] xyz=data[nSample][0];
S0+=w; S0+=w;
...@@ -168,151 +173,151 @@ public class PolynomialApproximation { ...@@ -168,151 +173,151 @@ public class PolynomialApproximation {
} }
public double[] quadraticMax2d (double [][][] data){ public double[] quadraticMax2d (double [][][] data){
return quadraticMax2d (data,1.0E-15); return quadraticMax2d (data,1.0E-15);
} }
public double[] quadraticMax2d (double [][][] data, double thresholdQuad){ public double[] quadraticMax2d (double [][][] data, double thresholdQuad){
return quadraticMax2d (data,thresholdQuad, debugLevel); return quadraticMax2d (data,thresholdQuad, debugLevel);
} }
public double[] quadraticMax2d (double [][][] data,double thresholdQuad, int debugLevel){ public double[] quadraticMax2d (double [][][] data,double thresholdQuad, int debugLevel){
double [][] coeff=quadraticApproximation(data, false, 1.0E-20, thresholdQuad,debugLevel); double [][] coeff=quadraticApproximation(data, false, 1.0E-20, thresholdQuad,debugLevel);
if (coeff==null) return null; if (coeff==null) return null;
if (coeff[0].length<6) return null; if (coeff[0].length<6) return null;
double [][] aM={ double [][] aM={
{2*coeff[0][0], coeff[0][2]}, // | 2A, C | {2*coeff[0][0], coeff[0][2]}, // | 2A, C |
{ coeff[0][2],2*coeff[0][1]}}; // | C, 2B | { coeff[0][2],2*coeff[0][1]}}; // | C, 2B |
Matrix M=(new Matrix(aM)); Matrix M=(new Matrix(aM));
double nmQ=normMatix(aM); double nmQ=normMatix(aM);
if (debugLevel>3) System.out.println("M.det()="+M.det()+" normMatix(aM)="+nmQ+" data.length="+data.length); if (debugLevel>3) System.out.println("M.det()="+M.det()+" normMatix(aM)="+nmQ+" data.length="+data.length);
if ((nmQ==0.0) || (Math.abs(M.det())/normMatix(aM)<thresholdQuad)) { if ((nmQ==0.0) || (Math.abs(M.det())/normMatix(aM)<thresholdQuad)) {
if (debugLevel>3) System.out.println("quadraticMax2d() failed: M.det()="+M.det()+" normMatix(aM)="+normMatix(aM)); if (debugLevel>3) System.out.println("quadraticMax2d() failed: M.det()="+M.det()+" normMatix(aM)="+normMatix(aM));
return null; return null;
} }
double [][] aB={ double [][] aB={
{-coeff[0][3]}, // | - D | {-coeff[0][3]}, // | - D |
{-coeff[0][4]}}; // | - E | {-coeff[0][4]}}; // | - E |
double [] xy=M.solve(new Matrix(aB)).getColumnPackedCopy(); double [] xy=M.solve(new Matrix(aB)).getColumnPackedCopy();
return xy; return xy;
} }
// returns maximum's coordinates, value, and coefficients for x2, y2 and xy // returns maximum's coordinates, value, and coefficients for x2, y2 and xy
public double[] quadraticMaxV2dX2Y2XY (double [][][] data,double thresholdQuad, int debugLevel){ public double[] quadraticMaxV2dX2Y2XY (double [][][] data,double thresholdQuad, int debugLevel){
double [][] coeff=quadraticApproximation(data, false, 1.0E-20, thresholdQuad,debugLevel); double [][] coeff=quadraticApproximation(data, false, 1.0E-20, thresholdQuad,debugLevel);
if (coeff==null) return null; if (coeff==null) return null;
if (coeff[0].length<6) return null; if (coeff[0].length<6) return null;
double [][] aM={ double [][] aM={
{2*coeff[0][0], coeff[0][2]}, // | 2A, C | {2*coeff[0][0], coeff[0][2]}, // | 2A, C |
{ coeff[0][2],2*coeff[0][1]}}; // | C, 2B | { coeff[0][2],2*coeff[0][1]}}; // | C, 2B |
Matrix M=(new Matrix(aM)); Matrix M=(new Matrix(aM));
double nmQ=normMatix(aM); double nmQ=normMatix(aM);
if (debugLevel>3) System.out.println("M.det()="+M.det()+" normMatix(aM)="+nmQ+" data.length="+data.length); if (debugLevel>3) System.out.println("M.det()="+M.det()+" normMatix(aM)="+nmQ+" data.length="+data.length);
if ((nmQ==0.0) || (Math.abs(M.det())/normMatix(aM)<thresholdQuad)) { if ((nmQ==0.0) || (Math.abs(M.det())/normMatix(aM)<thresholdQuad)) {
if (debugLevel>3) System.out.println("quadraticMax2d() failed: M.det()="+M.det()+" normMatix(aM)="+normMatix(aM)); if (debugLevel>3) System.out.println("quadraticMax2d() failed: M.det()="+M.det()+" normMatix(aM)="+normMatix(aM));
return null; return null;
} }
double [][] aB={ double [][] aB={
{-coeff[0][3]}, // | - D | {-coeff[0][3]}, // | - D |
{-coeff[0][4]}}; // | - E | {-coeff[0][4]}}; // | - E |
double [] xy=M.solve(new Matrix(aB)).getColumnPackedCopy(); double [] xy=M.solve(new Matrix(aB)).getColumnPackedCopy();
double vmax = coeff[0][0]* xy[0]*xy[0]+coeff[0][1]*xy[1]*xy[1]+coeff[0][2]*xy[0]*xy[1]+coeff[0][3]*xy[0]+coeff[0][4]*xy[1]+coeff[0][5]; double vmax = coeff[0][0]* xy[0]*xy[0]+coeff[0][1]*xy[1]*xy[1]+coeff[0][2]*xy[0]*xy[1]+coeff[0][3]*xy[0]+coeff[0][4]*xy[1]+coeff[0][5];
double [] xyx2y2 = {xy[0], xy[1], vmax, coeff[0][0], coeff[0][1], coeff[0][2], coeff[0][3], coeff[0][4], coeff[0][5]}; double [] xyx2y2 = {xy[0], xy[1], vmax, coeff[0][0], coeff[0][1], coeff[0][2], coeff[0][3], coeff[0][4], coeff[0][5]};
return xyx2y2; return xyx2y2;
} }
/* ======================================================================== */ /* ======================================================================== */
/** /**
* See below, this version is for backward compatibility with no damping * See below, this version is for backward compatibility with no damping
* @param data * @param data
* @param forceLinear * @param forceLinear
* @return * @return
*/ */
public double [][] quadraticApproximation( public double [][] quadraticApproximation(
double [][][] data, double [][][] data,
boolean forceLinear) // use linear approximation boolean forceLinear) // use linear approximation
{ {
return quadraticApproximation( return quadraticApproximation(
data, data,
forceLinear, forceLinear,
null); null);
} }
/** /**
* Approximate function z(x,y) as a second degree polynomial (or just linear) * Approximate function z(x,y) as a second degree polynomial (or just linear)
* f(x,y)=A*x^2+B*y^2+C*x*y+D*x+E*y+F or f(x,y)=D*x+E*y+F * f(x,y)=A*x^2+B*y^2+C*x*y+D*x+E*y+F or f(x,y)=D*x+E*y+F
* @param data array consists of lines of either 2 or 3 vectors: * @param data array consists of lines of either 2 or 3 vectors:
* 2-element vector x,y * 2-element vector x,y
* variable length vector z (should be the same for all samples) * variable length vector z (should be the same for all samples)
* optional 1- element vector w (weight of the sample) * optional 1- element vector w (weight of the sample)
* @param forceLinear force linear approximation * @param forceLinear force linear approximation
* @param damping optional (may be null) array of 3 (for linear) or 6 (quadratic) values that adds cost * @param damping optional (may be null) array of 3 (for linear) or 6 (quadratic) values that adds cost
* for corresponding coefficient be non-zero. This can be used to find reasonable solutions when * for corresponding coefficient be non-zero. This can be used to find reasonable solutions when
* data is insufficient. Just one data point would result in a plane of constant z, co-linear * data is insufficient. Just one data point would result in a plane of constant z, co-linear
* points will produce a plane with a gradient along this line * points will produce a plane with a gradient along this line
* @return array of vectors or null * @return array of vectors or null
* each vector (one per each z component) is either 6-element- (A,B,C,D,E,F) if quadratic is possible and enabled * each vector (one per each z component) is either 6-element- (A,B,C,D,E,F) if quadratic is possible and enabled
* or 3-element - (D,E,F) if linear is possible and quadratic is not possible or disabled * or 3-element - (D,E,F) if linear is possible and quadratic is not possible or disabled
* returns null if not enough data even for the linear approximation * returns null if not enough data even for the linear approximation
*/ */
public double [][] quadraticApproximation( public double [][] quadraticApproximation(
double [][][] data, double [][][] data,
boolean forceLinear, // use linear approximation boolean forceLinear, // use linear approximation
double [] damping) double [] damping)
{ {
return quadraticApproximation( return quadraticApproximation(
data, data,
forceLinear, // use linear approximation forceLinear, // use linear approximation
damping, damping,
this.debugLevel); this.debugLevel);
} }
public double [][] quadraticApproximation( // no use public double [][] quadraticApproximation( // no use
double [][][] data, double [][][] data,
boolean forceLinear, // use linear approximation boolean forceLinear, // use linear approximation
int debugLevel int debugLevel
){ ){
return quadraticApproximation( return quadraticApproximation(
data, data,
forceLinear, // use linear approximation forceLinear, // use linear approximation
null, null,
debugLevel); debugLevel);
} }
public double [][] quadraticApproximation( public double [][] quadraticApproximation(
double [][][] data, double [][][] data,
boolean forceLinear, // use linear approximation boolean forceLinear, // use linear approximation
double [] damping, double [] damping,
int debugLevel int debugLevel
){ ){
return quadraticApproximation( return quadraticApproximation(
data, data,
forceLinear, // use linear approximation forceLinear, // use linear approximation
damping, damping,
1.0E-10, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail) 11.0E-10 failed where it shouldn't? 1.0E-10, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail) 11.0E-10 failed where it shouldn't?
1.0E-15, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail) 1.0E-15, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail)
debugLevel); debugLevel);
} }
public double [][] quadraticApproximation( public double [][] quadraticApproximation(
double [][][] data, double [][][] data,
boolean forceLinear, // use linear approximation boolean forceLinear, // use linear approximation
double thresholdLin, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail) double thresholdLin, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail)
double thresholdQuad) // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail) double thresholdQuad) // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail)
{ {
return quadraticApproximation( return quadraticApproximation(
data, data,
forceLinear, // use linear approximation forceLinear, // use linear approximation
null, null,
1.0E-10, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail) 11.0E-10 failed where it shouldn't? 1.0E-10, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail) 11.0E-10 failed where it shouldn't?
1.0E-15, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail) 1.0E-15, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail)
this.debugLevel); this.debugLevel);
} }
/* /*
public double [][] quadraticApproximation( // no use public double [][] quadraticApproximation( // no use
double [][][] data, double [][][] data,
boolean forceLinear, // use linear approximation boolean forceLinear, // use linear approximation
...@@ -328,39 +333,39 @@ public class PolynomialApproximation { ...@@ -328,39 +333,39 @@ public class PolynomialApproximation {
1.0E-15, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail) 1.0E-15, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail)
this.debugLevel); this.debugLevel);
} }
*/ */
public double [][] quadraticApproximation( public double [][] quadraticApproximation(
double [][][] data, double [][][] data,
boolean forceLinear, // use linear approximation boolean forceLinear, // use linear approximation
double thresholdLin, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail) double thresholdLin, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail)
double thresholdQuad, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail) double thresholdQuad, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail)
int debugLevel) int debugLevel)
{ {
return quadraticApproximation( return quadraticApproximation(
data, data,
forceLinear, // use linear approximation forceLinear, // use linear approximation
null, null,
thresholdLin, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail) 11.0E-10 failed where it shouldn't? thresholdLin, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail) 11.0E-10 failed where it shouldn't?
thresholdQuad, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail) thresholdQuad, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail)
debugLevel); debugLevel);
} }
public double [][] quadraticApproximation( public double [][] quadraticApproximation(
double [][][] data, double [][][] data,
boolean forceLinear, // use linear approximation boolean forceLinear, // use linear approximation
double [] damping, double [] damping,
double thresholdLin, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail) double thresholdLin, // threshold ratio of matrix determinant to norm for linear approximation (det too low - fail)
double thresholdQuad, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail) double thresholdQuad, // threshold ratio of matrix determinant to norm for quadratic approximation (det too low - fail)
int debugLevel int debugLevel
){ ){
if (debugLevel>3) System.out.println("quadraticApproximation(...), debugLevel="+debugLevel+":"); if (debugLevel>3) System.out.println("quadraticApproximation(...), debugLevel="+debugLevel+":");
if ((data == null) || (data.length == 0)) { if ((data == null) || (data.length == 0)) {
return null; return null;
} }
/* ix, iy - the location of the point with maximal value. We'll approximate the vicinity of that maximum using a /* ix, iy - the location of the point with maximal value. We'll approximate the vicinity of that maximum using a
* second degree polynomial: * second degree polynomial:
Z(x,y)~=A*x^2+B*y^2+C*x*y+D*x+E*y+F Z(x,y)~=A*x^2+B*y^2+C*x*y+D*x+E*y+F
by minimizing sum of squared differenceS00between the actual (Z(x,uy)) and approximated values. by minimizing sum of squared differenceS00between the actual (Z(x,uy)) and approximated values.
and then find the maximum on the approximated surface. Here iS00the math: and then find the maximum on the approximated surface. Here iS00the math:
...@@ -424,183 +429,338 @@ public class PolynomialApproximation { ...@@ -424,183 +429,338 @@ public class PolynomialApproximation {
(4) 0= A*S30 + B*S12 + C*S21 + D*S20 + E*S11 + F*S10 - SZ10 (4) 0= A*S30 + B*S12 + C*S21 + D*S20 + E*S11 + F*S10 - SZ10
(5) 0= A*S21 + B*S03 + C*S12 + D*S11 + E*S02 + F*S01 - SZ01 (5) 0= A*S21 + B*S03 + C*S12 + D*S11 + E*S02 + F*S01 - SZ01
(6) 0= A*S20 + B*S02 + C*S11 + D*S10 + E*S01 + F*S00 - SZ00 (6) 0= A*S20 + B*S02 + C*S11 + D*S10 + E*S01 + F*S00 - SZ00
*/ */
Matrix mDampingLin = null; Matrix mDampingLin = null;
Matrix mDampingQuad = null; Matrix mDampingQuad = null;
if (damping != null){ if (damping != null){
mDampingLin = new Matrix(3,3); mDampingLin = new Matrix(3,3);
for (int i = 0; i < 3; i++){ for (int i = 0; i < 3; i++){
int j = damping.length + i - 3; int j = damping.length + i - 3;
if (j >= 0) mDampingLin.set(i,i,damping[j]); if (j >= 0) mDampingLin.set(i,i,damping[j]);
} }
if (!forceLinear) { if (!forceLinear) {
mDampingQuad = new Matrix(6,6); mDampingQuad = new Matrix(6,6);
for (int i = 0; i < 6; i++){ for (int i = 0; i < 6; i++){
int j = damping.length + i - 6; int j = damping.length + i - 6;
if (j >= 0) mDampingQuad.set(i,i,damping[j]); if (j >= 0) mDampingQuad.set(i,i,damping[j]);
} }
} }
} }
int zDim = 0; // =data[0][1].length; int zDim = 0; // =data[0][1].length;
for (int i = 0; i < data.length; i++) if (data[i] != null){ for (int i = 0; i < data.length; i++) if (data[i] != null){
zDim =data[i][1].length; zDim =data[i][1].length;
break; break;
} }
double w,z,x,x2,x3,x4,y,y2,y3,y4,wz; double w,z,x,x2,x3,x4,y,y2,y3,y4,wz;
int i,j,n=0; int i,j,n=0;
double S00=0.0, double S00=0.0,
S10=0.0,S01=0.0, S10=0.0,S01=0.0,
S20=0.0,S11=0.0,S02=0.0, S20=0.0,S11=0.0,S02=0.0,
S30=0.0,S21=0.0,S12=0.0,S03=0.0, S30=0.0,S21=0.0,S12=0.0,S03=0.0,
S40=0.0,S31=0.0,S22=0.0,S13=0.0,S04=0.0; S40=0.0,S31=0.0,S22=0.0,S13=0.0,S04=0.0;
double [] SZ00=new double [zDim]; double [] SZ00=new double [zDim];
double [] SZ01=new double [zDim]; double [] SZ01=new double [zDim];
double [] SZ10=new double [zDim]; double [] SZ10=new double [zDim];
double [] SZ11=new double [zDim]; double [] SZ11=new double [zDim];
double [] SZ02=new double [zDim]; double [] SZ02=new double [zDim];
double [] SZ20=new double [zDim]; double [] SZ20=new double [zDim];
for (i=0;i<zDim;i++) { for (i=0;i<zDim;i++) {
SZ00[i]=0.0; SZ00[i]=0.0;
SZ01[i]=0.0; SZ01[i]=0.0;
SZ10[i]=0.0; SZ10[i]=0.0;
SZ11[i]=0.0; SZ11[i]=0.0;
SZ02[i]=0.0; SZ02[i]=0.0;
SZ20[i]=0.0; SZ20[i]=0.0;
} }
for (i=0;i<data.length;i++) if (data[i] != null){ for (i=0;i<data.length;i++) if (data[i] != null){
w=(data[i].length>2)? data[i][2][0]:1.0; w=(data[i].length>2)? data[i][2][0]:1.0;
if (w>0) { if (w>0) {
n++; n++;
x=data[i][0][0]; x=data[i][0][0];
y=data[i][0][1]; y=data[i][0][1];
x2=x*x; x2=x*x;
y2=y*y; y2=y*y;
S00+=w; S00+=w;
S10+=w*x; S10+=w*x;
S01+=w*y; S01+=w*y;
S11+=w*x*y; S11+=w*x*y;
S20+=w*x2; S20+=w*x2;
S02+=w*y2; S02+=w*y2;
if (!forceLinear) { if (!forceLinear) {
x3=x2*x; x3=x2*x;
x4=x3*x; x4=x3*x;
y3=y2*y; y3=y2*y;
y4=y3*y; y4=y3*y;
S30+=w*x3; S30+=w*x3;
S21+=w*x2*y; S21+=w*x2*y;
S12+=w*x*y2; S12+=w*x*y2;
S03+=w*y3; S03+=w*y3;
S40+=w*x4; S40+=w*x4;
S31+=w*x3*y; S31+=w*x3*y;
S22+=w*x2*y2; S22+=w*x2*y2;
S13+=w*x*y3; S13+=w*x*y3;
S04+=w*y4; S04+=w*y4;
} }
for (j=0;j<zDim;j++) { for (j=0;j<zDim;j++) {
z=data[i][1][j]; z=data[i][1][j];
wz=w*z; wz=w*z;
SZ00[j]+=wz; SZ00[j]+=wz;
SZ10[j]+=wz*x; SZ10[j]+=wz*x;
SZ01[j]+=wz*y; SZ01[j]+=wz*y;
if (!forceLinear) { if (!forceLinear) {
SZ20[j]+=wz*x2; SZ20[j]+=wz*x2;
SZ11[j]+=wz*x*y; SZ11[j]+=wz*x*y;
SZ02[j]+=wz*y2; SZ02[j]+=wz*y2;
} }
} }
}
}
//need to decide if there is enough data for linear and quadratic
double [][] mAarrayL= {
{S20,S11,S10},
{S11,S02,S01},
{S10,S01,S00}};
Matrix mLin=new Matrix (mAarrayL);
if (mDampingLin != null){
mLin.plusEquals(mDampingLin);
}
// TODO Maybe bypass determinant checks for damped ?
Matrix Z;
if (debugLevel>3) System.out.println(">>> n="+n+" det_lin="+mLin.det()+" norm_lin="+normMatix(mAarrayL));
double nmL=normMatix(mAarrayL);
if ((nmL==0.0) || (Math.abs(mLin.det())/nmL<thresholdLin)){
// return average value for each channel
if (S00==0.0) return null; // not even average
double [][] ABCDEF=new double[zDim][3];
for (i=0;i<zDim;i++) {
ABCDEF[i][0]=0.0;
ABCDEF[i][1]=0.0;
ABCDEF[i][2]=SZ00[i]/S00;
}
return ABCDEF;
}
double []zAarrayL=new double [3];
double [][] ABCDEF=new double[zDim][];
// double [] zAarrayL={SZ10,SZ01,SZ00};
for (i=0;i<zDim;i++) {
zAarrayL[0]=SZ10[i];
zAarrayL[1]=SZ01[i];
zAarrayL[2]=SZ00[i];
Z=new Matrix (zAarrayL,3);
ABCDEF[i]= mLin.solve(Z).getRowPackedCopy();
}
if (forceLinear) return ABCDEF;
// quote try quadratic approximation
double [][] mAarrayQ= {
{S40,S22,S31,S30,S21,S20},
{S22,S04,S13,S12,S03,S02},
{S31,S13,S22,S21,S12,S11},
{S30,S12,S21,S20,S11,S10},
{S21,S03,S12,S11,S02,S01},
{S20,S02,S11,S10,S01,S00}};
Matrix mQuad=new Matrix (mAarrayQ);
if (mDampingQuad != null){
mQuad.plusEquals(mDampingQuad);
}
if (debugLevel>3) {
System.out.println(" n="+n+" det_quad="+mQuad.det()+" norm_quad="+normMatix(mAarrayQ)+" data.length="+data.length);
mQuad.print(10,5);
}
double nmQ=normMatix(mAarrayQ);
if ((nmQ==0.0) || (Math.abs(mQuad.det())/normMatix(mAarrayQ)<thresholdQuad)) {
if (debugLevel>0) System.out.println("Using linear approximation, M.det()="+mQuad.det()+
" normMatix(mAarrayQ)="+normMatix(mAarrayQ)+
", thresholdQuad="+thresholdQuad+
", nmQ="+nmQ+
", Math.abs(M.det())/normMatix(mAarrayQ)="+(Math.abs(mQuad.det())/normMatix(mAarrayQ))); //did not happen
return ABCDEF; // not enough data for the quadratic approximation, return linear
}
// double [] zAarrayQ={SZ20,SZ02,SZ11,SZ10,SZ01,SZ00};
double [] zAarrayQ=new double [6];
for (i=0;i<zDim;i++) {
zAarrayQ[0]=SZ20[i];
zAarrayQ[1]=SZ02[i];
zAarrayQ[2]=SZ11[i];
zAarrayQ[3]=SZ10[i];
zAarrayQ[4]=SZ01[i];
zAarrayQ[5]=SZ00[i];
Z=new Matrix (zAarrayQ,6);
ABCDEF[i]= mQuad.solve(Z).getRowPackedCopy();
}
return ABCDEF;
}
// calculate "volume" made of the matrix row-vectors, placed orthogonally
// to be compared to determinant
public double normMatix(double [][] a) {
double d,norm=1.0;
for (int i=0;i<a.length;i++) {
d=0;
for (int j=0;j<a[i].length;j++) d+=a[i][j]*a[i][j];
norm*=Math.sqrt(d);
}
return norm;
} }
}
//need to decide if there is enough data for linear and quadratic
double [][] mAarrayL= {
{S20,S11,S10},
{S11,S02,S01},
{S10,S01,S00}};
Matrix mLin=new Matrix (mAarrayL);
if (mDampingLin != null){
mLin.plusEquals(mDampingLin);
}
// TODO Maybe bypass determinant checks for damped ?
Matrix Z;
if (debugLevel>3) System.out.println(">>> n="+n+" det_lin="+mLin.det()+" norm_lin="+normMatix(mAarrayL));
double nmL=normMatix(mAarrayL);
if ((nmL==0.0) || (Math.abs(mLin.det())/nmL<thresholdLin)){
// return average value for each channel
if (S00==0.0) return null; // not even average
double [][] ABCDEF=new double[zDim][3];
for (i=0;i<zDim;i++) {
ABCDEF[i][0]=0.0;
ABCDEF[i][1]=0.0;
ABCDEF[i][2]=SZ00[i]/S00;
}
return ABCDEF;
}
double []zAarrayL=new double [3];
double [][] ABCDEF=new double[zDim][];
// double [] zAarrayL={SZ10,SZ01,SZ00};
for (i=0;i<zDim;i++) {
zAarrayL[0]=SZ10[i];
zAarrayL[1]=SZ01[i];
zAarrayL[2]=SZ00[i];
Z=new Matrix (zAarrayL,3);
ABCDEF[i]= mLin.solve(Z).getRowPackedCopy();
}
if (forceLinear) return ABCDEF;
// quote try quadratic approximation
double [][] mAarrayQ= {
{S40,S22,S31,S30,S21,S20},
{S22,S04,S13,S12,S03,S02},
{S31,S13,S22,S21,S12,S11},
{S30,S12,S21,S20,S11,S10},
{S21,S03,S12,S11,S02,S01},
{S20,S02,S11,S10,S01,S00}};
Matrix mQuad=new Matrix (mAarrayQ);
if (mDampingQuad != null){
mQuad.plusEquals(mDampingQuad);
}
if (debugLevel>3) {
System.out.println(" n="+n+" det_quad="+mQuad.det()+" norm_quad="+normMatix(mAarrayQ)+" data.length="+data.length);
mQuad.print(10,5);
}
double nmQ=normMatix(mAarrayQ);
if ((nmQ==0.0) || (Math.abs(mQuad.det())/normMatix(mAarrayQ)<thresholdQuad)) {
if (debugLevel>0) System.out.println("Using linear approximation, M.det()="+mQuad.det()+
" normMatix(mAarrayQ)="+normMatix(mAarrayQ)+
", thresholdQuad="+thresholdQuad+
", nmQ="+nmQ+
", Math.abs(M.det())/normMatix(mAarrayQ)="+(Math.abs(mQuad.det())/normMatix(mAarrayQ))); //did not happen
return ABCDEF; // not enough data for the quadratic approximation, return linear
}
// double [] zAarrayQ={SZ20,SZ02,SZ11,SZ10,SZ01,SZ00};
double [] zAarrayQ=new double [6];
for (i=0;i<zDim;i++) {
zAarrayQ[0]=SZ20[i];
zAarrayQ[1]=SZ02[i];
zAarrayQ[2]=SZ11[i];
zAarrayQ[3]=SZ10[i];
zAarrayQ[4]=SZ01[i];
zAarrayQ[5]=SZ00[i];
Z=new Matrix (zAarrayQ,6);
ABCDEF[i]= mQuad.solve(Z).getRowPackedCopy();
}
return ABCDEF;
}
// calculate "volume" made of the matrix row-vectors, placed orthogonally
// to be compared to determinant
public double normMatix(double [][] a) {
double d,norm=1.0;
for (int i=0;i<a.length;i++) {
d=0;
for (int j=0;j<a[i].length;j++) d+=a[i][j]*a[i][j];
norm*=Math.sqrt(d);
}
return norm;
}
//RuntimeException public static double [] getYXRegression(
final double [] data_x,
final double [] data_y,
final boolean [] mask) {
final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
final AtomicInteger ai = new AtomicInteger(0);
final double [] as0 = new double[threads.length];
final double [] asx = new double[threads.length];
final double [] asx2 = new double[threads.length];
final double [] asy = new double[threads.length];
final double [] asxy= new double[threads.length];
final AtomicInteger ati = new AtomicInteger(0);
ai.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
int thread_num = ati.getAndIncrement();
for (int ipix = ai.getAndIncrement(); ipix < data_x.length; ipix = ai.getAndIncrement()) if ((mask == null) || mask[ipix]){
double x = data_x[ipix];
double y = data_y[ipix];
if (!Double.isNaN(x) && !Double.isNaN(y)) {
as0 [thread_num] += 1;
asx [thread_num] += x;
asx2[thread_num] += x * x;
asy [thread_num] += y;
asxy[thread_num] += x * y;
}
} // for (int ipix
}
};
}
ImageDtt.startAndJoin(threads);
double s0 = 0.0;
double sx = 0.0;
double sx2 = 0.0;
double sy = 0.0;
double sxy= 0.0;
for (int i = 0; i < threads.length; i++) {
s0+= as0[i];
sx+= asx[i];
sx2+= asx2[i];
sy+= asy[i];
sxy+= asxy[i];
}
double dnm = s0 * sx2 - sx*sx;
double a = (sxy * s0 - sy * sx) / dnm;
double b = (sy * sx2 - sxy * sx) / dnm;
return new double[] {a,b};
}
/**
* Get best fit ax+b symmetrical for X and Y, same weights
* https://en.wikipedia.org/wiki/Deming_regression#Orthogonal_regression
* @param data_x
* @param data_y
* @param mask
* @return
*/
public static double [] getOrthoRegression( // symmetrical for X and Y, same eror weights
final double [] data_x,
final double [] data_y,
final boolean [] mask_in) {
final boolean [] mask = new boolean [data_x.length];
final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
final AtomicInteger ai = new AtomicInteger(0);
final double [] as0 = new double[threads.length];
final double [] asx = new double[threads.length];
final double [] asy = new double[threads.length];
final AtomicInteger ati = new AtomicInteger(0);
ai.set(0);
// Find centroid first
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
int thread_num = ati.getAndIncrement();
for (int ipix = ai.getAndIncrement(); ipix < data_x.length; ipix = ai.getAndIncrement()) if ((mask_in == null) || mask_in[ipix]){
double x = data_x[ipix];
double y = data_y[ipix];
if (!Double.isNaN(x) && !Double.isNaN(y)) {
as0 [thread_num] += 1;
asx [thread_num] += x;
asy [thread_num] += y;
mask[ipix] = true;
}
} // for (int ipix
}
};
}
ImageDtt.startAndJoin(threads);
double s0 = 0.0;
double sx = 0.0;
double sy = 0.0;
for (int i = 0; i < threads.length; i++) {
s0+= as0[i];
sx+= asx[i];
sy+= asy[i];
}
double [] z_mean = {sx/s0, sy/s0}; // complex
final double [] as_re = new double[threads.length];
final double [] as_im = new double[threads.length];
ai.set(0);
ati.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
int thread_num = ati.getAndIncrement();
for (int ipix = ai.getAndIncrement(); ipix < data_x.length; ipix = ai.getAndIncrement()) if ((mask == null) || mask[ipix]){
double x = data_x[ipix]-z_mean[0];
double y = data_y[ipix]-z_mean[1];
as_re[thread_num] += x*x - y*y;
as_im[thread_num] += 2*x*y;
} // for (int ipix
}
};
}
ImageDtt.startAndJoin(threads);
double s_re = 0.0;
double s_im = 0.0;
for (int i = 0; i < threads.length; i++) {
s_re+= as_re[i];
s_im+= as_im[i];
}
// https://en.wikipedia.org/wiki/Square_root#Algebraic_formula
// sqrt (s_re+i*s_im)
double sqrt_re = Math.sqrt(0.5 * (Math.sqrt(s_re*s_re + s_im*s_im) +s_re));
double sqrt_im = ((s_im > 0)? 1 : -1) * Math.sqrt(0.5 * (Math.sqrt(s_re*s_re + s_im*s_im) - s_re));
double a = sqrt_im/sqrt_re;
double b = z_mean[1]- a * z_mean[0];
return new double[] {a,b};
}
public static void applyRegression(
final double [] data, // clone by caller
final double [] regression) {
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() {
public void run() {
for (int ipix = ai.getAndIncrement(); ipix < data.length; ipix = ai.getAndIncrement()){
data[ipix] = regression[0] * data[ipix] + regression[1];
}
}
};
}
ImageDtt.startAndJoin(threads);
}
public static double [] invertRegression(double [] regression) {
return new double [] {1.0/regression[0], -regression[1]/regression[0]};
}
} }
...@@ -171,7 +171,7 @@ public class ComboMatch { ...@@ -171,7 +171,7 @@ public class ComboMatch {
boolean pattern_match = true; // false; boolean pattern_match = true; // false;
boolean bounds_to_indices = true; boolean bounds_to_indices = true;
int temp_mode = 1; int temp_mode = 0;
boolean restore_temp = true; boolean restore_temp = true;
double frac_remove = clt_parameters.imp.pmtch_frac_remove; // 0.15; double frac_remove = clt_parameters.imp.pmtch_frac_remove; // 0.15;
double metric_error = clt_parameters.imp.pmtch_metric_err; // 0.05; // 0.02;// 2 cm double metric_error = clt_parameters.imp.pmtch_metric_err; // 0.05; // 0.02;// 2 cm
...@@ -1030,10 +1030,13 @@ public class ComboMatch { ...@@ -1030,10 +1030,13 @@ public class ComboMatch {
} }
if (render_match) { if (render_match) {
String title=String.format("multi_%03d-%03d_%s-%s_zoom%d_%d",gpu_pair[0],gpu_pair[1],gpu_spair[0],gpu_spair[1],min_zoom_lev,zoom_lev); String title=String.format("multi_%03d-%03d_%s-%s_zoom%d_%d",gpu_pair[0],gpu_pair[1],gpu_spair[0],gpu_spair[1],min_zoom_lev,zoom_lev);
// Avoid renderMulti() - it duplicates code renderMultiDouble()
int eq_mode = 2; // calculate
ImagePlus imp_img_pair = maps_collection.renderMulti ( ImagePlus imp_img_pair = maps_collection.renderMulti (
//_zoom<integer> is needed for opening with "Extract Objects" command //_zoom<integer> is needed for opening with "Extract Objects" command
title, // String title, title, // String title,
OrthoMapsCollection.MODE_IMAGE, // int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask // boolean use_alt, // OrthoMapsCollection.MODE_IMAGE, // int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask // boolean use_alt,
eq_mode, //int eq_mode, // 0 - ignore equalization, 1 - use stored equalization, 2 - calculate equalization
gpu_pair, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) gpu_pair, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
bounds_to_indices, // boolean bounds_to_indices, bounds_to_indices, // boolean bounds_to_indices,
temp_mode, // int temp_mode, // 0 - do nothing, 1 - equalize average,2 - try to correct temp_mode, // int temp_mode, // 0 - do nothing, 1 - equalize average,2 - try to correct
......
...@@ -115,6 +115,7 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{ ...@@ -115,6 +115,7 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
public transient double agl = Double.NaN; public transient double agl = Double.NaN;
public transient int num_scenes = -1;; // number of scenes that made up this image public transient int num_scenes = -1;; // number of scenes that made up this image
public transient double sfm_gain = Double.NaN; // maximal SfM gain of this map public transient double sfm_gain = Double.NaN; // maximal SfM gain of this map
public transient double [] equalize = {1,0}; // rectified value = equalize[0]*source_value+equalize[1]
private void writeObject(ObjectOutputStream oos) throws IOException { private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject(); oos.defaultWriteObject();
oos.writeObject(path); oos.writeObject(path);
...@@ -137,8 +138,9 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{ ...@@ -137,8 +138,9 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
oos.writeObject(agl); oos.writeObject(agl);
oos.writeObject(num_scenes); oos.writeObject(num_scenes);
oos.writeObject(sfm_gain); oos.writeObject(sfm_gain);
oos.writeObject(equalize);
} }
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
// sfm_gain = Double.NaN; // sfm_gain = Double.NaN;
// num_scenes = -1; // num_scenes = -1;
...@@ -160,12 +162,26 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{ ...@@ -160,12 +162,26 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
agl = (double) ois.readObject(); agl = (double) ois.readObject();
num_scenes = (int) ois.readObject(); num_scenes = (int) ois.readObject();
sfm_gain = (double) ois.readObject(); sfm_gain = (double) ois.readObject();
// equalize = new double[] {1,0};
equalize = (double []) ois.readObject();
images = new HashMap <Integer, FloatImageData>(); // field images was not saved images = new HashMap <Integer, FloatImageData>(); // field images was not saved
averageImagePixel = Double.NaN; // average image pixel value (to combine with raw) averageImagePixel = Double.NaN; // average image pixel value (to combine with raw)
// pairwise_matches is not transient // pairwise_matches is not transient
// pairwise_matches = new HashMap<Double, PairwiseOrthoMatch>(); // pairwise_matches = new HashMap<Double, PairwiseOrthoMatch>();
} }
double getEqualized(double d) {
return d * equalize[0] + equalize[1];
}
double [] getEqualize() {
return equalize;
}
void setEqualize(double [] equalize) {
this.equalize = equalize;
}
@Override @Override
public int compareTo(OrthoMap otherPlayer) { public int compareTo(OrthoMap otherPlayer) {
...@@ -1717,9 +1733,9 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{ ...@@ -1717,9 +1733,9 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
}; };
} }
ImageDtt.startAndJoin(threads); ImageDtt.startAndJoin(threads);
double [] ab = getDatiRegression( double [] ab = PolynomialApproximation.getYXRegression(
temp, // final double [] temp, temp, // final double [] data_x,
dati, // final double [] dati, dati, // final double [] data_y,
flat); // final boolean [] mask); flat); // final boolean [] mask);
double a = ab[0]; double a = ab[0];
double b = ab[1]; double b = ab[1];
...@@ -1774,56 +1790,6 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{ ...@@ -1774,56 +1790,6 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
return flat; return flat;
} }
private static double [] getDatiRegression(
final double [] temp,
final double [] dati,
final boolean [] mask) {
final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
final AtomicInteger ai = new AtomicInteger(0);
final double [] as0 = new double[threads.length];
final double [] asx = new double[threads.length];
final double [] asx2 = new double[threads.length];
final double [] asy = new double[threads.length];
final double [] asxy= new double[threads.length];
final AtomicInteger ati = new AtomicInteger(0);
ai.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
int thread_num = ati.getAndIncrement();
for (int ipix = ai.getAndIncrement(); ipix < temp.length; ipix = ai.getAndIncrement()) if (mask[ipix]){
double x = temp[ipix];
double y = dati[ipix];
if (!Double.isNaN(x+y)) {
as0 [thread_num] += 1;
asx [thread_num] += x;
asx2[thread_num] += x * x;
asy [thread_num] += y;
asxy[thread_num] += x * y;
}
} // for (int ipix
}
};
}
ImageDtt.startAndJoin(threads);
double s0 = 0.0;
double sx = 0.0;
double sx2 = 0.0;
double sy = 0.0;
double sxy= 0.0;
for (int i = 0; i < threads.length; i++) {
s0+= as0[i];
sx+= asx[i];
sx2+= asx2[i];
sy+= asy[i];
sxy+= asxy[i];
}
double dnm = s0 * sx2 - sx*sx;
double a = (sxy * s0 - sy * sx) / dnm;
double b = (sy * sx2 - sxy * sx) / dnm;
return new double[] {a,b};
}
private static int [][] getCirclePoints( private static int [][] getCirclePoints(
double radius) { double radius) {
......
...@@ -30,6 +30,7 @@ import com.elphel.imagej.calibration.CalibrationFileManagement; ...@@ -30,6 +30,7 @@ import com.elphel.imagej.calibration.CalibrationFileManagement;
import com.elphel.imagej.cameras.CLTParameters; import com.elphel.imagej.cameras.CLTParameters;
import com.elphel.imagej.common.DoubleGaussianBlur; import com.elphel.imagej.common.DoubleGaussianBlur;
import com.elphel.imagej.common.GenericJTabbedDialog; import com.elphel.imagej.common.GenericJTabbedDialog;
import com.elphel.imagej.common.PolynomialApproximation;
import com.elphel.imagej.common.ShowDoubleFloatArrays; import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.gpu.GPUTileProcessor; import com.elphel.imagej.gpu.GPUTileProcessor;
import com.elphel.imagej.gpu.TpTask; import com.elphel.imagej.gpu.TpTask;
...@@ -537,32 +538,10 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -537,32 +538,10 @@ public class OrthoMapsCollection implements Serializable{
ol.setPixels(xy_src); ol.setPixels(xy_src);
} }
} }
public ImagePlus renderMulti (
String title,
int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask
boolean show_centers,
int zoom_level,
int temp_mode, // 0 - do nothing, 1 - equalize average,2 - try to correct
int [] origin){
return renderMulti (
title, // String title,
mode, // int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask
null, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
false, // bounds_to_indices, // boolean bounds_to_indices,
temp_mode, // int temp_mode, // 0 - do nothing, 1 - equalize average,2 - try to correct
null, // double [][][] affines, // null or [indices.length][2][3]
null, // FineXYCorr warp,
show_centers, // boolean show_centers,
zoom_level, // int zoom_level,
origin); // int [] origin)
}
public ImagePlus renderMulti ( public ImagePlus renderMulti (
String title, String title,
// boolean use_alt, int eq_mode, // 0 - ignore equalization, 1 - use stored equalization, 2 - calculate equalization
int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask
int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
boolean bounds_to_indices, boolean bounds_to_indices,
int temp_mode, // 0 - do nothing, 1 - equalize average,2 - try to correct int temp_mode, // 0 - do nothing, 1 - equalize average,2 - try to correct
...@@ -570,82 +549,157 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -570,82 +549,157 @@ public class OrthoMapsCollection implements Serializable{
FineXYCorr warp, // use for a single pair only FineXYCorr warp, // use for a single pair only
boolean show_centers, boolean show_centers,
int zoom_level, int zoom_level,
int [] origin){ int [] origin){
int num_images = (indices != null)? indices.length : ortho_maps.length;
int [] wh = new int[2]; int [] wh = new int[2];
double [][] centers = new double [(indices !=null)? indices.length: ortho_maps.length][]; double [][] centers = new double [(indices !=null)? indices.length: ortho_maps.length][];
/*
float [][] multi = renderMulti ( float [][] multi = renderMulti (
// use_alt, // boolean use_alt, OrthoMapsCollection.MODE_IMAGE, // int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask
mode, // int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
bounds_to_indices, // boolean bounds_to_indices, bounds_to_indices, // boolean bounds_to_indices,
affines, // double [][][] affines, // null or [indices.length][2][3] affines, // double [][][] affines, // null or [indices.length][2][3]
warp, // FineXYCorr warp,, warp, // FineXYCorr warp,
zoom_level, // int zoom_level, zoom_level, // int zoom_level,
wh, // int [] wh, wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers) centers); // double [][] centers)
int num_images = (indices != null)? indices.length : ortho_maps.length; */
String [] map_names = new String[num_images + (((num_images==2) && (mode == MODE_IMAGE))? 1 : 0)]; double [][] dmulti = renderMultiDouble (
float [][] extra_multi = new float [map_names.length][]; null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
bounds_to_indices, // boolean bounds_to_indices,
affines, // affines, // double [][][] affines, // null or [indices.length][2][3]
null, // double [][] equalize,
(eq_mode != 1), // boolean ignore_equalize,
null, // warp, // FineXYCorr warp,,
zoom_level, // int zoom_level,
wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers)
if ((eq_mode == 2) && (num_images == 2)) {
boolean [] mask = new boolean [dmulti[0].length];
// int hist_min = -140,hist_max=135; // 700,200
// int hist_min = -100,hist_max=100; // 700,200
int hist_min = -250,hist_max=100; // 700,200
int hist_width= hist_max-hist_min;
double [] hist = new double [hist_width*hist_width];
for (int i = 0; i < dmulti[0].length; i++) if (!Double.isNaN(dmulti[0][i]) && !Double.isNaN(dmulti[1][i])){
int x = (int) Math.round(dmulti[0][i]) - hist_min;
int y = (int) Math.round(dmulti[1][i]) - hist_min;
if ((x>=0) && (y>=0) && (x < hist_width) && (y < hist_width)) {
int indx = y*hist_width+x;
hist[indx] += 1.0;
mask[i] = true;
}
}
ShowDoubleFloatArrays.showArrays(
hist,
hist_width,
hist_width,
title+"hist_"+hist_min+"_"+hist_max);
double [] dmulti1 = dmulti[1].clone();
double [] regression = PolynomialApproximation.getOrthoRegression(
dmulti[0], // final double [] data_x,
dmulti[1], // final double [] data_y,
mask); // final boolean [] mask)
double [] inv_regression = PolynomialApproximation.invertRegression(regression);
double [] regression10 = PolynomialApproximation.getOrthoRegression(
dmulti[1], // final double [] data_x,
dmulti[0], // final double [] data_y,
mask); // final boolean [] mask)
double [] regression00 = PolynomialApproximation.getOrthoRegression(
dmulti[0], // final double [] data_x,
dmulti[0], // final double [] data_y,
mask); // final boolean [] mask)
double [] regression11 = PolynomialApproximation.getOrthoRegression(
dmulti[1], // final double [] data_x,
dmulti[1], // final double [] data_y,
mask); // final boolean [] mask)
PolynomialApproximation.applyRegression(
dmulti1, // final double [] data, // clone by caller
inv_regression); // final double [] regression) {
double [] regression01 = PolynomialApproximation.getOrthoRegression(
dmulti[0], // final double [] data_x,
dmulti1, // final double [] data_y,
mask); // final boolean [] mask)
double [] dmulti12 = dmulti[1].clone();
for (int i = 0; i < dmulti12.length; i++) {
dmulti12[i] = 2.0*dmulti12[i]+10;
}
double [] regression012 = PolynomialApproximation.getOrthoRegression(
dmulti[0], // final double [] data_x,
dmulti12, // final double [] data_y,
mask); // final boolean [] mask)
double [] dmulti13 = dmulti[1].clone();
for (int i = 0; i < dmulti13.length; i++) {
dmulti13[i] = dmulti13[i]+10;
}
double [] regression013 = PolynomialApproximation.getOrthoRegression(
dmulti[0], // final double [] data_x,
dmulti13, // final double [] data_y,
mask); // final boolean [] mask)
double [] dmulti14 = dmulti[1].clone();
for (int i = 0; i < dmulti14.length; i++) {
dmulti14[i] = 2*dmulti14[i];
}
double [] regression014 = PolynomialApproximation.getOrthoRegression(
dmulti[0], // final double [] data_x,
dmulti14, // final double [] data_y,
mask); // final boolean [] mask)
double [] regression_single = getYXRegression(
dmulti[0], // final double [] data_x,
dmulti[1]); // final double [] data_y,
System.out.println();
}
String [] map_names = new String[num_images + (((num_images==2))? 1 : 0)];
// float [][] extra_multi = new float [map_names.length][];
double [][] extra_multi = new double [map_names.length][];
for (int n = 0; n <num_images; n++) { for (int n = 0; n <num_images; n++) {
int mapn= (indices != null)? indices[n] : n; int mapn= (indices != null)? indices[n] : n;
map_names[n] = ortho_maps[mapn].getName()+"_"+ortho_maps[mapn].getLocalDateTime().toString().replace("T","_")+"_UTC"; map_names[n] = ortho_maps[mapn].getName()+"_"+ortho_maps[mapn].getLocalDateTime().toString().replace("T","_")+"_UTC";
map_names[n] += String.format(" raw=%7.1f", ortho_maps[mapn].getTemperature()); map_names[n] += String.format(" raw=%7.1f", ortho_maps[mapn].getTemperature());
extra_multi[n] = multi[n]; extra_multi[n] = dmulti[n];
} }
if (map_names.length > num_images) { // inefficient way, only for display if (map_names.length > num_images) { // inefficient way, only for display
// correct(offset) pixel values relative to multi[0] // correct(offset) pixel values relative to multi[0]
int map0= (indices != null)? indices[0] : 0; int map0= (indices != null)? indices[0] : 0;
if (mode == MODE_IMAGE) { for (int n = 1; n < num_images; n++) {
for (int n = 1; n < num_images; n++) { //temp_mode, // 0 - do nothing, 1 - equalize average,2 - try to correct
//temp_mode, // 0 - do nothing, 1 - equalize average,2 - try to correct int mapn= (indices != null)? indices[n] : n;
int mapn= (indices != null)? indices[n] : n; double offs = 0;
double offs = 0; switch (temp_mode) {
switch (temp_mode) { case 1:
case 1: offs = ortho_maps[map0].getAveragePixel()-ortho_maps[mapn].getAveragePixel();
offs = ortho_maps[map0].getAveragePixel()-ortho_maps[mapn].getAveragePixel(); break;
break; case 2:
case 2: offs = ortho_maps[mapn].getTemperature()-ortho_maps[mapn].getAveragePixel()
offs = ortho_maps[mapn].getTemperature()-ortho_maps[mapn].getAveragePixel() -(ortho_maps[map0].getTemperature()-ortho_maps[map0].getAveragePixel());
-(ortho_maps[map0].getTemperature()-ortho_maps[map0].getAveragePixel()); break;
break; }
} // float foffs= (float) offs;
float foffs= (float) offs; for (int i = 0; i < extra_multi[n].length; i++) if (!Double.isNaN(extra_multi[n][i])) {
for (int i = 0; i < extra_multi[n].length; i++) if (!Float.isNaN(extra_multi[n][i])) { extra_multi[n][i]+= offs;
extra_multi[n][i]+= foffs;
}
} }
} }
map_names[num_images] = "Diff 0-1"; map_names[num_images] = "Diff 0-1";
extra_multi[num_images] = new float[extra_multi[0].length]; extra_multi[num_images] = new double[extra_multi[0].length];
for (int i = 0; i < extra_multi[num_images].length; i++) { for (int i = 0; i < extra_multi[num_images].length; i++) {
extra_multi[num_images][i] = extra_multi[1][i]-extra_multi[0][i]; extra_multi[num_images][i] = extra_multi[1][i]-extra_multi[0][i];
} }
} }
ImageStack stack; ImageStack stack;
if (mode == MODE_MASK) {
title +="-MASK";
byte [][] byte_pix = new byte[multi.length][]; // multi[0].length];
for (int n = 0; n < multi.length; n++) { // slow
byte_pix[n] = new byte[multi[n].length];
for (int i = 0; i < multi[n].length; i++) {
byte_pix[n][i] = (byte) (Float.isNaN(multi[n][i]) ? 0 : 0xff);
}
}
stack = ShowDoubleFloatArrays.makeStack(
byte_pix,
wh[0],
wh[1],
map_names);
} else {
stack = ShowDoubleFloatArrays.makeStack( stack = ShowDoubleFloatArrays.makeStack(
extra_multi, extra_multi,
wh[0], wh[0],
wh[1], wh[1],
map_names, map_names,
false); false);
}
ImagePlus imp = new ImagePlus(title, stack); ImagePlus imp = new ImagePlus(title, stack);
if (show_centers) { if (show_centers) {
PointRoi roi = new PointRoi(); PointRoi roi = new PointRoi();
...@@ -657,9 +711,28 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -657,9 +711,28 @@ public class OrthoMapsCollection implements Serializable{
} }
imp.show(); // debugging imp.show(); // debugging
return imp; return imp;
} }
public static double [] getYXRegression(
final double [] data_x,
final double [] data_y) {
double s0=0,sx=0,sx2=0,sy = 0, sxy=0;
for (int i = 0; i < data_x.length; i++) {
double x = data_x[i];
double y = 2*data_x[i];
if (!Double.isNaN(x) && !Double.isNaN(y)) {
s0+= 1.0;
sx+= x;
sx2+=x*x;
sy+= y;
sxy += x*y;
}
}
double d = (s0*sx2-sx*sx);
double a = (sxy*s0-sy*sx)/d;
double b = (sy*sx2-sx*sxy)/d;
return new double [] {a,b};
}
/** /**
* Rectify and render multiple images (as slices) matching vert_meters to * Rectify and render multiple images (as slices) matching vert_meters to
...@@ -671,27 +744,8 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -671,27 +744,8 @@ public class OrthoMapsCollection implements Serializable{
* @param centers - null or double[maps.length][] - will return image centers coordinates * @param centers - null or double[maps.length][] - will return image centers coordinates
* @return * @return
*/ */
public float [][] renderMulti (
int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask
int zoom_level,
int [] wh,
int [] origin, // maps[0] as a reference
double [][] centers){
return renderMulti (
// use_alt, // boolean use_alt,
mode, // int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask
null, // int [] indices,
false, // boolean bounds_to_indices,
null, // double [][][] affines,
null, // FineXYCorr warp,
zoom_level, // int zoom_level,
wh, // int [] wh,
origin, // int [] origin, // maps[0] as a reference
centers); // double [][] centers)
}
public float [][] renderMulti ( public float [][] renderMulti (
// boolean use_alt,
int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask
int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
boolean bounds_to_indices, boolean bounds_to_indices,
...@@ -703,9 +757,17 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -703,9 +757,17 @@ public class OrthoMapsCollection implements Serializable{
double [][] centers){ double [][] centers){
final boolean use_alt = mode == MODE_ALT; final boolean use_alt = mode == MODE_ALT;
final int dbg_x=2783, dbg_y=-5228; final int dbg_x=2783, dbg_y=-5228;
int [][] bounds = getBoundsPixels( // should be for rectified, {-bounds[0][0], -bounds[0][1]} - exact center int [][] bounds;
zoom_level, if (affines == null) {
bounds_to_indices? indices: null); bounds = getBoundsPixels( // should be for rectified, {-bounds[0][0], -bounds[0][1]} - exact center
zoom_level,
bounds_to_indices? indices: null);
} else {
bounds = getBoundsPixels( // should be for rectified, {-bounds[0][0], -bounds[0][1]} - exact center
zoom_level,
bounds_to_indices? indices: null,
affines);
}
int width = bounds[0][1] - bounds[0][0]; // bounds[x][0] - negative int width = bounds[0][1] - bounds[0][0]; // bounds[x][0] - negative
int height = bounds[1][1] - bounds[1][0]; int height = bounds[1][1] - bounds[1][0];
if (wh != null) { if (wh != null) {
...@@ -724,27 +786,24 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -724,27 +786,24 @@ public class OrthoMapsCollection implements Serializable{
} }
final float [][] fpixels = new float [indices.length][width * height]; final float [][] fpixels = new float [indices.length][width * height];
// for (int nmap:indices) { // = 0; nmap< ortho_maps.length; nmap++) {
for (int indx = 0; indx < indices.length; indx++) { //:indices) { // = 0; nmap< ortho_maps.length; nmap++) { for (int indx = 0; indx < indices.length; indx++) { //:indices) { // = 0; nmap< ortho_maps.length; nmap++) {
final int findx= indx; final int findx= indx;
final int nmap = indices[indx]; // nmap; final int nmap = indices[indx]; // nmap;
final double [][] affine = (affines !=null) ? affines[indx]: ortho_maps[nmap].affine; // only here use provided
Arrays.fill(fpixels[findx], Float.NaN); Arrays.fill(fpixels[findx], Float.NaN);
final double scale = 1.0/OrthoMap.getPixelSizeMeters(zoom_level); final double scale = 1.0/OrthoMap.getPixelSizeMeters(zoom_level);
final double src_scale = 1.0/OrthoMap.getPixelSizeMeters(ortho_maps[nmap].orig_zoom_level); // pix per meter final double src_scale = 1.0/OrthoMap.getPixelSizeMeters(ortho_maps[nmap].orig_zoom_level); // pix per meter
// metric bounds of the rectified image relative to its origin // double [][] mbounds = ortho_maps[nmap].getBoundsMeters(true); // keep original bounds
// double [][] mbounds = (affines !=null) ? double [][] mbounds = ortho_maps[nmap].getBoundsMeters(true,affine); // keep original bounds
// ortho_maps[nmap].getBoundsMeters(true, affines[indx]): // use provided affine
// ortho_maps[nmap].getBoundsMeters(true);
double [][] mbounds = ortho_maps[nmap].getBoundsMeters(true); // keep original bounds
double [] enu_offset = ortho_maps[indices[0]].enuOffsetTo(ortho_maps[nmap]); double [] enu_offset = ortho_maps[indices[0]].enuOffsetTo(ortho_maps[nmap]);
final double [] scaled_out_center = { // xy center to apply affine to final double [] scaled_out_center = { // xy center to apply affine to in output pixels
-bounds[0][0] + scale * enu_offset[0], -bounds[0][0] + scale * enu_offset[0],
-bounds[1][0] - scale * enu_offset[1]}; -bounds[1][0] - scale * enu_offset[1]};
if (centers != null) { if (centers != null) {
centers[findx] = scaled_out_center; centers[findx] = scaled_out_center;
} }
final int [][] obounds = new int [2][2]; // output (rectified, combined) image bounds, relative to thje top-left final int [][] obounds = new int [2][2]; // output (rectified, combined) image bounds, relative to the top-left
for (int n = 0; n< 2; n++) { for (int n = 0; n< 2; n++) { // output pixels
obounds[n][0] = (int) Math.floor(scaled_out_center[n] + scale*mbounds[n][0]); obounds[n][0] = (int) Math.floor(scaled_out_center[n] + scale*mbounds[n][0]);
obounds[n][1] = (int) Math.ceil (scaled_out_center[n] + scale*mbounds[n][1]); obounds[n][1] = (int) Math.ceil (scaled_out_center[n] + scale*mbounds[n][1]);
} }
...@@ -752,44 +811,69 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -752,44 +811,69 @@ public class OrthoMapsCollection implements Serializable{
final int ownd_width = obounds[0][1] - obounds[0][0]; final int ownd_width = obounds[0][1] - obounds[0][0];
final int ownd_height = obounds[1][1] - obounds[1][0]; final int ownd_height = obounds[1][1] - obounds[1][0];
final int ownd_len = ownd_width * ownd_height; final int ownd_len = ownd_width * ownd_height;
// double [][] src_bounds=(affines !=null) ? // double [][] src_bounds=ortho_maps[nmap].getBoundsMeters (true); // using original affines
// ortho_maps[nmap].getBoundsMeters (true, affines[indx]): // use provided affine double [][] src_bounds=ortho_maps[nmap].getBoundsMeters (false,affine); // using provided affines
// ortho_maps[nmap].getBoundsMeters (true);
double [][] src_bounds=ortho_maps[nmap].getBoundsMeters (true); // using original affines
final double [] src_center = {-src_bounds[0][0],-src_bounds[1][0]}; // x,y center offset in the source image final double [] src_center = {-src_bounds[0][0],-src_bounds[1][0]}; // x,y center offset in the source image
final double [][] affine = (affines !=null) ? affines[indx]: ortho_maps[nmap].affine; // only here use provided
final int src_width = use_alt? ortho_maps[nmap].getAltData().width: ortho_maps[nmap].getImageData().width; final int src_width = use_alt? ortho_maps[nmap].getAltData().width: ortho_maps[nmap].getImageData().width;
final int src_height = use_alt? ortho_maps[nmap].getAltData().height : ortho_maps[nmap].getImageData().height; final int src_height = use_alt? ortho_maps[nmap].getAltData().height : ortho_maps[nmap].getImageData().height;
final float [] src_img = use_alt? ortho_maps[nmap].getAltData().data : ortho_maps[nmap].getImageData().data;
if ((indx==0) && (warp != null)) { // set center from the first image if ((indx==0) && (warp != null)) { // set center from the first image
warp.setRender( warp.setRender(
zoom_level, // int zoom_lev, zoom_level, // int zoom_lev,
scaled_out_center[0], // double px0, // in render pixels scaled_out_center[0], // double px0, // in render pixels
scaled_out_center[1]); // // double py0); scaled_out_center[1]); // // double py0);
} }
final float [] src_img = use_alt? ortho_maps[nmap].getAltData().data : ortho_maps[nmap].getImageData().data;
final Rectangle warp_woi =((indx==1) && (warp != null))? warp.getRenderWOI():null; final Rectangle warp_woi =((indx==1) && (warp != null))? warp.getRenderWOI():null;
final Thread[] threads = ImageDtt.newThreadArray(); final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0); final AtomicInteger ai = new AtomicInteger(0);
/*
boolean tilt_alt = (ground_planes != null) && (ground_planes[indx] != null);
final float [] src_img = use_alt?
(tilt_alt? ortho_maps[nmap].getAltData().data.clone(): ortho_maps[nmap].getAltData().data) :
ortho_maps[nmap].getImageData().data;
if (tilt_alt) {
// apply tilt to the source altitudes
double [] vert_meters = ortho_maps[nmap].getVertMeters();
// altitude at top-left pixel;
final double top_left_alt =
ground_planes[indx][2] - vert_meters[0]*ground_planes[indx][0] - vert_meters[1]*ground_planes[indx][1];
final double [] tilt_XY = {ground_planes[indx][0]/src_scale, ground_planes[indx][1]/src_scale};
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int nPix = ai.getAndIncrement(); nPix < src_img.length; nPix = ai.getAndIncrement()) {
int py = nPix / src_width;
int px = nPix % src_width;
src_img[nPix] -= (top_left_alt + px * tilt_XY[0] + py * tilt_XY[1]);
}
}
};
}
ImageDtt.startAndJoin(threads);
ai.set(0);
}
*/
for (int ithread = 0; ithread < threads.length; ithread++) { for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() { threads[ithread] = new Thread() {
public void run() { public void run() {
for (int nPix = ai.getAndIncrement(); nPix < ownd_len; nPix = ai.getAndIncrement()) { for (int nPix = ai.getAndIncrement(); nPix < ownd_len; nPix = ai.getAndIncrement()) {
int opX = nPix % ownd_width + obounds[0][0]; // absolute output pX, pY int opX = nPix % ownd_width + obounds[0][0]; // absolute output pX, pY
int opY = nPix / ownd_width + obounds[1][0]; int opY = nPix / ownd_width + obounds[1][0];
double dX = (opX - scaled_out_center[0]) /scale; // in original image scale double dX = (opX - scaled_out_center[0]) /scale; // in meters
double dY = (opY - scaled_out_center[1]) /scale; double dY = (opY - scaled_out_center[1]) /scale;
double [] xy_src = { // pixels of the source image double [] xy_src = { // pixels of the source image
src_scale * (affine[0][0]*dX + affine[0][1]*dY + affine[0][2] + src_center[0]), src_scale * (affine[0][0]*dX + affine[0][1]*dY + affine[0][2] + src_center[0]),
src_scale * (affine[1][0]*dX + affine[1][1]*dY + affine[1][2] + src_center[1])}; src_scale * (affine[1][0]*dX + affine[1][1]*dY + affine[1][2] + src_center[1])};
// limit to the source image // limit to the source image
if ((((int) opX)==dbg_x) && (((int) opY)==dbg_y)) {
System.out.println("opX="+opX+", opy="+opY);
}
if ((warp_woi != null) && (warp_woi.contains(opX,opY))) { if ((warp_woi != null) && (warp_woi.contains(opX,opY))) {
if ((opX==dbg_x) && (opY==dbg_y)) {
System.out.println("opX="+opX+", opy="+opY);
}
double [] dxy = warp.getWarp(opX,opY); double [] dxy = warp.getWarp(opX,opY);
xy_src[0] += dxy[0]; xy_src[0] += dxy[0];
xy_src[1] += dxy[1]; xy_src[1] += dxy[1];
} }
if ((xy_src[0] >= 0) && (xy_src[0] < (src_width-1)) && if ((xy_src[0] >= 0) && (xy_src[0] < (src_width-1)) &&
(xy_src[1] >= 0) && (xy_src[1] < (src_height-1))) { (xy_src[1] >= 0) && (xy_src[1] < (src_height-1))) {
int [] ixy_src = {(int) Math.floor(xy_src[0]), (int)Math.floor(xy_src[1]) }; int [] ixy_src = {(int) Math.floor(xy_src[0]), (int)Math.floor(xy_src[1]) };
...@@ -821,14 +905,16 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -821,14 +905,16 @@ public class OrthoMapsCollection implements Serializable{
double [][] ground_planes, // null - images, non-null altitudes. use new double[2][] for old way alt double [][] ground_planes, // null - images, non-null altitudes. use new double[2][] for old way alt
int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
boolean bounds_to_indices, boolean bounds_to_indices,
double [][][] affines, // null or [indices.length][2][3] double [][][] affines, // null or [indices.length][2][3]
double [][] equalize_in,
boolean ignore_equalize,
FineXYCorr warp, FineXYCorr warp,
int zoom_level, int zoom_level,
int [] wh, int [] wh,
int [] origin, // maps[0] as a reference int [] origin, // maps[0] as a reference
double [][] centers){ double [][] centers){
boolean use_alt = ground_planes != null; boolean use_alt = ground_planes != null;
final int dbg_x=707, dbg_y=615; final int dbg_x=707, dbg_y=-615;
int [][] bounds; int [][] bounds;
if (affines == null) { if (affines == null) {
bounds = getBoundsPixels( // should be for rectified, {-bounds[0][0], -bounds[0][1]} - exact center bounds = getBoundsPixels( // should be for rectified, {-bounds[0][0], -bounds[0][1]} - exact center
...@@ -862,6 +948,7 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -862,6 +948,7 @@ public class OrthoMapsCollection implements Serializable{
final int findx= indx; final int findx= indx;
final int nmap = indices[indx]; // nmap; final int nmap = indices[indx]; // nmap;
final double [][] affine = (affines !=null) ? affines[indx]: ortho_maps[nmap].affine; // only here use provided final double [][] affine = (affines !=null) ? affines[indx]: ortho_maps[nmap].affine; // only here use provided
final double [] equalize = ignore_equalize ? null:((equalize_in != null) ? equalize_in[indx] : ortho_maps[nmap].equalize);
Arrays.fill(dpixels[findx], Float.NaN); Arrays.fill(dpixels[findx], Float.NaN);
final double scale = 1.0/OrthoMap.getPixelSizeMeters(zoom_level); final double scale = 1.0/OrthoMap.getPixelSizeMeters(zoom_level);
final double src_scale = 1.0/OrthoMap.getPixelSizeMeters(ortho_maps[nmap].orig_zoom_level); // pix per meter final double src_scale = 1.0/OrthoMap.getPixelSizeMeters(ortho_maps[nmap].orig_zoom_level); // pix per meter
...@@ -960,7 +1047,10 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -960,7 +1047,10 @@ public class OrthoMapsCollection implements Serializable{
d01* kxy[0] *(1.0 - kxy[1])+ d01* kxy[0] *(1.0 - kxy[1])+
d10*(1.0 - kxy[0])* kxy[1]+ d10*(1.0 - kxy[0])* kxy[1]+
d11* kxy[0] * kxy[1]; d11* kxy[0] * kxy[1];
dpixels[findx][opX + opY*width] = (float) d; if (equalize != null) {
d = equalize[0] * d + equalize[1];
}
dpixels[findx][opX + opY*width] = d;
} }
} }
} }
...@@ -2351,10 +2441,12 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -2351,10 +2441,12 @@ public class OrthoMapsCollection implements Serializable{
int [] origin = new int[2]; int [] origin = new int[2];
double [][] centers = new double [indices.length][]; double [][] centers = new double [indices.length][];
double [][] dmulti = renderMultiDouble ( double [][] dmulti = renderMultiDouble (
null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
true, // boolean bounds_to_indices, true, // boolean bounds_to_indices,
affines, // double [][][] affines, // null or [indices.length][2][3] affines, // double [][][] affines, // null or [indices.length][2][3]
null, // double [][] equalize,
false, // boolean ignore_equalize,
warp, // FineXYCorr warp,, warp, // FineXYCorr warp,,
zoom_level, // int zoom_level, zoom_level, // int zoom_level,
wh, // int [] wh, wh, // int [] wh,
...@@ -2367,12 +2459,13 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -2367,12 +2459,13 @@ public class OrthoMapsCollection implements Serializable{
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
true, // boolean bounds_to_indices, true, // boolean bounds_to_indices,
affines, // double [][][] affines, // null or [indices.length][2][3] affines, // double [][][] affines, // null or [indices.length][2][3]
null, // double [][] equalize,
true, // boolean ignore_equalize,
warp, // FineXYCorr warp,, warp, // FineXYCorr warp,,
zoom_level, // int zoom_level, zoom_level, // int zoom_level,
wh, // int [] wh, wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference origin, // int [] origin){ // maps[0] as a reference
null); // centers); // double [][] centers) // already set with dmulti null); // centers); // double [][] centers) // already set with dmulti
} }
...@@ -4071,15 +4164,17 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -4071,15 +4164,17 @@ public class OrthoMapsCollection implements Serializable{
int [] origin = new int[2]; int [] origin = new int[2];
double [][] centers =new double [indices.length][]; double [][] centers =new double [indices.length][];
double [][] dmulti = renderMultiDouble ( double [][] dmulti = renderMultiDouble (
null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
bounds_to_indices, // boolean bounds_to_indices, bounds_to_indices, // boolean bounds_to_indices,
null, // affines, // double [][][] affines, // null or [indices.length][2][3] null, // affines, // double [][][] affines, // null or [indices.length][2][3]
null, // warp, // FineXYCorr warp,, null, // double [][] equalize,
zoom_lev, // int zoom_level, true, // boolean ignore_equalize,
wh, // int [] wh, null, // warp, // FineXYCorr warp,,
origin, // int [] origin){ // maps[0] as a reference zoom_lev, // int zoom_level,
centers); // double [][] centers) wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers)
double [] overlaps = getFracOverlaps( double [] overlaps = getFracOverlaps(
dmulti); // final double [][] dmulti) { dmulti); // final double [][] dmulti) {
...@@ -4418,7 +4513,7 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -4418,7 +4513,7 @@ public class OrthoMapsCollection implements Serializable{
if (!direct && (inv_match != null)) { // prefer inverse if (!direct && (inv_match != null)) { // prefer inverse
use_inverse = true; use_inverse = true;
} else if (direct_match != null) { } else if (direct_match != null) {
if (skip_existing) { if (skip_existing && (direct_match.overlap > 0)) { // do not skip old pairs - refine them
skip = true; skip = true;
} else if (refine_existing) { } else if (refine_existing) {
use_direct = true; use_direct = true;
...@@ -4751,15 +4846,17 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -4751,15 +4846,17 @@ public class OrthoMapsCollection implements Serializable{
int [] origin = new int[2]; int [] origin = new int[2];
double [][] centers = show_centers? (new double [indices.length][]): null; double [][] centers = show_centers? (new double [indices.length][]): null;
double [][] dmulti = renderMultiDouble ( double [][] dmulti = renderMultiDouble (
null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
bounds_to_indices, // boolean bounds_to_indices, bounds_to_indices, // boolean bounds_to_indices,
null, // affines, // double [][][] affines, // null or [indices.length][2][3] null, // affines, // double [][][] affines, // null or [indices.length][2][3]
null, // warp, // FineXYCorr warp,, null, // double [][] equalize,
zoom_lev, // int zoom_level, true, // boolean ignore_equalize,
wh, // int [] wh, null, // warp, // FineXYCorr warp,,
origin, // int [] origin){ // maps[0] as a reference zoom_lev, // int zoom_level,
centers); // double [][] centers) wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers)
if (margins > 0) { if (margins > 0) {
addMargins( addMargins(
dmulti, // double [][] dmulti, dmulti, // double [][] dmulti,
...@@ -4788,12 +4885,14 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -4788,12 +4885,14 @@ public class OrthoMapsCollection implements Serializable{
new double [indices.length][] , // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt new double [indices.length][] , // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
bounds_to_indices, // boolean bounds_to_indices, bounds_to_indices, // boolean bounds_to_indices,
null, // affines, // double [][][] affines, // null or [indices.length][2][3] null, // affines, // double [][][] affines, // null or [indices.length][2][3]
null, // warp, // FineXYCorr warp,, null, // double [][] equalize,
zoom_lev, // int zoom_level, true, // boolean ignore_equalize,
wh, // int [] wh, null, // warp, // FineXYCorr warp,,
origin, // int [] origin){ // maps[0] as a reference zoom_lev, // int zoom_level,
centers); // double [][] centers) wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers)
if (margins > 0) { if (margins > 0) {
addMargins( addMargins(
dmulti, // double [][] dmulti, dmulti, // double [][] dmulti,
...@@ -4818,15 +4917,17 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -4818,15 +4917,17 @@ public class OrthoMapsCollection implements Serializable{
int [] origin = new int[2]; int [] origin = new int[2];
double [][] centers = show_centers? (new double [indices.length][]): null; double [][] centers = show_centers? (new double [indices.length][]): null;
double [][] dmulti = renderMultiDouble ( double [][] dmulti = renderMultiDouble (
null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
bounds_to_indices, // boolean bounds_to_indices, bounds_to_indices, // boolean bounds_to_indices,
null, // affines, // double [][][] affines, // null or [indices.length][2][3] null, // affines, // double [][][] affines, // null or [indices.length][2][3]
null, // warp, // FineXYCorr warp,, null, // double [][] equalize,
zoom_lev, // int zoom_level, true, // boolean ignore_equalize,
wh, // int [] wh, null, // warp, // FineXYCorr warp,,
origin, // int [] origin){ // maps[0] as a reference zoom_lev, // int zoom_level,
centers); // double [][] centers) wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers)
if (margins > 0) { if (margins > 0) {
addMargins( addMargins(
dmulti, // double [][] dmulti, dmulti, // double [][] dmulti,
...@@ -4857,15 +4958,17 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -4857,15 +4958,17 @@ public class OrthoMapsCollection implements Serializable{
int [] origin = new int[2]; int [] origin = new int[2];
double [][] centers = show_centers? (new double [indices.length][]): null; double [][] centers = show_centers? (new double [indices.length][]): null;
double [][] dmulti = renderMultiDouble ( double [][] dmulti = renderMultiDouble (
null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt null, // double [][] ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
bounds_to_indices, // boolean bounds_to_indices, bounds_to_indices, // boolean bounds_to_indices,
null, // affines, // double [][][] affines, // null or [indices.length][2][3] null, // affines, // double [][][] affines, // null or [indices.length][2][3]
null, // warp, // FineXYCorr warp,, null, // double [][] equalize,
zoom_lev, // int zoom_level, true, // boolean ignore_equalize,
wh, // int [] wh, null, // warp, // FineXYCorr warp,,
origin, // int [] origin){ // maps[0] as a reference zoom_lev, // int zoom_level,
centers); // double [][] centers) wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers)
if (margins > 0) { if (margins > 0) {
addMargins( addMargins(
dmulti, // double [][] dmulti, dmulti, // double [][] dmulti,
......
...@@ -40,7 +40,8 @@ import ij.ImagePlus; ...@@ -40,7 +40,8 @@ import ij.ImagePlus;
import ij.gui.PointRoi; import ij.gui.PointRoi;
public class OrthoMultiLMA { public class OrthoMultiLMA {
final boolean move_only; final boolean move_only;
final boolean corr_avg; // correct average skew, tilt, scale
private double [] last_rms = null; // {rms, rms_pure}, matching this.vector private double [] last_rms = null; // {rms, rms_pure}, matching this.vector
private double [] good_or_bad_rms = null; // just for diagnostics, to read last (failed) rms private double [] good_or_bad_rms = null; // just for diagnostics, to read last (failed) rms
private double [] initial_rms = null; // {rms, rms_pure}, first-calcualted rms private double [] initial_rms = null; // {rms, rms_pure}, first-calcualted rms
...@@ -61,7 +62,11 @@ public class OrthoMultiLMA { ...@@ -61,7 +62,11 @@ public class OrthoMultiLMA {
private double [][] offsets = null; // scene offsets (rd) private double [][] offsets = null; // scene offsets (rd)
private int num_scenes = 0; private int num_scenes = 0;
private int num_pairs = 0; private int num_pairs = 0;
public OrthoMultiLMA (boolean move_only) { public OrthoMultiLMA (
boolean corr_avg,
boolean move_only
) {
this.corr_avg = corr_avg && !move_only;
this.move_only = move_only; this.move_only = move_only;
} }
public static boolean testMultiLMA( public static boolean testMultiLMA(
...@@ -122,6 +127,8 @@ public class OrthoMultiLMA { ...@@ -122,6 +127,8 @@ public class OrthoMultiLMA {
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
true, // boolean bounds_to_indices, true, // boolean bounds_to_indices,
affines_a, // affines_0d, // affines, // double [][][] affines, // null or [indices.length][2][3] affines_a, // affines_0d, // affines, // double [][][] affines, // null or [indices.length][2][3]
null, // double [][] equalize,
true, // boolean ignore_equalize,
null, // warp, // FineXYCorr warp,, null, // warp, // FineXYCorr warp,,
zoom_level, // int zoom_level, zoom_level, // int zoom_level,
wh, // int [] wh, wh, // int [] wh,
...@@ -147,6 +154,8 @@ public class OrthoMultiLMA { ...@@ -147,6 +154,8 @@ public class OrthoMultiLMA {
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
true, // boolean bounds_to_indices, true, // boolean bounds_to_indices,
affines_sym,// affines, // double [][][] affines, // null or [indices.length][2][3] affines_sym,// affines, // double [][][] affines, // null or [indices.length][2][3]
null, // double [][] equalize,
true, // boolean ignore_equalize,
null, // warp, // FineXYCorr warp,, null, // warp, // FineXYCorr warp,,
zoom_level, // int zoom_level, zoom_level, // int zoom_level,
wh, // int [] wh, wh, // int [] wh,
...@@ -213,19 +222,26 @@ public class OrthoMultiLMA { ...@@ -213,19 +222,26 @@ public class OrthoMultiLMA {
int debugLevel = 1; int debugLevel = 1;
boolean move_only = false; boolean move_only = false;
double [] val_coord = null; // 1 - valid, 0 - invalid, minimize coordinates errors double [] val_coord = null; // 1 - valid, 0 - invalid, minimize coordinates errors
double position_pull = 0.001;
boolean use_inv = false; boolean use_inv = false;
double overlap_pow = 2.0; // match weight as overlap fraction to this power double overlap_pow = 2.0; // match weight as overlap fraction to this power
double skew_pull = 1.0;
double tilt_pull = 1.0;
double scale_pull = 0.1; // .0;
double position_pull = 0.0001;
boolean corr_avg= (skew_pull > 0) || (tilt_pull > 0) || (scale_pull > 0);
int [] indices = maps_collection.getScenesSelection( int [] indices = maps_collection.getScenesSelection(
null, // boolean select_all, null, // boolean select_all,
" to build a map"); // String purpose) " to build a map"); // String purpose)
OrthoMultiLMA oml = new OrthoMultiLMA(move_only); OrthoMultiLMA oml = new OrthoMultiLMA(
corr_avg,
move_only);
double lambda = 0.1; double lambda = 0.1;
double lambda_scale_good = 0.5; double lambda_scale_good = 0.5;
double lambda_scale_bad = 8.0; double lambda_scale_bad = 8.0;
double lambda_max = 100; double lambda_max = 100;
double rms_diff = 0.000001; double rms_diff = 0.000001;
int num_iter = 20; int num_iter = 100; // 50;
boolean last_run = false; boolean last_run = false;
oml.prepareLMA ( oml.prepareLMA (
clt_parameters, // CLTParameters clt_parameters, clt_parameters, // CLTParameters clt_parameters,
...@@ -233,6 +249,9 @@ public class OrthoMultiLMA { ...@@ -233,6 +249,9 @@ public class OrthoMultiLMA {
indices, // int [] indices, indices, // int [] indices,
val_coord, // double [] val_coord, // 1 - valid, 0 - invalid, minimize coordinates errors val_coord, // double [] val_coord, // 1 - valid, 0 - invalid, minimize coordinates errors
position_pull, // double position_pull, position_pull, // double position_pull,
skew_pull, // double skew_pull,
tilt_pull, // double tilt_pull,
scale_pull, // double scale_pull,
use_inv, // boolean use_inv, use_inv, // boolean use_inv,
overlap_pow, // double overlap_pow, // match weight as overlap fraction to this power overlap_pow, // double overlap_pow, // match weight as overlap fraction to this power
debugLevel); // int debugLevel) debugLevel); // int debugLevel)
...@@ -256,7 +275,7 @@ public class OrthoMultiLMA { ...@@ -256,7 +275,7 @@ public class OrthoMultiLMA {
//Get and apply affines //Get and apply affines
//oml.updateAffines(maps_collection); //oml.updateAffines(maps_collection);
double [][][] affines = oml.getAffines(); double [][][] affines = oml.getAffines();
double [] fx = oml.getFx();
// test // test
/* /*
PairwiseOrthoMatch match = maps_collection.ortho_maps[indices[0]].getMatch(maps_collection.ortho_maps[indices[1]].getName()); PairwiseOrthoMatch match = maps_collection.ortho_maps[indices[0]].getMatch(maps_collection.ortho_maps[indices[1]].getName());
...@@ -284,6 +303,8 @@ public class OrthoMultiLMA { ...@@ -284,6 +303,8 @@ public class OrthoMultiLMA {
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison) indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
true, // boolean bounds_to_indices, true, // boolean bounds_to_indices,
affines, // null, // affines, // double [][][] affines, // null or [indices.length][2][3] affines, // null, // affines, // double [][][] affines, // null or [indices.length][2][3]
null, // double [][] equalize,
true, // boolean ignore_equalize,
null, // warp, // FineXYCorr warp,, null, // warp, // FineXYCorr warp,,
zoom_level, // int zoom_level, zoom_level, // int zoom_level,
wh, // int [] wh, wh, // int [] wh,
...@@ -307,6 +328,7 @@ public class OrthoMultiLMA { ...@@ -307,6 +328,7 @@ public class OrthoMultiLMA {
roi.setOptions("label"); roi.setOptions("label");
imp_multi.setRoi(roi); imp_multi.setRoi(roi);
imp_multi.show(); imp_multi.show();
/*
double [][] affine = getAffineAndDerivatives( double [][] affine = getAffineAndDerivatives(
move_only, //boolean move_only, move_only, //boolean move_only,
affines[0], // double [][] affine00, affines[0], // double [][] affine00,
...@@ -317,7 +339,7 @@ public class OrthoMultiLMA { ...@@ -317,7 +339,7 @@ public class OrthoMultiLMA {
affines[0], affines[0],
affines[1], affines[1],
oml.offsets[0]); oml.offsets[0]);
*/
/* /*
...@@ -336,6 +358,16 @@ public class OrthoMultiLMA { ...@@ -336,6 +358,16 @@ public class OrthoMultiLMA {
return 0; return 0;
} }
public double [] getParameters() {
return parameters_vector;
}
public double [] getFx() {
return getFxDerivs(
parameters_vector, // double [] vector,
null, // final double [][] jt, // should be null or initialized with [vector.length][]
0); // final int debug_level)
}
public int prepareLMA ( public int prepareLMA (
CLTParameters clt_parameters, CLTParameters clt_parameters,
...@@ -343,6 +375,9 @@ public class OrthoMultiLMA { ...@@ -343,6 +375,9 @@ public class OrthoMultiLMA {
int [] indices, int [] indices,
double [] val_coord, // 1 - valid, 0 - invalid, minimize coordinates errors double [] val_coord, // 1 - valid, 0 - invalid, minimize coordinates errors
double position_pull, double position_pull,
double skew_pull,
double tilt_pull,
double scale_pull,
boolean use_inv, boolean use_inv,
double overlap_pow, // match weight as overlap fraction to this power double overlap_pow, // match weight as overlap fraction to this power
int debugLevel) { int debugLevel) {
...@@ -383,7 +418,6 @@ public class OrthoMultiLMA { ...@@ -383,7 +418,6 @@ public class OrthoMultiLMA {
for (int np = 0; np < num_pairs; np++) { for (int np = 0; np < num_pairs; np++) {
Point pair = pairs_list.get(np); Point pair = pairs_list.get(np);
pairs[np] = new int[] {pair.x, pair.y}; pairs[np] = new int[] {pair.x, pair.y};
// double [] enuOffset = maps_collection.ortho_maps[indices[pair.x]].enuOffsetTo(maps_collection.ortho_maps[indices[pair.y]]);
double [] enuOffset = maps_collection.ortho_maps[indices[pair.y]].enuOffsetTo(maps_collection.ortho_maps[indices[pair.x]]); double [] enuOffset = maps_collection.ortho_maps[indices[pair.y]].enuOffsetTo(maps_collection.ortho_maps[indices[pair.x]]);
offsets[np] = new double[] {enuOffset[0], -enuOffset[1]}; // {right,down} of the image offsets[np] = new double[] {enuOffset[0], -enuOffset[1]}; // {right,down} of the image
} }
...@@ -396,9 +430,8 @@ public class OrthoMultiLMA { ...@@ -396,9 +430,8 @@ public class OrthoMultiLMA {
int n62 = move_only ? 2 : 6; int n62 = move_only ? 2 : 6;
int n13 = move_only ? 1 : 3; int n13 = move_only ? 1 : 3;
y_vector = new double [n62*num_pairs + 2 * num_scenes + (corr_avg ? 3:0)]; // last 2 * num_scenes + 3 will stay 0
y_vector = new double [n62*num_pairs + 2 * num_scenes]; // last 2 * num_scenes will stay 0 weights = new double [n62*num_pairs + 2 * num_scenes + (corr_avg ? 3:0)];
weights = new double [n62*num_pairs + 2 * num_scenes];
parameters_vector = new double [n62*num_scenes]; // maybe will need move-only mode? parameters_vector = new double [n62*num_scenes]; // maybe will need move-only mode?
for (int n = 0; n < num_scenes; n++) { for (int n = 0; n < num_scenes; n++) {
double [][] affine = maps_collection.ortho_maps[indices[n]].getAffine(); double [][] affine = maps_collection.ortho_maps[indices[n]].getAffine();
...@@ -441,7 +474,12 @@ public class OrthoMultiLMA { ...@@ -441,7 +474,12 @@ public class OrthoMultiLMA {
weights[wi++] = w; weights[wi++] = w;
weights[wi++] = w; weights[wi++] = w;
sw+= 2*w; sw+= 2*w;
} }
if (corr_avg) {
weights[wi++] = skew_pull;
weights[wi++] = tilt_pull;
weights[wi++] = scale_pull;
}
pure_weight = swp/sw; pure_weight = swp/sw;
double s = 1.0/sw; double s = 1.0/sw;
for (int i = 0; i <weights.length;i++) { for (int i = 0; i <weights.length;i++) {
...@@ -1166,6 +1204,49 @@ public class OrthoMultiLMA { ...@@ -1166,6 +1204,49 @@ public class OrthoMultiLMA {
}; };
} }
ImageDtt.startAndJoin(threads); ImageDtt.startAndJoin(threads);
ai.set(0);
if (corr_avg) { // && ((skew_pull > 0) || (tilt_pull > 0) || (scale_pull > 0))) {
final int pull_indices = weights.length-3;
for (int nScene = 0; nScene < num_scenes; nScene++){
int indx = 6 * nScene;
double a00 = vector[indx+0],a01=vector[indx+1],a10=vector[indx+3],a11=vector[indx+4];
double aa1 = 0.5*(a00*a00 + a10*a10);
double aa2 = 0.5*(a01*a01 + a11*a11);
fx[pull_indices + 0] += a00*a01+a10*a11;
fx[pull_indices + 1] += aa1-aa2;
fx[pull_indices + 2] += aa1+aa2 - 1.0;
}
if (jt!= null) {
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int nScene = ai.getAndIncrement(); nScene < num_scenes; nScene = ai.getAndIncrement()){
int indx = 6 * nScene;
double a00=vector[indx+0],a01=vector[indx+1],a10=vector[indx+3],a11=vector[indx+4];
jt[indx + 0][pull_indices + 0] = a01;
jt[indx + 1][pull_indices + 0] = a00;
jt[indx + 3][pull_indices + 0] = a11;
jt[indx + 4][pull_indices + 0] = a10;
jt[indx + 0][pull_indices + 1] = a00;
jt[indx + 1][pull_indices + 1] =-a01;
jt[indx + 3][pull_indices + 1] = a10;
jt[indx + 4][pull_indices + 1] =-a11;
jt[indx + 0][pull_indices + 2] = a00;
jt[indx + 1][pull_indices + 2] = a01;
jt[indx + 3][pull_indices + 2] = a10;
jt[indx + 4][pull_indices + 2] = a11;
}
}
};
}
ImageDtt.startAndJoin(threads);
ai.set(0);
}
}
return fx; return fx;
} }
......
...@@ -11,10 +11,12 @@ public class PairwiseOrthoMatch implements Serializable { ...@@ -11,10 +11,12 @@ public class PairwiseOrthoMatch implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public double [][] affine = new double[2][3]; public double [][] affine = new double[2][3];
public transient double [][] jtj = new double [6][6]; public transient double [][] jtj = new double [6][6];
public int zoom_lev; public int zoom_lev;
public double rms = Double.NaN; public double rms = Double.NaN;
public transient int [] nxy = null; // not saved, just to communicate for logging public transient int [] nxy = null; // not saved, just to communicate for logging
public transient double overlap = 0.0; public transient double overlap = 0.0;
public transient double [] equalize1to0 = {1,0}; // value1 = equalize2to1[0]*value2+equalize2to1[1]
public PairwiseOrthoMatch() { public PairwiseOrthoMatch() {
} }
...@@ -30,6 +32,11 @@ public class PairwiseOrthoMatch implements Serializable { ...@@ -30,6 +32,11 @@ public class PairwiseOrthoMatch implements Serializable {
this.rms = rms; this.rms = rms;
this.overlap = overlap; this.overlap = overlap;
} }
public void setEqualize2to1 (double [] equalize2to1) {
this.equalize1to0 = equalize2to1;
}
public PairwiseOrthoMatch clone() { public PairwiseOrthoMatch clone() {
double [][] affine = {this.affine[0].clone(),this.affine[1].clone()}; double [][] affine = {this.affine[0].clone(),this.affine[1].clone()};
double [][] jtj = new double [this.jtj.length][]; double [][] jtj = new double [this.jtj.length][];
...@@ -45,6 +52,7 @@ public class PairwiseOrthoMatch implements Serializable { ...@@ -45,6 +52,7 @@ public class PairwiseOrthoMatch implements Serializable {
if (nxy != null) { if (nxy != null) {
pom.nxy = nxy.clone(); pom.nxy = nxy.clone();
} }
pom.equalize1to0 = this.equalize1to0.clone();
return pom; return pom;
} }
/** /**
...@@ -102,6 +110,7 @@ public class PairwiseOrthoMatch implements Serializable { ...@@ -102,6 +110,7 @@ public class PairwiseOrthoMatch implements Serializable {
rd[0] * affine[1][0]+ rd[1]*(affine[1][1]-1.0)}; rd[0] * affine[1][0]+ rd[1]*(affine[1][1]-1.0)};
affine[0][2] += corr[0]; affine[0][2] += corr[0];
affine[1][2] += corr[1]; affine[1][2] += corr[1];
inverted_match.setEqualize2to1(new double [] {1/equalize1to0[0], -equalize1to0[1]/equalize1to0[0]});
return inverted_match; return inverted_match;
} }
...@@ -168,10 +177,16 @@ public class PairwiseOrthoMatch implements Serializable { ...@@ -168,10 +177,16 @@ public class PairwiseOrthoMatch implements Serializable {
affine = new double[][] { affine = new double[][] {
{A.get(0,0),A.get(0,1), B.get(0,0)}, {A.get(0,0),A.get(0,1), B.get(0,0)},
{A.get(1,0),A.get(1,1), B.get(1,0)}}; {A.get(1,0),A.get(1,1), B.get(1,0)}};
// jtj = null;
// rms = Double.NaN; // double rms,
// zoom_lev = 0; // int zoom_lev)
} }
public void combineEqualize(
double [] equalize0,
double [] equalize1 ) {
setEqualize2to1(new double[] {
equalize1[0]/equalize0[0],
equalize1[1]-equalize1[0]/equalize0[0]*equalize0[1]});
}
public static double [][] combineAffines( public static double [][] combineAffines(
double [][] affine0, double [][] affine0,
double [][] affine, // differential double [][] affine, // differential
...@@ -203,6 +218,8 @@ public class PairwiseOrthoMatch implements Serializable { ...@@ -203,6 +218,8 @@ public class PairwiseOrthoMatch implements Serializable {
} }
} }
oos.writeObject(overlap); oos.writeObject(overlap);
oos.writeObject(equalize1to0);
} }
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject(); ois.defaultReadObject();
...@@ -216,6 +233,8 @@ public class PairwiseOrthoMatch implements Serializable { ...@@ -216,6 +233,8 @@ public class PairwiseOrthoMatch implements Serializable {
} }
} }
overlap = (Double) ois.readObject(); overlap = (Double) ois.readObject();
// equalize1to0 = new double[] {1,0};
equalize1to0 = (double[]) ois.readObject();
} }
//private void readObjectNoData() throws ObjectStreamException; // used to modify default values //private void readObjectNoData() throws ObjectStreamException; // used to modify default values
} }
...@@ -1356,4 +1356,5 @@ public class TileNeibs{ ...@@ -1356,4 +1356,5 @@ public class TileNeibs{
} }
return filled; return filled;
} }
} }
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