Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
imagej-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
3
Issues
3
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Elphel
imagej-elphel
Commits
c48eb737
Commit
c48eb737
authored
Apr 15, 2024
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
improving matching from the center to mitigate scale/rotations
parent
5e03168f
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
220 additions
and
7 deletions
+220
-7
ComboMatch.java
src/main/java/com/elphel/imagej/orthomosaic/ComboMatch.java
+1
-1
OrthoMapsCollection.java
...va/com/elphel/imagej/orthomosaic/OrthoMapsCollection.java
+25
-3
OrthoPairLMA.java
...main/java/com/elphel/imagej/orthomosaic/OrthoPairLMA.java
+194
-3
No files found.
src/main/java/com/elphel/imagej/orthomosaic/ComboMatch.java
View file @
c48eb737
...
@@ -1299,7 +1299,7 @@ adjusted affines[1] for a pair: 1694564291_293695/1694564778_589341
...
@@ -1299,7 +1299,7 @@ adjusted affines[1] for a pair: 1694564291_293695/1694564778_589341
int
nSlices
=
stack_scenes
.
getSize
();
int
nSlices
=
stack_scenes
.
getSize
();
String
[]
scene_names
=
new
String
[
nSlices
];
String
[]
scene_names
=
new
String
[
nSlices
];
for
(
int
n
=
0
;
n
<
scene_names
.
length
;
n
++)
{
for
(
int
n
=
0
;
n
<
scene_names
.
length
;
n
++)
{
scene_names
[
n
]
=
stack_scenes
.
getSliceLabel
(
n
+
1
).
substring
(
0
,
17
);
scene_names
[
n
]
=
stack_scenes
.
getSliceLabel
(
n
+
1
).
substring
(
0
,
17
);
// wrong image opened-> StringIndexOutOfBoundsException: begin 0, end 17, length 8
}
}
if
(
all_scenes
!=
null
)
{
if
(
all_scenes
!=
null
)
{
all_scenes
[
0
]
=
scene_names
;
all_scenes
[
0
]
=
scene_names
;
...
...
src/main/java/com/elphel/imagej/orthomosaic/OrthoMapsCollection.java
View file @
c48eb737
...
@@ -1013,13 +1013,17 @@ public class OrthoMapsCollection implements Serializable{
...
@@ -1013,13 +1013,17 @@ public class OrthoMapsCollection implements Serializable{
null
,
// double [][] jtj,
null
,
// double [][] jtj,
Double
.
NaN
,
// double rms,
Double
.
NaN
,
// double rms,
zoom_lev
);
// int zoom_lev);
zoom_lev
);
// int zoom_lev);
double
max_std
=
1
.5
;
// maximal standard deviation to limit center area
double
max_std
=
0
.5
;
// maximal standard deviation to limit center area
double
min_std_rad
=
2.0
;
// minimal radius of the central area (if less - fail)
double
min_std_rad
=
2.0
;
// minimal radius of the central area (if less - fail)
while
((
Math
.
abs
(
nx
)
<=
nabs
)
&&
(
Math
.
abs
(
ny
)
<=
nabs
))
{
while
((
Math
.
abs
(
nx
)
<=
nabs
)
&&
(
Math
.
abs
(
ny
)
<=
nabs
))
{
affine1
[
0
][
2
]
=
affines_init
[
1
][
0
][
2
]
+
pix_step
*
pix_size
*
nx
;
for
(
int
i
=
0
;
i
<
affines_init
.
length
;
i
++)
{
affine1
[
1
][
2
]
=
affines_init
[
1
][
1
][
2
]
+
pix_step
*
pix_size
*
ny
;
System
.
arraycopy
(
affines_init
[
1
][
i
],
0
,
affine1
[
i
],
0
,
affine1
[
i
].
length
);
}
affine1
[
0
][
2
]
+=
pix_step
*
pix_size
*
nx
;
affine1
[
1
][
2
]
+=
pix_step
*
pix_size
*
ny
;
pairwiseOrthoMatch
.
rms
=
Double
.
NaN
;
pairwiseOrthoMatch
.
rms
=
Double
.
NaN
;
correlateOrthoPair
(
correlateOrthoPair
(
clt_parameters
,
// CLTParameters clt_parameters,
clt_parameters
,
// CLTParameters clt_parameters,
pairwiseOrthoMatch
,
//PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics
pairwiseOrthoMatch
,
//PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics
...
@@ -1262,6 +1266,7 @@ public class OrthoMapsCollection implements Serializable{
...
@@ -1262,6 +1266,7 @@ public class OrthoMapsCollection implements Serializable{
double
frac_below
=
0.1
;
double
frac_below
=
0.1
;
double
[][]
jtj
=
null
;
double
[][]
jtj
=
null
;
double
rms
=
Double
.
NaN
;
double
rms
=
Double
.
NaN
;
double
last_center_radius
=
0
;
for
(
int
ntry
=
0
;
ntry
<
num_tries
;
ntry
++)
{
for
(
int
ntry
=
0
;
ntry
<
num_tries
;
ntry
++)
{
if
(!
batch_mode
)
{
if
(!
batch_mode
)
{
if
(
debugLevel
>-
3
)
{
if
(
debugLevel
>-
3
)
{
...
@@ -1500,6 +1505,15 @@ public class OrthoMapsCollection implements Serializable{
...
@@ -1500,6 +1505,15 @@ public class OrthoMapsCollection implements Serializable{
min_std_rad
,
// double min_std_rad, // minimal radius of the central area (if less - fail)
min_std_rad
,
// double min_std_rad, // minimal radius of the central area (if less - fail)
debugLevel
);
// final int debug_level)
debugLevel
);
// final int debug_level)
last_center_radius
=
orthoPairLMA
.
getCenterRadius
();
if
((
min_std_rad
>
0
)
&&
(
last_center_radius
<
1
))
{
if
(
debugLevel
>-
3
)
{
System
.
out
.
println
(
"correlateOrthoPair(): center_radius="
+
orthoPairLMA
.
getCenterRadius
()+
" < "
+
1
);
}
return
null
;
}
if
(
num_good_tiles
<
min_good_tiles
)
{
if
(
num_good_tiles
<
min_good_tiles
)
{
if
(
debugLevel
>-
4
)
{
if
(
debugLevel
>-
4
)
{
System
.
out
.
println
(
"correlateOrthoPair(): num_good_tiles="
+
System
.
out
.
println
(
"correlateOrthoPair(): num_good_tiles="
+
...
@@ -1563,6 +1577,14 @@ public class OrthoMapsCollection implements Serializable{
...
@@ -1563,6 +1577,14 @@ public class OrthoMapsCollection implements Serializable{
prev_rms
=
rms
;
prev_rms
=
rms
;
}
// for (int ntry = 0; ntry < num_tries; ntry++) {
}
// for (int ntry = 0; ntry < num_tries; ntry++) {
if
((
min_std_rad
>
0
)
&&
(
last_center_radius
<
min_std_rad
))
{
if
(
debugLevel
>-
3
)
{
System
.
out
.
println
(
"correlateOrthoPair(): center_radius="
+
last_center_radius
+
" < "
+
min_std_rad
);
}
return
null
;
}
...
...
src/main/java/com/elphel/imagej/orthomosaic/OrthoPairLMA.java
View file @
c48eb737
...
@@ -37,8 +37,8 @@ import Jama.Matrix;
...
@@ -37,8 +37,8 @@ import Jama.Matrix;
public
class
OrthoPairLMA
{
public
class
OrthoPairLMA
{
private
boolean
thread_invariant
=
true
;
private
boolean
thread_invariant
=
true
;
private
int
N
=
0
;
private
int
N
=
0
;
// number of tiles in WOI: woi.width * woi.height
private
Rectangle
woi
=
null
;
private
Rectangle
woi
=
null
;
// in tiles
private
int
width
;
private
int
width
;
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
...
@@ -53,11 +53,15 @@ public class OrthoPairLMA {
...
@@ -53,11 +53,15 @@ public class OrthoPairLMA {
private
double
[]
last_ymfx
=
null
;
private
double
[]
last_ymfx
=
null
;
private
double
[][]
last_jt
=
null
;
private
double
[][]
last_jt
=
null
;
private
boolean
origin_center
=
false
;
// true - origin in overlap center, false - top left corner (as it was)
private
boolean
origin_center
=
false
;
// true - origin in overlap center, false - top left corner (as it was)
private
double
[]
origin
=
null
;
// either {0,0} for top-left or center of the woi
private
double
[]
origin
=
null
;
// in pixels either {0,0} for top-left or center of the woi
private
double
center_radius
=
0
;
// center zone radius (in tiles) that has limited standard deviation
public
int
num_good_tiles
=
0
;
public
int
num_good_tiles
=
0
;
public
OrthoPairLMA
(
boolean
origin_center
)
{
public
OrthoPairLMA
(
boolean
origin_center
)
{
this
.
origin_center
=
origin_center
;
this
.
origin_center
=
origin_center
;
}
}
public
double
getCenterRadius
()
{
return
center_radius
;
}
public
int
prepareLMA
(
public
int
prepareLMA
(
// will always calculate relative affine, starting with unity
// will always calculate relative affine, starting with unity
int
width
,
// tilesX
int
width
,
// tilesX
...
@@ -95,6 +99,24 @@ public class OrthoPairLMA {
...
@@ -95,6 +99,24 @@ public class OrthoPairLMA {
}
}
N
=
woi
.
width
*
woi
.
height
;
N
=
woi
.
width
*
woi
.
height
;
parameters_vector
=
new
double
[]
{
1
,
0
,
0
,
1
,
0
,
0
};
parameters_vector
=
new
double
[]
{
1
,
0
,
0
,
1
,
0
,
0
};
if
(
min_std_rad
>
0
)
{
int
min_tiles
=
4
;
getCenterRadius
(
max_std
,
// final double max_std, // maximal standard deviation to limit center area
min_tiles
,
// final int min_tiles,
vector_XYS
,
// final double [][] vector_XYS,
weights_extra
,
// final double [] weights_extra, // null or additional weights (such as elevation-based)
centers
);
// final double [][] centers)
// if (getCenterRadius() < min_std_rad) { // only after last pass of LMA!
// num_good_tiles = 0;
// return num_good_tiles;
// }
weights_extra
=
applyRadialWeights
(
// uses this.center_radius;
vector_XYS
,
// final double [][] vector_XYS,
weights_extra
,
// final double [] weights_extra,
centers
);
// final double [][] centers)
}
setSamplesWeightsYCenters
(
setSamplesWeightsYCenters
(
vector_XYS
,
vector_XYS
,
weights_extra
,
// null or additional weights (such as elevation-based)
weights_extra
,
// null or additional weights (such as elevation-based)
...
@@ -136,6 +158,175 @@ public class OrthoPairLMA {
...
@@ -136,6 +158,175 @@ public class OrthoPairLMA {
//getWJtJlambda(
//getWJtJlambda(
// lambda, // *10, // temporary
// lambda, // *10, // temporary
// this.last_jt)
// this.last_jt)
private
double
[]
applyRadialWeights
(
// uses this.center_radius;
final
double
[][]
vector_XYS
,
final
double
[]
weights_extra
,
final
double
[][]
centers
)
{
// null or additional weights (such as elevation-based)
return
applyRadialWeights
(
center_radius
,
// final double radius_tiles,
vector_XYS
,
// final double [][] vector_XYS,
weights_extra
,
// final double [] weights_extra, // null or additional weights (such as elevation-based)
centers
);
// final double [][] centers);
}
private
double
[]
applyRadialWeights
(
final
double
radius_tiles
,
final
double
[][]
vector_XYS
,
final
double
[]
weights_extra
,
// null or additional weights (such as elevation-based)
final
double
[][]
centers
)
{
if
(
Double
.
isInfinite
(
radius_tiles
))
{
return
weights_extra
;
// may be null - should be OK
}
final
double
radius_pix
=
radius_tiles
*
GPUTileProcessor
.
DTT_SIZE
;
final
double
radius_pix2
=
radius_pix
*
radius_pix
;
final
double
[]
weights
=
new
double
[
vector_XYS
.
length
];
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
();
final
AtomicInteger
ai
=
new
AtomicInteger
(
0
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
for
(
int
iTile
=
ai
.
getAndIncrement
();
iTile
<
N
;
iTile
=
ai
.
getAndIncrement
())
{
int
tileX
=
iTile
%
woi
.
width
+
woi
.
x
;
int
tileY
=
iTile
/
woi
.
width
+
woi
.
y
;
int
aTile
=
tileY
*
width
+
tileX
;
if
((
vector_XYS
[
aTile
]
!=
null
)
&&
(
centers
[
aTile
]
!=
null
))
{
double
w
=
vector_XYS
[
aTile
][
2
];
if
(
weights_extra
!=
null
)
w
*=
weights_extra
[
aTile
];
if
(
Double
.
isNaN
(
w
))
w
=
0
;
double
dx
=
centers
[
aTile
][
0
]
-
origin
[
0
];
double
dy
=
centers
[
aTile
][
1
]
-
origin
[
1
];
double
r_pix2
=
dx
*
dx
+
dy
*
dy
;
// radius in pixels, squared
if
(
r_pix2
<
4
*
radius_pix2
)
{
double
r_pix
=
Math
.
sqrt
(
r_pix2
);
// radius in pixels
double
wr
=
0.5
*(
1.0
+
Math
.
cos
(
0.5
*
Math
.
PI
*
r_pix
/
radius_pix
));
weights
[
aTile
]
=
w
*
wr
;
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
return
weights
;
}
/**
* Calculate center radius (in tiles) to use for LMA when initial rotation or
* scaling is inaccurate so the peripheral areas do not fit into correlation range.
* In that case try to adjust only the central area first, then increase that area
* in next iterations.
* @param max_std maximal standard deviation (average for X and Y) inside center area
* @param min_tiles minimal tiles in the center zone
* @param vector_XYS 2D correlation-measured X,Y, and strength
* @param weights_extra null or optional additional weights of the samples
* @param centers per tile (matching vector_XYS and weights_extra) tile centers in pixels
* @return maximal radius from the center (in pixels) where standard deviation of the inside samples is
* below max_std. Returns Double.POSITIVE_INFINITY if std is not reached
*/
private
double
getCenterRadius
(
final
double
max_std
,
// maximal standard deviation to limit center area
// final double min_std_rad, // minimal radius of the central area (if less - fail)
final
int
min_tiles
,
final
double
[][]
vector_XYS
,
final
double
[]
weights_extra
,
// null or additional weights (such as elevation-based)
final
double
[][]
centers
)
{
final
int
rad_max
=
Math
.
max
(
woi
.
width
,
woi
.
height
)/
2
+
1
;
final
int
rad_length
=
rad_max
+
1
;
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
();
final
AtomicInteger
ai
=
new
AtomicInteger
(
0
);
final
AtomicInteger
ati
=
new
AtomicInteger
(
0
);
final
double
[][]
s0_arr
=
new
double
[
threads
.
length
][
rad_length
];
final
double
[][]
sx_arr
=
new
double
[
threads
.
length
][
rad_length
];
final
double
[][]
sx2_arr
=
new
double
[
threads
.
length
][
rad_length
];
final
double
[][]
sy_arr
=
new
double
[
threads
.
length
][
rad_length
];
final
double
[][]
sy2_arr
=
new
double
[
threads
.
length
][
rad_length
];
final
int
[][]
sn_arr
=
new
int
[
threads
.
length
][
rad_length
];
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
int
thread_num
=
ati
.
getAndIncrement
();
for
(
int
iTile
=
ai
.
getAndIncrement
();
iTile
<
N
;
iTile
=
ai
.
getAndIncrement
())
{
int
tileX
=
iTile
%
woi
.
width
+
woi
.
x
;
int
tileY
=
iTile
/
woi
.
width
+
woi
.
y
;
int
aTile
=
tileY
*
width
+
tileX
;
if
((
vector_XYS
[
aTile
]
!=
null
)
&&
(
centers
[
aTile
]
!=
null
))
{
double
w
=
vector_XYS
[
aTile
][
2
];
if
(
weights_extra
!=
null
)
w
*=
weights_extra
[
aTile
];
if
(
Double
.
isNaN
(
w
))
w
=
0
;
double
dx
=
centers
[
aTile
][
0
]
-
origin
[
0
];
double
dy
=
centers
[
aTile
][
1
]
-
origin
[
1
];
double
r_t
=
Math
.
sqrt
(
dx
*
dx
+
dy
*
dy
)/
GPUTileProcessor
.
DTT_SIZE
;
// radius in tiles
int
irt
=
(
int
)
Math
.
round
(
r_t
);
if
(
irt
<
rad_length
)
{
double
fx
=
vector_XYS
[
aTile
][
0
];
double
fy
=
vector_XYS
[
aTile
][
1
];
sn_arr
[
thread_num
][
irt
]
+=
1
;
s0_arr
[
thread_num
][
irt
]
+=
w
;
sx_arr
[
thread_num
][
irt
]
+=
w
*
fx
;
sx2_arr
[
thread_num
][
irt
]
+=
w
*
fx
*
fx
;
sy_arr
[
thread_num
][
irt
]
+=
w
*
fy
;
sy2_arr
[
thread_num
][
irt
]
+=
w
*
fy
*
fy
;
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
final
double
[]
s0
=
new
double
[
rad_length
];
final
double
[]
sx
=
new
double
[
rad_length
];
final
double
[]
sx2
=
new
double
[
rad_length
];
final
double
[]
sy
=
new
double
[
rad_length
];
final
double
[]
sy2
=
new
double
[
rad_length
];
final
int
[]
sn
=
new
int
[
rad_length
];
ai
.
set
(
0
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
for
(
int
iRad
=
ai
.
getAndIncrement
();
iRad
<
rad_length
;
iRad
=
ai
.
getAndIncrement
())
{
for
(
int
i
=
0
;
i
<
threads
.
length
;
i
++)
{
s0
[
iRad
]+=
s0_arr
[
i
][
iRad
];
sx
[
iRad
]+=
sx_arr
[
i
][
iRad
];
sx2
[
iRad
]+=
sx2_arr
[
i
][
iRad
];
sy
[
iRad
]+=
sy_arr
[
i
][
iRad
];
sy2
[
iRad
]+=
sy2_arr
[
i
][
iRad
];
sn
[
iRad
]+=
sn_arr
[
i
][
iRad
];
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
double
sc0
=
0
,
scx
=
0
,
scx2
=
0
,
scy
=
0
,
scy2
=
0
,
std_prev
=
0
,
std
=
0
;
int
scn
=
0
;
center_radius
=
Double
.
POSITIVE_INFINITY
;
for
(
int
iRad
=
0
;
iRad
<
rad_length
;
iRad
++)
{
sc0
+=
s0
[
iRad
];
scx
+=
sx
[
iRad
];
scx2
+=
sx2
[
iRad
];
scy
+=
sy
[
iRad
];
scy2
+=
sy2
[
iRad
];
scn
+=
sn
[
iRad
];
if
((
scn
>
min_tiles
)
&&
(
sc0
>
0
))
{
// for one tile gets scrt() of a small negative error
std
=
Math
.
sqrt
((
scx2
*
sc0
-
scx
*
scx
+
scy2
*
sc0
-
scy
*
scy
)/
2
)/
sc0
;
}
if
((
scn
>=
min_tiles
)
&&
(
std
>=
max_std
))
{
if
(
iRad
==
0
)
{
center_radius
=
0
;
break
;
// probably can not happen
}
center_radius
=
iRad
-
(
std
-
max_std
)
/
(
std
-
std_prev
);
break
;
}
std_prev
=
std
;
}
return
center_radius
;
}
private
void
setSamplesWeightsYCenters
(
private
void
setSamplesWeightsYCenters
(
final
double
[][]
vector_XYS
,
final
double
[][]
vector_XYS
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment