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
f7d1b998
Commit
f7d1b998
authored
Dec 12, 2022
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Started debugging 2-level triangulation
parent
0ef14ecf
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
2097 additions
and
682 deletions
+2097
-682
QuadCLTCPU.java
...main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java
+15
-176
TexturedModel.java
...n/java/com/elphel/imagej/tileprocessor/TexturedModel.java
+196
-55
TileNeibs.java
src/main/java/com/elphel/imagej/tileprocessor/TileNeibs.java
+4
-2
TileProcessor.java
...n/java/com/elphel/imagej/tileprocessor/TileProcessor.java
+2
-446
TriMesh.java
src/main/java/com/elphel/imagej/x3d/export/TriMesh.java
+1877
-0
X3dOutput.java
src/main/java/com/elphel/imagej/x3d/export/X3dOutput.java
+3
-3
No files found.
src/main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java
View file @
f7d1b998
...
...
@@ -12037,7 +12037,10 @@ public class QuadCLTCPU {
boolean
showTri
=
false
;
// ((scanIndex < next_pass + 1) && clt_parameters.show_triangles) ||((scanIndex - next_pass) == 73);
try
{
generateClusterX3d
(
TriMesh
.
generateClusterX3d
(
false
,
// boolean full_texture, // true - full size image, false - bounds only
0
,
// int subdivide_mesh, // 0,1 - full tiles only, 2 - 2x2 pixels, 4 - 2x2 pixels
// null, // boolean [] alpha, // boolean alpha - true - opaque, false - transparent. Full/bounds
x3dOutput
,
wfOutput
,
// output WSavefront if not null
tri_meshes
,
// ArrayList<TriMesh> tri_meshes,
...
...
@@ -12048,6 +12051,9 @@ public class QuadCLTCPU {
bgndScan
.
getSelected
(),
// selected,
scan_disparity
,
// scan.disparity_map[ImageDtt.DISPARITY_INDEX_CM],
clt_parameters
.
transform_size
,
tp
.
getTilesX
(),
// int tilesX,
tp
.
getTilesY
(),
// int tilesY,
getGeometryCorrection
(),
// GeometryCorrection geometryCorrection,
clt_parameters
.
correct_distortions
,
// requires backdrop image to be corrected also
showTri
,
// (scanIndex < next_pass + 1) && clt_parameters.show_triangles,
infinity_disparity
,
// 0.3
...
...
@@ -12136,7 +12142,10 @@ public class QuadCLTCPU {
}
boolean
showTri
=
!
batch_mode
&&
(
debugLevel
>
-
1
)
&&
(((
scanIndex
<
next_pass
+
1
)
&&
clt_parameters
.
show_triangles
)
||((
scanIndex
-
next_pass
)
==
73
));
try
{
generateClusterX3d
(
TriMesh
.
generateClusterX3d
(
false
,
// boolean full_texture, // true - full size image, false - bounds only
0
,
// int subdivide_mesh, // 0,1 - full tiles only, 2 - 2x2 pixels, 4 - 2x2 pixels
// null, // boolean [] alpha, // boolean alpha - true - opaque, false - transparent. Full/bounds
x3dOutput
,
wfOutput
,
// output WSavefront if not null
tri_meshes
,
// ArrayList<TriMesh> tri_meshes,
...
...
@@ -12147,6 +12156,9 @@ public class QuadCLTCPU {
scan
.
getSelected
(),
scan_disparity
,
// scan.disparity_map[ImageDtt.DISPARITY_INDEX_CM],
clt_parameters
.
transform_size
,
tp
.
getTilesX
(),
// int tilesX,
tp
.
getTilesY
(),
// int tilesY,
getGeometryCorrection
(),
// GeometryCorrection geometryCorrection,
clt_parameters
.
correct_distortions
,
// requires backdrop image to be corrected also
showTri
,
// (scanIndex < next_pass + 1) && clt_parameters.show_triangles,
// FIXME: make a separate parameter:
...
...
@@ -12187,179 +12199,6 @@ public class QuadCLTCPU {
public
void
generateClusterX3d
(
// USED in lwir
X3dOutput
x3dOutput
,
// output x3d if not null
WavefrontExport
wfOutput
,
// output WSavefront if not null
ArrayList
<
TriMesh
>
tri_meshes
,
String
texturePath
,
String
id
,
String
class_name
,
Rectangle
bounds
,
boolean
[]
selected
,
double
[]
disparity
,
// if null, will use min_disparity
int
tile_size
,
boolean
correctDistortions
,
// requires backdrop image to be corrected also
boolean
show_triangles
,
double
min_disparity
,
double
max_disparity
,
double
maxDispTriangle
,
// relative <=0 - do not use
double
maxZtoXY
,
// 10.0. <=0 - do not use
double
maxZ
,
// far clip (0 - do not clip). Negative - limit by max
boolean
limitZ
,
double
[][]
dbg_disp_tri_slice
,
int
debug_level
)
throws
IOException
{
// int debug_level = 1;
if
(
bounds
==
null
)
{
return
;
// not used in lwir
}
int
[][]
indices
=
tp
.
getCoordIndices
(
// starting with 0, -1 - not selected // updated 09.18.2022
bounds
,
selected
);
double
[][]
texCoord
=
TileProcessor
.
getTexCoords
(
// get texture coordinates for indices
indices
);
double
[][]
worldXYZ
=
tp
.
getCoords
(
// get world XYZ in meters for indices // updated 09.18.2022
disparity
,
min_disparity
,
max_disparity
,
bounds
,
indices
,
tile_size
,
correctDistortions
,
// requires backdrop image to be corrected also
this
.
geometryCorrection
);
double
[]
indexedDisparity
=
tp
.
getIndexedDisparities
(
// get disparity for each index // updated 09.18.2022
disparity
,
min_disparity
,
max_disparity
,
bounds
,
indices
,
tile_size
);
int
[][]
triangles
=
TileProcessor
.
triangulateCluster
(
indices
);
// double maxZtoXY = 10.0; // maximal delta_z to sqrt(dx^23 + dy^2)
int
num_removed
=
0
;
if
(
maxDispTriangle
>
0.0
)
{
int
pre_num
=
triangles
.
length
;
triangles
=
TileProcessor
.
filterTriangles
(
// remove crazy triangles with large disparity difference
triangles
,
indexedDisparity
,
// disparities per vertex index
maxDispTriangle
,
// maximal disparity difference in a triangle
debug_level
+
0
);
// int debug_level);
if
(
triangles
.
length
<
pre_num
)
{
num_removed
+=
pre_num
-
triangles
.
length
;
if
(
debug_level
>
0
)
{
System
.
out
.
println
(
"filterTriangles() removed "
+
(
pre_num
-
triangles
.
length
)+
" triangles"
);
}
}
}
if
((
maxZ
!=
0.0
)
&&
limitZ
)
{
for
(
int
i
=
0
;
i
<
worldXYZ
.
length
;
i
++)
{
if
(
worldXYZ
[
i
][
2
]
<
-
maxZ
)
{
double
k
=
-
maxZ
/
worldXYZ
[
i
][
2
];
worldXYZ
[
i
][
0
]
*=
k
;
worldXYZ
[
i
][
1
]
*=
k
;
worldXYZ
[
i
][
2
]
*=
k
;
}
}
}
if
((
maxZtoXY
>
0.0
)
||
((
maxZ
!=
0
)
&&
!
limitZ
)
)
{
int
pre_num
=
triangles
.
length
;
triangles
=
TileProcessor
.
filterTrianglesWorld
(
triangles
,
worldXYZ
,
// world per vertex index
maxZtoXY
,
maxZ
);
if
(
triangles
.
length
<
pre_num
)
{
num_removed
+=
pre_num
-
triangles
.
length
;
if
(
debug_level
>
0
)
{
System
.
out
.
println
(
"filterTrianglesWorld() removed "
+
(
pre_num
-
triangles
.
length
)+
" triangles"
);
}
}
}
if
(
triangles
.
length
==
0
)
{
if
(
debug_level
>
0
)
{
System
.
out
.
println
(
"generateClusterX3d() no triangles left in a cluster"
);
}
return
;
// all triangles removed
}
if
(
num_removed
>
0
)
{
int
[]
re_index
=
TileProcessor
.
reIndex
(
// Move to TriMesh?
indices
,
// will be modified if needed (if some indices are removed
triangles
);
if
(
re_index
!=
null
)
{
// need to update other arrays: texCoord, worldXYZ. indexedDisparity[] will not be used
int
num_indices_old
=
worldXYZ
.
length
;
int
[]
inv_index
=
new
int
[
num_indices_old
];
Arrays
.
fill
(
inv_index
,-
1
);
// just to get an error
for
(
int
i
=
0
;
i
<
re_index
.
length
;
i
++)
{
inv_index
[
re_index
[
i
]]
=
i
;
}
double
[][]
texCoord_new
=
new
double
[
re_index
.
length
][];
double
[][]
worldXYZ_new
=
new
double
[
re_index
.
length
][];
for
(
int
i
=
0
;
i
<
re_index
.
length
;
i
++)
{
texCoord_new
[
i
]
=
texCoord
[
re_index
[
i
]];
worldXYZ_new
[
i
]
=
worldXYZ
[
re_index
[
i
]];
}
texCoord
=
texCoord_new
;
worldXYZ
=
worldXYZ_new
;
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
triangles
[
i
].
length
;
j
++)
{
triangles
[
i
][
j
]
=
inv_index
[
triangles
[
i
][
j
]];
}
}
}
if
(
debug_level
>
0
)
{
show_triangles
=
true
;
// show after removed
}
}
if
(
show_triangles
||
(
dbg_disp_tri_slice
!=
null
))
{
double
[]
ddisp
=
(
disparity
==
null
)?(
new
double
[
1
]):
disparity
;
if
(
disparity
==
null
)
{
ddisp
[
0
]
=
min_disparity
;
}
tp
.
testTriangles
(
(
show_triangles
?
texturePath:
null
),
bounds
,
selected
,
ddisp
,
// disparity, // if disparity.length == 1 - use for all
tile_size
,
indices
,
triangles
,
dbg_disp_tri_slice
);
// double [][] debug_triangles);
}
if
(
x3dOutput
!=
null
)
{
x3dOutput
.
addCluster
(
texturePath
,
id
,
class_name
,
texCoord
,
worldXYZ
,
triangles
);
}
if
(
wfOutput
!=
null
)
{
wfOutput
.
addCluster
(
texturePath
,
id
,
// class_name,
texCoord
,
worldXYZ
,
triangles
);
}
if
(
tri_meshes
!=
null
)
{
tri_meshes
.
add
(
new
TriMesh
(
texturePath
,
// String texture_image,
worldXYZ
,
// double [][] worldXYZ,
texCoord
,
// double [][] texCoord,
triangles
));
// int [][] triangles
}
}
// public ImagePlus getBackgroundImage( // USED in lwir
public
boolean
[]
getBackgroundImageMasks
(
// USED in lwir
...
...
@@ -14690,7 +14529,7 @@ public class QuadCLTCPU {
true
,
// smart,
true
);
//newAllowed, // save
double
ts
=
Double
.
parseDouble
(
image_name
.
replace
(
'_'
,
'.'
));
(
new
X3dOutput
())
.
generateKML
(
X3dOutput
.
generateKML
(
kml_copy_dir
+
Prefs
.
getFileSeparator
()+
image_name
+
".kml"
,
// String path,
false
,
// boolean overwrite,
""
,
// String icon_path, //<href>x3d/1487451413_967079.x3d</href> ?
...
...
src/main/java/com/elphel/imagej/tileprocessor/TexturedModel.java
View file @
f7d1b998
...
...
@@ -1829,6 +1829,8 @@ public class TexturedModel {
final
int
ref_index
=
scenes
.
length
-
1
;
final
QuadCLT
ref_scene
=
scenes
[
ref_index
];
final
TileProcessor
tp
=
ref_scene
.
getTileProcessor
();
final
boolean
split_textures
=
(
debugLevel
>
1000
);
// false;
final
int
subdiv_tiles
=
4
;
// subdivide tiles to smaller triangles
final
boolean
debug_disp_tri
=
!
batch_mode
&&
(
debugLevel
>
0
);
// TODO: use clt_parameters
if
(
ref_scene
.
image_data
==
null
){
...
...
@@ -1858,7 +1860,7 @@ public class TexturedModel {
final
int
tex_cluster_gap
=
2
;
// gap between clusters Make clt_parameters
final
double
max_disparity_lim
=
100.0
;
// do not allow stray disparities above this
final
double
min_trim_disparity
=
2.0
;
// do not try to trim texture outlines with lower disparities
final
int
width
=
tilesX
*
transform_size
;
// for debug only
final
int
width
=
tilesX
*
transform_size
;
final
int
height
=
tp
.
getTilesY
()
*
transform_size
;
// get multi-scene disparity map for FG and BG and filter it
if
(
combo_dsn_final
==
null
)
{
...
...
@@ -1928,6 +1930,7 @@ public class TexturedModel {
disp_adiffj
,
// final double disp_adiffj,
disp_rdiffj
,
// final double disp_rdiffj,
debugLevel
);
//1); // 2); // final int debugLevel)
/*
// Debugging up to here:
// if (debugLevel > -1000) {
// return false;
...
...
@@ -1937,7 +1940,7 @@ public class TexturedModel {
System.out.println("Temporary exit after clusterizeFgBg()");
return false;
}
*/
boolean
[]
scenes_sel
=
new
boolean
[
scenes
.
length
];
// for (int i = scenes.length - 10; i < scenes.length; i++) { // start with just one (reference) scene
for
(
int
i
=
0
;
i
<
scenes
.
length
;
i
++)
{
// start with just one (reference) scene
...
...
@@ -1956,11 +1959,10 @@ public class TexturedModel {
boolean
renormalize
=
true
;
// false - use normalizations from previous scenes to keep consistent colors
final
boolean
no_alpha
=
true
;
ImagePlus
[]
combined_textures
=
getInterCombinedTextures
(
// return ImagePlus[] matching tileClusters[], with alpha
double
[][][]
faded_textures
=
getInterCombinedTextures
(
// return ImagePlus[] matching tileClusters[], with alpha
clt_parameters
,
// final CLTParameters clt_parameters,
colorProcParameters
,
// ColorProcParameters colorProcParameters,
rgbParameters
,
// EyesisCorrectionParameters.RGBParameters rgbParameters,
no_alpha
,
// final boolean no_alpha,
parameter_scene
,
// final QuadCLT parameter_scene, // to use for rendering parameters in multi-series sequences
// if null - use reference scene
ref_index
,
// final int ref_index,
...
...
@@ -1971,10 +1973,22 @@ public class TexturedModel {
max_disparity_lim
,
// final double max_disparity_lim, // 100.0; // do not allow stray disparities above this
min_trim_disparity
,
// final double min_trim_disparity, // 2.0; // do not try to trim texture outlines with lower disparities
debugLevel
);
// final int debug_level)
ImagePlus
[]
combined_textures
=
getInterCombinedTextures
(
// return ImagePlus[] matching tileClusters[], with alpha
clt_parameters
,
// final CLTParameters clt_parameters,
no_alpha
,
// final boolean no_alpha,
scenes
[
ref_index
],
// QuadCLT ref_scene,
parameter_scene
,
// final QuadCLT parameter_scene, // to use for rendering parameters in multi-series sequences
faded_textures
,
// double [][][] faded_textures,
tilesX
,
// int tilesX,
ref_scene
.
getTileProcessor
().
getTilesY
(),
// int tilesY,
transform_size
,
// int transform_size,
debugLevel
);
// final int debug_level)
boolean
save_full_textures
=
true
;
// false; // true;
EyesisCorrectionParameters
.
CorrectionParameters
correctionsParameters
=
ref_scene
.
correctionsParameters
;
String
x3d_dir
=
ref_scene
.
getX3dDirectory
();
if
(
save_full_textures
)
{
if
(
save_full_textures
||
!
split_textures
)
{
for
(
int
nslice
=
0
;
nslice
<
combined_textures
.
length
;
nslice
++)
{
EyesisCorrections
.
saveAndShow
(
combined_textures
[
nslice
],
// imp_texture_cluster,
...
...
@@ -1985,22 +1999,33 @@ public class TexturedModel {
1
);
//
}
}
// Maybe will switch to combined textures (less files)
ImagePlus
[]
imp_textures
=
splitCombinedTextures
(
tileClusters
,
// TileCluster [] tileClusters, //should have name <timestamp>-*
transform_size
,
// int transform_size,
combined_textures
);
// ImagePlus [] combo_textures )
for
(
int
i
=
0
;
i
<
imp_textures
.
length
;
i
++)
if
(
imp_textures
[
i
]
!=
null
)
{
// should not be
EyesisCorrections
.
saveAndShow
(
imp_textures
[
i
],
// imp_texture_cluster,
x3d_dir
,
correctionsParameters
.
png
,
false
,
// (nslice < 4), // clt_parameters.show_textures,
-
1
,
// jpegQuality){// <0 - keep current, 0 - force Tiff, >0 use for JPEG
1
);
//
double
alpha_threshold
=
0.5
;
boolean
[][]
combined_alphas
=
null
;
if
(
subdiv_tiles
>
0
)
{
combined_alphas
=
new
boolean
[
faded_textures
.
length
][
faded_textures
[
0
][
0
].
length
];
for
(
int
i
=
0
;
i
<
faded_textures
.
length
;
i
++)
{
// TODO: accelerate with multi
for
(
int
j
=
0
;
j
<
faded_textures
[
i
][
1
].
length
;
j
++)
{
combined_alphas
[
i
][
j
]
=
faded_textures
[
i
][
1
][
j
]
>
alpha_threshold
;
}
}
}
ImagePlus
[]
imp_textures
=
null
;
if
(
split_textures
)
{
// Maybe will switch to combined textures (less files)
imp_textures
=
splitCombinedTextures
(
tileClusters
,
// TileCluster [] tileClusters, //should have name <timestamp>-*
transform_size
,
// int transform_size,
combined_textures
);
// ImagePlus [] combo_textures )
for
(
int
i
=
0
;
i
<
imp_textures
.
length
;
i
++)
if
(
imp_textures
[
i
]
!=
null
)
{
// should not be
EyesisCorrections
.
saveAndShow
(
imp_textures
[
i
],
// imp_texture_cluster,
x3d_dir
,
correctionsParameters
.
png
,
false
,
// (nslice < 4), // clt_parameters.show_textures,
-
1
,
// jpegQuality){// <0 - keep current, 0 - force Tiff, >0 use for JPEG
1
);
//
}
}
// create x3d file
if
(
clt_parameters
.
output_x3d
)
{
x3dOutput
=
new
X3dOutput
(
...
...
@@ -2025,7 +2050,7 @@ public class TexturedModel {
// do nothing, just keep
}
}
if
(
clt_parameters
.
output_glTF
&&
(
x3d_dir
!=
null
))
{
if
(
(
clt_parameters
.
output_x3d
||
clt_parameters
.
output_glTF
)
&&
(
x3d_dir
!=
null
))
{
tri_meshes
=
new
ArrayList
<
TriMesh
>();
}
...
...
@@ -2046,21 +2071,30 @@ public class TexturedModel {
final
double
[][]
dbg_tri_disp
=
debug_disp_tri
?
(
new
double
[
tileClusters
.
length
][
width
*
height
]):
null
;
final
double
[][]
dbg_tri_tri
=
debug_disp_tri
?
(
new
double
[
tileClusters
.
length
][
width
*
height
]):
null
;
boolean
showTri
=
!
batch_mode
&&
(
debugLevel
>
-
1
)
&&
(
clt_parameters
.
show_triangles
);
int
dbg_scale_mesh
=
4
;
// <=0 - do not show
int
dbg_scaled_width
=
tp
.
getTilesX
()
*
transform_size
*
dbg_scale_mesh
;
int
dbg_scaled_height
=
tp
.
getTilesY
()
*
transform_size
*
dbg_scale_mesh
;
double
[][]
dbg_mesh_imgs
=
null
;
if
(
dbg_scale_mesh
>
0
)
{
dbg_mesh_imgs
=
new
double
[
tileClusters
.
length
][
dbg_scaled_width
*
dbg_scaled_height
];
// maybe fill with NaN?
}
// double [][] dbg
/*
tp.getTilesX(), // int tilesX,
tp.getTilesY(), // int tilesY,
*/
for
(
int
nslice
=
0
;
nslice
<
tileClusters
.
length
;
nslice
++){
if
(
dbg_tri_disp
!=
null
)
{
Arrays
.
fill
(
dbg_tri_disp
[
nslice
],
Double
.
NaN
);
}
// keep them all 0, not NaN
// if (dbg_tri_tri != null) {
// Arrays.fill(dbg_tri_tri[nslice], Double.NaN);
// }
final
double
[][]
dbg_disp_tri_slice
=
(
dbg_tri_tri
!=
null
)
?
((
dbg_tri_disp
!=
null
)?
(
new
double
[][]
{
dbg_tri_disp
[
nslice
],
dbg_tri_tri
[
nslice
]}):
(
new
double
[][]
{
dbg_tri_tri
[
nslice
]})
):
null
;
if
(
debugLevel
>
-
1
){
// System.out.println("Generating cluster images (limit is set to "+clt_parameters.max_clusters+") largest, scan #"+scanIndex);
System
.
out
.
println
(
"Generating cluster images from texture slice "
+
nslice
);
}
int
[]
indices
=
tileClusters
[
nslice
].
getSubIndices
();
...
...
@@ -2069,20 +2103,37 @@ public class TexturedModel {
for
(
int
sub_i
=
0
;
sub_i
<
indices
.
length
;
sub_i
++)
{
Rectangle
roi
=
bounds
[
sub_i
];
int
cluster_index
=
indices
[
sub_i
];
ImagePlus
imp_texture_cluster
=
imp_textures
[
cluster_index
];
if
(
imp_textures
[
cluster_index
]
==
null
)
{
ImagePlus
imp_texture_cluster
=
combined_textures
[
nslice
];
boolean
[]
alpha
=
(
combined_alphas
!=
null
)
?
combined_alphas
[
nslice
]
:
null
;
if
(
imp_textures
!=
null
)
{
imp_texture_cluster
=
imp_textures
[
cluster_index
];
if
(
combined_alphas
!=
null
)
{
alpha
=
new
boolean
[
roi
.
height
*
roi
.
width
];
for
(
int
row
=
0
;
row
<
roi
.
height
;
row
++)
{
System
.
arraycopy
(
combined_alphas
[
nslice
],
(
roi
.
y
+
row
)
*
width
+
roi
.
x
,
alpha
,
row
*
roi
.
width
,
roi
.
width
);
}
}
}
if
(
imp_texture_cluster
==
null
)
{
if
(
debugLevel
>
-
1
){
System
.
out
.
println
(
"Empty cluster #"
+
cluster_index
);
}
continue
;
}
String
texturePath
=
imp_texture_cluster
.
getTitle
()+
".png"
;
double
[]
scan_disparity
=
tileClusters
[
nslice
].
getSubDisparity
(
sub_i
);
boolean
[]
scan_selected
=
tileClusters
[
nslice
].
getSubSelected
(
sub_i
);
// skipping averaging disparity fro a whole cluster (needs strength and does not seem to be useful)
boolean
showTri
=
!
batch_mode
&&
(
debugLevel
>
-
1
)
&&
(
clt_parameters
.
show_triangles
)
&&
(
cluster_index
==
dbg_tri_indx
);
double
[]
scan_disparity
=
tileClusters
[
nslice
].
getSubDisparity
(
sub_i
);
// limited to cluster bounds
boolean
[]
scan_selected
=
tileClusters
[
nslice
].
getSubSelected
(
sub_i
);
// limited to cluster bounds
// skipping averaging disparity for a whole cluster (needs strength and does not seem to be useful)
try
{
ref_scene
.
generateClusterX3d
(
// also generates wavefront obj
if
(
alpha
==
null
)
{
TriMesh
.
generateClusterX3d
(
// old version also generates wavefront obj
(
imp_textures
==
null
),
// boolean full_texture, // true - full size image, false - bounds only
0
,
// int subdivide_mesh, // 0,1 - full tiles only, 2 - 2x2 pixels, 4 - 2x2 pixels
x3dOutput
,
wfOutput
,
// output WSavefront if not null
tri_meshes
,
// ArrayList<TriMesh> tri_meshes,
...
...
@@ -2093,8 +2144,11 @@ public class TexturedModel {
scan_selected
,
// scan.getSelected(),
scan_disparity
,
// scan.disparity_map[ImageDtt.DISPARITY_INDEX_CM],
clt_parameters
.
transform_size
,
tp
.
getTilesX
(),
// int tilesX,
tp
.
getTilesY
(),
// int tilesY,
ref_scene
.
getGeometryCorrection
(),
// GeometryCorrection geometryCorrection,
clt_parameters
.
correct_distortions
,
// requires backdrop image to be corrected also
showTri
,
// (scanIndex < next_pass + 1) && clt_parameters.show_triangles,
showTri
&&
(
cluster_index
==
dbg_tri_indx
)
,
// (scanIndex < next_pass + 1) && clt_parameters.show_triangles,
// FIXME: make a separate parameter:
infinity_disparity
,
// 0.25 * clt_parameters.bgnd_range, // 0.3
clt_parameters
.
grow_disp_max
,
// other_range, // 2.0 'other_range - difference from the specified (*_CM)
...
...
@@ -2104,6 +2158,38 @@ public class TexturedModel {
clt_parameters
.
limitZ
,
dbg_disp_tri_slice
,
// double [][] dbg_disp_tri_slice,
debugLevel
+
1
);
// int debug_level) > 0
}
else
{
TriMesh
.
generateClusterX3d
(
// new version with small triangles for alpha also generates wavefront obj
(
imp_textures
==
null
),
// boolean full_texture, // true - full size image, false - bounds only
subdiv_tiles
,
// int subdivide_mesh, // 0,1 - full tiles only, 2 - 2x2 pixels, 4 - 2x2 pixels
alpha
,
// boolean [] alpha, // boolean alpha - true - opaque, false - transparent. Full/bounds
x3dOutput
,
wfOutput
,
// output WSavefront if not null
tri_meshes
,
// ArrayList<TriMesh> tri_meshes,
texturePath
,
"shape_id-"
+
cluster_index
,
// id
null
,
// class
roi
,
// scan.getTextureBounds(),
scan_selected
,
// scan.getSelected(),
scan_disparity
,
// scan.disparity_map[ImageDtt.DISPARITY_INDEX_CM],
clt_parameters
.
transform_size
,
tp
.
getTilesX
(),
// int tilesX,
tp
.
getTilesY
(),
// int tilesY,
ref_scene
.
getGeometryCorrection
(),
// GeometryCorrection geometryCorrection,
clt_parameters
.
correct_distortions
,
// requires backdrop image to be corrected also
dbg_mesh_imgs
[
nslice
],
// double [] tri_img, //
dbg_scaled_width
,
// int tri_img_width,
// showTri, // (scanIndex < next_pass + 1) && clt_parameters.show_triangles,
// FIXME: make a separate parameter:
infinity_disparity
,
// 0.25 * clt_parameters.bgnd_range, // 0.3
clt_parameters
.
grow_disp_max
,
// other_range, // 2.0 'other_range - difference from the specified (*_CM)
clt_parameters
.
maxDispTriangle
,
clt_parameters
.
maxZtoXY
,
// double maxZtoXY, // 10.0. <=0 - do not use
clt_parameters
.
maxZ
,
clt_parameters
.
limitZ
,
// dbg_disp_tri_slice, // double [][] dbg_disp_tri_slice,
debugLevel
+
1
);
// int debug_level) > 0
}
//dbg_disp_tri_slice
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
...
...
@@ -2145,6 +2231,12 @@ public class TexturedModel {
ref_scene
.
getImageName
()+
"-mesh_disparity_triangles"
,
dbg_titles
);
}
boolean
exit_now
=
(
debugLevel
>
1000
);
if
(
exit_now
)
{
return
false
;
}
if
((
x3d_dir
!=
null
)
&&
(
x3dOutput
!=
null
)){
x3dOutput
.
generateX3D
(
x3d_dir
+
Prefs
.
getFileSeparator
()
+
ref_scene
.
correctionsParameters
.
getModelName
(
ref_scene
.
getImageName
())+
".x3d"
);
...
...
@@ -2155,7 +2247,7 @@ public class TexturedModel {
System
.
out
.
println
(
"Wavefront object file saved to "
+
wfOutput
.
obj_path
);
System
.
out
.
println
(
"Wavefront material file saved to "
+
wfOutput
.
mtl_path
);
}
if
(
tri_meshes
!=
null
)
{
if
(
clt_parameters
.
output_glTF
&&
(
tri_meshes
!=
null
)
)
{
try
{
GlTfExport
.
glTFExport
(
x3d_dir
,
// String x3d_dir,
...
...
@@ -2967,7 +3059,7 @@ public class TexturedModel {
final
double
min_edge_variance
,
final
int
width
,
final
int
transform_size
)
{
boolean
dbg
=
true
;
boolean
dbg
=
false
;
//
true;
final
int
num_slices
=
texture_en
.
length
;
final
int
img_size
=
texture_en
[
0
].
length
;
final
int
tilesX
=
width
/
transform_size
;
...
...
@@ -3030,15 +3122,15 @@ public class TexturedModel {
dbg_img
[
4
][
i
]
=
erase
[
i
]?
1.0
:
0.0
;
dbg_img
[
5
][
i
]
=
texture_en
[
nslice
][
i
]?
1.0
:
0.0
;
}
ShowDoubleFloatArrays
.
showArrays
(
dbg_img
,
width
,
img_size
/
width
,
true
,
"VAR_EDGE_FILTER-"
+
String
.
format
(
"%02d"
,
nslice
),
dbg_titles
);
}
ShowDoubleFloatArrays
.
showArrays
(
dbg_img
,
width
,
img_size
/
width
,
true
,
"VAR_EDGE_FILTER-"
+
String
.
format
(
"%02d"
,
nslice
),
dbg_titles
);
}
}
};
...
...
@@ -4111,11 +4203,12 @@ public class TexturedModel {
* @param debugLevel debug level - controls generation of images.
* @return array of ImagePlus instances corresponding to tileClusters array
*/
public
static
ImagePlus
[]
getInterCombinedTextures
(
// return ImagePlus[] matching tileClusters[], with alpha
// public static ImagePlus[] getInterCombinedTextures( // return ImagePlus[] matching tileClusters[], with alpha
public
static
double
[][][]
getInterCombinedTextures
(
// return ImagePlus[] matching tileClusters[], with alpha
final
CLTParameters
clt_parameters
,
ColorProcParameters
colorProcParameters
,
EyesisCorrectionParameters
.
RGBParameters
rgbParameters
,
final
boolean
no_alpha
,
//
EyesisCorrectionParameters.RGBParameters rgbParameters,
//
final boolean no_alpha,
QuadCLT
parameter_scene
,
final
int
ref_index
,
final
QuadCLT
[]
scenes
,
...
...
@@ -4158,8 +4251,8 @@ public class TexturedModel {
final
double
tex_hist_amount
=
clt_parameters
.
tex_hist_amount
;
// clt_parameters. 0.7;
final
int
tex_hist_bins
=
clt_parameters
.
tex_hist_bins
;
// 1024 ;
final
int
tex_hist_segments
=
clt_parameters
.
tex_hist_segments
;
// 32 ;
final
boolean
tex_color
=
clt_parameters
.
tex_color
;
// true;
final
int
tex_palette
=
clt_parameters
.
tex_palette
;
// 2 ;
///
final boolean tex_color = clt_parameters.tex_color; // true;
///
final int tex_palette = clt_parameters.tex_palette; // 2 ;
// final boolean extend_sky = true;
final
int
shrink_sky_tiles
=
4
;
// 2; sum of 2 +bg extend
final
boolean
grow_sky
=
true
;
...
...
@@ -4412,7 +4505,7 @@ public class TexturedModel {
tileClusters
,
// final TileCluster[] tileClusters, // to process blue_sky?
max_disparity_lim
,
// final double max_disparity_lim, // do not allow stray disparities above this
min_trim_disparity
,
// final double min_trim_disparity, // do not try to trim texture outlines with lower disparities
ref_scene
.
getImageName
());
// null); // ref_scene.getImageName()); // final String dbg_prefix);
null
);
//
ref_scene.getImageName()); // null); // ref_scene.getImageName()); // final String dbg_prefix);
if
(
debugLevel
>
-
1
)
{
double
[][]
dbg_textures
=
new
double
[
faded_textures
.
length
*
faded_textures
[
0
].
length
][
faded_textures
[
0
][
0
].
length
];
String
[]
dbg_titles
=
new
String
[
dbg_textures
.
length
];
...
...
@@ -4618,12 +4711,61 @@ public class TexturedModel {
ref_scene
.
getImageName
()+
"-texture_weights"
);
}
}
return
faded_textures
;
/*
double [] minmax = parameter_scene.getColdHot(); // used in linearStackToColor
ImagePlus [] imp_tex = new ImagePlus[num_slices];
for (int nslice = 0; nslice < num_slices; nslice++) {
String title=String.format("%s-combo%03d-texture",ref_scene.getImageName(), nslice);
double [][] rendered_texture = faded_textures[nslice];
if (no_alpha) {
rendered_texture[1] = new double [rendered_texture[0].length];
for (int i = 0; i < rendered_texture[0].length; i++) {
rendered_texture[1][i] = Double.isNaN(rendered_texture[0][i])? 0.0: 1.0;
}
}
imp_tex[nslice] = QuadCLTCPU.linearStackToColorLWIR(
clt_parameters, // CLTParameters clt_parameters,
tex_palette, // int lwir_palette, // <0 - do not convert
minmax, // double [] minmax,
title, // String name,
"", // String suffix, // such as disparity=...
tex_color, // boolean toRGB,
rendered_texture, // faded_textures[nslice], // double [][] texture_data,
tilesX * transform_size, // int width, // int tilesX,
tilesY * transform_size, // int height, // int tilesY,
debugLevel); // int debugLevel )
// Add synthetic mesh only with higher resolution? or just any by a specified period?what king of mesh - vertical random, ...
// Split and save as png
}
// Process accumulated textures: average, apply borders, convert to color or apply UM, add synthetic mesh, ...
return imp_tex; // ImagePlus[] ? with alpha, to be split into png and saved with alpha.
*/
}
public
static
ImagePlus
[]
getInterCombinedTextures
(
// return ImagePlus[] matching tileClusters[], with alpha
final
CLTParameters
clt_parameters
,
boolean
no_alpha
,
QuadCLT
ref_scene
,
QuadCLT
parameter_scene
,
double
[][][]
faded_textures
,
int
tilesX
,
int
tilesY
,
int
transform_size
,
int
debugLevel
)
{
final
boolean
tex_color
=
clt_parameters
.
tex_color
;
// true;
final
int
tex_palette
=
clt_parameters
.
tex_palette
;
// 2 ;
int
num_slices
=
faded_textures
.
length
;
if
(
parameter_scene
==
null
)
{
parameter_scene
=
ref_scene
;
}
double
[]
minmax
=
parameter_scene
.
getColdHot
();
// used in linearStackToColor
ImagePlus
[]
imp_tex
=
new
ImagePlus
[
num_slices
];
for
(
int
nslice
=
0
;
nslice
<
num_slices
;
nslice
++)
{
String
title
=
String
.
format
(
"%s-combo%03d-texture"
,
ref_scene
.
getImageName
(),
nslice
);
double
[][]
rendered_texture
=
faded_textures
[
nslice
].
clone
();
// shallow !
if
(
no_alpha
)
{
rendered_texture
[
1
]
=
new
double
[
rendered_texture
[
0
].
length
];
for
(
int
i
=
0
;
i
<
rendered_texture
[
0
].
length
;
i
++)
{
...
...
@@ -4643,12 +4785,11 @@ public class TexturedModel {
debugLevel
);
// int debugLevel )
// Add synthetic mesh only with higher resolution? or just any by a specified period?what king of mesh - vertical random, ...
// Split and save as png
}
// Process accumulated textures: average, apply borders, convert to color or apply UM, add synthetic mesh, ...
return
imp_tex
;
// ImagePlus[] ? with alpha, to be split into png and saved with alpha.
}
...
...
src/main/java/com/elphel/imagej/tileprocessor/TileNeibs.java
View file @
f7d1b998
...
...
@@ -40,8 +40,10 @@ public class TileNeibs{
final
public
static
int
DIR_LEFT
=
2
;
// Right
final
public
static
int
DIR_DOWN
=
4
;
// Down
final
public
static
int
DIR_RIGHT
=
6
;
// Left
final
public
static
int
DIRS
=
8
;
// total dirs
final
public
static
int
[][]
DIR_XY
=
{{
0
,-
1
},
{
1
,-
1
},
{
1
,
0
},
{
1
,
1
},
{
0
,
1
},
{-
1
,
1
},
{-
1
,
0
},
{-
1
,-
1
}};
final
public
static
int
DIRS
=
DIR_XY
.
length
;
//8; // total dirs
public
static
int
reverseDir
(
int
dir
)
{
if
((
dir
<
0
)
||
(
dir
>=
DIRS
))
{
return
dir
;
...
...
src/main/java/com/elphel/imagej/tileprocessor/TileProcessor.java
View file @
f7d1b998
...
...
@@ -8619,167 +8619,9 @@ ImageDtt.startAndJoin(threads);
return
rslt
;
}
public
int
[][]
getCoordIndices
(
// starting with 0, -1 - not selected
Rectangle
bounds
,
boolean
[]
selected
)
{
int
[][]
indices
=
new
int
[
bounds
.
height
][
bounds
.
width
];
int
indx
=
0
;
if
(
selected
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
y
=
0
;
y
<
bounds
.
height
;
y
++)
{
for
(
int
x
=
0
;
x
<
bounds
.
width
;
x
++){
if
(
selected
[
this
.
tilesX
*
(
bounds
.
y
+
y
)
+
(
bounds
.
x
+
x
)]){
indices
[
y
][
x
]
=
indx
++;
}
else
{
indices
[
y
][
x
]
=
-
1
;
}
}
}
}
else
{
// 09.18.2022
for
(
int
y
=
0
;
y
<
bounds
.
height
;
y
++)
{
for
(
int
x
=
0
;
x
<
bounds
.
width
;
x
++){
if
(
selected
[
bounds
.
width
*
y
+
x
]){
indices
[
y
][
x
]
=
indx
++;
}
else
{
indices
[
y
][
x
]
=
-
1
;
}
}
}
}
return
indices
;
}
public
static
double
[][]
getTexCoords
(
// get texture coordinates for indices
int
[][]
indices
)
{
int
maxIndex
=
-
1
;
int
height
=
indices
.
length
;
int
width
=
indices
[
0
].
length
;
outer_label:
{
for
(
int
y
=
height
-
1
;
y
>=
0
;
y
--)
{
for
(
int
x
=
width
-
1
;
x
>=
0
;
x
--){
if
(
indices
[
y
][
x
]
>=
0
){
maxIndex
=
indices
[
y
][
x
];
break
outer_label
;
}
}
}
}
double
[][]
textureCoordinate
=
new
double
[
maxIndex
+
1
][
2
];
int
indx
=
0
;
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
textureCoordinate
[
indx
][
0
]
=
(
x
+
0.5
)/
width
;
textureCoordinate
[
indx
][
1
]
=
(
height
-
y
-
0.5
)
/
height
;
// y is up
indx
++;
}
}
}
return
textureCoordinate
;
}
public
double
[]
getIndexedDisparities
(
// get disparity for each index
double
[]
disparity
,
double
min_disparity
,
double
max_disparity
,
Rectangle
bounds
,
int
[][]
indices
,
int
tile_size
)
{
// int height = indices.length;
int
width
=
indices
[
0
].
length
;
int
maxIndex
=
getMaxIndex
(
indices
);
double
[]
indexedDisparity
=
new
double
[
maxIndex
+
1
];
int
indx
=
0
;
if
(
disparity
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
// center coordinates for 8*8 tile is [3.5,3.5]
double
disp
=
(
disparity
==
null
)?
min_disparity:
(
disparity
[(
bounds
.
y
+
y
)
*
tilesX
+
(
bounds
.
x
+
x
)]);
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
indexedDisparity
[
indx
]
=
disp
;
indx
++;
}
}
}
}
else
{
// 09.18.2022
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
// center coordinates for 8*8 tile is [3.5,3.5]
double
disp
=
(
disparity
==
null
)?
min_disparity:
(
disparity
[
bounds
.
width
*
y
+
x
]);
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
indexedDisparity
[
indx
]
=
disp
;
indx
++;
}
}
}
}
return
indexedDisparity
;
}
public
double
[][]
getCoords
(
// get world XYZ in meters for indices
double
[]
disparity
,
// null - use min_disparity
double
min_disparity
,
double
max_disparity
,
Rectangle
bounds
,
int
[][]
indices
,
int
tile_size
,
boolean
correctDistortions
,
// requires backdrop image to be corrected also
GeometryCorrection
geometryCorrection
)
{
// int height = indices.length;
int
width
=
indices
[
0
].
length
;
int
maxIndex
=
getMaxIndex
(
indices
);
double
[][]
coordinate
=
new
double
[
maxIndex
+
1
][];
int
indx
=
0
;
if
(
disparity
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
// center coordinates for 8*8 tile is [3.5,3.5]
double
px
=
(
bounds
.
x
+
x
+
0.5
)
*
tile_size
-
0.5
;
double
py
=
(
bounds
.
y
+
y
+
0.5
)
*
tile_size
-
0.5
;
double
disp
=
(
disparity
==
null
)?
min_disparity:
(
disparity
[(
bounds
.
y
+
y
)
*
tilesX
+
(
bounds
.
x
+
x
)]);
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
coordinate
[
indx
]
=
geometryCorrection
.
getWorldCoordinates
(
px
,
py
,
disp
,
correctDistortions
);
indx
++;
}
}
}
}
else
{
// 09.18.2022
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
// center coordinates for 8*8 tile is [3.5,3.5]
double
px
=
(
bounds
.
x
+
x
+
0.5
)
*
tile_size
-
0.5
;
double
py
=
(
bounds
.
y
+
y
+
0.5
)
*
tile_size
-
0.5
;
double
disp
=
(
disparity
==
null
)?
min_disparity:
(
disparity
[
bounds
.
width
*
y
+
x
]);
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
coordinate
[
indx
]
=
geometryCorrection
.
getWorldCoordinates
(
px
,
py
,
disp
,
correctDistortions
);
indx
++;
}
}
}
// preparing to move to TriMesh
}
return
coordinate
;
}
static
int
getMaxIndex
(
int
[][]
indices
)
{
...
...
@@ -8795,292 +8637,6 @@ ImageDtt.startAndJoin(threads);
return
-
1
;
}
public
static
int
[][]
filterTriangles
(
int
[][]
triangles
,
double
[]
disparity
,
// disparities per vertex index
double
maxDispDiff
,
// maximal relative disparity difference in a triangle
int
debug_level
)
{
final
double
min_avg
=
3.0
;
// 0.5; // minimal average disparity to normalize triangle
class
Triangle
{
int
[]
points
=
new
int
[
3
];
Triangle
(
int
i1
,
int
i2
,
int
i3
){
points
[
0
]
=
i1
;
points
[
1
]
=
i2
;
points
[
2
]
=
i3
;
}
}
ArrayList
<
Triangle
>
triList
=
new
ArrayList
<
Triangle
>();
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++){
double
disp_avg
=
(
disparity
[
triangles
[
i
][
0
]]
+
disparity
[
triangles
[
i
][
1
]]+
disparity
[
triangles
[
i
][
2
]])/
3.0
;
// fixed 09.18.2022!
if
(
disp_avg
<
min_avg
)
disp_avg
=
min_avg
;
loop:
{
for
(
int
j
=
0
;
j
<
3
;
j
++){
int
j1
=
(
j
+
1
)
%
3
;
if
(
Math
.
abs
(
disparity
[
triangles
[
i
][
j
]]
-
disparity
[
triangles
[
i
][
j1
]])
>
(
disp_avg
*
maxDispDiff
))
{
if
(
debug_level
>
1
)
{
System
.
out
.
println
(
"removed triangle "
+
i
+
": "
+
disparity
[
triangles
[
i
][
0
]]+
". "
+
disparity
[
triangles
[
i
][
1
]]+
". "
+
disparity
[
triangles
[
i
][
2
]]+
". Avg = "
+
disp_avg
);
}
break
loop
;
}
}
triList
.
add
(
new
Triangle
(
triangles
[
i
][
0
],
triangles
[
i
][
1
],
triangles
[
i
][
2
]));
}
}
int
[][]
filteredTriangles
=
new
int
[
triList
.
size
()][
3
];
for
(
int
i
=
0
;
i
<
filteredTriangles
.
length
;
i
++){
filteredTriangles
[
i
]
=
triList
.
get
(
i
).
points
;
}
return
filteredTriangles
;
}
public
static
int
[][]
filterTrianglesWorld
(
int
[][]
triangles
,
double
[][]
worldXYZ
,
// world per vertex index
double
maxZtoXY
,
double
maxZ
)
{
final
double
maxZtoXY2
=
maxZtoXY
*
maxZtoXY
;
class
Triangle
{
int
[]
points
=
new
int
[
3
];
Triangle
(
int
i1
,
int
i2
,
int
i3
){
points
[
0
]
=
i1
;
points
[
1
]
=
i2
;
points
[
2
]
=
i3
;
}
}
ArrayList
<
Triangle
>
triList
=
new
ArrayList
<
Triangle
>();
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++){
double
[][]
min_max
=
new
double
[
3
][
2
];
boolean
not_too_far
=
true
;
for
(
int
di
=
0
;
di
<
3
;
di
++)
{
min_max
[
di
][
0
]
=
worldXYZ
[
triangles
[
i
][
0
]][
di
];
min_max
[
di
][
1
]
=
min_max
[
di
][
0
];
// both min and max to the same vertex 0
}
if
(
maxZ
!=
0
)
{
not_too_far
&=
worldXYZ
[
triangles
[
i
][
0
]][
2
]
>
-
maxZ
;
}
for
(
int
vi
=
1
;
vi
<
3
;
vi
++)
{
for
(
int
di
=
0
;
di
<
3
;
di
++)
{
min_max
[
di
][
0
]
=
Math
.
min
(
min_max
[
di
][
0
],
worldXYZ
[
triangles
[
i
][
vi
]][
di
]);
min_max
[
di
][
1
]
=
Math
.
max
(
min_max
[
di
][
1
],
worldXYZ
[
triangles
[
i
][
vi
]][
di
]);
}
}
double
dx
=
min_max
[
0
][
1
]-
min_max
[
0
][
0
];
double
dy
=
min_max
[
1
][
1
]-
min_max
[
1
][
0
];
double
dz
=
min_max
[
2
][
1
]-
min_max
[
2
][
0
];
double
ratio2
=
dz
*
dz
/(
dx
*
dx
+
dy
*
dy
+
0.001
);
if
(
not_too_far
&&
((
maxZtoXY
==
0
)
||
(
ratio2
<
maxZtoXY2
)))
{
triList
.
add
(
new
Triangle
(
triangles
[
i
][
0
],
triangles
[
i
][
1
],
triangles
[
i
][
2
]));
}
}
int
[][]
filteredTriangles
=
new
int
[
triList
.
size
()][
3
];
for
(
int
i
=
0
;
i
<
filteredTriangles
.
length
;
i
++){
filteredTriangles
[
i
]
=
triList
.
get
(
i
).
points
;
}
return
filteredTriangles
;
}
public
static
int
[]
reIndex
(
int
[][]
indices
,
int
[][]
triangles
)
{
int
last_index
=
-
1
;
for
(
int
i
=
0
;
i
<
indices
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
indices
[
i
].
length
;
j
++)
{
if
(
indices
[
i
][
j
]
>
last_index
)
{
last_index
=
indices
[
i
][
j
];
}
}
}
boolean
[]
used_indices
=
new
boolean
[
last_index
+
1
];
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
triangles
[
i
].
length
;
j
++)
{
// always 3
used_indices
[
triangles
[
i
][
j
]]
=
true
;
}
}
int
new_len
=
0
;
for
(
int
i
=
0
;
i
<
used_indices
.
length
;
i
++)
if
(
used_indices
[
i
])
{
new_len
++;
}
if
(
new_len
==
used_indices
.
length
)
{
return
null
;
// no re-indexing is needed
}
int
[]
re_index
=
new
int
[
new_len
];
int
indx
=
0
;
for
(
int
i
=
0
;
i
<
indices
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
indices
[
i
].
length
;
j
++)
{
int
old_index
=
indices
[
i
][
j
];
if
(
old_index
>=
0
)
{
if
(
used_indices
[
old_index
])
{
// keep
re_index
[
indx
]
=
old_index
;
indices
[
i
][
j
]
=
indx
++;
}
else
{
indices
[
i
][
j
]
=
-
1
;
}
}
}
}
return
re_index
;
}
public
static
int
[][]
triangulateCluster
(
int
[][]
indices
)
{
int
height
=
indices
.
length
;
int
width
=
indices
[
0
].
length
;
class
Triangle
{
int
[]
points
=
new
int
[
3
];
Triangle
(
int
i1
,
int
i2
,
int
i3
){
points
[
0
]
=
i1
;
points
[
1
]
=
i2
;
points
[
2
]
=
i3
;
}
}
ArrayList
<
Triangle
>
triList
=
new
ArrayList
<
Triangle
>();
for
(
int
y
=
0
;
y
<
(
height
-
1
);
y
++){
for
(
int
x
=
0
;
x
<
width
;
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
if
((
x
>
0
)
&&
(
indices
[
y
+
1
][
x
-
1
]
>=
0
)
&&
(
indices
[
y
+
1
][
x
]
>=
0
)){
triList
.
add
(
new
Triangle
(
indices
[
y
][
x
],
indices
[
y
+
1
][
x
],
indices
[
y
+
1
][
x
-
1
]));
}
if
(
x
<
(
width
-
1
))
{
if
(
indices
[
y
+
1
][
x
]
>=
0
){
if
(
indices
[
y
][
x
+
1
]
>=
0
){
triList
.
add
(
new
Triangle
(
indices
[
y
][
x
],
indices
[
y
][
x
+
1
],
indices
[
y
+
1
][
x
]));
}
else
if
(
indices
[
y
+
1
][
x
+
1
]
>=
0
){
triList
.
add
(
new
Triangle
(
indices
[
y
][
x
],
indices
[
y
+
1
][
x
+
1
],
indices
[
y
+
1
][
x
]));
}
}
else
if
((
indices
[
y
][
x
+
1
]
>=
0
)
&&
(
indices
[
y
+
1
][
x
+
1
]
>=
0
))
{
triList
.
add
(
new
Triangle
(
indices
[
y
][
x
],
indices
[
y
][
x
+
1
],
indices
[
y
+
1
][
x
+
1
]));
}
}
}
}
}
int
[][]
triangles
=
new
int
[
triList
.
size
()][
3
];
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++){
triangles
[
i
]
=
triList
.
get
(
i
).
points
;
}
return
triangles
;
}
static
int
iSign
(
int
a
)
{
return
(
a
>
0
)
?
1
:
((
a
<
0
)?
-
1
:
0
);}
public
void
testTriangles
(
String
texturePath
,
// if not null - will show
Rectangle
bounds
,
boolean
[]
selected
,
double
[]
disparity
,
int
tile_size
,
int
[][]
indices
,
int
[][]
triangles
,
double
[][]
debug_triangles
)
// if not null - should be [2][width* height], will mark disparity and triangles
{
String
[]
titles
=
{
"disparity"
,
"triangles"
};
double
[][]
dbg_img
=
new
double
[
titles
.
length
][
tilesX
*
tilesY
*
tile_size
*
tile_size
];
Arrays
.
fill
(
dbg_img
[
0
],
Double
.
NaN
);
if
(
selected
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
i
=
0
;
i
<
selected
.
length
;
i
++
){
double
d
=
selected
[
i
]?
((
disparity
.
length
>
1
)
?
disparity
[
i
]
:
disparity
[
0
]):
Double
.
NaN
;
int
y
=
i
/
tilesX
;
int
x
=
i
%
tilesX
;
for
(
int
dy
=
0
;
dy
<
tile_size
;
dy
++){
for
(
int
dx
=
0
;
dx
<
tile_size
;
dx
++){
dbg_img
[
0
][(
y
*
tile_size
+
dy
)*(
tile_size
*
tilesX
)
+
(
x
*
tile_size
+
dx
)]
=
d
;
}
}
}
}
else
{
// 09.18.2022
for
(
int
i
=
0
;
i
<
selected
.
length
;
i
++
){
double
d
=
selected
[
i
]?
((
disparity
.
length
>
1
)
?
disparity
[
i
]
:
disparity
[
0
]):
Double
.
NaN
;
int
y
=
i
/
bounds
.
width
+
bounds
.
y
;
int
x
=
i
%
bounds
.
width
+
bounds
.
x
;
for
(
int
dy
=
0
;
dy
<
tile_size
;
dy
++){
for
(
int
dx
=
0
;
dx
<
tile_size
;
dx
++){
dbg_img
[
0
][(
y
*
tile_size
+
dy
)*(
tile_size
*
tilesX
)
+
(
x
*
tile_size
+
dx
)]
=
d
;
}
}
}
}
int
maxIndex
=
getMaxIndex
(
indices
);
int
[][]
pxy
=
new
int
[
maxIndex
+
1
][
2
];
int
height
=
indices
.
length
;
int
width
=
indices
[
0
].
length
;
for
(
int
y
=
0
;
y
<
height
;
y
++){
for
(
int
x
=
0
;
x
<
width
;
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
pxy
[
indices
[
y
][
x
]][
0
]
=
(
bounds
.
x
+
x
)*
tile_size
+
(
tile_size
/
2
);
pxy
[
indices
[
y
][
x
]][
1
]
=
(
bounds
.
y
+
y
)*
tile_size
+
(
tile_size
/
2
);
}
}
}
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++
){
for
(
int
side
=
0
;
side
<
triangles
[
i
].
length
;
side
++){
int
[]
pntIndx
=
{
triangles
[
i
][
side
],
(
side
==
(
triangles
[
i
].
length
-
1
)?
triangles
[
i
][
0
]:
triangles
[
i
][
side
+
1
])};
int
dx
=
iSign
(
pxy
[
pntIndx
[
1
]][
0
]
-
pxy
[
pntIndx
[
0
]][
0
]);
int
dy
=
iSign
(
pxy
[
pntIndx
[
1
]][
1
]
-
pxy
[
pntIndx
[
0
]][
1
]);
for
(
int
j
=
0
;
j
<
tile_size
;
j
++){
int
x
=
pxy
[
pntIndx
[
0
]][
0
]
+
dx
*
j
;
int
y
=
pxy
[
pntIndx
[
0
]][
1
]
+
dy
*
j
;
dbg_img
[
1
][
y
*
tile_size
*
tilesX
+
x
]
=
10.0
;
//1711748
}
}
}
if
(
texturePath
!=
null
)
{
ShowDoubleFloatArrays
.
showArrays
(
dbg_img
,
tilesX
*
tile_size
,
tilesY
*
tile_size
,
true
,
"triangles-"
+
texturePath
,
titles
);
}
if
(
debug_triangles
!=
null
)
{
int
indx_tri
=
(
debug_triangles
.
length
>
1
)
?
1
:
0
;
for
(
int
i
=
0
;
i
<
debug_triangles
[
indx_tri
].
length
;
i
++)
{
if
(
dbg_img
[
1
][
i
]
>
0
)
{
debug_triangles
[
indx_tri
][
i
]
=
dbg_img
[
1
][
i
];
// 10.0 to have the same scale as disparity
}
}
if
(
indx_tri
>
0
)
{
for
(
int
i
=
0
;
i
<
debug_triangles
[
indx_tri
].
length
;
i
++)
{
if
(!
Double
.
isNaN
(
dbg_img
[
0
][
i
]))
{
debug_triangles
[
0
][
i
]
=
dbg_img
[
0
][
i
];
// disparity if not NaN
}
}
}
}
}
public
static
double
[]
fillNaNs
(
final
double
[]
data
,
int
width
,
...
...
src/main/java/com/elphel/imagej/x3d/export/TriMesh.java
View file @
f7d1b998
package
com
.
elphel
.
imagej
.
x3d
.
export
;
import
java.awt.Rectangle
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
com.elphel.imagej.common.ShowDoubleFloatArrays
;
import
com.elphel.imagej.tileprocessor.GeometryCorrection
;
import
com.elphel.imagej.tileprocessor.ImageDtt
;
import
com.elphel.imagej.tileprocessor.TexturedModel
;
import
com.elphel.imagej.tileprocessor.TileNeibs
;
/**
**
** TriMesh - triangular mesh representation
...
...
@@ -24,6 +37,19 @@ package com.elphel.imagej.x3d.export;
*/
public
class
TriMesh
{
public
static
final
int
TRI_DOWN_LEFT
=
0
;
// down, then left (independent)
public
static
final
int
TRI_RIGHT_DOWNLEFT
=
1
;
// right, then down-left (one of this and two next)
public
static
final
int
TRI_DOWNRIGHT_LEFT
=
2
;
// down-right, then left
public
static
final
int
TRI_RIGHT_DOWN
=
3
;
// right, then down
public
static
final
int
[]
TRI_NONE
=
{-
1
,-
1
,-
1
,-
1
};
// four possible triangles
public
static
final
int
[][]
TRI_OFFS_XY
=
{{
0
,
0
},
{
1
,
0
},
{
1
,
1
},
{
0
,
1
}};
// X and Y relative to top-left
public
static
final
int
[][][]
TRI_SET_xy
=
{
{{
0
,
0
},{
0
,
1
},{-
1
,
1
}},
// TRI_DOWN_LEFT
{{
0
,
0
},{
1
,
0
},{
0
,
1
}},
// TRI_RIGHT_DOWNLEFT
{{
0
,
0
},{
1
,
1
},{
0
,
1
}},
// TRI_DOWNRIGHT_LEFT
{{
0
,
0
},{
1
,
0
},{
1
,
1
}}};
// TRI_RIGHT_DOWN
public
String
texture_image
;
public
double
[][]
worldXYZ
;
public
double
[][]
texCoord
;
...
...
@@ -134,7 +160,1858 @@ public class TriMesh {
}
return
inv_worldXYZ
;
}
// moved here from TileProcessor
/**
* Enumerate selected tiles. Input boolean array maybe either full size (tilesY*tilesX)
* or bounds.width*bounds.height
* @param bounds Rectangle specifing selection area
* @param selected boolean array of populated tiles
* @param tilesX full width of image array
* @return [y][x] array of incremental indices, -1 for unselected tiles.
*/
public
static
int
[][]
getCoordIndices
(
// starting with 0, -1 - not selected
Rectangle
bounds
,
boolean
[]
selected
,
int
tilesX
)
{
int
[][]
indices
=
new
int
[
bounds
.
height
][
bounds
.
width
];
int
indx
=
0
;
if
(
selected
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
y
=
0
;
y
<
bounds
.
height
;
y
++)
{
for
(
int
x
=
0
;
x
<
bounds
.
width
;
x
++){
if
(
selected
[
tilesX
*
(
bounds
.
y
+
y
)
+
(
bounds
.
x
+
x
)]){
indices
[
y
][
x
]
=
indx
++;
}
else
{
indices
[
y
][
x
]
=
-
1
;
}
}
}
}
else
{
// 09.18.2022
for
(
int
y
=
0
;
y
<
bounds
.
height
;
y
++)
{
for
(
int
x
=
0
;
x
<
bounds
.
width
;
x
++){
if
(
selected
[
bounds
.
width
*
y
+
x
]){
indices
[
y
][
x
]
=
indx
++;
}
else
{
indices
[
y
][
x
]
=
-
1
;
}
}
}
}
return
indices
;
}
/**
* Enumerate "large" and "small" tiles, where "large" are actual tiles and "small" are
* subdivided (by subdiv in each direction) ones to increase lateral mesh resolution.
* sub-tiles are populated if at least one pixel in it is opaque. Input selected_tiles
* and alpha arrays may correspond to either full image or rectangular bounds, output
* array always corresponds to bounds.
*
* @param bounds Rectangle roi for output and optionally input data
* @param selected_tiles selected tiles, all unselected are ignored
* @param tilesX full image width in tiles
* @param tile_size tile size (8)
* @param alpha pixel array, where true means "opaque". may be either full image
* or be bound to bounds (scaled to pixels from tiles)
* @param subdiv subdivide tiles. Best if is equal to 1,2,4 and 8 that results in
* uniform tiles
* @param num_indices return parameter if int[1] - will provide total number of selected
* tiles - large and small.
* @return array with tile indices (all different) int [bounds.height][bounds.width][][]
* Each "large" tile may be null if empty, contain a single int [][] {{index}}
* for "large" tiles or [subdiv][subdiv] array of the sub-tile indices with
* -1 for empty subtile.
*/
public
static
int
[][][][]
getCoordIndices
(
// starting with 0, -1 - not selected
final
Rectangle
bounds
,
final
boolean
[]
selected_tiles
,
final
int
tilesX
,
final
int
tile_size
,
final
boolean
[]
alpha
,
final
int
subdiv
,
final
int
[]
num_indices
)
{
//TODO: add optimization (merging some in-tile triangles)
final
boolean
full_image
=
selected_tiles
.
length
>
(
bounds
.
height
*
bounds
.
width
);
final
int
[][][][]
indices
=
new
int
[
bounds
.
height
][
bounds
.
width
][][];
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
TexturedModel
.
THREADS_MAX
);
final
AtomicInteger
ai
=
new
AtomicInteger
(
0
);
final
int
source_tile_width
=
full_image
?
tilesX
:
bounds
.
width
;
final
int
source_pix_width
=
source_tile_width
*
tile_size
;
final
int
source_tile_offsx
=
full_image
?
bounds
.
x
:
0
;
final
int
source_tile_offsy
=
full_image
?
bounds
.
y
:
0
;
// final int source_tile_offs = source_tile_offsx + source_tile_offsy * source_tile_width;
final
int
source_pix_offsx
=
source_tile_offsx
*
tile_size
;
final
int
source_pix_offsy
=
source_tile_offsy
*
tile_size
;
// final int source_pix_offs = source_pix_offsx + source_pix_offsy * source_pix_width;
// final int sub_size = Math.max(tile_size / subdiv, 1);
final
int
btiles
=
bounds
.
width
*
bounds
.
height
;
final
AtomicInteger
aindx
=
new
AtomicInteger
(
0
);
ai
.
set
(
0
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
boolean
[][]
pix_sel
=
new
boolean
[
tile_size
][
tile_size
];
for
(
int
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bounds
.
width
;
int
btiley
=
btile
/
bounds
.
width
;
int
stile
=
(
btilex
+
source_tile_offsx
)
+
(
btiley
+
source_tile_offsy
)
*
source_tile_width
;
if
(
selected_tiles
[
stile
])
{
boolean
all_sel
=
true
,
some_sel
=
false
;
int
pindx0
=
(
source_pix_offsx
+
btilex
*
tile_size
)
+
(
source_pix_offsy
+
btiley
*
tile_size
)
*
source_pix_width
;
for
(
int
y
=
0
;
y
<
tile_size
;
y
++)
{
int
pindx1
=
pindx0
+
y
*
source_pix_width
;
for
(
int
x
=
0
;
x
<
tile_size
;
x
++)
{
int
pindx
=
pindx1
+
x
;
boolean
psel
=
alpha
[
pindx
];
pix_sel
[
y
][
x
]
=
psel
;
all_sel
&=
psel
;
some_sel
|=
psel
;
}
}
if
(
some_sel
)
{
if
(
all_sel
)
{
indices
[
btiley
][
btilex
]
=
new
int
[][]
{{
aindx
.
getAndIncrement
()}};
// single center index
}
else
{
indices
[
btiley
][
btilex
]
=
new
int
[
subdiv
][
subdiv
];
for
(
int
ny
=
0
;
ny
<
subdiv
;
ny
++)
{
int
y0
=
(
ny
*
tile_size
)/
subdiv
;
int
y1
=
Math
.
min
(((
ny
+
1
)
*
tile_size
)/
subdiv
,
tile_size
);
for
(
int
nx
=
0
;
nx
<
subdiv
;
nx
++)
{
int
x0
=
(
nx
*
tile_size
)/
subdiv
;
int
x1
=
Math
.
min
(((
nx
+
1
)
*
tile_size
)/
subdiv
,
tile_size
);
boolean
has_any
=
false
;
lhas_any:
for
(
int
y
=
y0
;
y
<
y1
;
y
++)
{
for
(
int
x
=
x0
;
x
<
x1
;
x
++)
{
if
(
pix_sel
[
y
][
x
])
{
has_any
=
true
;
break
lhas_any
;
}
}
}
if
(
has_any
)
{
indices
[
btiley
][
btilex
][
ny
][
nx
]
=
aindx
.
getAndIncrement
();
}
else
{
indices
[
btiley
][
btilex
][
ny
][
nx
]
=
-
1
;
}
}
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
if
(
num_indices
!=
null
)
{
num_indices
[
0
]
=
aindx
.
get
();
}
return
indices
;
}
/**
* Convert "large" tiles to arrays of small ones if it has a small-tile neighbor with
* gaps along the border with this one
* @param indices - array of [height][width]{{index}} for large tiles and [heigh][width][py][px]
* for small ones. This array will be modified and re-indexed if needed.
* @param subdiv subdivide tiles. Best if is equal to 1,2,4 and 8 that results in
* uniform tiles
* @return number of indices after re-indexing.
*/
public
static
int
splitLargeTileIndices
(
int
[][][][]
indices
,
final
int
subdiv
)
{
final
int
bwidth
=
indices
[
0
].
length
;
final
int
bheight
=
indices
.
length
;
final
boolean
[][]
need_split
=
new
boolean
[
bheight
][
bwidth
];
final
int
btiles
=
bwidth
*
bheight
;
final
int
[][]
dxy
=
{{
0
,
-
1
},{
1
,
0
},{
0
,
1
},{-
1
,
0
}};
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
TexturedModel
.
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
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
if
((
indices
[
btiley
][
btilex
]
!=
null
)
&&
(
indices
[
btiley
][
btilex
].
length
==
1
))
{
// full tile, not split
l_split:
for
(
int
dir
=
0
;
dir
<
dxy
.
length
;
dir
++)
{
int
btilex1
=
btilex
+
dxy
[
dir
][
0
];
int
btiley1
=
btiley
+
dxy
[
dir
][
1
];
if
((
btilex1
>=
0
)
&&
(
btiley1
>=
0
)
&&
(
btilex1
<
bwidth
)
&&
(
btiley1
<
bheight
))
{
int
[][]
index_xy
=
indices
[
btiley1
][
btilex1
];
if
((
index_xy
!=
null
)
&&
(
index_xy
.
length
>
1
))
{
// split tile
int
x0
=
(
dxy
[
dir
][
0
]
>
0
)
?
0
:
(
index_xy
[
0
].
length
-
1
);
int
y0
=
(
dxy
[
dir
][
1
]
>
0
)
?
0
:
(
index_xy
.
length
-
1
);
if
(
dxy
[
dir
][
0
]
==
0
)
{
// top or bottom row
for
(
int
x
=
0
;
x
<
index_xy
[
0
].
length
;
x
++)
{
if
(
index_xy
[
y0
][
x
]
<
0
)
{
need_split
[
btiley
][
btilex
]
=
true
;
break
l_split
;
}
}
}
else
{
// right or left column
for
(
int
y
=
0
;
y
<
index_xy
.
length
;
y
++)
{
if
(
index_xy
[
y
][
x0
]
<
0
)
{
need_split
[
btiley
][
btilex
]
=
true
;
break
l_split
;
}
}
}
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
// re-index
final
AtomicInteger
aindx
=
new
AtomicInteger
(
0
);
ai
.
set
(
0
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
for
(
int
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
int
[][]
index_xy
=
indices
[
btiley
][
btilex
];
if
(
index_xy
!=
null
)
{
if
(
need_split
[
btiley
][
btilex
])
{
indices
[
btiley
][
btilex
]
=
new
int
[
subdiv
][
subdiv
];
for
(
int
y
=
0
;
y
<
subdiv
;
y
++)
{
for
(
int
x
=
0
;
x
<
subdiv
;
x
++)
{
indices
[
btiley
][
btilex
][
y
][
x
]
=
aindx
.
getAndIncrement
();
}
}
}
else
{
for
(
int
y
=
0
;
y
<
index_xy
.
length
;
y
++)
{
for
(
int
x
=
0
;
x
<
index_xy
[
y
].
length
;
x
++)
{
if
(
index_xy
[
y
][
x
]
>=
0
)
{
index_xy
[
y
][
x
]
=
aindx
.
getAndIncrement
();
// re-index any non-negative
}
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
return
aindx
.
get
();
}
/**
* Assuming only neighbor tiles
* @param x
* @param y
* @param size
* @return
*/
static
int
[]
getNeibNode
(
int
x
,
int
y
,
int
size
)
{
int
dir
=
8
;
if
(
x
<
0
)
{
if
(
y
<
0
)
{
x
+=
size
;
y
+=
size
;
dir
=
7
;
}
else
if
(
y
>=
size
)
{
x
+=
size
;
y
-=
size
;
dir
=
5
;
}
else
{
x
+=
size
;
dir
=
6
;
}
}
else
if
(
x
>=
size
)
{
if
(
y
<
0
)
{
x
-=
size
;
y
+=
size
;
dir
=
1
;
}
else
if
(
y
>=
size
)
{
x
-=
size
;
y
-=
size
;
dir
=
3
;
}
else
{
x
-=
size
;
dir
=
2
;
}
}
else
{
if
(
y
<
0
)
{
y
+=
size
;
dir
=
0
;
}
else
if
(
y
>=
size
)
{
y
-=
size
;
dir
=
4
;
}
else
{
dir
=
8
;
}
}
return
new
int
[]
{
x
,
y
,
dir
};
}
/**
* get edge indices, CCW: 0 - top edge, 1 right edge, 2 - bottom edge, 3 - left edge
* @param tile square tile [y][x]
* @param dir direction/edge 0..3
* @return edge values of the tile in counter-clockwise order
*/
public
static
int
[]
getEdgeIndices
(
int
[][]
tile
,
int
dir
)
{
if
(
tile
==
null
)
return
null
;
int
subdiv
=
tile
.
length
;
int
[]
edge
=
new
int
[
subdiv
];
switch
(
dir
)
{
case
0
:
for
(
int
i
=
0
;
i
<
subdiv
;
i
++)
{
edge
[
i
]
=
tile
[
0
][
subdiv
-
i
-
1
];}
break
;
case
1
:
for
(
int
i
=
0
;
i
<
subdiv
;
i
++)
{
edge
[
i
]
=
tile
[
subdiv
-
i
-
1
][
subdiv
-
1
];}
break
;
case
4
:
for
(
int
i
=
0
;
i
<
subdiv
;
i
++)
{
edge
[
i
]
=
tile
[
subdiv
-
1
][
i
];}
break
;
case
3
:
for
(
int
i
=
0
;
i
<
subdiv
;
i
++)
{
edge
[
i
]
=
tile
[
i
][
0
];}
break
;
}
return
edge
;
}
/**
* Triangulate large and small equilateral 45-degree triangles
* @param indices - array of [height][width]{{index}} for large tiles and [heigh][width][py][px]
* for small ones. This array will be modified and re-indexed if needed.
* @return int [][3] - array of triangles 3 vertex indices, clockwise
*/
public
static
int
[][]
triangulateSameSize
(
int
[][][][]
indices
)
{
final
int
bwidth
=
indices
[
0
].
length
;
final
int
bheight
=
indices
.
length
;
final
int
btiles
=
bwidth
*
bheight
;
final
int
[][][][][]
tris
=
new
int
[
bheight
][
bwidth
][][][];
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
TexturedModel
.
THREADS_MAX
);
final
AtomicInteger
ai
=
new
AtomicInteger
(
0
);
final
AtomicInteger
atri
=
new
AtomicInteger
(
0
);
// initialize triangles array
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
for
(
int
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
if
(
indices
[
btiley
][
btilex
]
!=
null
)
{
tris
[
btiley
][
btilex
]
=
new
int
[
indices
[
btiley
][
btilex
].
length
][
indices
[
btiley
][
btilex
][
0
].
length
][];
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
// triangulate macro (large triangles) - similar as tit was implemented before
ai
.
set
(
0
);
final
int
btiles_wo_last_row
=
bwidth
*
(
bheight
-
1
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
for
(
int
btile
=
ai
.
getAndIncrement
();
btile
<
btiles_wo_last_row
;
btile
=
ai
.
getAndIncrement
())
{
int
x
=
btile
%
bwidth
;
int
y
=
btile
/
bwidth
;
if
((
indices
[
y
][
x
]
!=
null
)
&&
(
indices
[
y
][
x
].
length
==
1
)){
int
tris_en
=
0
;
if
((
x
>
0
)
&&
(
indices
[
y
+
1
][
x
-
1
]
!=
null
)
&&
(
indices
[
y
+
1
][
x
-
1
].
length
==
1
)
&&
(
indices
[
y
+
1
][
x
]
!=
null
)
&&
(
indices
[
y
+
1
][
x
].
length
==
1
)){
tris_en
|=
(
1
<<
TRI_DOWN_LEFT
);
}
if
(
x
<
(
bwidth
-
1
))
{
if
((
indices
[
y
+
1
][
x
]
!=
null
)
&&
(
indices
[
y
+
1
][
x
].
length
==
1
)){
if
((
indices
[
y
][
x
+
1
]
!=
null
)
&&
(
indices
[
y
][
x
+
1
].
length
==
1
)){
tris_en
|=
(
1
<<
TRI_RIGHT_DOWNLEFT
);
}
else
if
((
indices
[
y
+
1
][
x
+
1
]
!=
null
)
&&
(
indices
[
y
+
1
][
x
+
1
].
length
==
1
)){
tris_en
|=
(
1
<<
TRI_DOWNRIGHT_LEFT
);
}
}
else
if
((
indices
[
y
][
x
+
1
]
!=
null
)
&&
(
indices
[
y
][
x
+
1
].
length
==
1
)
&&
(
indices
[
y
+
1
][
x
+
1
]
!=
null
)
&&
(
indices
[
y
+
1
][
x
+
1
].
length
==
1
))
{
tris_en
|=
(
1
<<
TRI_RIGHT_DOWN
);
}
}
if
(
tris_en
!=
0
)
{
tris
[
y
][
x
][
0
][
0
]=
TRI_NONE
.
clone
();
for
(
int
i
=
0
;
i
<
TRI_NONE
.
length
;
i
++)
{
if
((
tris_en
&
(
1
<<
i
))
!=
0
)
{
tris
[
y
][
x
][
0
][
0
][
i
]
=
atri
.
getAndIncrement
();
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
// triangulate micro (small triangles) - without crossing tiles borders
ai
.
set
(
0
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
for
(
int
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
if
((
indices
[
btiley
][
btilex
]
!=
null
)
&&
(
indices
[
btiley
][
btilex
].
length
>
1
)){
// subdivided
int
[][]
tindices
=
indices
[
btiley
][
btilex
];
for
(
int
y
=
0
;
y
<
(
tindices
.
length
-
1
);
y
++){
for
(
int
x
=
0
;
x
<
tindices
[
y
].
length
;
x
++){
if
(
tindices
[
y
][
x
]
>=
0
){
int
tris_en
=
0
;
if
((
x
>
0
)
&&
(
tindices
[
y
+
1
][
x
-
1
]
>=
0
)
&&
(
tindices
[
y
+
1
][
x
]
>=
0
)){
tris_en
|=
(
1
<<
TRI_DOWN_LEFT
);
}
if
(
x
<
(
tindices
[
y
].
length
-
1
))
{
if
(
tindices
[
y
+
1
][
x
]
>=
0
){
if
(
tindices
[
y
][
x
+
1
]
>=
0
){
tris_en
|=
(
1
<<
TRI_RIGHT_DOWNLEFT
);
}
else
if
(
tindices
[
y
+
1
][
x
+
1
]
>=
0
){
tris_en
|=
(
1
<<
TRI_DOWNRIGHT_LEFT
);
}
}
else
if
((
tindices
[
y
][
x
+
1
]
>=
0
)
&&
(
tindices
[
y
+
1
][
x
+
1
]
>=
0
))
{
tris_en
|=
(
1
<<
TRI_RIGHT_DOWN
);
}
}
if
(
tris_en
!=
0
)
{
tris
[
btiley
][
btilex
][
y
][
x
]=
TRI_NONE
.
clone
();
for
(
int
i
=
0
;
i
<
TRI_NONE
.
length
;
i
++)
{
if
((
tris_en
&
(
1
<<
i
))
!=
0
)
{
tris
[
btiley
][
btilex
][
y
][
x
][
i
]
=
atri
.
getAndIncrement
();
}
}
}
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
// now triangulate between subdivided tiles - first right and down
ai
.
set
(
0
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
boolean
[]
quad_corners
=
new
boolean
[
TRI_NONE
.
length
];
// 4 corners: top-left, top=right, bottom-right and borrom-left
for
(
int
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
if
((
indices
[
btiley
][
btilex
]
!=
null
)
&&
(
indices
[
btiley
][
btilex
].
length
>
1
)){
// subdivided
int
[][][]
tneib_indices
=
new
int
[
TileNeibs
.
DIR_XY
.
length
+
1
][][];
tneib_indices
[
8
]
=
indices
[
btiley
][
btilex
];
for
(
int
dir
=
2
;
dir
<
7
;
dir
++)
{
// not all directions needed
int
btx
=
btilex
+
TileNeibs
.
DIR_XY
[
dir
][
0
];
int
bty
=
btiley
+
TileNeibs
.
DIR_XY
[
dir
][
1
];
if
((
btx
>=
0
)
&&
(
btx
<
bwidth
)
&&
(
bty
>=
0
)
&&
(
bty
<
bheight
)
&&
(
indices
[
bty
][
btx
]
!=
null
)
&&
(
indices
[
bty
][
btx
].
length
>
1
))
{
tneib_indices
[
dir
]
=
indices
[
bty
][
btx
];
}
}
int
subdiv
=
tneib_indices
[
8
].
length
;
// assuming square
// First trying TRI_DOWN_LEFT going along left and bottom edge. This point is top-right, not top-left as for others
for
(
int
i
=
0
;
i
<
(
2
*
subdiv
-
1
);
i
++)
{
int
x
=
i
;
int
y
=
subdiv
-
1
;
if
(
i
>=
subdiv
)
{
x
=
0
;
y
=
i
-
subdiv
;
}
int
num_corn
=
0
;
for
(
int
dir
=
1
;
dir
<
4
;
dir
++)
{
// skipping top-left corner
int
x1
=
x
+
TRI_OFFS_XY
[
dir
][
0
]
-
1
;
// -1 as this point is top-right, not top-left
int
y1
=
y
+
TRI_OFFS_XY
[
dir
][
1
];
int
[]
xyd
=
getNeibNode
(
x1
,
y1
,
subdiv
);
boolean
exists
=
false
;
if
(
tneib_indices
[
xyd
[
2
]]
!=
null
)
{
exists
=
tneib_indices
[
xyd
[
2
]][
xyd
[
1
]][
xyd
[
0
]]
>=
0
;
// is populated
quad_corners
[
dir
]
=
exists
;
}
if
(
exists
)
{
num_corn
++;
}
else
{
break
;
// here all 3 tested corners should be good
}
}
if
(
num_corn
>=
3
)
{
// all 3 corners exist
if
(
tris
[
btiley
][
btilex
][
y
][
x
]
==
null
)
{
tris
[
btiley
][
btilex
][
y
][
x
]
=
TRI_NONE
.
clone
();
}
tris
[
btiley
][
btilex
][
y
][
x
][
1
<<
TRI_DOWN_LEFT
]
=
atri
.
getAndIncrement
();
}
}
Arrays
.
fill
(
quad_corners
,
false
);
// now try 3 other triangles
for
(
int
i
=
0
;
i
<
(
2
*
subdiv
-
1
);
i
++)
{
int
x
=
i
;
int
y
=
subdiv
-
1
;
if
(
i
>=
subdiv
)
{
x
=
subdiv
-
1
;
y
=
i
-
subdiv
;
}
int
num_corn
=
0
;
for
(
int
dir
=
1
;
dir
<
4
;
dir
++)
{
// skipping top-left corner
int
x1
=
x
+
TRI_OFFS_XY
[
dir
][
0
];
int
y1
=
y
+
TRI_OFFS_XY
[
dir
][
1
];
int
[]
xyd
=
getNeibNode
(
x1
,
y1
,
subdiv
);
boolean
exists
=
false
;
if
(
tneib_indices
[
xyd
[
2
]]
!=
null
)
{
exists
=
tneib_indices
[
xyd
[
2
]][
xyd
[
1
]][
xyd
[
0
]]
>=
0
;
// is populated
quad_corners
[
dir
]
=
exists
;
}
if
(
exists
)
{
num_corn
++;
}
}
if
((
num_corn
>=
3
)
&&
quad_corners
[
0
])
{
// that triangle (TRI_DOWN_LEFT) should already exist
if
(
tris
[
btiley
][
btilex
][
y
][
x
]
==
null
)
{
tris
[
btiley
][
btilex
][
y
][
x
]
=
TRI_NONE
.
clone
();
}
if
(
quad_corners
[
3
])
{
if
(
quad_corners
[
1
])
{
tris
[
btiley
][
btilex
][
y
][
x
][
1
<<
TRI_RIGHT_DOWNLEFT
]
=
atri
.
getAndIncrement
();
}
else
{
tris
[
btiley
][
btilex
][
y
][
x
][
1
<<
TRI_DOWNRIGHT_LEFT
]
=
atri
.
getAndIncrement
();
}
}
else
{
tris
[
btiley
][
btilex
][
y
][
x
][
1
<<
TRI_RIGHT_DOWN
]
=
atri
.
getAndIncrement
();
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
int
num_tris
=
atri
.
get
();
// initialize triangles array
final
int
[][]
tri_indices
=
new
int
[
num_tris
][
3
];
// Collect equilateral large and small triangles, generate triangles array
ai
.
set
(
0
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
for
(
int
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
int
[][][]
tile_tris
=
tris
[
btiley
][
btilex
];
int
subdiv
=
1
;
if
(
tile_tris
!=
null
)
{
int
[][][]
tneib_indices
=
null
;
subdiv
=
tile_tris
.
length
;
if
(
subdiv
>
1
)
{
tneib_indices
=
new
int
[
TileNeibs
.
DIR_XY
.
length
+
1
][][];
tneib_indices
[
8
]
=
indices
[
btiley
][
btilex
];
for
(
int
dir
=
2
;
dir
<
7
;
dir
++)
{
// not all directions needed
int
btx
=
btilex
+
TileNeibs
.
DIR_XY
[
dir
][
0
];
int
bty
=
btiley
+
TileNeibs
.
DIR_XY
[
dir
][
1
];
if
((
btx
>=
0
)
&&
(
btx
<
bwidth
)
&&
(
bty
>=
0
)
&&
(
bty
<
bheight
)
&&
(
indices
[
bty
][
btx
]
!=
null
)
&&
(
indices
[
bty
][
btx
].
length
>
1
))
{
tneib_indices
[
dir
]
=
indices
[
bty
][
btx
];
}
}
}
for
(
int
y
=
0
;
y
<
tile_tris
.
length
;
y
++)
{
for
(
int
x
=
0
;
x
<
tile_tris
[
y
].
length
;
x
++)
{
if
(
tile_tris
[
y
][
x
]
!=
null
)
{
for
(
int
nt
=
0
;
nt
<
tile_tris
[
y
][
x
].
length
;
nt
++)
{
int
tri_indx
=
tile_tris
[
y
][
x
][
nt
];
if
(
tri_indx
>=
0
)
{
if
(
tile_tris
.
length
>
1
)
{
// mini
for
(
int
v
=
0
;
v
<
3
;
v
++)
{
int
x1
=
x
+
TRI_SET_xy
[
nt
][
v
][
0
];
int
y1
=
y
+
TRI_SET_xy
[
nt
][
v
][
1
];
int
[]
xyd
=
getNeibNode
(
x1
,
y1
,
subdiv
);
tri_indices
[
tri_indx
][
v
]
=
tneib_indices
[
xyd
[
2
]][
xyd
[
1
]][
xyd
[
0
]];
}
}
else
{
// macro
for
(
int
v
=
0
;
v
<
3
;
v
++)
{
tri_indices
[
tri_indx
][
v
]
=
indices
[
btiley
+
TRI_SET_xy
[
nt
][
v
][
1
]]
[
btilex
+
TRI_SET_xy
[
nt
][
v
][
0
]][
0
][
0
];
}
}
}
}
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
return
tri_indices
;
}
/**
* Triangulate connections between large (tile centers) and small triangles (subdivided tiles).
* All subdivided tiles have full row/column facing non-divided tiles.
* @param indices - array of [height][width]{{index}} for large tiles and [heigh][width][py][px]
* for small ones. This array will be modified and re-indexed if needed.
* @return int [][3] - array of triangles 3 vertex indices, clockwise
*/
public
static
int
[][]
connectLargeSmallTriangles
(
int
[][][][]
indices
)
{
final
int
bwidth
=
indices
[
0
].
length
;
final
int
bheight
=
indices
.
length
;
final
int
btiles
=
bwidth
*
bheight
;
final
int
[][][][]
tris
=
new
int
[
bheight
][
bwidth
][][];
// subdivided tiles that have non-subdivided neighbors have or may have different triangle configurations:
// Below subdivided is 2, full tile - 1, empty 0
// type 0 (4 dirs, subdiv-1 triangles):
// 2->1 in any of 4 directions produce subdiv - 1 triangles (subdiv-1) connected to tile center
// type 1 (4 dirs, 1 triangle):
// two 1 in ortho directions with 0 or 1 between them - produces 1 triangle between
// centers of 1 and the corner of center 2.
// type 2 (4 dirs, 1 triangle):
// 1 in ortho, 2 CCW from it, 0 or 2 (not 1) CCW from 2
// type 3 (4 dirs, 1 triangle) - mirror of type2:
// 1 in ortho, 2 CW from it, 0 or 2 (not 1) CW from 2
// type 4 (4 dirs, 2 triangles):
// 1 in ortho, 1 CCW from it, 2 CCW from 1. Does not need mirror, as the mirror will be if looking
// from the last 2 (90 degrees CCW from the first 1)
// First pass - reserving triangles indices
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
TexturedModel
.
THREADS_MAX
);
final
AtomicInteger
ai
=
new
AtomicInteger
(
0
);
final
AtomicInteger
atri
=
new
AtomicInteger
(
0
);
// initialize triangles array
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
for
(
int
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
if
((
indices
[
btiley
][
btilex
]
!=
null
)
&&
(
indices
[
btiley
][
btilex
].
length
>
1
))
{
// only for subdivided
int
[]
tneib_types
=
new
int
[
TileNeibs
.
DIR_XY
.
length
+
1
];
tneib_types
[
8
]
=
2
;
int
subdiv
=
indices
[
btiley
][
btilex
].
length
;
boolean
has_full_neib
=
false
;
for
(
int
dir
=
0
;
dir
<
8
;
dir
++)
{
// not all directions needed
int
btx
=
btilex
+
TileNeibs
.
DIR_XY
[
dir
][
0
];
int
bty
=
btiley
+
TileNeibs
.
DIR_XY
[
dir
][
1
];
if
((
btx
>=
0
)
&&
(
btx
<
bwidth
)
&&
(
bty
>=
0
)
&&
(
bty
<
bheight
)
&&
(
indices
[
bty
][
btx
]
!=
null
))
{
tneib_types
[
dir
]
=
0
;
if
(
indices
[
bty
][
btx
]
!=
null
)
{
tneib_types
[
dir
]
=
(
indices
[
bty
][
btx
].
length
>
1
)
?
2
:
1
;
}
has_full_neib
|=
(
tneib_types
[
dir
]
==
1
);
}
}
if
(
has_full_neib
)
{
tris
[
btiley
][
btilex
]
=
new
int
[
5
][
4
];
// [types][directions
// reserve indices for type0:
for
(
int
dir
=
0
;
dir
<
4
;
dir
++)
{
int
tneib
=
tneib_types
[
2
*
dir
];
if
(
tneib
==
1
)
{
tris
[
btiley
][
btilex
][
0
][
dir
]
=
atri
.
getAndAdd
(
subdiv
-
1
);
}
}
// reserve indices for type1:
for
(
int
dir
=
0
;
dir
<
4
;
dir
++)
{
int
tneib
=
tneib_types
[
2
*
dir
];
// pointed
int
tneib1
=
tneib_types
[(
2
*
dir
+
7
)
%
8
];
// CCW 1 from pointed
int
tneib2
=
tneib_types
[(
2
*
dir
+
6
)
%
8
];
// CCW 2 from pointed
if
((
tneib
==
1
)
&&
(
tneib1
!=
2
)
&&
(
tneib2
==
1
))
{
tris
[
btiley
][
btilex
][
1
][
dir
]
=
atri
.
getAndAdd
(
1
);
}
}
// reserve indices for type2:
for
(
int
dir
=
0
;
dir
<
4
;
dir
++)
{
int
tneib
=
tneib_types
[
2
*
dir
];
// pointed
int
tneib1
=
tneib_types
[(
2
*
dir
+
7
)
%
8
];
// CCW 1 from pointed
int
tneib2
=
tneib_types
[(
2
*
dir
+
6
)
%
8
];
// CCW 2 from pointed
if
((
tneib
==
1
)
&&
(
tneib1
==
2
)
&&
(
tneib2
!=
1
))
{
tris
[
btiley
][
btilex
][
2
][
dir
]
=
atri
.
getAndAdd
(
1
);
}
}
// reserve indices for type3:
for
(
int
dir
=
0
;
dir
<
4
;
dir
++)
{
int
tneib
=
tneib_types
[
2
*
dir
];
// pointed
int
tneib1
=
tneib_types
[(
2
*
dir
+
1
)
%
8
];
// CW 1 from pointed
int
tneib2
=
tneib_types
[(
2
*
dir
+
2
)
%
8
];
// CW 2 from pointed
if
((
tneib
==
1
)
&&
(
tneib1
==
2
)
&&
(
tneib2
!=
1
))
{
tris
[
btiley
][
btilex
][
3
][
dir
]
=
atri
.
getAndAdd
(
1
);
}
}
// reserve indices for type4:
for
(
int
dir
=
0
;
dir
<
4
;
dir
++)
{
int
tneib
=
tneib_types
[
2
*
dir
];
// pointed
int
tneib1
=
tneib_types
[(
2
*
dir
+
7
)
%
8
];
// CCW 1 from pointed
int
tneib2
=
tneib_types
[(
2
*
dir
+
6
)
%
8
];
// CCW 2 from pointed
if
((
tneib
==
1
)
&&
(
tneib1
==
1
)
&&
(
tneib2
==
2
))
{
tris
[
btiley
][
btilex
][
4
][
dir
]
=
atri
.
getAndAdd
(
2
);
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
int
num_tris
=
atri
.
get
();
// initialize triangles array
final
int
[][]
tri_indices
=
new
int
[
num_tris
][
3
];
// Collect seam triangles, generate triangles array
ai
.
set
(
0
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
for
(
int
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
if
(
tris
[
btiley
][
btilex
]
!=
null
)
{
// only for subdivided
int
[][][]
tneib_indices
=
new
int
[
TileNeibs
.
DIR_XY
.
length
+
1
][][];
tneib_indices
[
8
]
=
indices
[
btiley
][
btilex
];
int
subdiv_m1
=
indices
[
btiley
][
btilex
].
length
-
1
;
for
(
int
dir
=
0
;
dir
<
8
;
dir
++)
{
// not all directions needed
int
btx
=
btilex
+
TileNeibs
.
DIR_XY
[
dir
][
0
];
int
bty
=
btiley
+
TileNeibs
.
DIR_XY
[
dir
][
1
];
if
((
btx
>=
0
)
&&
(
btx
<
bwidth
)
&&
(
bty
>=
0
)
&&
(
bty
<
bheight
)
&&
(
indices
[
bty
][
btx
]
!=
null
))
{
tneib_indices
[
dir
]
=
indices
[
bty
][
btx
];
}
}
// build triangles for type0:
for
(
int
dir4
=
0
;
dir4
<
4
;
dir4
++)
{
int
tri_index
=
tris
[
btiley
][
btilex
][
0
][
dir4
];
// type0
if
(
tri_index
>=
0
)
{
int
[]
edge
=
getEdgeIndices
(
tneib_indices
[
8
],
dir4
);
int
indx_1
=
tneib_indices
[
2
*
dir4
][
0
][
0
];
for
(
int
i
=
0
;
i
<
subdiv_m1
;
i
++)
{
tri_indices
[
tri_index
+
i
][
0
]
=
indx_1
;
tri_indices
[
tri_index
+
i
][
1
]
=
edge
[
i
];
tri_indices
[
tri_index
+
i
][
2
]
=
edge
[
i
+
1
];
}
}
}
// build triangles for type1:
for
(
int
dir4
=
0
;
dir4
<
4
;
dir4
++)
{
int
tri_index
=
tris
[
btiley
][
btilex
][
1
][
dir4
];
// type1
if
(
tri_index
>=
0
)
{
int
[]
edge
=
getEdgeIndices
(
tneib_indices
[
8
],
dir4
);
int
indx_1
=
tneib_indices
[
2
*
dir4
][
0
][
0
];
int
indx_2
=
tneib_indices
[(
2
*
dir4
+
6
)
%
8
][
0
][
0
];
tri_indices
[
tri_index
][
0
]
=
indx_1
;
tri_indices
[
tri_index
][
1
]
=
edge
[
subdiv_m1
];
tri_indices
[
tri_index
][
2
]
=
indx_2
;
}
}
// build triangles for type2:
for
(
int
dir4
=
0
;
dir4
<
4
;
dir4
++)
{
int
tri_index
=
tris
[
btiley
][
btilex
][
2
][
dir4
];
// type2
if
(
tri_index
>=
0
)
{
int
[]
edge
=
getEdgeIndices
(
tneib_indices
[
8
],
dir4
);
int
[]
edge1
=
getEdgeIndices
(
tneib_indices
[(
2
*
dir4
+
7
)
%
8
],
(
dir4
+
1
)
%
4
);
int
indx_1
=
tneib_indices
[
2
*
dir4
][
0
][
0
];
tri_indices
[
tri_index
][
0
]
=
indx_1
;
tri_indices
[
tri_index
][
1
]
=
edge
[
subdiv_m1
];
tri_indices
[
tri_index
][
2
]
=
edge1
[
0
];
}
}
// build triangles for type3:
for
(
int
dir4
=
0
;
dir4
<
4
;
dir4
++)
{
int
tri_index
=
tris
[
btiley
][
btilex
][
3
][
dir4
];
// type3
if
(
tri_index
>=
0
)
{
int
[]
edge
=
getEdgeIndices
(
tneib_indices
[
8
],
dir4
);
int
[]
edge1
=
getEdgeIndices
(
tneib_indices
[(
2
*
dir4
+
1
)
%
8
],
(
dir4
+
3
)
%
4
);
int
indx_1
=
tneib_indices
[
2
*
dir4
][
0
][
0
];
tri_indices
[
tri_index
][
0
]
=
indx_1
;
tri_indices
[
tri_index
][
1
]
=
edge1
[
subdiv_m1
];
tri_indices
[
tri_index
][
2
]
=
edge
[
0
];
}
}
// build triangles for type4:
for
(
int
dir4
=
0
;
dir4
<
4
;
dir4
++)
{
int
tri_index
=
tris
[
btiley
][
btilex
][
4
][
dir4
];
// type4
if
(
tri_index
>=
0
)
{
int
[]
edge
=
getEdgeIndices
(
tneib_indices
[
8
],
dir4
);
int
indx_1
=
tneib_indices
[
2
*
dir4
][
0
][
0
];
int
indx_2
=
tneib_indices
[(
2
*
dir4
+
7
)
%
8
][
0
][
0
];
int
[]
edge1
=
getEdgeIndices
(
tneib_indices
[(
2
*
dir4
+
6
)
%
8
],
dir4
);
tri_indices
[
tri_index
][
0
]
=
indx_1
;
tri_indices
[
tri_index
][
1
]
=
edge
[
subdiv_m1
];
tri_indices
[
tri_index
][
2
]
=
indx_2
;
tri_indices
[
tri_index
+
1
][
0
]
=
indx_2
;
tri_indices
[
tri_index
+
1
][
1
]
=
edge
[
subdiv_m1
];
tri_indices
[
tri_index
+
1
][
2
]
=
edge
[
0
];
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
return
tri_indices
;
}
/**
* Triangulate all vertice indices - combine triangulation of same-size equailateral 45-degree
* large (tile size) and small (tile subdivisions) and add connections between large and small ones
* @param indices - array of [height][width]{{index}} for large tiles and [heigh][width][py][px]
* for small ones. This array will be modified and re-indexed if needed.
* @return int [][3] - array of triangles 3 vertex indices, clockwise
*/
public
static
int
[][]
triangulateAll
(
int
[][][][]
indices
)
{
int
[][]
tri_same
=
triangulateSameSize
(
indices
);
int
[][]
tri_inter
=
connectLargeSmallTriangles
(
indices
);
int
[][]
triangles
=
new
int
[
tri_same
.
length
+
tri_inter
.
length
][];
System
.
arraycopy
(
tri_same
,
0
,
triangles
,
0
,
tri_same
.
length
);
System
.
arraycopy
(
tri_inter
,
0
,
triangles
,
tri_same
.
length
,
tri_inter
.
length
);
return
triangles
;
}
/**
* Get texture coordinates (0..1) for horizontal (positive - to the right) and vertical (positive - up)
* @param wh null if texture image is cropped one, or {full_width, full_height} otherwise
* @param indices pairs of [x,y] in integer tiles
* @return texture x,y for the tile centers
*/
public
static
double
[][]
getTexCoords
(
// get texture coordinates for indices
int
[]
wh
,
// 0 or full width, full height of the image in tiles
int
[][]
indices
)
{
int
maxIndex
=
-
1
;
int
height
=
indices
.
length
;
int
width
=
indices
[
0
].
length
;
int
tex_width
=
(
wh
!=
null
)?
wh
[
0
]:
width
;
int
tex_height
=
(
wh
!=
null
)?
wh
[
1
]:
height
;
outer_label:
{
for
(
int
y
=
height
-
1
;
y
>=
0
;
y
--)
{
for
(
int
x
=
width
-
1
;
x
>=
0
;
x
--){
if
(
indices
[
y
][
x
]
>=
0
){
maxIndex
=
indices
[
y
][
x
];
break
outer_label
;
}
}
}
}
double
[][]
textureCoordinate
=
new
double
[
maxIndex
+
1
][
2
];
int
indx
=
0
;
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
textureCoordinate
[
indx
][
0
]
=
(
x
+
0.5
)/
tex_width
;
textureCoordinate
[
indx
][
1
]
=
(
tex_height
-
y
-
0.5
)
/
tex_height
;
// y is up
indx
++;
}
}
}
return
textureCoordinate
;
}
/**
* Create texture coordinates for 2 levels of triangles - tile centers and subdivided tiles
* @param rect null if texture image matches indices[][][][] array, otherwise
* x,y - top left corner corresponding indices, width, height - full image
* size in tiles
* @param num_indices total number of vertices in indices[][][][] array
* @param indices two level vertices indices - [tilesy][tilesx][1][1] for "large" tiles
* (single vertice in the tile centre) or [tilesy][tilesx][subdiv][subdiv]
* for subdivided indices[tilesy][tilesx] may be null if the tile is empty,
* [tilesy][tilesx][y][x] is either unique index or -1 for missing subtile.
* @return [num_indices][2] texture coordinates in 0..1.0 range, positive texture y is up
*/
public
static
double
[][]
getTexCoords
(
// get texture coordinates for indices
final
Rectangle
rect
,
// 0 or full width, full height of the image in tiles
final
int
num_indices
,
final
int
[][][][]
indices
)
{
final
int
bwidth
=
indices
[
0
].
length
;
final
int
bheight
=
indices
.
length
;
final
int
btiles
=
bwidth
*
bheight
;
final
int
tex_width
=
(
rect
!=
null
)?
rect
.
width
:
bwidth
;
final
int
tex_height
=
(
rect
!=
null
)?
rect
.
height
:
bheight
;
final
int
tex_x
=
(
rect
!=
null
)?
rect
.
x
:
0
;
final
int
tex_y
=
(
rect
!=
null
)?
rect
.
y
:
0
;
final
double
[][]
textureCoordinate
=
new
double
[
num_indices
][
2
];
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
TexturedModel
.
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
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
if
(
indices
[
btiley
][
btilex
]
!=
null
)
{
int
subdiv
=
indices
[
btiley
][
btilex
].
length
;
for
(
int
y
=
0
;
y
<
indices
[
btiley
][
btilex
].
length
;
y
++)
{
for
(
int
x
=
0
;
x
<
indices
[
btiley
][
btilex
][
y
].
length
;
x
++)
{
int
indx
=
indices
[
btiley
][
btilex
][
y
][
x
];
if
(
indx
>=
0
)
{
textureCoordinate
[
indx
][
0
]
=
(
tex_x
+
btilex
+
(
x
+
0.5
)
/
subdiv
)
/
tex_width
;
textureCoordinate
[
indx
][
1
]
=
(
tex_height
-
tex_y
-
btiley
-
(
y
+
0.5
)
/
subdiv
)
/
tex_height
;
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
return
textureCoordinate
;
}
public
static
double
[]
getIndexedDisparities
(
// get disparity for each index
final
double
[]
disparity
,
final
double
min_disparity
,
final
double
max_disparity
,
final
Rectangle
bounds
,
final
int
num_indices
,
final
int
[][][][]
indices
,
final
int
tilesX
)
{
final
int
bwidth
=
indices
[
0
].
length
;
final
int
bheight
=
indices
.
length
;
final
int
btiles
=
bwidth
*
bheight
;
final
boolean
full_disparity
=
disparity
.
length
>
(
bounds
.
height
*
bounds
.
width
);
final
double
[]
indexedDisparity
=
new
double
[
num_indices
];
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
TexturedModel
.
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
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
int
tile
=
btile
;
if
(
full_disparity
)
{
tile
=
(
btiley
+
bounds
.
y
)
*
tilesX
+
(
btilex
+
bounds
.
x
);
}
if
(
indices
[
btiley
][
btilex
]
!=
null
)
{
int
subdiv
=
indices
[
btiley
][
btilex
].
length
;
double
disp
=
disparity
[
tile
];
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
for
(
int
y
=
0
;
y
<
indices
[
btiley
][
btilex
].
length
;
y
++)
{
for
(
int
x
=
0
;
x
<
indices
[
btiley
][
btilex
][
y
].
length
;
x
++)
{
int
indx
=
indices
[
btiley
][
btilex
][
y
][
x
];
if
(
indx
>=
0
)
{
indexedDisparity
[
indx
]
=
disp
;
// currently - same disparity for subdivisions
// TODO - linear interpolate
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
return
indexedDisparity
;
}
public
static
double
[][]
getCoords
(
// get disparity for each index
final
double
[]
disparity
,
final
double
min_disparity
,
final
double
max_disparity
,
final
Rectangle
bounds
,
final
int
num_indices
,
final
int
[][][][]
indices
,
final
int
tilesX
,
final
int
tile_size
,
final
boolean
correctDistortions
,
// requires backdrop image to be corrected also
final
GeometryCorrection
geometryCorrection
)
{
final
int
bwidth
=
indices
[
0
].
length
;
final
int
bheight
=
indices
.
length
;
final
int
btiles
=
bwidth
*
bheight
;
final
boolean
full_disparity
=
disparity
.
length
>
(
bounds
.
height
*
bounds
.
width
);
final
double
[][]
coordinate
=
new
double
[
num_indices
][];
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
TexturedModel
.
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
btile
=
ai
.
getAndIncrement
();
btile
<
btiles
;
btile
=
ai
.
getAndIncrement
())
{
int
btilex
=
btile
%
bwidth
;
int
btiley
=
btile
/
bwidth
;
int
tile
=
btile
;
if
(
full_disparity
)
{
tile
=
(
btiley
+
bounds
.
y
)
*
tilesX
+
(
btilex
+
bounds
.
x
);
}
if
(
indices
[
btiley
][
btilex
]
!=
null
)
{
int
subdiv
=
indices
[
btiley
][
btilex
].
length
;
double
disp
=
disparity
[
tile
];
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
for
(
int
y
=
0
;
y
<
indices
[
btiley
][
btilex
].
length
;
y
++)
{
for
(
int
x
=
0
;
x
<
indices
[
btiley
][
btilex
][
y
].
length
;
x
++)
{
// TODO - linear interpolate disparity here
int
indx
=
indices
[
btiley
][
btilex
][
y
][
x
];
if
(
indx
>=
0
)
{
double
px
=
(
bounds
.
x
+
btilex
+
(
x
+
0.5
)
/
subdiv
)
*
tile_size
-
0.5
;
double
py
=
(
bounds
.
y
+
btiley
+
(
y
+
0.5
)
/
subdiv
)
*
tile_size
-
0.5
;
coordinate
[
indx
]
=
geometryCorrection
.
getWorldCoordinates
(
px
,
py
,
disp
,
// currently - same for all tile
correctDistortions
);
}
}
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
return
coordinate
;
}
/** Plot generated triangles on a provided canvas. Can combine multiple meshes on the same canvas
*
* @param canvas 2D canvas in a line-scan order
* @param width canvas width in pixels
* @param tex_coord texture coordinates as [vertice_index]{x,y}, where 0 <=x <1.0, 0 <=y <1.0, y - upward
* @param triangles [tri_index]{p0_index, p1_index, p2_index}, where p*_index is vertice_index in tex_coord
* @param plot_center plot triangle center
* @param line_color pixel to use for lines
* @param center_color pixel to use for triangle centers
*/
public
static
void
plotMesh
(
final
double
[]
canvas
,
final
int
width
,
final
double
[][]
tex_coord
,
final
int
[][]
triangles
,
final
boolean
plot_center
,
final
double
line_color
,
final
double
center_color
)
{
final
int
height
=
canvas
.
length
/
width
;
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
TexturedModel
.
THREADS_MAX
);
final
AtomicInteger
ai
=
new
AtomicInteger
(
0
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
int
width_m1
=
width
-
1
;
int
height_m1
=
height
-
1
;
for
(
int
ntri
=
ai
.
getAndIncrement
();
ntri
<
triangles
.
length
;
ntri
=
ai
.
getAndIncrement
())
{
for
(
int
i0
=
0
;
i0
<
3
;
i0
++)
{
int
i1
=
(
i0
+
1
)
%
3
;
double
[]
pxy0
=
{
width
*
tex_coord
[
triangles
[
ntri
][
i0
]][
0
],
height
*(
1.0
-
tex_coord
[
triangles
[
ntri
][
i0
]][
1
])};
double
[]
pxy1
=
{
width
*
tex_coord
[
triangles
[
ntri
][
i1
]][
0
],
height
*(
1.0
-
tex_coord
[
triangles
[
ntri
][
i1
]][
1
])};
double
dx
=
pxy1
[
0
]
-
pxy0
[
0
];
double
dy
=
pxy1
[
1
]
-
pxy0
[
1
];
double
l
=
Math
.
sqrt
(
dx
*
dx
+
dy
*
dy
);
for
(
int
j
=
0
;
j
<
l
;
j
++)
{
int
px
=
(
int
)
Math
.
round
(
pxy0
[
0
]+
j
*
dx
/
l
);
int
py
=
(
int
)
Math
.
round
(
pxy0
[
1
]+
j
*
dy
/
l
);
px
=
Math
.
min
(
Math
.
max
(
0
,
px
),
width_m1
);
py
=
Math
.
min
(
Math
.
max
(
0
,
py
),
height_m1
);
canvas
[
py
*
width
+
px
]
=
line_color
;
}
}
if
(
plot_center
)
{
double
sx
=
0.0
,
sy
=
0.0
;
for
(
int
i
=
0
;
i
<
3
;
i
++)
{
sx
+=
width
*
tex_coord
[
triangles
[
ntri
][
i
]][
0
];
sy
+=
height
*(
1.0
-
tex_coord
[
triangles
[
ntri
][
i
]][
1
]);
}
sx
/=
3
;
sy
/=
3
;
int
px
=
(
int
)
Math
.
round
(
sx
);
int
py
=
(
int
)
Math
.
round
(
sy
);
px
=
Math
.
min
(
Math
.
max
(
0
,
px
),
width_m1
);
py
=
Math
.
min
(
Math
.
max
(
0
,
py
),
height_m1
);
canvas
[
py
*
width
+
px
]
=
center_color
;
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
}
public
static
double
[]
getIndexedDisparities
(
// get disparity for each index
double
[]
disparity
,
double
min_disparity
,
double
max_disparity
,
Rectangle
bounds
,
int
[][]
indices
,
int
tile_size
,
int
tilesX
)
{
// int height = indices.length;
int
width
=
indices
[
0
].
length
;
int
maxIndex
=
getMaxIndex
(
indices
);
double
[]
indexedDisparity
=
new
double
[
maxIndex
+
1
];
int
indx
=
0
;
if
(
disparity
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
// center coordinates for 8*8 tile is [3.5,3.5]
double
disp
=
(
disparity
==
null
)?
min_disparity:
(
disparity
[(
bounds
.
y
+
y
)
*
tilesX
+
(
bounds
.
x
+
x
)]);
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
indexedDisparity
[
indx
]
=
disp
;
indx
++;
}
}
}
}
else
{
// 09.18.2022
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
// center coordinates for 8*8 tile is [3.5,3.5]
double
disp
=
(
disparity
==
null
)?
min_disparity:
(
disparity
[
bounds
.
width
*
y
+
x
]);
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
indexedDisparity
[
indx
]
=
disp
;
indx
++;
}
}
}
}
return
indexedDisparity
;
}
public
static
double
[][]
getCoords
(
// get world XYZ in meters for indices
double
[]
disparity
,
// null - use min_disparity
double
min_disparity
,
double
max_disparity
,
Rectangle
bounds
,
int
[][]
indices
,
int
tile_size
,
int
tilesX
,
boolean
correctDistortions
,
// requires backdrop image to be corrected also
GeometryCorrection
geometryCorrection
)
{
// int height = indices.length;
int
width
=
indices
[
0
].
length
;
int
maxIndex
=
getMaxIndex
(
indices
);
double
[][]
coordinate
=
new
double
[
maxIndex
+
1
][];
int
indx
=
0
;
if
(
disparity
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
// center coordinates for 8*8 tile is [3.5,3.5]
double
px
=
(
bounds
.
x
+
x
+
0.5
)
*
tile_size
-
0.5
;
double
py
=
(
bounds
.
y
+
y
+
0.5
)
*
tile_size
-
0.5
;
double
disp
=
(
disparity
==
null
)?
min_disparity:
(
disparity
[(
bounds
.
y
+
y
)
*
tilesX
+
(
bounds
.
x
+
x
)]);
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
coordinate
[
indx
]
=
geometryCorrection
.
getWorldCoordinates
(
px
,
py
,
disp
,
correctDistortions
);
indx
++;
}
}
}
}
else
{
// 09.18.2022
for
(
int
y
=
0
;
indx
<=
maxIndex
;
y
++)
{
for
(
int
x
=
0
;
(
x
<
width
)
&&
(
indx
<=
maxIndex
);
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
// center coordinates for 8*8 tile is [3.5,3.5]
double
px
=
(
bounds
.
x
+
x
+
0.5
)
*
tile_size
-
0.5
;
double
py
=
(
bounds
.
y
+
y
+
0.5
)
*
tile_size
-
0.5
;
double
disp
=
(
disparity
==
null
)?
min_disparity:
(
disparity
[
bounds
.
width
*
y
+
x
]);
if
(
disp
<
min_disparity
)
disp
=
min_disparity
;
else
if
(
disp
>
max_disparity
)
disp
=
max_disparity
;
coordinate
[
indx
]
=
geometryCorrection
.
getWorldCoordinates
(
px
,
py
,
disp
,
correctDistortions
);
indx
++;
}
}
}
}
return
coordinate
;
}
public
static
int
[][]
filterTriangles
(
int
[][]
triangles
,
double
[]
disparity
,
// disparities per vertex index
double
maxDispDiff
,
// maximal relative disparity difference in a triangle
int
debug_level
)
{
final
double
min_avg
=
3.0
;
// 0.5; // minimal average disparity to normalize triangle
class
Triangle
{
int
[]
points
=
new
int
[
3
];
Triangle
(
int
i1
,
int
i2
,
int
i3
){
points
[
0
]
=
i1
;
points
[
1
]
=
i2
;
points
[
2
]
=
i3
;
}
}
ArrayList
<
Triangle
>
triList
=
new
ArrayList
<
Triangle
>();
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++){
double
disp_avg
=
(
disparity
[
triangles
[
i
][
0
]]
+
disparity
[
triangles
[
i
][
1
]]+
disparity
[
triangles
[
i
][
2
]])/
3.0
;
// fixed 09.18.2022!
if
(
disp_avg
<
min_avg
)
disp_avg
=
min_avg
;
loop:
{
for
(
int
j
=
0
;
j
<
3
;
j
++){
int
j1
=
(
j
+
1
)
%
3
;
if
(
Math
.
abs
(
disparity
[
triangles
[
i
][
j
]]
-
disparity
[
triangles
[
i
][
j1
]])
>
(
disp_avg
*
maxDispDiff
))
{
if
(
debug_level
>
1
)
{
System
.
out
.
println
(
"removed triangle "
+
i
+
": "
+
disparity
[
triangles
[
i
][
0
]]+
". "
+
disparity
[
triangles
[
i
][
1
]]+
". "
+
disparity
[
triangles
[
i
][
2
]]+
". Avg = "
+
disp_avg
);
}
break
loop
;
}
}
triList
.
add
(
new
Triangle
(
triangles
[
i
][
0
],
triangles
[
i
][
1
],
triangles
[
i
][
2
]));
}
}
int
[][]
filteredTriangles
=
new
int
[
triList
.
size
()][
3
];
for
(
int
i
=
0
;
i
<
filteredTriangles
.
length
;
i
++){
filteredTriangles
[
i
]
=
triList
.
get
(
i
).
points
;
}
return
filteredTriangles
;
}
public
static
int
[][]
filterTrianglesWorld
(
int
[][]
triangles
,
double
[][]
worldXYZ
,
// world per vertex index
double
maxZtoXY
,
double
maxZ
)
{
final
double
maxZtoXY2
=
maxZtoXY
*
maxZtoXY
;
class
Triangle
{
int
[]
points
=
new
int
[
3
];
Triangle
(
int
i1
,
int
i2
,
int
i3
){
points
[
0
]
=
i1
;
points
[
1
]
=
i2
;
points
[
2
]
=
i3
;
}
}
ArrayList
<
Triangle
>
triList
=
new
ArrayList
<
Triangle
>();
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++){
double
[][]
min_max
=
new
double
[
3
][
2
];
boolean
not_too_far
=
true
;
for
(
int
di
=
0
;
di
<
3
;
di
++)
{
min_max
[
di
][
0
]
=
worldXYZ
[
triangles
[
i
][
0
]][
di
];
min_max
[
di
][
1
]
=
min_max
[
di
][
0
];
// both min and max to the same vertex 0
}
if
(
maxZ
!=
0
)
{
not_too_far
&=
worldXYZ
[
triangles
[
i
][
0
]][
2
]
>
-
maxZ
;
}
for
(
int
vi
=
1
;
vi
<
3
;
vi
++)
{
for
(
int
di
=
0
;
di
<
3
;
di
++)
{
min_max
[
di
][
0
]
=
Math
.
min
(
min_max
[
di
][
0
],
worldXYZ
[
triangles
[
i
][
vi
]][
di
]);
min_max
[
di
][
1
]
=
Math
.
max
(
min_max
[
di
][
1
],
worldXYZ
[
triangles
[
i
][
vi
]][
di
]);
}
}
double
dx
=
min_max
[
0
][
1
]-
min_max
[
0
][
0
];
double
dy
=
min_max
[
1
][
1
]-
min_max
[
1
][
0
];
double
dz
=
min_max
[
2
][
1
]-
min_max
[
2
][
0
];
double
ratio2
=
dz
*
dz
/(
dx
*
dx
+
dy
*
dy
+
0.001
);
if
(
not_too_far
&&
((
maxZtoXY
==
0
)
||
(
ratio2
<
maxZtoXY2
)))
{
triList
.
add
(
new
Triangle
(
triangles
[
i
][
0
],
triangles
[
i
][
1
],
triangles
[
i
][
2
]));
}
}
int
[][]
filteredTriangles
=
new
int
[
triList
.
size
()][
3
];
for
(
int
i
=
0
;
i
<
filteredTriangles
.
length
;
i
++){
filteredTriangles
[
i
]
=
triList
.
get
(
i
).
points
;
}
return
filteredTriangles
;
}
public
static
int
[]
reIndex
(
int
[][]
indices
,
int
[][]
triangles
)
{
int
last_index
=
-
1
;
for
(
int
i
=
0
;
i
<
indices
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
indices
[
i
].
length
;
j
++)
{
if
(
indices
[
i
][
j
]
>
last_index
)
{
last_index
=
indices
[
i
][
j
];
}
}
}
boolean
[]
used_indices
=
new
boolean
[
last_index
+
1
];
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
triangles
[
i
].
length
;
j
++)
{
// always 3
used_indices
[
triangles
[
i
][
j
]]
=
true
;
}
}
int
new_len
=
0
;
for
(
int
i
=
0
;
i
<
used_indices
.
length
;
i
++)
if
(
used_indices
[
i
])
{
new_len
++;
}
if
(
new_len
==
used_indices
.
length
)
{
return
null
;
// no re-indexing is needed
}
int
[]
re_index
=
new
int
[
new_len
];
int
indx
=
0
;
for
(
int
i
=
0
;
i
<
indices
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
indices
[
i
].
length
;
j
++)
{
int
old_index
=
indices
[
i
][
j
];
if
(
old_index
>=
0
)
{
if
(
used_indices
[
old_index
])
{
// keep
re_index
[
indx
]
=
old_index
;
indices
[
i
][
j
]
=
indx
++;
}
else
{
indices
[
i
][
j
]
=
-
1
;
}
}
}
}
return
re_index
;
}
public
static
int
[][]
triangulateCluster
(
int
[][]
indices
)
{
int
height
=
indices
.
length
;
int
width
=
indices
[
0
].
length
;
class
Triangle
{
int
[]
points
=
new
int
[
3
];
Triangle
(
int
i1
,
int
i2
,
int
i3
){
points
[
0
]
=
i1
;
points
[
1
]
=
i2
;
points
[
2
]
=
i3
;
}
}
ArrayList
<
Triangle
>
triList
=
new
ArrayList
<
Triangle
>();
for
(
int
y
=
0
;
y
<
(
height
-
1
);
y
++){
for
(
int
x
=
0
;
x
<
width
;
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
if
((
x
>
0
)
&&
(
indices
[
y
+
1
][
x
-
1
]
>=
0
)
&&
(
indices
[
y
+
1
][
x
]
>=
0
)){
triList
.
add
(
new
Triangle
(
indices
[
y
][
x
],
indices
[
y
+
1
][
x
],
indices
[
y
+
1
][
x
-
1
]));
}
if
(
x
<
(
width
-
1
))
{
if
(
indices
[
y
+
1
][
x
]
>=
0
){
if
(
indices
[
y
][
x
+
1
]
>=
0
){
triList
.
add
(
new
Triangle
(
indices
[
y
][
x
],
indices
[
y
][
x
+
1
],
indices
[
y
+
1
][
x
]));
}
else
if
(
indices
[
y
+
1
][
x
+
1
]
>=
0
){
triList
.
add
(
new
Triangle
(
indices
[
y
][
x
],
indices
[
y
+
1
][
x
+
1
],
indices
[
y
+
1
][
x
]));
}
}
else
if
((
indices
[
y
][
x
+
1
]
>=
0
)
&&
(
indices
[
y
+
1
][
x
+
1
]
>=
0
))
{
triList
.
add
(
new
Triangle
(
indices
[
y
][
x
],
indices
[
y
][
x
+
1
],
indices
[
y
+
1
][
x
+
1
]));
}
}
}
}
}
int
[][]
triangles
=
new
int
[
triList
.
size
()][
3
];
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++){
triangles
[
i
]
=
triList
.
get
(
i
).
points
;
}
return
triangles
;
}
public
static
void
testTriangles
(
String
texturePath
,
// if not null - will show
Rectangle
bounds
,
boolean
[]
selected
,
double
[]
disparity
,
int
tile_size
,
int
tilesX
,
int
tilesY
,
int
[][]
indices
,
int
[][]
triangles
,
double
[][]
debug_triangles
)
// if not null - should be [2][width* height], will mark disparity and triangles
{
String
[]
titles
=
{
"disparity"
,
"triangles"
};
double
[][]
dbg_img
=
new
double
[
titles
.
length
][
tilesX
*
tilesY
*
tile_size
*
tile_size
];
Arrays
.
fill
(
dbg_img
[
0
],
Double
.
NaN
);
if
(
selected
.
length
>
(
bounds
.
height
*
bounds
.
width
))
{
// old version - selected is full size
for
(
int
i
=
0
;
i
<
selected
.
length
;
i
++
){
double
d
=
selected
[
i
]?
((
disparity
.
length
>
1
)
?
disparity
[
i
]
:
disparity
[
0
]):
Double
.
NaN
;
int
y
=
i
/
tilesX
;
int
x
=
i
%
tilesX
;
for
(
int
dy
=
0
;
dy
<
tile_size
;
dy
++){
for
(
int
dx
=
0
;
dx
<
tile_size
;
dx
++){
dbg_img
[
0
][(
y
*
tile_size
+
dy
)*(
tile_size
*
tilesX
)
+
(
x
*
tile_size
+
dx
)]
=
d
;
}
}
}
}
else
{
// 09.18.2022
for
(
int
i
=
0
;
i
<
selected
.
length
;
i
++
){
double
d
=
selected
[
i
]?
((
disparity
.
length
>
1
)
?
disparity
[
i
]
:
disparity
[
0
]):
Double
.
NaN
;
int
y
=
i
/
bounds
.
width
+
bounds
.
y
;
int
x
=
i
%
bounds
.
width
+
bounds
.
x
;
for
(
int
dy
=
0
;
dy
<
tile_size
;
dy
++){
for
(
int
dx
=
0
;
dx
<
tile_size
;
dx
++){
dbg_img
[
0
][(
y
*
tile_size
+
dy
)*(
tile_size
*
tilesX
)
+
(
x
*
tile_size
+
dx
)]
=
d
;
}
}
}
}
int
maxIndex
=
getMaxIndex
(
indices
);
int
[][]
pxy
=
new
int
[
maxIndex
+
1
][
2
];
int
height
=
indices
.
length
;
int
width
=
indices
[
0
].
length
;
for
(
int
y
=
0
;
y
<
height
;
y
++){
for
(
int
x
=
0
;
x
<
width
;
x
++){
if
(
indices
[
y
][
x
]
>=
0
){
pxy
[
indices
[
y
][
x
]][
0
]
=
(
bounds
.
x
+
x
)*
tile_size
+
(
tile_size
/
2
);
pxy
[
indices
[
y
][
x
]][
1
]
=
(
bounds
.
y
+
y
)*
tile_size
+
(
tile_size
/
2
);
}
}
}
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++
){
for
(
int
side
=
0
;
side
<
triangles
[
i
].
length
;
side
++){
int
[]
pntIndx
=
{
triangles
[
i
][
side
],
(
side
==
(
triangles
[
i
].
length
-
1
)?
triangles
[
i
][
0
]:
triangles
[
i
][
side
+
1
])};
int
dx
=
iSign
(
pxy
[
pntIndx
[
1
]][
0
]
-
pxy
[
pntIndx
[
0
]][
0
]);
int
dy
=
iSign
(
pxy
[
pntIndx
[
1
]][
1
]
-
pxy
[
pntIndx
[
0
]][
1
]);
for
(
int
j
=
0
;
j
<
tile_size
;
j
++){
int
x
=
pxy
[
pntIndx
[
0
]][
0
]
+
dx
*
j
;
int
y
=
pxy
[
pntIndx
[
0
]][
1
]
+
dy
*
j
;
dbg_img
[
1
][
y
*
tile_size
*
tilesX
+
x
]
=
10.0
;
//1711748
}
}
}
if
(
texturePath
!=
null
)
{
ShowDoubleFloatArrays
.
showArrays
(
dbg_img
,
tilesX
*
tile_size
,
tilesY
*
tile_size
,
true
,
"triangles-"
+
texturePath
,
titles
);
}
if
(
debug_triangles
!=
null
)
{
int
indx_tri
=
(
debug_triangles
.
length
>
1
)
?
1
:
0
;
for
(
int
i
=
0
;
i
<
debug_triangles
[
indx_tri
].
length
;
i
++)
{
if
(
dbg_img
[
1
][
i
]
>
0
)
{
debug_triangles
[
indx_tri
][
i
]
=
dbg_img
[
1
][
i
];
// 10.0 to have the same scale as disparity
}
}
if
(
indx_tri
>
0
)
{
for
(
int
i
=
0
;
i
<
debug_triangles
[
indx_tri
].
length
;
i
++)
{
if
(!
Double
.
isNaN
(
dbg_img
[
0
][
i
]))
{
debug_triangles
[
0
][
i
]
=
dbg_img
[
0
][
i
];
// disparity if not NaN
}
}
}
}
}
static
int
iSign
(
int
a
)
{
return
(
a
>
0
)
?
1
:
((
a
<
0
)?
-
1
:
0
);}
static
int
getMaxIndex
(
int
[][]
indices
)
{
int
height
=
indices
.
length
;
int
width
=
indices
[
0
].
length
;
for
(
int
y
=
height
-
1
;
y
>=
0
;
y
--)
{
for
(
int
x
=
width
-
1
;
x
>=
0
;
x
--){
if
(
indices
[
y
][
x
]
>=
0
){
return
indices
[
y
][
x
];
}
}
}
return
-
1
;
}
public
static
void
generateClusterX3d
(
boolean
full_texture
,
// true - full size image, false - bounds only
int
subdivide_mesh
,
// 0,1 - full tiles only, 2 - 2x2 pixels, 4 - 2x2 pixels
// boolean [] alpha, // boolean alpha - true - opaque, false - transparent. Full/bounds
// matching selection
X3dOutput
x3dOutput
,
// output x3d if not null
WavefrontExport
wfOutput
,
// output WSavefront if not null
ArrayList
<
TriMesh
>
tri_meshes
,
String
texturePath
,
String
id
,
String
class_name
,
Rectangle
bounds
,
boolean
[]
selected
,
// may be either tilesX * tilesY or bounds.width*bounds.height
double
[]
disparity
,
// if null, will use min_disparity
int
tile_size
,
int
tilesX
,
int
tilesY
,
GeometryCorrection
geometryCorrection
,
boolean
correctDistortions
,
// requires backdrop image to be corrected also
boolean
show_triangles
,
double
min_disparity
,
double
max_disparity
,
double
maxDispTriangle
,
// relative <=0 - do not use
double
maxZtoXY
,
// 10.0. <=0 - do not use
double
maxZ
,
// far clip (0 - do not clip). Negative - limit by max
boolean
limitZ
,
double
[][]
dbg_disp_tri_slice
,
int
debug_level
)
throws
IOException
{
// int debug_level = 1;
if
(
bounds
==
null
)
{
return
;
// not used in lwir
}
int
[][]
indices
=
getCoordIndices
(
// starting with 0, -1 - not selected // updated 09.18.2022
bounds
,
selected
,
tilesX
);
double
[][]
texCoord
=
getTexCoords
(
// get texture coordinates for indices
full_texture
?
(
new
int
[]
{
tilesX
,
tilesY
}):
null
,
indices
);
double
[][]
worldXYZ
=
getCoords
(
// get world XYZ in meters for indices // updated 09.18.2022
disparity
,
min_disparity
,
max_disparity
,
bounds
,
indices
,
tile_size
,
tilesX
,
correctDistortions
,
// requires backdrop image to be corrected also
geometryCorrection
);
double
[]
indexedDisparity
=
getIndexedDisparities
(
// get disparity for each index // updated 09.18.2022
disparity
,
min_disparity
,
max_disparity
,
bounds
,
indices
,
tile_size
,
tilesX
);
int
[][]
triangles
=
triangulateCluster
(
indices
);
int
num_removed
=
0
;
if
(
maxDispTriangle
>
0.0
)
{
int
pre_num
=
triangles
.
length
;
triangles
=
filterTriangles
(
// remove crazy triangles with large disparity difference
triangles
,
indexedDisparity
,
// disparities per vertex index
maxDispTriangle
,
// maximal disparity difference in a triangle
debug_level
+
0
);
// int debug_level);
if
(
triangles
.
length
<
pre_num
)
{
num_removed
+=
pre_num
-
triangles
.
length
;
if
(
debug_level
>
0
)
{
System
.
out
.
println
(
"filterTriangles() removed "
+
(
pre_num
-
triangles
.
length
)+
" triangles"
);
}
}
}
if
((
maxZ
!=
0.0
)
&&
limitZ
)
{
for
(
int
i
=
0
;
i
<
worldXYZ
.
length
;
i
++)
{
if
(
worldXYZ
[
i
][
2
]
<
-
maxZ
)
{
double
k
=
-
maxZ
/
worldXYZ
[
i
][
2
];
worldXYZ
[
i
][
0
]
*=
k
;
worldXYZ
[
i
][
1
]
*=
k
;
worldXYZ
[
i
][
2
]
*=
k
;
}
}
}
if
((
maxZtoXY
>
0.0
)
||
((
maxZ
!=
0
)
&&
!
limitZ
)
)
{
int
pre_num
=
triangles
.
length
;
triangles
=
filterTrianglesWorld
(
triangles
,
worldXYZ
,
// world per vertex index
maxZtoXY
,
maxZ
);
if
(
triangles
.
length
<
pre_num
)
{
num_removed
+=
pre_num
-
triangles
.
length
;
if
(
debug_level
>
0
)
{
System
.
out
.
println
(
"filterTrianglesWorld() removed "
+
(
pre_num
-
triangles
.
length
)+
" triangles"
);
}
}
}
if
(
triangles
.
length
==
0
)
{
if
(
debug_level
>
0
)
{
System
.
out
.
println
(
"generateClusterX3d() no triangles left in a cluster"
);
}
return
;
// all triangles removed
}
if
(
num_removed
>
0
)
{
int
[]
re_index
=
reIndex
(
// Move to TriMesh?
indices
,
// will be modified if needed (if some indices are removed
triangles
);
if
(
re_index
!=
null
)
{
// need to update other arrays: texCoord, worldXYZ. indexedDisparity[] will not be used
int
num_indices_old
=
worldXYZ
.
length
;
int
[]
inv_index
=
new
int
[
num_indices_old
];
Arrays
.
fill
(
inv_index
,-
1
);
// just to get an error
for
(
int
i
=
0
;
i
<
re_index
.
length
;
i
++)
{
inv_index
[
re_index
[
i
]]
=
i
;
}
double
[][]
texCoord_new
=
new
double
[
re_index
.
length
][];
double
[][]
worldXYZ_new
=
new
double
[
re_index
.
length
][];
for
(
int
i
=
0
;
i
<
re_index
.
length
;
i
++)
{
texCoord_new
[
i
]
=
texCoord
[
re_index
[
i
]];
worldXYZ_new
[
i
]
=
worldXYZ
[
re_index
[
i
]];
}
texCoord
=
texCoord_new
;
worldXYZ
=
worldXYZ_new
;
for
(
int
i
=
0
;
i
<
triangles
.
length
;
i
++)
{
for
(
int
j
=
0
;
j
<
triangles
[
i
].
length
;
j
++)
{
triangles
[
i
][
j
]
=
inv_index
[
triangles
[
i
][
j
]];
}
}
}
if
(
debug_level
>
0
)
{
show_triangles
=
true
;
// show after removed
}
}
if
(
show_triangles
||
(
dbg_disp_tri_slice
!=
null
))
{
double
[]
ddisp
=
(
disparity
==
null
)?(
new
double
[
1
]):
disparity
;
if
(
disparity
==
null
)
{
ddisp
[
0
]
=
min_disparity
;
}
testTriangles
(
(
show_triangles
?
texturePath:
null
),
bounds
,
selected
,
ddisp
,
// disparity, // if disparity.length == 1 - use for all
tile_size
,
tilesX
,
// int tilesX,
tilesY
,
// int tilesY,
indices
,
triangles
,
dbg_disp_tri_slice
);
// double [][] debug_triangles);
}
if
(
x3dOutput
!=
null
)
{
x3dOutput
.
addCluster
(
texturePath
,
id
,
class_name
,
texCoord
,
worldXYZ
,
triangles
);
}
if
(
wfOutput
!=
null
)
{
wfOutput
.
addCluster
(
texturePath
,
id
,
// class_name,
texCoord
,
worldXYZ
,
triangles
);
}
if
(
tri_meshes
!=
null
)
{
tri_meshes
.
add
(
new
TriMesh
(
texturePath
,
// String texture_image,
worldXYZ
,
// double [][] worldXYZ,
texCoord
,
// double [][] texCoord,
triangles
));
// int [][] triangles
}
}
// New version with subdivision
public
static
void
generateClusterX3d
(
// New version with alpha
boolean
full_texture
,
// true - full size image, false - bounds only
int
subdivide_mesh
,
// 0,1 - full tiles only, 2 - 2x2 pixels, 4 - 2x2 pixels
boolean
[]
alpha
,
// boolean alpha - true - opaque, false - transparent. Full/bounds
// matching selection
X3dOutput
x3dOutput
,
// output x3d if not null
WavefrontExport
wfOutput
,
// output WSavefront if not null
ArrayList
<
TriMesh
>
tri_meshes
,
String
texturePath
,
String
id
,
String
class_name
,
Rectangle
bounds
,
// Below selected and disparity are bounds.width*bounds.height
boolean
[]
selected
,
// may be either tilesX * tilesY or bounds.width*bounds.height
double
[]
disparity
,
// if null, will use min_disparity
int
tile_size
,
int
tilesX
,
int
tilesY
,
GeometryCorrection
geometryCorrection
,
boolean
correctDistortions
,
// requires backdrop image to be corrected also
double
[]
tri_img
,
//
int
tri_img_width
,
double
min_disparity
,
double
max_disparity
,
double
maxDispTriangle
,
// relative <=0 - do not use
double
maxZtoXY
,
// 10.0. <=0 - do not use
double
maxZ
,
// far clip (0 - do not clip). Negative - limit by max
boolean
limitZ
,
// double [][] dbg_disp_tri_slice,
int
debug_level
)
throws
IOException
{
boolean
show_triangles
=
tri_img
!=
null
;
if
(
bounds
==
null
)
{
return
;
// not used in lwir
}
/*
int [][] indices = getCoordIndices( // starting with 0, -1 - not selected // updated 09.18.2022
bounds,
selected,
tilesX);
*/
int
[]
pnum_indices
=
new
int
[
1
];
/*
* Enumerate "large" and "small" tiles, where "large" are actual tiles and "small" are
* subdivided (by subdiv in each direction) ones to increase lateral mesh resolution.
* sub-tiles are populated if at least one pixel in it is opaque. Input selected_tiles
* and alpha arrays may correspond to either full image or rectangular bounds, output
* array always corresponds to bounds.
*/
int
[][][][]
indices
=
getCoordIndices
(
// starting with 0, -1 - not selected
bounds
,
// final Rectangle bounds,
selected
,
// final boolean [] selected_tiles, can not be null
tilesX
,
// final int tilesX,
tile_size
,
// final int tile_size,
alpha
,
// final boolean [] alpha,
subdivide_mesh
,
// final int subdiv,
pnum_indices
);
// final int [] num_indices
/*
* Convert "large" tiles to arrays of small ones if it has a small-tile neighbor with
* gaps along the border with this one
*/
pnum_indices
[
0
]
=
splitLargeTileIndices
(
indices
,
// int [][][][] indices)
subdivide_mesh
);
// final int [] num_indices) {
Rectangle
tex_rect
=
full_texture
?
new
Rectangle
(
bounds
.
x
,
bounds
.
y
,
tilesX
,
tilesY
)
:
null
;
/*
* Get texture coordinates (0..1) for horizontal (positive - to the right) and vertical (positive - up)
*/
double
[][]
texCoord
=
getTexCoords
(
// get texture coordinates for indices
tex_rect
,
// final Rectangle rect, // 0 or full width, full height of the image in tiles
pnum_indices
[
0
],
// final int num_indices,
indices
);
// final int [][][][] indices)
double
[][]
worldXYZ
=
getCoords
(
// get world XYZ in meters for indices // updated 09.18.2022
disparity
,
// final double [] disparity,
min_disparity
,
// final double min_disparity,
max_disparity
,
// final double max_disparity,
bounds
,
// final Rectangle bounds,
pnum_indices
[
0
],
// final int num_indices,
indices
,
// final int [][][][] indices,
tilesX
,
// final int tilesX,
tile_size
,
// final int tile_size,
correctDistortions
,
// requires backdrop image to be corrected also
geometryCorrection
);
// final GeometryCorrection geometryCorrection)
/*
double [] indexedDisparity = getIndexedDisparities( // get disparity for each index // updated 09.18.2022
disparity,
min_disparity,
max_disparity,
bounds,
pnum_indices[0], // final int num_indices,
indices,
tilesX);
*/
/*
* Triangulate all vertice indices - combine triangulation of same-size equailateral 45-degree
* large (tile size) and small (tile subdivisions) and add connections between large and small ones
*/
int
[][]
triangles
=
triangulateAll
(
indices
);
final
boolean
plot_center
=
true
;
final
double
line_color
=
1.0
;
final
double
center_color
=
3.0
;
if
(
tri_img
!=
null
)
{
plotMesh
(
tri_img
,
// final double [] canvas,
tri_img_width
,
// final int width,
texCoord
,
// final double [][] tex_coord,
triangles
,
// final int [][] triangles,
plot_center
,
// final boolean plot_center,
line_color
,
// final double line_color,
center_color
);
// final double center_color)
}
if
(
x3dOutput
!=
null
)
{
x3dOutput
.
addCluster
(
texturePath
,
id
,
class_name
,
texCoord
,
worldXYZ
,
triangles
);
}
if
(
wfOutput
!=
null
)
{
wfOutput
.
addCluster
(
texturePath
,
id
,
texCoord
,
worldXYZ
,
triangles
);
}
if
(
tri_meshes
!=
null
)
{
tri_meshes
.
add
(
new
TriMesh
(
texturePath
,
// String texture_image,
worldXYZ
,
// double [][] worldXYZ,
texCoord
,
// double [][] texCoord,
triangles
));
// int [][] triangles
}
}
}
src/main/java/com/elphel/imagej/x3d/export/X3dOutput.java
View file @
f7d1b998
...
...
@@ -248,7 +248,7 @@ public class X3dOutput {
return
bbox
;
}
public
void
generateKML
(
public
static
void
generateKML
(
String
path
,
boolean
overwrite
,
String
icon_path
,
//<href>x3d/1487451413_967079.x3d</href> ?
...
...
@@ -341,14 +341,14 @@ public class X3dOutput {
}
Element
addTextElement
(
Document
doc
,
Element
parent
,
String
name
,
String
text
)
static
Element
addTextElement
(
Document
doc
,
Element
parent
,
String
name
,
String
text
)
{
Element
child
=
doc
.
createElement
(
name
);
child
.
setTextContent
(
text
);
parent
.
appendChild
(
child
);
return
child
;
}
Element
addElement
(
Document
doc
,
Element
parent
,
String
name
)
static
Element
addElement
(
Document
doc
,
Element
parent
,
String
name
)
{
Element
child
=
doc
.
createElement
(
name
);
parent
.
appendChild
(
child
);
...
...
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