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
f97f3155
Commit
f97f3155
authored
Feb 17, 2024
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implemented OrthoMapCollection class and possibility to save maps state
w/o images
parent
624f1144
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
576 additions
and
350 deletions
+576
-350
Eyesis_Correction.java
.../java/com/elphel/imagej/correction/Eyesis_Correction.java
+2
-2
ComboMatch.java
src/main/java/com/elphel/imagej/orthomosaic/ComboMatch.java
+53
-33
OrthoMap.java
src/main/java/com/elphel/imagej/orthomosaic/OrthoMap.java
+71
-315
OrthoMapsCollection.java
...va/com/elphel/imagej/orthomosaic/OrthoMapsCollection.java
+414
-0
PairwiseOrthoMatch.java
...ava/com/elphel/imagej/orthomosaic/PairwiseOrthoMatch.java
+36
-0
No files found.
src/main/java/com/elphel/imagej/correction/Eyesis_Correction.java
View file @
f97f3155
...
...
@@ -109,7 +109,7 @@ import com.elphel.imagej.ims.EventLogger;
import
com.elphel.imagej.ims.Imx5
;
import
com.elphel.imagej.jp4.JP46_Reader_camera
;
import
com.elphel.imagej.lwir.LwirReader
;
import
com.elphel.imagej.orthomosaic.
Comb
oMap
;
import
com.elphel.imagej.orthomosaic.
Orth
oMap
;
import
com.elphel.imagej.orthomosaic.ComboMatch
;
import
com.elphel.imagej.readers.ChangeImageResolution
;
import
com.elphel.imagej.readers.DumpImageMetadata
;
...
...
@@ -5732,7 +5732,7 @@ public class Eyesis_Correction implements PlugIn, ActionListener {
IJ
.
showMessage
(
"Error"
,
"No images selected"
);
return
;
}
Comb
oMap
.
testVideo
(
imp_sel
);
Orth
oMap
.
testVideo
(
imp_sel
);
}
}
...
...
src/main/java/com/elphel/imagej/orthomosaic/ComboMatch.java
View file @
f97f3155
...
...
@@ -45,7 +45,8 @@ public class ComboMatch {
GPU_TILE_PROCESSOR
=
gpu_tile_processor
;
// find -L /media/elphel/SSD3-4GB/lwir16-proc/berdich3/linked/linked_1697875868-1697879449-b/ -type f -name "*-GCORR-GEO.tiff" | sort > GCORR-GEO.list
String
files_list_path
=
"/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_berdich2.list"
;
String
files_list_path
=
"/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_03_short.list"
;
String
orthoMapsCollection_path
=
"/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/ortho_maps_collection.data"
;
double
[][][]
image_enuatr
=
{{{
0
,
0
,
0
},{
0
,
0
,
0
}},{{
0
,
0
,
0
},{
0
,
0
,
0
}}};
int
gpu_width
=
clt_parameters
.
imp
.
rln_gpu_width
;
// 3008;
...
...
@@ -53,8 +54,13 @@ public class ComboMatch {
int
zoom_lev
=
-
4
;
// 0; // +1 - zoom in twice, -1 - zoom out twice
boolean
use_alt
=
false
;
boolean
show_centers
=
true
;
boolean
use_saved_collection
=
false
;
boolean
save_collection
=
true
;
GenericJTabbedDialog
gd
=
new
GenericJTabbedDialog
(
"Set image pair"
,
1200
,
800
);
gd
.
addStringField
(
"Image list full path "
,
files_list_path
,
180
,
"Image listfull path."
);
gd
.
addStringField
(
"Image list full path"
,
files_list_path
,
180
,
"Image list full path."
);
gd
.
addStringField
(
"Maps collection save path"
,
orthoMapsCollection_path
,
180
,
"Save path for serialized map collection data."
);
gd
.
addCheckbox
(
"Use saved maps collection"
,
use_saved_collection
,
"If false - use files list."
);
gd
.
addCheckbox
(
"Save maps collection"
,
save_collection
,
"If false - use files list."
);
// for (int n = 0; n < image_paths_pre.length; n++) {
// gd.addStringField ("Image path "+n, image_paths_pre[n], 180, "Image "+n+" full path w/o ext");
// }
...
...
@@ -81,11 +87,11 @@ public class ComboMatch {
gd
.
showDialog
();
if
(
gd
.
wasCanceled
())
return
false
;
files_list_path
=
gd
.
getNextString
();
// for (int n = 0; n < image_paths_pre.length; n++) {
// image_paths_pre[n]
= gd.getNextString();
// }
// image_paths_pre[0] = gd.getNextString
();
// image_paths_pre[1] = gd.getNextString();
orthoMapsCollection_path
=
gd
.
getNextString
();
use_saved_collection
=
gd
.
getNextBoolean
();
save_collection
=
gd
.
getNextBoolean
();
for
(
int
n
=
0
;
n
<
image_enuatr
.
length
;
n
++)
{
image_enuatr
[
n
][
0
][
0
]
=
gd
.
getNextNumber
();
image_enuatr
[
n
][
0
][
1
]
=
gd
.
getNextNumber
();
...
...
@@ -98,58 +104,71 @@ public class ComboMatch {
gpu_width
=
(
int
)
gd
.
getNextNumber
();
gpu_height
=
(
int
)
gd
.
getNextNumber
();
Comb
oMap
.
setGPUWidthHeight
(
gpu_width
,
gpu_height
);
Orth
oMap
.
setGPUWidthHeight
(
gpu_width
,
gpu_height
);
show_centers
=
gd
.
getNextBoolean
();
use_alt
=
gd
.
getNextBoolean
();
// ComboMap[] combo_maps = ComboMap.initializeComboMaps(
// full_paths); // String [] image_paths);
ComboMap
[]
combo_maps
=
ComboMap
.
initializeComboMaps
(
files_list_path
);
// String [] image_paths);
String
[]
map_names
=
ComboMap
.
getNames
(
combo_maps
);
OrthoMapsCollection
maps_collection
=
null
;
if
(
use_saved_collection
)
{
try
{
maps_collection
=
OrthoMapsCollection
.
readOrthoMapsCollection
(
orthoMapsCollection_path
);
}
catch
(
ClassNotFoundException
|
IOException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
();
}
}
else
{
maps_collection
=
new
OrthoMapsCollection
(
files_list_path
);
// should have ".list" extensiohn
}
String
[]
names
=
maps_collection
.
getNames
();
// which pair to compare
int
[]
gpu_pair
=
{
1
,
2
};
String
[]
gpu_spair
=
{
names
[
gpu_pair
[
0
]],
names
[
gpu_pair
[
1
]]};
int
[]
origin
=
new
int
[
2
];
ImagePlus
imp_img
=
ComboMap
.
renderMulti
(
ImagePlus
imp_img
=
maps_collection
.
renderMulti
(
"multi_"
+
zoom_lev
,
// String title,
false
,
// boolean use_alt,
show_centers
,
// boolean show_centers,
combo_maps
,
// ComboMap [] maps,
zoom_lev
,
// int zoom_level,
origin
);
// int [] origin){
imp_img
.
show
();
ImagePlus
imp_alt
=
null
;
if
(
use_alt
)
{
imp_alt
=
ComboMap
.
renderMulti
(
imp_alt
=
maps_collection
.
renderMulti
(
"multi_alt_"
+
zoom_lev
,
// String title,
true
,
// boolean use_alt,
show_centers
,
// boolean show_centers,
combo_maps
,
// ComboMap [] maps,
zoom_lev
,
// int zoom_level,
origin
);
// int [] origin){
imp_alt
.
show
();
}
// which pair to compare
int
[]
gpu_pair
=
{
1
,
2
};
float
[][]
gpu_pair_img
=
new
float
[
2
][];
for
(
int
n
=
0
;
n
<
gpu_pair
.
length
;
n
++)
{
gpu_pair_img
[
n
]
=
combo_maps
[
gpu_pair
[
n
]].
getPaddedGPU
(
zoom_lev
,
// int zoom_level,
gpu_width
,
// int gpu_width,
gpu_height
);
// int gpu_height)
}
float
[][]
gpu_pair_img
=
maps_collection
.
getPaddedPairGPU
(
gpu_spair
,
// String [] spair,
zoom_lev
);
// int zoom_lev);
ShowDoubleFloatArrays
.
showArrays
(
gpu_pair_img
,
gpu_width
,
gpu_height
,
true
,
"gpu_pair-zoom"
+
zoom_lev
+
"-"
+
combo_maps
[
gpu_pair
[
0
]].
getName
()+
"-"
+
combo_maps
[
gpu_pair
[
1
]].
getName
(),
map_names
);
"gpu_pair-zoom"
+
zoom_lev
+
"-"
+
gpu_spair
[
0
]+
"-"
+
gpu_spair
[
1
],
gpu_spair
);
if
(
save_collection
)
{
try
{
maps_collection
.
writeOrthoMapsCollection
(
orthoMapsCollection_path
);
}
catch
(
IOException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
();
}
}
if
(
debugLevel
<
1000
)
{
return
true
;
}
/* */
OrthoMap
[]
ortho_maps
=
maps_collection
.
getMaps
();
// just temporarily
int
[]
widths
=
new
int
[
imp_src
.
length
];
int
[]
heights
=
new
int
[
imp_src
.
length
];
for
(
int
n
=
0
;
n
<
imp_src
.
length
;
n
++)
{
...
...
@@ -178,8 +197,8 @@ public class ComboMatch {
}
/* */
if
(
show_centers
)
{
for
(
int
n
=
0
;
n
<
comb
o_maps
.
length
;
n
++)
{
comb
o_maps
[
n
].
getOriginalImage
(
true
);
for
(
int
n
=
0
;
n
<
orth
o_maps
.
length
;
n
++)
{
orth
o_maps
[
n
].
getOriginalImage
(
true
);
}
}
/*
...
...
@@ -187,11 +206,12 @@ public class ComboMatch {
imp_src[n].show();
}
*/
if
(
combo_maps
[
0
].
orig_zoom_level
!=
combo_maps
[
1
].
orig_zoom_level
)
{
if
(
ortho_maps
[
0
].
orig_zoom_level
!=
ortho_maps
[
1
].
orig_zoom_level
)
{
System
.
out
.
println
(
"openTestPairGps() does not yet handle different scales, aborting"
);
return
false
;
}
double
[]
enu_diff
=
combo_maps
[
0
].
enuOffsetTo
(
comb
o_maps
[
0
]);
double
[]
enu_diff
=
ortho_maps
[
0
].
enuOffsetTo
(
orth
o_maps
[
0
]);
double
pix_size1
=
ElphelTiffReader
.
getPixelSize
(
imp_prop
[
0
])[
0
];
double
[]
pix_shift
=
{
enu_diff
[
0
]/
pix_size1
,
-
enu_diff
[
1
]/
pix_size1
};
// E->X, N->-Y
...
...
src/main/java/com/elphel/imagej/orthomosaic/
Comb
oMap.java
→
src/main/java/com/elphel/imagej/orthomosaic/
Orth
oMap.java
View file @
f97f3155
...
...
@@ -4,6 +4,9 @@ import java.awt.Color;
import
java.awt.Font
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.ObjectInputStream
;
import
java.io.ObjectOutputStream
;
import
java.io.Serializable
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
...
...
@@ -39,28 +42,73 @@ import ij.process.FloatProcessor;
import
ij.process.ImageConverter
;
import
ij.process.ImageProcessor
;
public
class
ComboMap
{
public
class
OrthoMap
implements
Comparable
<
OrthoMap
>,
Serializable
{
private
static
final
long
serialVersionUID
=
1L
;
public
static
boolean
FIX_VERT_Y
=
false
;
// true; // temporarily fix vertical Y coordinate bug (use -GCORR in the filename?)
public
static
int
gpu_width
=
4096
;
public
static
int
gpu_height
=
4096
;
public
static
final
String
[]
KEY_DIRS
=
{
"rootDirectory"
,
// from EyesisCorrectionParameters
"sourceDirectory"
,
"linkedModels"
,
"videoDirectory"
,
"x3dDirectory"
,
"resultsDirectory"
};
public
static
final
String
ALT_SUFFIX
=
"-ALT"
;
public
final
String
name
;
// timestamp
public
String
path
;
// full path to the model directory (including /vXX?)
public
double
[]
lla
;
// lat/long/alt
public
LocalDateTime
dt
;
// public transient final String name; // timestamp
// public transient final double ts;
public
transient
String
name
;
// timestamp
public
transient
double
ts
;
public
transient
String
path
;
// full path to the model directory (including /vXX?)
public
double
[]
lla
;
// lat/long/alt
public
LocalDateTime
dt
;
// affine convert (input) rectified coordinates (meters) relative to vert_meters to source image
// coordinates relative to vert_meters
private
double
[][]
affine
=
new
double
[][]
{{
1
,
0
,
0
},{
0
,
1
,
0
}};
// relative to vert_meters[]
public
double
orig_pix_meters
;
public
double
[]
vert_meters
;
// offset of the image vertical in meters (scale-invariant)
public
FloatImageData
orig_image
;
public
FloatImageData
alt_image
;
public
int
orig_zoom_level
;
public
boolean
orig_zoom_valid
;
public
double
need_extra_zoom
;
HashMap
<
Integer
,
FloatImageData
>
images
;
public
double
[][]
affine
=
new
double
[][]
{{
1
,
0
,
0
},{
0
,
1
,
0
}};
// relative to vert_meters[]
public
double
orig_pix_meters
;
public
double
[]
vert_meters
;
// offset of the image vertical in meters (scale-invariant)
public
transient
FloatImageData
orig_image
;
public
transient
FloatImageData
alt_image
;
public
int
orig_zoom_level
;
public
boolean
orig_zoom_valid
;
public
double
need_extra_zoom
;
transient
HashMap
<
Integer
,
FloatImageData
>
images
;
HashMap
<
Double
,
PairwiseOrthoMatch
>
pairwise_matches
;
private
void
writeObject
(
ObjectOutputStream
oos
)
throws
IOException
{
oos
.
defaultWriteObject
();
oos
.
writeObject
(
path
);
// lla is not transient
// dt is not transient
// affine is not transient
// orig_pix_meters is not transient
// vert_meters is not transient
// orig_image does not need to be saved
// alt_image does not need to be saved
// orig_zoom_level is not transient
// orig_zoom_valid is not transient
// need_extra_zoom is not transient
// images is not saved
// pairwise_matches is not transient
}
private
void
readObject
(
ObjectInputStream
ois
)
throws
ClassNotFoundException
,
IOException
{
ois
.
defaultReadObject
();
path
=
(
String
)
ois
.
readObject
();
name
=
getNameFromPath
(
path
);
ts
=
Double
.
parseDouble
(
name
.
replace
(
"_"
,
"."
));
// lla is not transient
// dt is not transient
// affine is not transient
// orig_pix_meters is not transient
// vert_meters is not transient
// orig_image was not saved
// alt_image was not saved
images
=
new
HashMap
<
Integer
,
FloatImageData
>();
// field images was not saved
// pairwise_matches is not transient
// pairwise_matches = new HashMap<Double, PairwiseOrthoMatch>();
}
@Override
public
int
compareTo
(
OrthoMap
otherPlayer
)
{
return
Double
.
compare
(
ts
,
otherPlayer
.
ts
);
}
public
static
void
setGPUWidthHeight
(
int
width
,
...
...
@@ -83,9 +131,10 @@ public class ComboMap {
return
path
.
substring
(
p1
+
1
,
p2
);
}
public
Comb
oMap
(
String
path
)
{
public
Orth
oMap
(
String
path
)
{
this
.
path
=
path
;
name
=
getNameFromPath
(
path
);
ts
=
Double
.
parseDouble
(
name
.
replace
(
"_"
,
"."
));
Properties
imp_prop
=
null
;
try
{
imp_prop
=
ElphelTiffReader
.
getTiffMeta
(
path
);
...
...
@@ -107,87 +156,13 @@ public class ComboMap {
orig_zoom_valid
=
FloatImageData
.
isZoomValid
(
orig_pix_meters
);
need_extra_zoom
=
FloatImageData
.
needZoomIn
(
orig_pix_meters
);
images
=
new
HashMap
<
Integer
,
FloatImageData
>();
pairwise_matches
=
new
HashMap
<
Double
,
PairwiseOrthoMatch
>();
}
public
LocalDateTime
getLocalDateTime
()
{
return
dt
;
}
public
static
ComboMap
[]
initializeComboMaps
(
String
[]
image_paths
)
{
// full paths, including ext
double
[][]
affine
=
{{
1
,
0
,
0
},{
0
,
1
,
0
}};
// maybe later calculate from mage_enuatr
ComboMap
[]
combo_maps
=
new
ComboMap
[
image_paths
.
length
];
for
(
int
n
=
0
;
n
<
combo_maps
.
length
;
n
++)
{
combo_maps
[
n
]
=
new
ComboMap
(
image_paths
[
n
]);
combo_maps
[
n
].
setAffine
(
affine
);
}
return
combo_maps
;
}
public
static
ComboMap
[]
initializeComboMaps
(
String
files_list
)
{
List
<
String
>
lines
;
List
<
String
>
rel_files
=
new
ArrayList
<
String
>();
Path
seq_path
=
Paths
.
get
(
files_list
);
try
{
lines
=
Files
.
readAllLines
(
seq_path
,
StandardCharsets
.
UTF_8
);
// lines.stream().forEach(System.out::println);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
return
null
;
}
Path
base_path
=
seq_path
.
getParent
();
HashMap
<
String
,
String
>
dir_map
=
new
HashMap
<
String
,
String
>();
for
(
String
line:
lines
){
if
(
line
.
split
(
"#"
).
length
>
0
)
{
String
[]
tokens
=
line
.
split
(
"#"
)[
0
].
trim
().
split
(
"[\\s,;=]+"
);
if
((
tokens
.
length
>
2
)
&&
(
tokens
[
0
].
toUpperCase
().
equals
(
"SET"
)))
{
parse_set:
{
for
(
String
dir_name:
KEY_DIRS
)
if
(
dir_name
.
equals
(
tokens
[
1
]))
{
dir_map
.
put
(
dir_name
,
tokens
[
2
]);
System
.
out
.
println
(
"Parsed SET: "
+
tokens
[
1
]+
" in line: "
+
line
);
break
parse_set
;
}
System
.
out
.
println
(
"*********** Unknown SET: "
+
tokens
[
1
]+
" in line: "
+
line
);
}
}
else
if
((
tokens
.
length
==
1
)
&&
(
tokens
[
0
].
length
()
>
0
))
{
rel_files
.
add
(
tokens
[
0
]);
}
}
}
if
(
dir_map
.
containsKey
(
"rootDirectory"
))
{
base_path
=
base_path
.
resolve
(
Paths
.
get
(
dir_map
.
get
(
"rootDirectory"
)));
File
base_dir
=
new
File
(
base_path
.
toString
());
// if (!base_dir.exists()) {
// base_dir.mkdirs();
// }
}
String
sourceDirectory
=
base_path
.
toString
();
// set sourceDirectory:
if
(
dir_map
.
containsKey
(
"sourceDirectory"
))
{
sourceDirectory
=(
base_path
.
resolve
(
Paths
.
get
(
dir_map
.
get
(
"sourceDirectory"
)))).
toString
();
}
Path
source_path
=
Paths
.
get
(
sourceDirectory
);
File
source_dir
=
new
File
(
source_path
.
toString
());
String
[]
paths
=
new
String
[
rel_files
.
size
()];
for
(
int
i
=
0
;
i
<
paths
.
length
;
i
++)
{
paths
[
i
]
=
(
source_path
.
resolve
(
Paths
.
get
(
rel_files
.
get
(
i
)))).
toString
();
}
return
initializeComboMaps
(
paths
);
}
public
static
String
[]
getNames
(
ComboMap
[]
maps
)
{
String
[]
names
=
new
String
[
maps
.
length
];
for
(
int
n
=
0
;
n
<
maps
.
length
;
n
++)
{
names
[
n
]
=
maps
[
n
].
getName
();
}
return
names
;
}
public
String
getName
()
{
return
name
;
...
...
@@ -293,7 +268,7 @@ public class ComboMap {
return
null
;
}
public
double
[]
enuOffsetTo
(
Comb
oMap
other
)
{
public
double
[]
enuOffsetTo
(
Orth
oMap
other
)
{
return
Imx5
.
enuFromLla
(
other
.
lla
,
lla
);
}
...
...
@@ -378,27 +353,6 @@ public class ComboMap {
return
bounds_pix
;
}
/**
* Get rectified bounds of all provided combo images relative to the origin (vertical
* point) of the first one in meters
* @param maps array of combo images
* @return {{min_x,max_x},{min_y,max_y}} bounds that include all provided maps
* relative to the origin (vertical point) of the first image
*/
public
static
double
[][]
getBoundsMeters
(
ComboMap
[]
maps
){
// maps[0] as a reference
double
[][]
bounds
=
maps
[
0
].
getBoundsMeters
(
true
);
for
(
int
nmap
=
1
;
nmap
<
maps
.
length
;
nmap
++)
{
double
[][]
bounds_other
=
maps
[
nmap
].
getBoundsMeters
(
true
);
double
[]
enuOffset
=
maps
[
0
].
enuOffsetTo
(
maps
[
nmap
]);
double
[]
rd
=
{
enuOffset
[
0
],
-
enuOffset
[
1
]};
// {right,down} of the image
for
(
int
n
=
0
;
n
<
bounds
.
length
;
n
++)
{
bounds
[
n
][
0
]
=
Math
.
min
(
bounds
[
n
][
0
],
bounds_other
[
n
][
0
]+
rd
[
n
]);
bounds
[
n
][
1
]
=
Math
.
max
(
bounds
[
n
][
1
],
bounds_other
[
n
][
1
]+
rd
[
n
]);
}
}
return
bounds
;
}
/**
* In preparation for the GPU correlation (zoomed out images of the fixed
* size are calculated separately and have NaN for unused pixels.
...
...
@@ -407,8 +361,8 @@ public class ComboMap {
* affine matrices for both images ([2][2][3]).
* The overlap area should fit into gpu_width, gpu_hight, the affine-generated
* image coordinates will be limited during TpTask[][] generation
* @param ref_map
Comb
oMap instance for the reference map
* @param var_map
Comb
oMap instance for the variable map instance
* @param ref_map
Orth
oMap instance for the reference map
* @param var_map
Orth
oMap instance for the variable map instance
* @param zoom_lev zoom level (0 - 1 pix=1cm, 1 - 1 pix = 0.5cm, -1 - 1 pix = 2 cm.
* @param var_offset additional (to affine and lla, vert_meters) x,y offset of
* the var_map (in output pixels). Used for spiral search for initial
...
...
@@ -420,35 +374,13 @@ public class ComboMap {
* (is centered) to the reference image origin (vertical point)
*/
public
static
int
[][]
getPairOvelapBoundsAffine
(
Comb
oMap
ref_map
,
Comb
oMap
var_map
,
Orth
oMap
ref_map
,
Orth
oMap
var_map
,
int
zoom_lev
,
int
[]
var_offset
,
double
[][][]
gpu_affine
){
return
null
;
}
/**
* Get rectified bounds of all provided combo images relative to the origin (vertical
* point) of the first one in pixels at the provided zoom level. Center of the first
* image correspond to the {0,0} point from which the bounds are counted
* @param maps array of map instances
* @param zoom_level zoom level - 0 corresponds to 1pix=1cm scale, +1 - to 1pix = 0.5cm
* @return {{min_x,max_x},{min_y, max_y}} relative to the origin of the first image
*/
public
static
int
[][]
getBoundsPixels
(
ComboMap
[]
maps
,
int
zoom_level
){
// maps[0] as a reference
double
[][]
bounds_meters
=
getBoundsMeters
(
maps
);
double
pix_size
=
getPixelSizeMeters
(
zoom_level
);
int
[][]
bounds_pix
=
new
int
[
2
][
2
];
for
(
int
n
=
0
;
n
<
bounds_pix
.
length
;
n
++)
{
bounds_pix
[
n
][
0
]
=
(
int
)
Math
.
floor
(
bounds_meters
[
n
][
0
]/
pix_size
);
bounds_pix
[
n
][
1
]
=
(
int
)
Math
.
ceil
(
bounds_meters
[
n
][
1
]/
pix_size
);
}
return
bounds_pix
;
}
/**
* Convert from the affine matrix that calculates image coordinates from the rectified one
...
...
@@ -550,14 +482,10 @@ public class ComboMap {
* Copy prepared scaled image to the top-left corner of the fixed-size
* float[] array for the GPU input
* @param zoom_level
* @param gpu_width
* @param gpu_height
* @return
*/
public
float
[]
getPaddedGPU
(
int
zoom_level
,
int
gpu_width
,
int
gpu_height
){
int
zoom_level
){
boolean
got_image
=
downScaleForGPU
(
zoom_level
);
// will create if does not exist
if
(!
got_image
)
{
System
.
out
.
println
(
"getPaddedGPU(): failed to prepare a scaled image"
);
...
...
@@ -593,179 +521,7 @@ public class ComboMap {
return
padded_gpu
;
}
public
static
ImagePlus
renderMulti
(
String
title
,
boolean
use_alt
,
boolean
show_centers
,
ComboMap
[]
maps
,
int
zoom_level
,
int
[]
origin
){
int
[]
wh
=
new
int
[
2
];
double
[][]
centers
=
new
double
[
maps
.
length
][];
float
[][]
multi
=
renderMulti
(
use_alt
,
// boolean use_alt,
maps
,
// ComboMap [] maps,
zoom_level
,
// int zoom_level,
wh
,
// int [] wh,
origin
,
// int [] origin){ // maps[0] as a reference
centers
);
// double [][] centers)
String
[]
map_names
=
new
String
[
maps
.
length
];
for
(
int
n
=
0
;
n
<
maps
.
length
;
n
++)
{
map_names
[
n
]
=
maps
[
n
].
getName
()+
"_"
+
maps
[
n
].
getLocalDateTime
().
toString
().
replace
(
"T"
,
"_"
)+
"_UTC"
;
}
ImageStack
stack
=
ShowDoubleFloatArrays
.
makeStack
(
multi
,
wh
[
0
],
wh
[
1
],
map_names
,
false
);
ImagePlus
imp
=
new
ImagePlus
(
title
,
stack
);
if
(
show_centers
)
{
PointRoi
roi
=
new
PointRoi
();
for
(
int
i
=
0
;
i
<
centers
.
length
;
i
++)
{
roi
.
addPoint
(
centers
[
i
][
0
],
centers
[
i
][
1
],
i
+
1
);
}
roi
.
setOptions
(
"label"
);
imp
.
setRoi
(
roi
);
}
return
imp
;
}
/**
* Rectify and render multiple images (as slices) matching vert_meters to
* their (vert_meters points) provided IMS coordinates
* @param show altitudes instead of thermal data
* @param maps array of the combo images
* @param zoom_level zoom level (0 - 1pix=1cm, 1 - 1pix=0.5cm, -1 - 1pix=2cm
* @param wh null or int [2], will return {width, height}
* @param origin - null or double [2], will return {x0, y0} in pixels
* @param centers - null or double[maps.length][] - will return image centers coordinates
* @return
*/
public
static
float
[][]
renderMulti
(
boolean
use_alt
,
ComboMap
[]
maps
,
int
zoom_level
,
int
[]
wh
,
int
[]
origin
,
// maps[0] as a reference
double
[][]
centers
){
int
[][]
bounds
=
getBoundsPixels
(
// should be for rectified, {-bounds[0][0], -bounds[0][1]} - exact center
maps
,
zoom_level
);
int
width
=
bounds
[
0
][
1
]
-
bounds
[
0
][
0
];
// bounds[x][0] - negative
int
height
=
bounds
[
1
][
1
]
-
bounds
[
1
][
0
];
if
(
wh
!=
null
)
{
wh
[
0
]
=
width
;
wh
[
1
]
=
height
;
}
if
(
origin
!=
null
)
{
origin
[
0
]
=
-
bounds
[
0
][
0
];
origin
[
1
]
=
-
bounds
[
1
][
0
];
}
final
float
[][]
fpixels
=
new
float
[
maps
.
length
][
width
*
height
];
for
(
int
nmap
=
0
;
nmap
<
maps
.
length
;
nmap
++)
{
final
int
fnmap
=
nmap
;
Arrays
.
fill
(
fpixels
[
nmap
],
Float
.
NaN
);
final
double
scale
=
1.0
/
getPixelSizeMeters
(
zoom_level
);
final
double
src_scale
=
1.0
/
getPixelSizeMeters
(
maps
[
nmap
].
orig_zoom_level
);
// pix per meter
// metric bounds of the rectified image relative to its origin
double
[][]
mbounds
=
maps
[
nmap
].
getBoundsMeters
(
true
);
double
[]
enu_offset
=
maps
[
0
].
enuOffsetTo
(
maps
[
nmap
]);
final
double
[]
scaled_out_center
=
{
// xy center to apply affine to
-
bounds
[
0
][
0
]
+
scale
*
enu_offset
[
0
],
-
bounds
[
1
][
0
]
-
scale
*
enu_offset
[
1
]};
if
(
centers
!=
null
)
{
centers
[
nmap
]
=
scaled_out_center
;
}
final
int
[][]
obounds
=
new
int
[
2
][
2
];
// output (rectified, combined) image bounds, relative to thje top-left
for
(
int
n
=
0
;
n
<
2
;
n
++)
{
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
]);
}
// Output window size
final
int
ownd_width
=
obounds
[
0
][
1
]
-
obounds
[
0
][
0
];
final
int
ownd_height
=
obounds
[
1
][
1
]
-
obounds
[
1
][
0
];
final
int
ownd_len
=
ownd_width
*
ownd_height
;
double
[][]
src_bounds
=
maps
[
nmap
].
getBoundsMeters
(
true
);
final
double
[]
src_center
=
{-
src_bounds
[
0
][
0
],-
src_bounds
[
1
][
0
]};
// x,y center offset in the source image
final
double
[][]
affine
=
maps
[
nmap
].
affine
;
final
int
src_width
=
use_alt
?
maps
[
nmap
].
getAltData
().
width
:
maps
[
nmap
].
getImageData
().
width
;
final
int
src_height
=
use_alt
?
maps
[
nmap
].
getAltData
().
height
:
maps
[
nmap
].
getImageData
().
height
;
final
float
[]
src_img
=
use_alt
?
maps
[
nmap
].
getAltData
().
data
:
maps
[
nmap
].
getImageData
().
data
;
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
nPix
=
ai
.
getAndIncrement
();
nPix
<
ownd_len
;
nPix
=
ai
.
getAndIncrement
())
{
int
opX
=
nPix
%
ownd_width
+
obounds
[
0
][
0
];
// absolute output pX, pY
int
opY
=
nPix
/
ownd_width
+
obounds
[
1
][
0
];
double
dX
=
(
opX
-
scaled_out_center
[
0
])
/
scale
;
// in original image scale
double
dY
=
(
opY
-
scaled_out_center
[
1
])
/
scale
;
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
[
1
][
0
]*
dX
+
affine
[
1
][
1
]*
dY
+
affine
[
1
][
2
]
+
src_center
[
1
])};
// limit to the source image
if
((
xy_src
[
0
]
>=
0
)
&&
(
xy_src
[
0
]
<
(
src_width
-
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
])
};
double
[]
kxy
=
{
xy_src
[
0
]-
ixy_src
[
0
],
xy_src
[
1
]-
ixy_src
[
1
]};
int
indx00
=
ixy_src
[
0
]
+
ixy_src
[
1
]
*
src_width
;
double
d00
=
src_img
[
indx00
];
if
(!
Double
.
isNaN
(
d00
))
{
double
d01
=
src_img
[
indx00
+
1
];
double
d10
=
src_img
[
indx00
+
src_width
];
double
d11
=
src_img
[
indx00
+
src_width
+
1
];
double
d
=
d00
*(
1.0
-
kxy
[
0
])*(
1.0
-
kxy
[
1
])+
d01
*
kxy
[
0
]
*(
1.0
-
kxy
[
1
])+
d10
*(
1.0
-
kxy
[
0
])*
kxy
[
1
]+
d11
*
kxy
[
0
]
*
kxy
[
1
];
fpixels
[
fnmap
][
opX
+
opY
*
width
]
=
(
float
)
d
;
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
}
return
fpixels
;
}
public
static
double
[][]
correlateComboPair
(
CLTParameters
clt_parameters
,
ComboMap
[]
combo_maps
,
int
first_index
,
int
second_index
,
int
zoom_lev
,
double
[]
offset_xy_second
,
// on top of affine and GPS
final
int
debugLevel
){
int
[]
gpu_pair
=
{
first_index
,
second_index
};
double
[][][]
bounds_out
=
new
double
[
2
][][];
float
[][]
gpu_pair_img
=
new
float
[
2
][];
for
(
int
n
=
0
;
n
<
gpu_pair
.
length
;
n
++)
{
gpu_pair_img
[
n
]
=
combo_maps
[
gpu_pair
[
n
]].
getPaddedGPU
(
zoom_lev
,
// int zoom_level,
gpu_width
,
// int gpu_width,
gpu_height
);
// int gpu_height)
}
if
(
debugLevel
>
1
)
{
String
[]
map_names
=
{
combo_maps
[
gpu_pair
[
0
]].
getName
(),
combo_maps
[
gpu_pair
[
1
]].
getName
()};
ShowDoubleFloatArrays
.
showArrays
(
gpu_pair_img
,
gpu_width
,
gpu_height
,
true
,
"gpu_pair-zoom"
+
zoom_lev
+
"-"
+
combo_maps
[
gpu_pair
[
0
]].
getName
()+
"-"
+
combo_maps
[
gpu_pair
[
1
]].
getName
(),
map_names
);
}
return
null
;
}
public
static
void
testVideo
(
ImagePlus
imp
)
{
String
path_prefix
=
"/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/videos/video_"
;
boolean
keep_original
=
true
;
...
...
src/main/java/com/elphel/imagej/orthomosaic/OrthoMapsCollection.java
0 → 100644
View file @
f97f3155
package
com
.
elphel
.
imagej
.
orthomosaic
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.ObjectInputStream
;
import
java.io.ObjectOutputStream
;
import
java.io.Serializable
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
com.elphel.imagej.cameras.CLTParameters
;
import
com.elphel.imagej.common.ShowDoubleFloatArrays
;
import
com.elphel.imagej.tileprocessor.ImageDtt
;
import
ij.ImagePlus
;
import
ij.ImageStack
;
import
ij.gui.PointRoi
;
public
class
OrthoMapsCollection
implements
Serializable
{
private
static
final
long
serialVersionUID
=
1L
;
public
static
final
String
[]
KEY_DIRS
=
{
"rootDirectory"
,
// from EyesisCorrectionParameters
"sourceDirectory"
,
"linkedModels"
,
"videoDirectory"
,
"x3dDirectory"
,
"resultsDirectory"
};
OrthoMap
[]
ortho_maps
;
transient
HashMap
<
Double
,
Integer
>
map_index
;
transient
HashMap
<
String
,
Integer
>
map_index_string
;
private
void
writeObject
(
ObjectOutputStream
oos
)
throws
IOException
{
// ?
oos
.
defaultWriteObject
();
// oos.writeObject(path);
// ortho_maps is not transient
}
private
void
readObject
(
ObjectInputStream
ois
)
throws
ClassNotFoundException
,
IOException
{
ois
.
defaultReadObject
();
reindex
();
// will recreate map_index, map_index_string
// lla is not transient
}
public
OrthoMapsCollection
(
String
path
)
{
if
(
path
.
endsWith
(
".list"
))
{
String
[]
paths
=
getPathsFromSorceList
(
path
);
double
[][]
affine
=
{{
1
,
0
,
0
},{
0
,
1
,
0
}};
// maybe later calculate from mage_enuatr
ortho_maps
=
new
OrthoMap
[
paths
.
length
];
for
(
int
n
=
0
;
n
<
ortho_maps
.
length
;
n
++)
{
ortho_maps
[
n
]
=
new
OrthoMap
(
paths
[
n
]);
ortho_maps
[
n
].
setAffine
(
affine
);
}
}
Arrays
.
sort
(
ortho_maps
);
reindex
();
}
public
int
reindex
()
{
map_index
=
new
HashMap
<
Double
,
Integer
>();
map_index_string
=
new
HashMap
<
String
,
Integer
>();
for
(
int
i
=
0
;
i
<
ortho_maps
.
length
;
i
++)
{
map_index
.
put
(
ortho_maps
[
i
].
ts
,
i
);
map_index_string
.
put
(
ortho_maps
[
i
].
name
,
i
);
}
return
ortho_maps
.
length
;
}
OrthoMap
[]
getMaps
()
{
return
ortho_maps
;
}
public
String
[]
getNames
()
{
String
[]
names
=
new
String
[
ortho_maps
.
length
];
for
(
int
n
=
0
;
n
<
ortho_maps
.
length
;
n
++)
{
names
[
n
]
=
ortho_maps
[
n
].
getName
();
}
return
names
;
}
public
static
String
[]
getPathsFromSorceList
(
String
files_list
)
{
List
<
String
>
lines
;
List
<
String
>
rel_files
=
new
ArrayList
<
String
>();
Path
seq_path
=
Paths
.
get
(
files_list
);
try
{
lines
=
Files
.
readAllLines
(
seq_path
,
StandardCharsets
.
UTF_8
);
// lines.stream().forEach(System.out::println);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
return
null
;
}
Path
base_path
=
seq_path
.
getParent
();
HashMap
<
String
,
String
>
dir_map
=
new
HashMap
<
String
,
String
>();
for
(
String
line:
lines
){
if
(
line
.
split
(
"#"
).
length
>
0
)
{
String
[]
tokens
=
line
.
split
(
"#"
)[
0
].
trim
().
split
(
"[\\s,;=]+"
);
if
((
tokens
.
length
>
2
)
&&
(
tokens
[
0
].
toUpperCase
().
equals
(
"SET"
)))
{
parse_set:
{
for
(
String
dir_name:
KEY_DIRS
)
if
(
dir_name
.
equals
(
tokens
[
1
]))
{
dir_map
.
put
(
dir_name
,
tokens
[
2
]);
System
.
out
.
println
(
"Parsed SET: "
+
tokens
[
1
]+
" in line: "
+
line
);
break
parse_set
;
}
System
.
out
.
println
(
"*********** Unknown SET: "
+
tokens
[
1
]+
" in line: "
+
line
);
}
}
else
if
((
tokens
.
length
==
1
)
&&
(
tokens
[
0
].
length
()
>
0
))
{
rel_files
.
add
(
tokens
[
0
]);
}
}
}
if
(
dir_map
.
containsKey
(
"rootDirectory"
))
{
base_path
=
base_path
.
resolve
(
Paths
.
get
(
dir_map
.
get
(
"rootDirectory"
)));
File
base_dir
=
new
File
(
base_path
.
toString
());
}
String
sourceDirectory
=
base_path
.
toString
();
// set sourceDirectory:
if
(
dir_map
.
containsKey
(
"sourceDirectory"
))
{
sourceDirectory
=(
base_path
.
resolve
(
Paths
.
get
(
dir_map
.
get
(
"sourceDirectory"
)))).
toString
();
}
Path
source_path
=
Paths
.
get
(
sourceDirectory
);
// File source_dir = new File(source_path.toString());
String
[]
paths
=
new
String
[
rel_files
.
size
()];
for
(
int
i
=
0
;
i
<
paths
.
length
;
i
++)
{
paths
[
i
]
=
(
source_path
.
resolve
(
Paths
.
get
(
rel_files
.
get
(
i
)))).
toString
();
}
return
paths
;
}
/**
* Get rectified bounds of all provided ortho images relative to the origin (vertical
* point) of the first one in pixels at the provided zoom level. Center of the first
* image correspond to the {0,0} point from which the bounds are counted
* @param zoom_level zoom level - 0 corresponds to 1pix=1cm scale, +1 - to 1pix = 0.5cm
* @return {{min_x,max_x},{min_y, max_y}} relative to the origin of the first image
*/
public
int
[][]
getBoundsPixels
(
int
zoom_level
){
// maps[0] as a reference
double
[][]
bounds_meters
=
getBoundsMeters
();
double
pix_size
=
OrthoMap
.
getPixelSizeMeters
(
zoom_level
);
int
[][]
bounds_pix
=
new
int
[
2
][
2
];
for
(
int
n
=
0
;
n
<
bounds_pix
.
length
;
n
++)
{
bounds_pix
[
n
][
0
]
=
(
int
)
Math
.
floor
(
bounds_meters
[
n
][
0
]/
pix_size
);
bounds_pix
[
n
][
1
]
=
(
int
)
Math
.
ceil
(
bounds_meters
[
n
][
1
]/
pix_size
);
}
return
bounds_pix
;
}
/**
* Get rectified bounds of all provided ortho images relative to the origin (vertical
* point) of the first one in meters
* @return {{min_x,max_x},{min_y,max_y}} bounds that include all provided maps
* relative to the origin (vertical point) of the first image
*/
public
double
[][]
getBoundsMeters
(){
// maps[0] as a reference
double
[][]
bounds
=
ortho_maps
[
0
].
getBoundsMeters
(
true
);
for
(
int
nmap
=
1
;
nmap
<
ortho_maps
.
length
;
nmap
++)
{
double
[][]
bounds_other
=
ortho_maps
[
nmap
].
getBoundsMeters
(
true
);
double
[]
enuOffset
=
ortho_maps
[
0
].
enuOffsetTo
(
ortho_maps
[
nmap
]);
double
[]
rd
=
{
enuOffset
[
0
],
-
enuOffset
[
1
]};
// {right,down} of the image
for
(
int
n
=
0
;
n
<
bounds
.
length
;
n
++)
{
bounds
[
n
][
0
]
=
Math
.
min
(
bounds
[
n
][
0
],
bounds_other
[
n
][
0
]+
rd
[
n
]);
bounds
[
n
][
1
]
=
Math
.
max
(
bounds
[
n
][
1
],
bounds_other
[
n
][
1
]+
rd
[
n
]);
}
}
return
bounds
;
}
public
ImagePlus
renderMulti
(
String
title
,
boolean
use_alt
,
boolean
show_centers
,
// OrthoMap [] maps,
int
zoom_level
,
int
[]
origin
){
int
[]
wh
=
new
int
[
2
];
double
[][]
centers
=
new
double
[
ortho_maps
.
length
][];
float
[][]
multi
=
renderMulti
(
use_alt
,
// boolean use_alt,
// maps, // OrthoMap [] maps,
zoom_level
,
// int zoom_level,
wh
,
// int [] wh,
origin
,
// int [] origin){ // maps[0] as a reference
centers
);
// double [][] centers)
String
[]
map_names
=
new
String
[
ortho_maps
.
length
];
for
(
int
n
=
0
;
n
<
ortho_maps
.
length
;
n
++)
{
map_names
[
n
]
=
ortho_maps
[
n
].
getName
()+
"_"
+
ortho_maps
[
n
].
getLocalDateTime
().
toString
().
replace
(
"T"
,
"_"
)+
"_UTC"
;
}
ImageStack
stack
=
ShowDoubleFloatArrays
.
makeStack
(
multi
,
wh
[
0
],
wh
[
1
],
map_names
,
false
);
ImagePlus
imp
=
new
ImagePlus
(
title
,
stack
);
if
(
show_centers
)
{
PointRoi
roi
=
new
PointRoi
();
for
(
int
i
=
0
;
i
<
centers
.
length
;
i
++)
{
roi
.
addPoint
(
centers
[
i
][
0
],
centers
[
i
][
1
],
i
+
1
);
}
roi
.
setOptions
(
"label"
);
imp
.
setRoi
(
roi
);
}
return
imp
;
}
/**
* Rectify and render multiple images (as slices) matching vert_meters to
* their (vert_meters points) provided IMS coordinates
* @param show altitudes instead of thermal data
* @param maps array of the ortho images
* @param zoom_level zoom level (0 - 1pix=1cm, 1 - 1pix=0.5cm, -1 - 1pix=2cm
* @param wh null or int [2], will return {width, height}
* @param origin - null or double [2], will return {x0, y0} in pixels
* @param centers - null or double[maps.length][] - will return image centers coordinates
* @return
*/
public
float
[][]
renderMulti
(
boolean
use_alt
,
// OrthoMap [] maps,
int
zoom_level
,
int
[]
wh
,
int
[]
origin
,
// maps[0] as a reference
double
[][]
centers
){
int
[][]
bounds
=
getBoundsPixels
(
// should be for rectified, {-bounds[0][0], -bounds[0][1]} - exact center
zoom_level
);
int
width
=
bounds
[
0
][
1
]
-
bounds
[
0
][
0
];
// bounds[x][0] - negative
int
height
=
bounds
[
1
][
1
]
-
bounds
[
1
][
0
];
if
(
wh
!=
null
)
{
wh
[
0
]
=
width
;
wh
[
1
]
=
height
;
}
if
(
origin
!=
null
)
{
origin
[
0
]
=
-
bounds
[
0
][
0
];
origin
[
1
]
=
-
bounds
[
1
][
0
];
}
final
float
[][]
fpixels
=
new
float
[
ortho_maps
.
length
][
width
*
height
];
for
(
int
nmap
=
0
;
nmap
<
ortho_maps
.
length
;
nmap
++)
{
final
int
fnmap
=
nmap
;
Arrays
.
fill
(
fpixels
[
nmap
],
Float
.
NaN
);
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
// metric bounds of the rectified image relative to its origin
double
[][]
mbounds
=
ortho_maps
[
nmap
].
getBoundsMeters
(
true
);
double
[]
enu_offset
=
ortho_maps
[
0
].
enuOffsetTo
(
ortho_maps
[
nmap
]);
final
double
[]
scaled_out_center
=
{
// xy center to apply affine to
-
bounds
[
0
][
0
]
+
scale
*
enu_offset
[
0
],
-
bounds
[
1
][
0
]
-
scale
*
enu_offset
[
1
]};
if
(
centers
!=
null
)
{
centers
[
nmap
]
=
scaled_out_center
;
}
final
int
[][]
obounds
=
new
int
[
2
][
2
];
// output (rectified, combined) image bounds, relative to thje top-left
for
(
int
n
=
0
;
n
<
2
;
n
++)
{
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
]);
}
// Output window size
final
int
ownd_width
=
obounds
[
0
][
1
]
-
obounds
[
0
][
0
];
final
int
ownd_height
=
obounds
[
1
][
1
]
-
obounds
[
1
][
0
];
final
int
ownd_len
=
ownd_width
*
ownd_height
;
double
[][]
src_bounds
=
ortho_maps
[
nmap
].
getBoundsMeters
(
true
);
final
double
[]
src_center
=
{-
src_bounds
[
0
][
0
],-
src_bounds
[
1
][
0
]};
// x,y center offset in the source image
final
double
[][]
affine
=
ortho_maps
[
nmap
].
affine
;
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
float
[]
src_img
=
use_alt
?
ortho_maps
[
nmap
].
getAltData
().
data
:
ortho_maps
[
nmap
].
getImageData
().
data
;
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
nPix
=
ai
.
getAndIncrement
();
nPix
<
ownd_len
;
nPix
=
ai
.
getAndIncrement
())
{
int
opX
=
nPix
%
ownd_width
+
obounds
[
0
][
0
];
// absolute output pX, pY
int
opY
=
nPix
/
ownd_width
+
obounds
[
1
][
0
];
double
dX
=
(
opX
-
scaled_out_center
[
0
])
/
scale
;
// in original image scale
double
dY
=
(
opY
-
scaled_out_center
[
1
])
/
scale
;
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
[
1
][
0
]*
dX
+
affine
[
1
][
1
]*
dY
+
affine
[
1
][
2
]
+
src_center
[
1
])};
// limit to the source image
if
((
xy_src
[
0
]
>=
0
)
&&
(
xy_src
[
0
]
<
(
src_width
-
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
])
};
double
[]
kxy
=
{
xy_src
[
0
]-
ixy_src
[
0
],
xy_src
[
1
]-
ixy_src
[
1
]};
int
indx00
=
ixy_src
[
0
]
+
ixy_src
[
1
]
*
src_width
;
double
d00
=
src_img
[
indx00
];
if
(!
Double
.
isNaN
(
d00
))
{
double
d01
=
src_img
[
indx00
+
1
];
double
d10
=
src_img
[
indx00
+
src_width
];
double
d11
=
src_img
[
indx00
+
src_width
+
1
];
double
d
=
d00
*(
1.0
-
kxy
[
0
])*(
1.0
-
kxy
[
1
])+
d01
*
kxy
[
0
]
*(
1.0
-
kxy
[
1
])+
d10
*(
1.0
-
kxy
[
0
])*
kxy
[
1
]+
d11
*
kxy
[
0
]
*
kxy
[
1
];
fpixels
[
fnmap
][
opX
+
opY
*
width
]
=
(
float
)
d
;
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
}
return
fpixels
;
}
public
float
[][]
getPaddedPairGPU
(
String
[]
spair
,
int
zoom_lev
){
int
[]
pair
=
new
int
[
spair
.
length
];
for
(
int
i
=
0
;
i
<
pair
.
length
;
i
++)
{
pair
[
i
]
=
map_index_string
.
get
(
spair
[
i
]);
}
return
getPaddedPairGPU
(
pair
,
// int [] pair,
zoom_lev
);
// int zoom_lev,
}
private
float
[][]
getPaddedPairGPU
(
int
[]
pair
,
int
zoom_lev
){
float
[][]
gpu_pair_img
=
new
float
[
2
][];
for
(
int
n
=
0
;
n
<
pair
.
length
;
n
++)
{
gpu_pair_img
[
n
]
=
ortho_maps
[
pair
[
n
]].
getPaddedGPU
(
zoom_lev
);
// int zoom_level,
}
return
gpu_pair_img
;
}
public
double
[][]
correlateOrthoPair
(
CLTParameters
clt_parameters
,
String
first_name
,
String
second_name
,
int
zoom_lev
,
double
[]
offset_xy_second
,
// on top of affine and GPS
final
int
debugLevel
){
int
first_index
=
map_index_string
.
get
(
first_name
);
int
second_index
=
map_index_string
.
get
(
second_name
);
return
correlateOrthoPair
(
clt_parameters
,
// CLTParameters clt_parameters,
first_index
,
// int first_index,
second_index
,
// int second_index,
zoom_lev
,
// int zoom_lev,
offset_xy_second
,
// double [] offset_xy_second, // on top of affine and GPS
debugLevel
);
// final int debugLevel)
}
private
double
[][]
correlateOrthoPair
(
CLTParameters
clt_parameters
,
int
first_index
,
int
second_index
,
int
zoom_lev
,
double
[]
offset_xy_second
,
// on top of affine and GPS
final
int
debugLevel
){
int
[]
gpu_pair
=
{
first_index
,
second_index
};
double
[][][]
bounds_out
=
new
double
[
2
][][];
float
[][]
gpu_pair_img
=
new
float
[
2
][];
for
(
int
n
=
0
;
n
<
gpu_pair
.
length
;
n
++)
{
gpu_pair_img
[
n
]
=
ortho_maps
[
gpu_pair
[
n
]].
getPaddedGPU
(
zoom_lev
);
// int zoom_level,
}
if
(
debugLevel
>
1
)
{
String
[]
map_names
=
{
ortho_maps
[
gpu_pair
[
0
]].
getName
(),
ortho_maps
[
gpu_pair
[
1
]].
getName
()};
ShowDoubleFloatArrays
.
showArrays
(
gpu_pair_img
,
OrthoMap
.
gpu_width
,
OrthoMap
.
gpu_height
,
true
,
"gpu_pair-zoom"
+
zoom_lev
+
"-"
+
ortho_maps
[
gpu_pair
[
0
]].
getName
()+
"-"
+
ortho_maps
[
gpu_pair
[
1
]].
getName
(),
map_names
);
}
return
null
;
}
public
static
OrthoMapsCollection
readOrthoMapsCollection
(
String
path
)
throws
IOException
,
ClassNotFoundException
{
FileInputStream
fileInputStream
=
new
FileInputStream
(
path
);
ObjectInputStream
objectInputStream
=
new
ObjectInputStream
(
fileInputStream
);
OrthoMapsCollection
orthoMapsCollection
=
(
OrthoMapsCollection
)
objectInputStream
.
readObject
();
objectInputStream
.
close
();
return
orthoMapsCollection
;
}
public
void
writeOrthoMapsCollection
(
String
path
)
throws
IOException
{
FileOutputStream
fileOutputStream
=
new
FileOutputStream
(
path
);
ObjectOutputStream
objectOutputStream
=
new
ObjectOutputStream
(
fileOutputStream
);
objectOutputStream
.
writeObject
(
this
);
objectOutputStream
.
flush
();
objectOutputStream
.
close
();
}
/*
float [][] gpu_pair_img = new float [2][];
for (int n = 0; n < gpu_pair.length; n++) {
gpu_pair_img[n] = ortho_maps[gpu_pair[n]].getPaddedGPU (
zoom_lev, // int zoom_level,
gpu_width, // int gpu_width,
gpu_height); // int gpu_height)
}
map_index_string
*/
}
src/main/java/com/elphel/imagej/orthomosaic/PairwiseOrthoMatch.java
0 → 100644
View file @
f97f3155
package
com
.
elphel
.
imagej
.
orthomosaic
;
import
java.io.IOException
;
import
java.io.ObjectInputStream
;
import
java.io.ObjectOutputStream
;
import
java.io.Serializable
;
public
class
PairwiseOrthoMatch
implements
Serializable
{
public
PairwiseOrthoMatch
(
double
[][]
affine
,
double
[][]
jtj
)
{
this
.
affine
=
affine
;
this
.
jtj
=
jtj
;
}
private
static
final
long
serialVersionUID
=
1L
;
public
double
[][]
affine
=
new
double
[
2
][
3
];
public
transient
double
[][]
jtj
=
new
double
[
6
][
6
];
private
void
writeObject
(
ObjectOutputStream
oos
)
throws
IOException
{
oos
.
defaultWriteObject
();
for
(
int
i
=
0
;
i
<
jtj
.
length
;
i
++)
{
for
(
int
j
=
i
;
j
<
jtj
[
i
].
length
;
j
++)
{
oos
.
writeObject
(
jtj
[
i
][
j
]);
}
}
}
private
void
readObject
(
ObjectInputStream
ois
)
throws
ClassNotFoundException
,
IOException
{
ois
.
defaultReadObject
();
for
(
int
i
=
0
;
i
<
jtj
.
length
;
i
++)
{
for
(
int
j
=
i
;
j
<
jtj
[
i
].
length
;
j
++)
{
jtj
[
i
][
j
]
=
(
Double
)
ois
.
readObject
();
if
(
j
>
i
)
{
jtj
[
j
][
i
]
=
jtj
[
i
][
j
];
}
}
}
}
//private void readObjectNoData() throws ObjectStreamException; // used to modify default values
}
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