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
8dad66d7
Commit
8dad66d7
authored
Sep 18, 2022
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
histogram normalization, color combined textures
parent
3a520ab0
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
650 additions
and
109 deletions
+650
-109
CLTParameters.java
src/main/java/com/elphel/imagej/cameras/CLTParameters.java
+78
-0
OpticalFlow.java
...ain/java/com/elphel/imagej/tileprocessor/OpticalFlow.java
+3
-1
QuadCLTCPU.java
...main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java
+434
-38
TexturedModel.java
...n/java/com/elphel/imagej/tileprocessor/TexturedModel.java
+135
-70
No files found.
src/main/java/com/elphel/imagej/cameras/CLTParameters.java
View file @
8dad66d7
...
@@ -392,6 +392,19 @@ public class CLTParameters {
...
@@ -392,6 +392,19 @@ public class CLTParameters {
public
double
tex_distort
=
0.8
;
// Maximal texture distortion to accumulate multiple scenes (0 - any)
public
double
tex_distort
=
0.8
;
// Maximal texture distortion to accumulate multiple scenes (0 - any)
public
double
tex_mb
=
1.0
;
// Reduce texture weight if motion blur exceeds this (as square of MB length)
public
double
tex_mb
=
1.0
;
// Reduce texture weight if motion blur exceeds this (as square of MB length)
public
boolean
tex_um
=
true
;
// Use unsharp mask filter for textures
public
double
tex_um_sigma
=
10.0
;
// Unsharp mask sigma for textures
public
double
tex_um_weight
=
0.97
;
// Unsharp mask weight
public
boolean
tex_lwir_autorange
=
true
;
// Autorange LWIR textures
public
boolean
tex_um_fixed
=
false
;
// Use fixed range after unsharp mask instead of autorange
public
double
tex_um_range
=
500
;
// Full range after unsharp mask
public
boolean
tex_hist_norm
=
true
;
// Normalize texture histogram
public
double
tex_hist_amount
=
0.7
;
// Texture histogram normalization amount (0.0 - no normalization, 1.0 - full normalization)
public
int
tex_hist_bins
=
1024
;
// Number of histogram bins to use for texture histograms
public
int
tex_hist_segments
=
32
;
// Number of evenly-spaced percentiles to use for histogram normalization
public
boolean
tex_color
=
true
;
// Use pseudo-colored textures
public
int
tex_palette
=
2
;
// Palette number for pseudo colors
public
boolean
show_textures
=
true
;
// show generated textures
public
boolean
show_textures
=
true
;
// show generated textures
public
boolean
debug_filters
=
false
;
// show intermediate results of filtering
public
boolean
debug_filters
=
false
;
// show intermediate results of filtering
// not used anywhere so far
// not used anywhere so far
...
@@ -1394,6 +1407,19 @@ public class CLTParameters {
...
@@ -1394,6 +1407,19 @@ public class CLTParameters {
properties
.
setProperty
(
prefix
+
"tex_distort"
,
this
.
tex_distort
+
""
);
// double
properties
.
setProperty
(
prefix
+
"tex_distort"
,
this
.
tex_distort
+
""
);
// double
properties
.
setProperty
(
prefix
+
"tex_mb"
,
this
.
tex_mb
+
""
);
// double
properties
.
setProperty
(
prefix
+
"tex_mb"
,
this
.
tex_mb
+
""
);
// double
properties
.
setProperty
(
prefix
+
"tex_um"
,
this
.
tex_um
+
""
);
// boolean
properties
.
setProperty
(
prefix
+
"tex_um_sigma"
,
this
.
tex_um_sigma
+
""
);
// double
properties
.
setProperty
(
prefix
+
"tex_um_weight"
,
this
.
tex_um_weight
+
""
);
// double
properties
.
setProperty
(
prefix
+
"tex_lwir_autorange"
,
this
.
tex_lwir_autorange
+
""
);
// boolean
properties
.
setProperty
(
prefix
+
"tex_um_fixed"
,
this
.
tex_um_fixed
+
""
);
// boolean
properties
.
setProperty
(
prefix
+
"tex_um_range"
,
this
.
tex_um_range
+
""
);
// double
properties
.
setProperty
(
prefix
+
"tex_hist_norm"
,
this
.
tex_hist_norm
+
""
);
// boolean
properties
.
setProperty
(
prefix
+
"tex_hist_amount"
,
this
.
tex_hist_amount
+
""
);
// double
properties
.
setProperty
(
prefix
+
"tex_hist_bins"
,
this
.
tex_hist_bins
+
""
);
// int
properties
.
setProperty
(
prefix
+
"tex_hist_segments"
,
this
.
tex_hist_segments
+
""
);
// int
properties
.
setProperty
(
prefix
+
"tex_color"
,
this
.
tex_color
+
""
);
// boolean
properties
.
setProperty
(
prefix
+
"tex_palette"
,
this
.
tex_palette
+
""
);
// int
properties
.
setProperty
(
prefix
+
"show_textures"
,
this
.
show_textures
+
""
);
properties
.
setProperty
(
prefix
+
"show_textures"
,
this
.
show_textures
+
""
);
properties
.
setProperty
(
prefix
+
"debug_filters"
,
this
.
debug_filters
+
""
);
properties
.
setProperty
(
prefix
+
"debug_filters"
,
this
.
debug_filters
+
""
);
...
@@ -2274,6 +2300,19 @@ public class CLTParameters {
...
@@ -2274,6 +2300,19 @@ public class CLTParameters {
if
(
properties
.
getProperty
(
prefix
+
"tex_distort"
)!=
null
)
this
.
tex_distort
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"tex_distort"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_distort"
)!=
null
)
this
.
tex_distort
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"tex_distort"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_mb"
)!=
null
)
this
.
tex_mb
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"tex_mb"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_mb"
)!=
null
)
this
.
tex_mb
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"tex_mb"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_um"
)!=
null
)
this
.
tex_um
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"tex_um"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_um_sigma"
)!=
null
)
this
.
tex_um_sigma
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"tex_um_sigma"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_um_weight"
)!=
null
)
this
.
tex_um_weight
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"tex_um_weight"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_lwir_autorange"
)!=
null
)
this
.
tex_lwir_autorange
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"tex_lwir_autorange"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_um_fixed"
)!=
null
)
this
.
tex_um_fixed
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"tex_um_fixed"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_um_range"
)!=
null
)
this
.
tex_um_range
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"tex_um_range"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_hist_norm"
)!=
null
)
this
.
tex_hist_norm
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"tex_hist_norm"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_hist_amount"
)!=
null
)
this
.
tex_hist_amount
=
Double
.
parseDouble
(
properties
.
getProperty
(
prefix
+
"tex_hist_amount"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_hist_bins"
)!=
null
)
this
.
tex_hist_bins
=
Integer
.
parseInt
(
properties
.
getProperty
(
prefix
+
"tex_hist_bins"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_hist_segments"
)!=
null
)
this
.
tex_hist_segments
=
Integer
.
parseInt
(
properties
.
getProperty
(
prefix
+
"tex_hist_segments"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_color"
)!=
null
)
this
.
tex_color
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"tex_color"
));
if
(
properties
.
getProperty
(
prefix
+
"tex_palette"
)!=
null
)
this
.
tex_palette
=
Integer
.
parseInt
(
properties
.
getProperty
(
prefix
+
"tex_palette"
));
if
(
properties
.
getProperty
(
prefix
+
"show_textures"
)!=
null
)
this
.
show_textures
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"show_textures"
));
if
(
properties
.
getProperty
(
prefix
+
"show_textures"
)!=
null
)
this
.
show_textures
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"show_textures"
));
if
(
properties
.
getProperty
(
prefix
+
"debug_filters"
)!=
null
)
this
.
debug_filters
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"debug_filters"
));
if
(
properties
.
getProperty
(
prefix
+
"debug_filters"
)!=
null
)
this
.
debug_filters
=
Boolean
.
parseBoolean
(
properties
.
getProperty
(
prefix
+
"debug_filters"
));
...
@@ -3313,6 +3352,32 @@ public class CLTParameters {
...
@@ -3313,6 +3352,32 @@ public class CLTParameters {
"Maximal texture distortion to accumulate multiple scenes (neighbor tile center offset from the uniform grid. 0 - do not filter"
);
"Maximal texture distortion to accumulate multiple scenes (neighbor tile center offset from the uniform grid. 0 - do not filter"
);
gd
.
addNumericField
(
"Maximal motion blur to reduce weight"
,
this
.
tex_mb
,
5
,
7
,
"pix"
,
gd
.
addNumericField
(
"Maximal motion blur to reduce weight"
,
this
.
tex_mb
,
5
,
7
,
"pix"
,
"Reduce texture weight if motion blur exceeds this (as square of MB length)."
);
"Reduce texture weight if motion blur exceeds this (as square of MB length)."
);
gd
.
addMessage
(
"Textures rendering"
);
gd
.
addCheckbox
(
"Apply unsharp mask"
,
this
.
tex_um
,
"Use unsharp mask filter for texture."
);
gd
.
addNumericField
(
"Unsharp mask sigma"
,
this
.
tex_um_sigma
,
5
,
7
,
"pix"
,
"Unsharp mask sigma for textures."
);
gd
.
addNumericField
(
"Unsharp mask weight"
,
this
.
tex_um_weight
,
5
,
7
,
""
,
"Unsharp mask weight."
);
gd
.
addCheckbox
(
"Autorange LWIR textures"
,
this
.
tex_lwir_autorange
,
"Autorange LWIR textures (inluding after unsharp mask)."
);
gd
.
addCheckbox
(
"Fixed range (after unsharp only)"
,
this
.
tex_um_fixed
,
"Use fixed range after unsharp mask instead of autorange."
);
gd
.
addNumericField
(
"Full range"
,
this
.
tex_um_range
,
5
,
7
,
"counts"
,
"Full range after unsharp mask."
);
gd
.
addCheckbox
(
"Normalize texture histogram"
,
this
.
tex_hist_norm
,
"Normalize texture histogram."
);
gd
.
addNumericField
(
"Histogram normalization amount"
,
this
.
tex_hist_amount
,
5
,
7
,
""
,
"Texture histogram normalization amount (0.0 - no normalization, 1.0 - full normalization)."
);
gd
.
addNumericField
(
"Number of histogram bins"
,
this
.
tex_hist_bins
,
0
,
3
,
""
,
"Number of histogram bins to use for texture histograms."
);
gd
.
addNumericField
(
"Number of histogram percentiles"
,
this
.
tex_hist_segments
,
0
,
3
,
""
,
"Number of evenly-spaced percentiles to use for histogram normalization."
);
gd
.
addCheckbox
(
"Use pseudo-color"
,
this
.
tex_color
,
"Use pseudo-colored textures (false - monochrome, float)."
);
gd
.
addNumericField
(
"Palette number"
,
this
.
tex_palette
,
0
,
3
,
""
,
"Palette number for pseudo colors."
);
gd
.
addMessage
(
"Earlier 3D generation parameters"
);
gd
.
addMessage
(
"Earlier 3D generation parameters"
);
gd
.
addCheckbox
(
"Show generated textures"
,
this
.
show_textures
);
gd
.
addCheckbox
(
"Show generated textures"
,
this
.
show_textures
);
gd
.
addCheckbox
(
"show intermediate results of filtering"
,
this
.
debug_filters
);
gd
.
addCheckbox
(
"show intermediate results of filtering"
,
this
.
debug_filters
);
...
@@ -4329,6 +4394,19 @@ public class CLTParameters {
...
@@ -4329,6 +4394,19 @@ public class CLTParameters {
this
.
tex_distort
=
gd
.
getNextNumber
();
this
.
tex_distort
=
gd
.
getNextNumber
();
this
.
tex_mb
=
gd
.
getNextNumber
();
this
.
tex_mb
=
gd
.
getNextNumber
();
this
.
tex_um
=
gd
.
getNextBoolean
();
this
.
tex_um_sigma
=
gd
.
getNextNumber
();
this
.
tex_um_weight
=
gd
.
getNextNumber
();
this
.
tex_lwir_autorange
=
gd
.
getNextBoolean
();
this
.
tex_um_fixed
=
gd
.
getNextBoolean
();
this
.
tex_um_range
=
gd
.
getNextNumber
();
this
.
tex_hist_norm
=
gd
.
getNextBoolean
();
this
.
tex_hist_amount
=
gd
.
getNextNumber
();
this
.
tex_hist_bins
=
(
int
)
gd
.
getNextNumber
();
this
.
tex_hist_segments
=
(
int
)
gd
.
getNextNumber
();
this
.
tex_color
=
gd
.
getNextBoolean
();
this
.
tex_palette
=
(
int
)
gd
.
getNextNumber
();
this
.
show_textures
=
gd
.
getNextBoolean
();
this
.
show_textures
=
gd
.
getNextBoolean
();
this
.
debug_filters
=
gd
.
getNextBoolean
();
this
.
debug_filters
=
gd
.
getNextBoolean
();
this
.
min_smth
=
gd
.
getNextNumber
();
this
.
min_smth
=
gd
.
getNextNumber
();
...
...
src/main/java/com/elphel/imagej/tileprocessor/OpticalFlow.java
View file @
8dad66d7
...
@@ -5296,10 +5296,12 @@ public class OpticalFlow {
...
@@ -5296,10 +5296,12 @@ public class OpticalFlow {
clt_parameters
,
// CLTParameters clt_parameters,
clt_parameters
,
// CLTParameters clt_parameters,
colorProcParameters
,
// ColorProcParameters colorProcParameters,
colorProcParameters
,
// ColorProcParameters colorProcParameters,
rgbParameters
,
// EyesisCorrectionParameters.RGBParameters rgbParameters,
rgbParameters
,
// EyesisCorrectionParameters.RGBParameters rgbParameters,
quadCLTs
[
quadCLTs
.
length
-
1
],
// quadCLT_main, // final QuadCLT parameter_scene, // to use for rendering parameters in multi-series sequences
// if null - use reference scene
quadCLTs
,
// QuadCLT [] scenes,
quadCLTs
,
// QuadCLT [] scenes,
combo_dsn_final
,
//double [][] combo_dsn_final, // null OK, will read file
combo_dsn_final
,
//double [][] combo_dsn_final, // null OK, will read file
updateStatus
,
// final boolean updateStatus,
updateStatus
,
// final boolean updateStatus,
debugLevel
+
1
);
// final int debugLevel)
debugLevel
);
//
+ 1); // final int debugLevel)
System
.
out
.
println
(
"TexturedModel.output3d() -> "
+
ok_3d
);
System
.
out
.
println
(
"TexturedModel.output3d() -> "
+
ok_3d
);
}
}
...
...
src/main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java
View file @
8dad66d7
...
@@ -7292,21 +7292,21 @@ public class QuadCLTCPU {
...
@@ -7292,21 +7292,21 @@ public class QuadCLTCPU {
return
hist
;
return
hist
;
}
}
public
static
int
[]
getLwirHistogramSliceAlpha
(
public
static
double
[]
getLwirHistogramSliceAlpha
(
double
[][]
data
,
double
[][]
data
,
double
hard_cold
,
double
hard_cold
,
double
hard_hot
,
double
hard_hot
,
int
num_bins
)
{
int
num_bins
)
{
int
chn_y
=
0
;
int
chn_y
=
0
;
int
chn_alpha
=
1
;
int
chn_alpha
=
1
;
int
[]
hist
=
new
int
[
num_bins
];
double
[]
hist
=
new
double
[
num_bins
];
double
k
=
num_bins
/
(
hard_hot
-
hard_cold
);
double
k
=
num_bins
/
(
hard_hot
-
hard_cold
);
for
(
int
i
=
0
;
i
<
data
[
chn_y
].
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
data
[
chn_y
].
length
;
i
++)
{
double
d
=
data
[
chn_y
][
i
]
*
data
[
chn_alpha
][
i
]
;
double
d
=
data
[
chn_y
][
i
]
;
int
bin
=
(
int
)
((
d
-
hard_cold
)*
k
);
int
bin
=
(
int
)
((
d
-
hard_cold
)*
k
);
if
(
bin
<
0
)
bin
=
0
;
if
(
bin
<
0
)
bin
=
0
;
else
if
(
bin
>=
num_bins
)
bin
=
(
num_bins
-
1
);
else
if
(
bin
>=
num_bins
)
bin
=
(
num_bins
-
1
);
hist
[
bin
]
++
;
hist
[
bin
]
+=
data
[
chn_alpha
][
i
]
;
}
}
return
hist
;
return
hist
;
}
}
...
@@ -7336,11 +7336,22 @@ public class QuadCLTCPU {
...
@@ -7336,11 +7336,22 @@ public class QuadCLTCPU {
}
}
return
this_hist
;
return
this_hist
;
}
}
public
static
double
[]
addHist
(
// USED in lwir
double
[]
this_hist
,
double
[]
other_hist
)
{
for
(
int
i
=
0
;
i
<
this_hist
.
length
;
i
++)
{
this_hist
[
i
]
+=
other_hist
[
i
];
}
return
this_hist
;
}
// get low/high (soft min/max) from the histogram
// get low/high (soft min/max) from the histogram
// returns value between 0.0 (low histogram limit and 1.0 - high histgram limit
// returns value between 0.0 (low histogram limit and 1.0 - high histgram limit
public
static
double
getMarginFromHist
(
// USED in lwir
public
static
double
getMarginFromHist
(
// USED in lwir
int
[]
hist
,
// histogram
int
[]
hist
,
// histogram
double
cumul_val
,
// cum
m
ulative number of items to be ignored
double
cumul_val
,
// cumulative number of items to be ignored
boolean
high_marg
)
{
// false - find low margin(output ~0.0) , true - find high margin (output ~1.0)
boolean
high_marg
)
{
// false - find low margin(output ~0.0) , true - find high margin (output ~1.0)
int
n
=
0
;
int
n
=
0
;
int
n_prev
=
0
;
int
n_prev
=
0
;
...
@@ -7374,6 +7385,44 @@ public class QuadCLTCPU {
...
@@ -7374,6 +7385,44 @@ public class QuadCLTCPU {
return
v
;
return
v
;
}
}
public
static
double
getMarginFromHist
(
// USED in lwir
double
[]
hist
,
// histogram
double
cumul_val
,
// cumulative number of items to be ignored
boolean
high_marg
)
{
// false - find low margin(output ~0.0) , true - find high margin (output ~1.0)
double
n
=
0
;
double
n_prev
=
0
;
int
bin
;
double
s
=
1.0
/
hist
.
length
;
double
v
;
if
(
high_marg
)
{
for
(
bin
=
hist
.
length
-
1
;
bin
>=
0
;
bin
--)
{
n_prev
=
n
;
n
+=
hist
[
bin
];
if
(
n
>
cumul_val
)
break
;
}
if
(
n
<=
cumul_val
)
{
// not used in lwir
v
=
0.0
;
// cumul_val > total number of samples
}
else
{
v
=
s
*
(
bin
+
1
-
(
cumul_val
-
n_prev
)/(
n
-
n_prev
));
}
}
else
{
for
(
bin
=
0
;
bin
<
hist
.
length
;
bin
++)
{
n_prev
=
n
;
n
+=
hist
[
bin
];
if
(
n
>
cumul_val
)
break
;
}
if
(
n
<=
cumul_val
)
{
// not used in lwir
v
=
1.0
;
// cumul_val > total number of samples
}
else
{
v
=
s
*
(
bin
+
(
cumul_val
-
n_prev
)/(
n
-
n_prev
));
}
}
return
v
;
}
public
static
double
[]
autorange
(
// USED in lwir (double input)
public
static
double
[]
autorange
(
// USED in lwir (double input)
double
[][][]
iclt_data
,
// [iQuad][ncol][i] - normally only [][2][] is non-null
double
[][][]
iclt_data
,
// [iQuad][ncol][i] - normally only [][2][] is non-null
double
hard_cold
,
// matches data, DC (this.lwir_offset) subtracted
double
hard_cold
,
// matches data, DC (this.lwir_offset) subtracted
...
@@ -7485,13 +7534,9 @@ public class QuadCLTCPU {
...
@@ -7485,13 +7534,9 @@ public class QuadCLTCPU {
double
too_cold
,
// pixels per image
double
too_cold
,
// pixels per image
double
too_hot
,
// pixels per image
double
too_hot
,
// pixels per image
int
num_bins
)
{
int
num_bins
)
{
// int num_channels = textures[0].length;
double
[]
hist
=
null
;
// boolean is_mono = num_channels < 3;
// too_cold *= num_chn; // iclt_data.length;
// too_hot *= num_chn; // iclt_data.length;
int
[]
hist
=
null
;
for
(
int
nslice
=
0
;
nslice
<
textures
.
length
;
nslice
++)
{
for
(
int
nslice
=
0
;
nslice
<
textures
.
length
;
nslice
++)
{
int
[]
this_hist
=
getLwirHistogramSliceAlpha
(
double
[]
this_hist
=
getLwirHistogramSliceAlpha
(
textures
[
nslice
],
// double [][][] data,
textures
[
nslice
],
// double [][][] data,
hard_cold
,
hard_cold
,
hard_hot
,
hard_hot
,
...
@@ -7520,7 +7565,236 @@ public class QuadCLTCPU {
...
@@ -7520,7 +7565,236 @@ public class QuadCLTCPU {
return
abs_lim
;
return
abs_lim
;
}
}
public
static
double
[]
getMinMaxTextures
(
double
[][][]
textures
// [nslices][nchn][i]
)
{
if
((
textures
==
null
)
||
(
textures
.
length
==
0
))
{
throw
new
IllegalArgumentException
(
"umTextures(): Empty textures"
);
}
final
boolean
is_mono
=
textures
[
0
].
length
<=
2
;
final
int
alpha_chn
=
is_mono
?
1
:
3
;
final
boolean
has_alpha
=
textures
[
0
].
length
>
alpha_chn
;
final
double
alpha_min
=
0.9
;
// only consider pixels with higher alpha
final
int
num_um_chn
=
alpha_chn
*
textures
.
length
;
// number of images to UM
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
QuadCLT
.
THREADS_MAX
);
final
AtomicInteger
ai
=
new
AtomicInteger
(
0
);
final
AtomicInteger
ati
=
new
AtomicInteger
(
0
);
final
double
[][]
tminmax
=
new
double
[
threads
.
length
][];
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
int
thread_num
=
ati
.
getAndIncrement
();
tminmax
[
thread_num
]
=
new
double
[]
{
Double
.
NaN
,
Double
.
NaN
};
for
(
int
nimg
=
ai
.
getAndIncrement
();
nimg
<
num_um_chn
;
nimg
=
ai
.
getAndIncrement
())
{
int
nslice
=
nimg
/
alpha_chn
;
int
nchn
=
nimg
%
alpha_chn
;
double
[]
alpha
=
has_alpha
?
textures
[
nslice
][
alpha_chn
]
:
null
;
double
[]
texture
=
textures
[
nslice
][
nchn
];
for
(
int
i
=
0
;
i
<
texture
.
length
;
i
++)
if
(!
has_alpha
||
(
alpha
[
i
]
>
alpha_min
))
{
if
(!(
texture
[
i
]
>=
tminmax
[
thread_num
][
0
]))
{
tminmax
[
thread_num
][
0
]
=
texture
[
i
];
}
if
(!(
texture
[
i
]
<=
tminmax
[
thread_num
][
1
]))
{
tminmax
[
thread_num
][
1
]
=
texture
[
i
];
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
double
[]
minmax
=
{
Double
.
NaN
,
Double
.
NaN
};
for
(
int
i
=
0
;
i
<
tminmax
.
length
;
i
++)
if
((
tminmax
[
i
]
!=
null
)
&&
!
Double
.
isNaN
(
tminmax
[
i
][
0
])
&&!
Double
.
isNaN
(
tminmax
[
i
][
1
]))
{
if
(!(
tminmax
[
i
][
0
]
>=
minmax
[
0
]))
{
minmax
[
0
]
=
tminmax
[
i
][
0
];
}
if
(!(
tminmax
[
i
][
1
]
<=
minmax
[
1
]))
{
minmax
[
1
]
=
tminmax
[
i
][
1
];
}
}
return
minmax
;
}
public
static
void
umTextures
(
final
double
[][][]
textures
,
// [nslices][nchn][i]
final
int
width
,
final
double
um_sigma
,
final
double
um_weight
){
if
((
textures
==
null
)
||
(
textures
.
length
==
0
))
{
throw
new
IllegalArgumentException
(
"umTextures(): Empty textures"
);
}
final
int
height
=
textures
[
0
][
0
].
length
/
width
;
final
boolean
is_mono
=
textures
[
0
].
length
<=
2
;
final
int
alpha_chn
=
is_mono
?
1
:
3
;
final
boolean
has_alpha
=
textures
[
0
].
length
>
alpha_chn
;
final
int
num_um_chn
=
alpha_chn
*
textures
.
length
;
// number of images to UM
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
QuadCLT
.
THREADS_MAX
);
final
AtomicInteger
ai
=
new
AtomicInteger
(
0
);
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
double
[]
texture_orig
=
new
double
[
width
*
height
];
for
(
int
nimg
=
ai
.
getAndIncrement
();
nimg
<
num_um_chn
;
nimg
=
ai
.
getAndIncrement
())
{
int
nslice
=
nimg
/
alpha_chn
;
int
nchn
=
nimg
%
alpha_chn
;
double
[]
texture
=
textures
[
nslice
][
nchn
];
double
[]
texture_alpha
=
has_alpha
?
textures
[
nslice
][
alpha_chn
]:
null
;
System
.
arraycopy
(
texture
,
0
,
texture_orig
,
0
,
texture
.
length
);
(
new
DoubleGaussianBlur
()).
blurDouble
(
texture
,
// FloatProcessor ip,
width
,
height
,
um_sigma
,
// double sigmaX,
um_sigma
,
// double sigmaY,
0.01
);
// double accuracy)
for
(
int
i
=
0
;
i
<
texture
.
length
;
i
++)
{
texture
[
i
]
=
texture_orig
[
i
]
-
um_weight
*
texture
[
i
];
}
if
(
has_alpha
)
{
for
(
int
i
=
0
;
i
<
texture
.
length
;
i
++)
if
(
texture_alpha
[
i
]
<=
0.0
){
texture
[
i
]
=
0.0
;
}
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
}
public
static
double
[]
getHistogramNormalization
(
double
[][][]
textures
,
// [nslices][nchn][i]
double
[]
minmax
,
int
num_bins
,
int
num_nodes
,
double
hist_normalize_amount
// 1.0 - full
)
{
double
[]
hist
=
null
;
for
(
int
nslice
=
0
;
nslice
<
textures
.
length
;
nslice
++)
{
double
[]
this_hist
=
getLwirHistogramSliceAlpha
(
textures
[
nslice
],
// double [][][] data,
minmax
[
0
],
minmax
[
1
],
num_bins
);
if
(
hist
==
null
)
{
hist
=
this_hist
;
}
else
{
addHist
(
hist
,
this_hist
);
}
}
for
(
int
i
=
1
;
i
<
hist
.
length
;
i
++)
{
hist
[
i
]
+=
hist
[
i
-
1
];
}
if
(
hist_normalize_amount
<
1.0
)
{
double
full
=
hist
[
hist
.
length
-
1
];
for
(
int
i
=
0
;
i
<
hist
.
length
;
i
++)
{
hist
[
i
]
=
hist_normalize_amount
*
hist
[
i
]
+
(
1.0
-
hist_normalize_amount
)
*
full
;
}
}
double
[]
norm_table
=
new
double
[
num_nodes
];
int
indx
=
0
;
// norm_table[num_nodes - 1] = 1.0;
for
(
int
n
=
0
;
n
<
num_nodes
;
n
++)
{
double
thresh
=
hist
[
hist
.
length
-
1
]
*
(
n
+
1
)
/(
num_nodes
+
1
);
if
(
thresh
>
hist
[
hist
.
length
-
1
])
{
// full histogram
thresh
=
hist
[
hist
.
length
-
1
];
}
for
(;
((
indx
<
hist
.
length
)
&&
(
hist
[
indx
]
<=
thresh
));
indx
++);
double
hist_prev
=
(
indx
==
0
)
?
0.0
:
hist
[
indx
-
1
];
if
(
indx
>=
hist
.
length
)
{
norm_table
[
n
]
=
1.0
;
// not normal?
}
else
{
norm_table
[
n
]
=
(
1.0
*
indx
)/
hist
.
length
+
(
thresh
-
hist_prev
)/(
hist
[
indx
]
-
hist_prev
)/
hist
.
length
;
}
}
return
norm_table
;
}
/**
* Calculate long inverted table from short normalization one for fast application
* @param direct_table
* @param num_bins
* @return
*/
public
static
double
[]
invertHistogramNormalization
(
double
[]
direct_table
,
// last is <1.0, first > 0
int
num_bins
)
{
int
num_nodes
=
direct_table
.
length
;
double
out_scale
=
num_bins
-
1
;
// 1023, last is 1.0
double
out_step
=
1.0
/
out_scale
;
double
[]
inverted_table
=
new
double
[
num_bins
];
int
i_last
=
-
1
;
double
inv_step
=
1.0
/(
direct_table
.
length
+
1
);
for
(
int
indx
=
0
;
indx
<=
direct_table
.
length
;
indx
++)
{
double
frac_l
=
(
indx
>
0
)
?
direct_table
[
indx
-
1
]
:
0.0
;
double
frac_h
=
(
indx
==
direct_table
.
length
)
?
1.0
:
direct_table
[
indx
];
int
i_l
=
(
int
)
Math
.
floor
(
frac_l
*
out_scale
);
int
i_h
=
(
int
)
Math
.
ceil
(
frac_h
*
out_scale
);
if
(
i_h
>
num_bins
)
i_h
=
num_bins
;
if
(
i_l
<=
i_last
)
i_l
++;
i_last
=
i_h
-
1
;
double
out_range
=
frac_h
-
frac_l
;
if
(
out_range
<=
0
)
{
continue
;
// may happen at the beginning/end?
}
double
inv_l
=
inv_step
*
indx
;
for
(
int
i
=
i_l
;
i
<
i_h
;
i
++)
{
double
out_diff
=
i
*
out_step
-
frac_l
;
inverted_table
[
i
]
=
inv_l
+
out_diff
*
inv_step
/
out_range
;
}
}
inverted_table
[
inverted_table
.
length
-
1
]
=
1.0
;
return
inverted_table
;
}
public
static
void
applyTexturesNormHist
(
final
double
[][][]
textures
,
// [nslices][nchn][i]
final
double
[]
min_max
,
final
double
[]
inv_table
)
{
final
double
range
=
min_max
[
1
]
-
min_max
[
0
];
final
boolean
is_mono
=
textures
[
0
].
length
<=
2
;
final
int
alpha_chn
=
is_mono
?
1
:
3
;
final
boolean
has_alpha
=
textures
[
0
].
length
>
alpha_chn
;
final
Thread
[]
threads
=
ImageDtt
.
newThreadArray
(
QuadCLT
.
THREADS_MAX
);
final
AtomicInteger
ai
=
new
AtomicInteger
(
0
);
for
(
int
nslice
=
0
;
nslice
<
textures
.
length
;
nslice
++)
{
final
double
[]
texture_alpha
=
(
has_alpha
)
?
textures
[
nslice
][
alpha_chn
]
:
null
;
for
(
int
nchn
=
0
;
nchn
<
alpha_chn
;
nchn
++)
{
final
double
[]
texture
=
textures
[
nslice
][
nchn
];
for
(
int
ithread
=
0
;
ithread
<
threads
.
length
;
ithread
++)
{
threads
[
ithread
]
=
new
Thread
()
{
public
void
run
()
{
for
(
int
npix
=
ai
.
getAndIncrement
();
npix
<
texture
.
length
;
npix
=
ai
.
getAndIncrement
())
{
if
(!
has_alpha
||
(
texture_alpha
[
npix
]
>
0.0
))
{
double
rel_in
=
(
texture
[
npix
]
-
min_max
[
0
])
/
range
;
if
(
rel_in
<
0.0
)
{
rel_in
=
0.0
;
}
else
if
(
rel_in
>
1.0
)
{
rel_in
=
1.0
;
}
// interpolate by table
double
srel_in
=
rel_in
*
inv_table
.
length
;
int
il
=
(
int
)
Math
.
floor
(
srel_in
);
if
(
il
>
(
inv_table
.
length
-
1
))
il
=
inv_table
.
length
-
1
;
double
dl
=
inv_table
[
il
];
double
dh
=
(
il
<
(
inv_table
.
length
-
1
))
?
inv_table
[
il
+
1
]
:
1.0
;
texture
[
npix
]
=
min_max
[
0
]+
(
dl
+
(
srel_in
-
il
)
*
(
dh
-
dl
))*
range
;
}
}
}
};
}
ImageDtt
.
startAndJoin
(
threads
);
ai
.
set
(
0
);
}
}
return
;
}
// float, for GPU
// float, for GPU
public
ImagePlus
linearStackToColor
(
// not used in lwir
public
ImagePlus
linearStackToColor
(
// not used in lwir
CLTParameters
clt_parameters
,
CLTParameters
clt_parameters
,
...
@@ -7540,30 +7814,50 @@ public class QuadCLTCPU {
...
@@ -7540,30 +7814,50 @@ public class QuadCLTCPU {
)
)
{
{
// convert to ImageStack of 3 slices
// convert to ImageStack of 3 slices
String
[]
sliceNames
=
{
"red"
,
"blue"
,
"green"
};
String
[]
sliceNames
=
isMonochrome
()?
new
String
[]{
"mono"
}:
new
String
[]{
"red"
,
"blue"
,
"green"
};
int
green_index
=
2
;
int
main_color_index
=
isMonochrome
()?
0
:
2
;
float
[][]
rbg_in
;
// int green_index = 2;
float
[][]
rbg_in
=
isMonochrome
()?
new
float
[][]
{
iclt_data
[
0
]}
:
new
float
[][]
{
iclt_data
[
0
],
iclt_data
[
1
],
iclt_data
[
2
]};
/*
if (iclt_data.length >= 3) {
if (iclt_data.length >= 3) {
rbg_in = new float [][] {iclt_data[0],iclt_data[1],iclt_data[2]}; // RBG or LWIR CPU
rbg_in = new float [][] {iclt_data[0],iclt_data[1],iclt_data[2]}; // RBG or LWIR CPU
} else {
} else {
rbg_in = new float [][] {iclt_data[0],iclt_data[0],iclt_data[0]}; // after LWIR/GPU
rbg_in = new float [][] {iclt_data[0],iclt_data[0],iclt_data[0]}; // after LWIR/GPU
green_index = 0;
green_index = 0;
}
}
float
[]
alpha
=
null
;
// (0..1.0)
*/
if
(
iclt_data
.
length
>
3
)
alpha
=
iclt_data
[
3
];
float
[]
alpha_pixels
=
null
;
// (0..1.0)
if
(
iclt_data
.
length
>
rbg_in
.
length
)
{
alpha_pixels
=
iclt_data
[
rbg_in
.
length
];
}
if
(
isLwir
())
{
if
(
isLwir
())
{
//// if (!colorProcParameters.lwir_pseudocolor) {
if
(!
toRGB
)
{
// Double [][] uses
if
(!
toRGB
)
{
/// if (!colorProcParameters.lwir_pseudocolor) {
ImageProcessor
ip
=
new
FloatProcessor
(
width
,
height
);
ImagePlus
imp
;
ip
.
setPixels
(
iclt_data
[
0
]);
if
(
alpha_pixels
!=
null
)
{
ip
.
resetMinAndMax
();
String
[]
titles
=
{
"Y"
,
"alpha"
};
ImagePlus
imp
=
new
ImagePlus
(
name
+
suffix
,
ip
);
ImageStack
stack
=
ShowDoubleFloatArrays
.
makeStack
(
new
float
[][]
{
rbg_in
[
0
],
alpha_pixels
},
// iclt_data,
width
,
// (tilesX + 0) * clt_parameters.transform_size,
height
,
// (tilesY + 0) * clt_parameters.transform_size,
titles
,
// or use null to get chn-nn slice names
true
);
// replace NaN with 0.0
imp
=
new
ImagePlus
(
name
+
suffix
,
stack
);
imp
.
getProcessor
().
resetMinAndMax
();
}
else
{
ImageProcessor
ip
=
new
FloatProcessor
(
width
,
height
);
ip
.
setPixels
(
rbg_in
[
0
]);
ip
.
resetMinAndMax
();
imp
=
new
ImagePlus
(
name
+
suffix
,
ip
);
}
return
imp
;
return
imp
;
}
}
String
[]
rgb_titles
=
{
"red"
,
"green"
,
"blue"
};
String
[]
rgb_titles
=
{
"red"
,
"green"
,
"blue"
};
String
[]
rgba_titles
=
{
"red"
,
"green"
,
"blue"
,
"alpha"
};
String
[]
rgba_titles
=
{
"red"
,
"green"
,
"blue"
,
"alpha"
};
String
[]
titles
=
(
alpha
==
null
)
?
rgb_titles
:
rgba_titles
;
String
[]
titles
=
(
alpha
_pixels
==
null
)
?
rgb_titles
:
rgba_titles
;
int
num_slices
=
(
alpha
==
null
)
?
3
:
4
;
int
num_slices
=
(
alpha
_pixels
==
null
)
?
3
:
4
;
double
mn
=
colorProcParameters
.
lwir_low
;
double
mn
=
colorProcParameters
.
lwir_low
;
double
mx
=
colorProcParameters
.
lwir_high
;
double
mx
=
colorProcParameters
.
lwir_high
;
double
[]
cold_hot
=
getColdHot
();
double
[]
cold_hot
=
getColdHot
();
...
@@ -7584,18 +7878,18 @@ public class QuadCLTCPU {
...
@@ -7584,18 +7878,18 @@ public class QuadCLTCPU {
mx
,
mx
,
255.0
);
255.0
);
float
[][]
rgba
=
new
float
[
num_slices
][];
float
[][]
rgba
=
new
float
[
num_slices
][];
for
(
int
i
=
0
;
i
<
3
;
i
++)
rgba
[
i
]
=
new
float
[
iclt_data
[
green
_index
].
length
];
for
(
int
i
=
0
;
i
<
3
;
i
++)
rgba
[
i
]
=
new
float
[
iclt_data
[
main_color
_index
].
length
];
for
(
int
i
=
0
;
i
<
rbg_in
[
green
_index
].
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
rbg_in
[
main_color
_index
].
length
;
i
++)
{
// if (i == 700) {
// if (i == 700) {
// System.out.println("linearStackToColor(): i="+i);
// System.out.println("linearStackToColor(): i="+i);
// }
// }
float
[]
rgb
=
tc
.
getRGB
(
iclt_data
[
green
_index
][
i
]);
float
[]
rgb
=
tc
.
getRGB
(
iclt_data
[
main_color
_index
][
i
]);
rgba
[
0
][
i
]
=
rgb
[
0
];
// red
rgba
[
0
][
i
]
=
rgb
[
0
];
// red
rgba
[
1
][
i
]
=
rgb
[
1
];
// green
rgba
[
1
][
i
]
=
rgb
[
1
];
// green
rgba
[
2
][
i
]
=
rgb
[
2
];
// blue
rgba
[
2
][
i
]
=
rgb
[
2
];
// blue
}
}
if
(
alpha
!=
null
)
{
if
(
alpha
_pixels
!=
null
)
{
rgba
[
3
]
=
alpha
;
// 0..1
rgba
[
3
]
=
alpha
_pixels
;
// 0..1
}
}
ImageStack
stack
=
ShowDoubleFloatArrays
.
makeStack
(
ImageStack
stack
=
ShowDoubleFloatArrays
.
makeStack
(
rgba
,
// iclt_data,
rgba
,
// iclt_data,
...
@@ -7636,7 +7930,7 @@ public class QuadCLTCPU {
...
@@ -7636,7 +7930,7 @@ public class QuadCLTCPU {
saveShowIntermediate
,
// boolean saveShowIntermediate, // save/show if set globally
saveShowIntermediate
,
// boolean saveShowIntermediate, // save/show if set globally
saveShowFinal
,
// boolean saveShowFinal, // save/show result (color image?)
saveShowFinal
,
// boolean saveShowFinal, // save/show result (color image?)
stack
,
// ImageStack stack,
stack
,
// ImageStack stack,
alpha
,
// float [] alpha_pixels,
alpha
_pixels
,
// float [] alpha_pixels,
width
,
// int width, // int tilesX,
width
,
// int width, // int tilesX,
height
,
// int height, // int tilesY,
height
,
// int height, // int tilesY,
scaleExposure
,
// double scaleExposure,
scaleExposure
,
// double scaleExposure,
...
@@ -7685,21 +7979,23 @@ public class QuadCLTCPU {
...
@@ -7685,21 +7979,23 @@ public class QuadCLTCPU {
for
(
int
i
=
0
;
i
<
pixels
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
pixels
.
length
;
i
++)
{
pixels
[
i
]
=
(
float
)
iclt_data
[
0
][
i
];
pixels
[
i
]
=
(
float
)
iclt_data
[
0
][
i
];
}
}
ImagePlus
imp
;
if
(
alpha_pixels
!=
null
)
{
if
(
alpha_pixels
!=
null
)
{
/*
String
[]
titles
=
{
"Y"
,
"alpha"
};
ImageStack
stack
=
ShowDoubleFloatArrays
.
makeStack
(
ImageStack
stack
=
ShowDoubleFloatArrays
.
makeStack
(
{pixels,alpha_pixels}, // iclt_data,
new
float
[][]
{
pixels
,
alpha_pixels
},
// iclt_data,
width
,
// (tilesX + 0) * clt_parameters.transform_size,
width
,
// (tilesX + 0) * clt_parameters.transform_size,
height
,
// (tilesY + 0) * clt_parameters.transform_size,
height
,
// (tilesY + 0) * clt_parameters.transform_size,
titles
,
// or use null to get chn-nn slice names
titles
,
// or use null to get chn-nn slice names
true
);
// replace NaN with 0.0
true
);
// replace NaN with 0.0
*/
imp
=
new
ImagePlus
(
name
+
suffix
,
stack
);
imp
.
getProcessor
().
resetMinAndMax
();
}
else
{
ImageProcessor
ip
=
new
FloatProcessor
(
width
,
height
);
ip
.
setPixels
(
pixels
);
ip
.
resetMinAndMax
();
imp
=
new
ImagePlus
(
name
+
suffix
,
ip
);
}
}
ImageProcessor
ip
=
new
FloatProcessor
(
width
,
height
);
ip
.
setPixels
(
pixels
);
ip
.
resetMinAndMax
();
ImagePlus
imp
=
new
ImagePlus
(
name
+
suffix
,
ip
);
return
imp
;
return
imp
;
}
}
String
[]
rgb_titles
=
{
"red"
,
"green"
,
"blue"
};
String
[]
rgb_titles
=
{
"red"
,
"green"
,
"blue"
};
...
@@ -7783,7 +8079,107 @@ public class QuadCLTCPU {
...
@@ -7783,7 +8079,107 @@ public class QuadCLTCPU {
debugLevel
);
//int debugLevel
debugLevel
);
//int debugLevel
}
}
// float, for GPU
public
static
ImagePlus
linearStackToColorLWIR
(
CLTParameters
clt_parameters
,
int
lwir_palette
,
// <0 - do not convert
double
[]
minmax
,
String
name
,
String
suffix
,
// such as disparity=...
boolean
toRGB
,
double
[][]
texture_data
,
int
width
,
// int tilesX,
int
height
,
// int tilesY,
int
debugLevel
)
{
final
boolean
is_mono
=
texture_data
.
length
<=
2
;
final
int
alpha_chn
=
is_mono
?
1
:
3
;
// final boolean has_alpha = texture_data.length > alpha_chn;
// convert to ImageStack of 3 slices
// String [] sliceNames = is_mono? new String[]{"mono"}: new String[]{"red", "blue", "green"};
int
main_color_index
=
is_mono
?
0
:
2
;
double
[][]
rbg_in
=
is_mono
?
new
double
[][]
{
texture_data
[
0
]}
:
new
double
[][]
{
texture_data
[
0
],
texture_data
[
1
],
texture_data
[
2
]};
double
[]
alpha_pixels
=
null
;
// (0..1.0)
if
(
texture_data
.
length
>
rbg_in
.
length
)
{
alpha_pixels
=
texture_data
[
rbg_in
.
length
];
}
if
(!
toRGB
)
{
// Double [][] uses
ImagePlus
imp
;
if
(
alpha_pixels
!=
null
)
{
String
[]
titles
=
{
"Y"
,
"alpha"
};
ImageStack
stack
=
ShowDoubleFloatArrays
.
makeStack
(
new
double
[][]
{
rbg_in
[
0
],
alpha_pixels
},
// iclt_data,
width
,
// (tilesX + 0) * clt_parameters.transform_size,
height
,
// (tilesY + 0) * clt_parameters.transform_size,
titles
,
// or use null to get chn-nn slice names
true
);
// replace NaN with 0.0
imp
=
new
ImagePlus
(
name
+
suffix
,
stack
);
imp
.
getProcessor
().
resetMinAndMax
();
}
else
{
ImageProcessor
ip
=
new
FloatProcessor
(
width
,
height
);
ip
.
setPixels
(
rbg_in
[
0
]);
ip
.
resetMinAndMax
();
imp
=
new
ImagePlus
(
name
+
suffix
,
ip
);
}
return
imp
;
}
String
[]
rgb_titles
=
{
"red"
,
"green"
,
"blue"
};
String
[]
rgba_titles
=
{
"red"
,
"green"
,
"blue"
,
"alpha"
};
String
[]
titles
=
(
alpha_pixels
==
null
)
?
rgb_titles
:
rgba_titles
;
int
num_slices
=
(
alpha_pixels
==
null
)
?
3
:
4
;
double
mn
=
minmax
[
0
];
// colorProcParameters.lwir_low;
double
mx
=
minmax
[
1
];
// colorProcParameters.lwir_high;
ThermalColor
tc
=
new
ThermalColor
(
lwir_palette
,
// colorProcParameters.lwir_palette,
mn
,
mx
,
255.0
);
double
[][]
rgba
=
new
double
[
num_slices
][];
for
(
int
i
=
0
;
i
<
3
;
i
++)
rgba
[
i
]
=
new
double
[
texture_data
[
main_color_index
].
length
];
for
(
int
i
=
0
;
i
<
rbg_in
[
main_color_index
].
length
;
i
++)
{
double
[]
rgb
=
tc
.
getRGB
(
texture_data
[
main_color_index
][
i
]);
rgba
[
0
][
i
]
=
rgb
[
0
];
// red
rgba
[
1
][
i
]
=
rgb
[
1
];
// green
rgba
[
2
][
i
]
=
rgb
[
2
];
// blue
}
if
(
alpha_pixels
!=
null
)
{
rgba
[
3
]
=
alpha_pixels
;
// 0..1
}
ImageStack
stack
=
ShowDoubleFloatArrays
.
makeStack
(
rgba
,
// iclt_data,
width
,
// (tilesX + 0) * clt_parameters.transform_size,
height
,
// (tilesY + 0) * clt_parameters.transform_size,
titles
,
// or use null to get chn-nn slice names
true
);
// replace NaN with 0.0
ImagePlus
imp_rgba
=
EyesisCorrections
.
convertRGBAFloatToRGBA32
(
stack
,
// ImageStack stackFloat, //r,g,b,a
// name+"ARGB"+suffix, // String title,
name
+
suffix
,
// String title,
0.0
,
// double r_min,
255.0
,
// double r_max,
0.0
,
// double g_min,
255.0
,
// double g_max,
0.0
,
// double b_min,
255.0
,
// double b_max,
0.0
,
// double alpha_min,
1.0
);
// double alpha_max)
return
imp_rgba
;
}
// Convert a single value pixels to color (r,b,g) values to be processed instead of the normal colors
// Convert a single value pixels to color (r,b,g) values to be processed instead of the normal colors
...
...
src/main/java/com/elphel/imagej/tileprocessor/TexturedModel.java
View file @
8dad66d7
...
@@ -32,6 +32,7 @@ import com.elphel.imagej.cameras.CLTParameters;
...
@@ -32,6 +32,7 @@ import com.elphel.imagej.cameras.CLTParameters;
import
com.elphel.imagej.cameras.ColorProcParameters
;
import
com.elphel.imagej.cameras.ColorProcParameters
;
import
com.elphel.imagej.cameras.EyesisCorrectionParameters
;
import
com.elphel.imagej.cameras.EyesisCorrectionParameters
;
import
com.elphel.imagej.common.ShowDoubleFloatArrays
;
import
com.elphel.imagej.common.ShowDoubleFloatArrays
;
import
com.elphel.imagej.correction.EyesisCorrections
;
import
com.elphel.imagej.gpu.GpuQuad
;
import
com.elphel.imagej.gpu.GpuQuad
;
import
com.elphel.imagej.gpu.TpTask
;
import
com.elphel.imagej.gpu.TpTask
;
import
com.elphel.imagej.x3d.export.WavefrontExport
;
import
com.elphel.imagej.x3d.export.WavefrontExport
;
...
@@ -528,6 +529,8 @@ public class TexturedModel {
...
@@ -528,6 +529,8 @@ public class TexturedModel {
CLTParameters
clt_parameters
,
CLTParameters
clt_parameters
,
ColorProcParameters
colorProcParameters
,
ColorProcParameters
colorProcParameters
,
EyesisCorrectionParameters
.
RGBParameters
rgbParameters
,
EyesisCorrectionParameters
.
RGBParameters
rgbParameters
,
final
QuadCLT
parameter_scene
,
// to use for rendering parameters in multi-series sequences
// if null - use reference scene
QuadCLT
[]
scenes
,
QuadCLT
[]
scenes
,
double
[][]
combo_dsn_final
,
// null OK, will read file
double
[][]
combo_dsn_final
,
// null OK, will read file
// final int threadsMax, // maximal number of threads to launch
// final int threadsMax, // maximal number of threads to launch
...
@@ -615,21 +618,45 @@ public class TexturedModel {
...
@@ -615,21 +618,45 @@ public class TexturedModel {
double
[][]
inter_weights
=
new
double
[
tilesY
][
tilesX
];
// per-tile texture weights for inter-scene accumulation;
double
[][]
inter_weights
=
new
double
[
tilesY
][
tilesX
];
// per-tile texture weights for inter-scene accumulation;
double
[][][][]
inter_textures
=
new
double
[
tilesY
][
tilesX
][][];
// [channel][256] - non-overlapping textures
double
[][][][]
inter_textures
=
new
double
[
tilesY
][
tilesX
][][];
// [channel][256] - non-overlapping textures
boolean
[]
scenes_sel
=
new
boolean
[
scenes
.
length
];
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 = 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
for
(
int
i
=
0
;
i
<
scenes
.
length
;
i
++)
{
// start with just one (reference) scene
scenes_sel
[
i
]
=
true
;
scenes_sel
[
i
]
=
true
;
}
}
boolean
renormalize
=
true
;
// false - use normalizations from previous scenes to keep consistent colors
ImagePlus
[]
combined_textures
=
getInterCombinedTextures
(
// return ImagePlus[] matching tileClusters[], with alpha
ImagePlus
[]
combined_textures
=
getInterCombinedTextures
(
// return ImagePlus[] matching tileClusters[], with alpha
clt_parameters
,
// final CLTParameters clt_parameters,
clt_parameters
,
// final CLTParameters clt_parameters,
colorProcParameters
,
// ColorProcParameters colorProcParameters,
colorProcParameters
,
// ColorProcParameters colorProcParameters,
rgbParameters
,
// EyesisCorrectionParameters.RGBParameters rgbParameters,
rgbParameters
,
// EyesisCorrectionParameters.RGBParameters rgbParameters,
parameter_scene
,
// final QuadCLT parameter_scene, // to use for rendering parameters in multi-series sequences
// if null - use reference scene
scenes
,
// final QuadCLT [] scenes,
scenes
,
// final QuadCLT [] scenes,
scenes_sel
,
// final boolean [] scenes_sel, // null or which scenes to process
scenes_sel
,
// final boolean [] scenes_sel, // null or which scenes to process
null
,
// final boolean [] selection, // may be null, if not null do not process unselected tiles
null
,
// final boolean [] selection, // may be null, if not null do not process unselected tiles
tileClusters
,
// final TileCluster [] tileClusters, // disparities, borders, selections for texture passes
tileClusters
,
// final TileCluster [] tileClusters, // disparities, borders, selections for texture passes
// final int margin,
// final int margin,
renormalize
,
// final boolean renormalize, // false - use normalizations from previous scenes to keep consistent colors
debugLevel
);
// final int debug_level)
debugLevel
);
// final int debug_level)
boolean
save_full_textures
=
true
;
if
(
save_full_textures
)
{
EyesisCorrectionParameters
.
CorrectionParameters
correctionsParameters
=
ref_scene
.
correctionsParameters
;
for
(
int
nslice
=
0
;
nslice
<
combined_textures
.
length
;
nslice
++)
{
String
path
=
correctionsParameters
.
selectX3dDirectory
(
//TODO: Which one to use - name or this.image_name ?
correctionsParameters
.
getModelName
(
ref_scene
.
getImageName
()),
// quad timestamp. Will be ignored if correctionsParameters.use_x3d_subdirs is false
correctionsParameters
.
x3dModelVersion
,
true
,
// smart,
true
);
//newAllowed, // save
EyesisCorrections
.
saveAndShow
(
combined_textures
[
nslice
],
// imp_texture_cluster,
path
,
correctionsParameters
.
png
,
false
,
// (nslice < 4), // clt_parameters.show_textures,
-
1
,
// jpegQuality){// <0 - keep current, 0 - force Tiff, >0 use for JPEG
1
);
//
}
}
if
(
debugLevel
>
-
100
)
{
if
(
debugLevel
>
-
100
)
{
return
true
;
return
true
;
}
}
...
@@ -885,16 +912,21 @@ public class TexturedModel {
...
@@ -885,16 +912,21 @@ public class TexturedModel {
final
CLTParameters
clt_parameters
,
final
CLTParameters
clt_parameters
,
ColorProcParameters
colorProcParameters
,
ColorProcParameters
colorProcParameters
,
EyesisCorrectionParameters
.
RGBParameters
rgbParameters
,
EyesisCorrectionParameters
.
RGBParameters
rgbParameters
,
QuadCLT
parameter_scene
,
// to use for rendering parameters in multi-series sequences
// if null - use reference scene
final
QuadCLT
[]
scenes
,
final
QuadCLT
[]
scenes
,
final
boolean
[]
scenes_sel
,
// null or which scenes to process
final
boolean
[]
scenes_sel
,
// null or which scenes to process
final
boolean
[]
selection
,
// may be null, if not null do not process unselected tiles
final
boolean
[]
selection
,
// may be null, if not null do not process unselected tiles
final
TileCluster
[]
tileClusters
,
// disparities, borders, selections for texture passes
final
TileCluster
[]
tileClusters
,
// disparities, borders, selections for texture passes
// final int margin,
final
boolean
renormalize
,
// false - use normalizations from previous scenes to keep consistent colors
final
int
debug_level
)
final
int
debug_level
)
{
{
// TODO: ***** scenes with high motion blur also have high ERS to be corrected ! *****
// TODO: ***** scenes with high motion blur also have high ERS to be corrected ! *****
final
int
ref_index
=
scenes
.
length
-
1
;
final
int
ref_index
=
scenes
.
length
-
1
;
final
QuadCLT
ref_scene
=
scenes
[
ref_index
];
final
QuadCLT
ref_scene
=
scenes
[
ref_index
];
if
(
parameter_scene
==
null
)
{
parameter_scene
=
ref_scene
;
}
final
int
earliestScene
=
ref_scene
.
getEarliestScene
(
scenes
);
final
int
earliestScene
=
ref_scene
.
getEarliestScene
(
scenes
);
final
ErsCorrection
ers_reference
=
ref_scene
.
getErsCorrection
();
final
ErsCorrection
ers_reference
=
ref_scene
.
getErsCorrection
();
final
int
tilesX
=
ref_scene
.
getTileProcessor
().
getTilesX
();
final
int
tilesX
=
ref_scene
.
getTileProcessor
().
getTilesX
();
...
@@ -912,7 +944,23 @@ public class TexturedModel {
...
@@ -912,7 +944,23 @@ public class TexturedModel {
final
double
tex_mb
=
clt_parameters
.
tex_mb
;
// 1.0; // Reduce texture weight if motion blur exceeds this (as square of MB length)
final
double
tex_mb
=
clt_parameters
.
tex_mb
;
// 1.0; // Reduce texture weight if motion blur exceeds this (as square of MB length)
final
boolean
sharp_alpha
=
clt_parameters
.
sharp_alpha
;
final
boolean
sharp_alpha
=
clt_parameters
.
sharp_alpha
;
final
boolean
is_lwir
=
ref_scene
.
isLwir
();
final
boolean
is_lwir
=
ref_scene
.
isLwir
();
final
boolean
lwir_autorange
=
is_lwir
&&
colorProcParameters
.
lwir_autorange
;
final
boolean
tex_um
=
clt_parameters
.
tex_um
;
// imp.um_mono; // TODO: add own parameter
final
double
tex_um_sigma
=
clt_parameters
.
tex_um_sigma
;
// imp.um_sigma;
final
double
tex_um_weight
=
clt_parameters
.
tex_um_weight
;
// imp.um_weight;
// TODO: - make texture variants, tex_um_fixed/tex_um_range apply only to unsharp mask, regardless of colors
final
boolean
lwir_autorange
=
is_lwir
&&
clt_parameters
.
tex_lwir_autorange
;
// colorProcParameters.lwir_autorange;
final
boolean
tex_um_fixed
=
clt_parameters
.
tex_um_fixed
;
// imp.mono_fixed; // true; // normalize to fixed range when converting to 8 bits
final
double
tex_um_range
=
clt_parameters
.
tex_um_range
;
// imp.mono_range; // 500.0; // monochrome full-scale range (+/- half)
final
boolean
tex_hist_norm
=
clt_parameters
.
tex_hist_norm
;
// true;
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 ;
ImageDtt
image_dtt
;
ImageDtt
image_dtt
;
image_dtt
=
new
ImageDtt
(
image_dtt
=
new
ImageDtt
(
...
@@ -932,7 +980,6 @@ public class TexturedModel {
...
@@ -932,7 +980,6 @@ public class TexturedModel {
double
[][][]
inter_weights
=
new
double
[
num_slices
][
tilesY
][
tilesX
];
// per-tile texture weights for inter-scene accumulation;
double
[][][]
inter_weights
=
new
double
[
num_slices
][
tilesY
][
tilesX
];
// per-tile texture weights for inter-scene accumulation;
double
[][][][][]
inter_textures
=
new
double
[
num_slices
][
tilesY
][
tilesX
][][];
// [channel][256] - non-overlapping textures
double
[][][][][]
inter_textures
=
new
double
[
num_slices
][
tilesY
][
tilesX
][][];
// [channel][256] - non-overlapping textures
/// double [][] scene_pXpYD;
/// double [][] scene_pXpYD;
/// final double disparity_corr = 0.00; // (z_correction == 0) ? 0.0 : geometryCorrection.getDisparityFromZ(1.0/z_correction);
/// final double disparity_corr = 0.00; // (z_correction == 0) ? 0.0 : geometryCorrection.getDisparityFromZ(1.0/z_correction);
/// TpTask[] tp_tasks_ref = null;
/// TpTask[] tp_tasks_ref = null;
double
[][][]
ref_pXpYDs
=
new
double
[
num_slices
][][];
// individual for each slice
double
[][][]
ref_pXpYDs
=
new
double
[
num_slices
][][];
// individual for each slice
...
@@ -1118,30 +1165,77 @@ public class TexturedModel {
...
@@ -1118,30 +1165,77 @@ public class TexturedModel {
}
}
}
}
}
}
// Optionally apply UM (before auto/manual range)
if
(
tex_um
)
{
QuadCLTCPU
.
umTextures
(
faded_textures
,
// final double [][][] textures, // [nslices][nchn][i]
tilesX
*
transform_size
,
// final int width,
tex_um_sigma
,
// final double um_sigma,
tex_um_weight
);
// final double um_weight)
}
//renormalize
// normalize all slices together if LWIR
// normalize all slices together if LWIR
// FIXME: Should it be here? Will setColdHot() change photometric calibration ? Or should it be disabled?
// FIXME: Should it be here? Will setColdHot() change photometric calibration ? Or should it be disabled?
if
(
lwir_autorange
)
{
double
[]
norm_table
=
null
;
// first try, then make save to properties with cold/hot
double
rel_low
=
colorProcParameters
.
lwir_low
;
if
(
renormalize
)
{
double
rel_high
=
colorProcParameters
.
lwir_high
;
if
(
lwir_autorange
)
{
if
(!
Double
.
isNaN
(
ref_scene
.
getLwirOffset
()))
{
double
rel_low
;
rel_low
-=
ref_scene
.
getLwirOffset
();
double
rel_high
;
rel_high
-=
ref_scene
.
getLwirOffset
();
boolean
force_min_max
=
true
;
}
if
(!
tex_um
&&
!
force_min_max
)
{
// for UM will use min/max
double
[]
cold_hot
=
QuadCLTCPU
.
autorangeTextures
(
rel_low
=
colorProcParameters
.
lwir_low
;
faded_textures
,
// double [][][] textures, // [nslices][nchn][i]
rel_high
=
colorProcParameters
.
lwir_high
;
rel_low
,
// double hard_cold,// matches data, DC (this.lwir_offset) subtracted
if
(!
Double
.
isNaN
(
parameter_scene
.
getLwirOffset
()))
{
// ref_scene or parameter_scene? Or both?
rel_high
,
// double hard_hot, // matches data, DC (this.lwir_offset) subtracted
rel_low
-=
parameter_scene
.
getLwirOffset
();
colorProcParameters
.
lwir_too_cold
,
// double too_cold, // pixels per image
rel_high
-=
parameter_scene
.
getLwirOffset
();
colorProcParameters
.
lwir_too_hot
,
// double too_hot, // pixels per image
}
1024
);
// int num_bins)
}
else
{
// for UM need to calculate min and max (probably OK for non-UM too !)
if
(
cold_hot
!=
null
)
{
double
[]
minmax
=
QuadCLTCPU
.
getMinMaxTextures
(
if
(!
Double
.
isNaN
(
ref_scene
.
getLwirOffset
()))
{
faded_textures
);
//double [][][] textures // [nslices][nchn][i]
cold_hot
[
0
]
+=
ref_scene
.
getLwirOffset
();
rel_low
=
minmax
[
0
];
cold_hot
[
1
]
+=
ref_scene
.
getLwirOffset
();
rel_high
=
minmax
[
1
];
}
double
[]
cold_hot
=
QuadCLTCPU
.
autorangeTextures
(
faded_textures
,
// double [][][] textures, // [nslices][nchn][i]
rel_low
,
// double hard_cold,// matches data, DC (this.lwir_offset) subtracted
rel_high
,
// double hard_hot, // matches data, DC (this.lwir_offset) subtracted
colorProcParameters
.
lwir_too_cold
,
// double too_cold, // pixels per image
colorProcParameters
.
lwir_too_hot
,
// double too_hot, // pixels per image
tex_hist_bins
);
// int num_bins)
if
((
cold_hot
!=
null
)
&&
!
tex_um
&&
!
force_min_max
)
{
if
(!
Double
.
isNaN
(
parameter_scene
.
getLwirOffset
()))
{
cold_hot
[
0
]
+=
parameter_scene
.
getLwirOffset
();
cold_hot
[
1
]
+=
parameter_scene
.
getLwirOffset
();
}
}
}
parameter_scene
.
setColdHot
(
cold_hot
);
// will be used for shifted images and for texture tiles
}
else
if
(
tex_um
&&
tex_um_fixed
)
{
// apply fixed range, but for UM only (what about RGB?)
parameter_scene
.
setColdHot
(-
0.5
*
tex_um_range
,
0.5
*
tex_um_range
);
}
}
ref_scene
.
setColdHot
(
cold_hot
);
// will be used for shifted images and for texture tiles
if
(
tex_hist_norm
)
{
// will normalize (0..1) keeping cold_hot to apply during rendering
// last norm_table element is <=1.0, first >=0;
norm_table
=
QuadCLTCPU
.
getHistogramNormalization
(
faded_textures
,
// double [][][] textures, // [nslices][nchn][i]
parameter_scene
.
getColdHot
(),
// double [] minmax,
tex_hist_bins
,
// int num_bins,
tex_hist_segments
,
//int num_nodes
tex_hist_amount
);
//double hist_normalize_amount // 1.0 - full
}
}
if
(
tex_hist_norm
&&
(
norm_table
!=
null
))
{
// apply histogram normalization
double
[]
cold_hot
=
parameter_scene
.
getColdHot
();
// used in linearStackToColor
double
[]
inverted_table
=
QuadCLTCPU
.
invertHistogramNormalization
(
norm_table
,
// double [] direct_table, // last is <1.0, first > 0
tex_hist_bins
);
// int num_bins)
QuadCLTCPU
.
applyTexturesNormHist
(
faded_textures
,
// final double [][][] textures, // [nslices][nchn][i]
cold_hot
,
// final double [] min_max,
inverted_table
);
// final double [] inv_table)
}
}
if
(
debug_level
>
-
1
)
{
if
(
debug_level
>
-
1
)
{
double
[][]
dbg_textures
=
new
double
[
faded_textures
.
length
*
faded_textures
[
0
].
length
][
faded_textures
[
0
][
0
].
length
];
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
];
String
[]
dbg_titles
=
new
String
[
dbg_textures
.
length
];
...
@@ -1181,58 +1275,29 @@ public class TexturedModel {
...
@@ -1181,58 +1275,29 @@ public class TexturedModel {
ref_scene
.
getImageName
()+
"-texture_weights"
);
ref_scene
.
getImageName
()+
"-texture_weights"
);
}
}
}
}
for
(
int
nslice
=
0
;
nslice
<
num_slices
;
nslice
++)
{
// See how textures where processed with alpha
/*
// Prepare 4-channel images
ImagePlus [] imps_RGB = new ImagePlus[iclt_fimg.length];
for (int ncam = 0; ncam < iclt_fimg.length; ncam++) if (iclt_fimg[ncam] != null){
String title=String.format("%s%s-%02d",image_name, sAux(), ncam);
imps_RGB[ncam] = linearStackToColor( // probably no need to separate and process the second half with quadCLT_aux (!)
clt_parameters,
colorProcParameters,
rgbParameters,
title, // String name,
"-D"+clt_parameters.disparity, //String suffix, // such as disparity=...
toRGB, // does not work here?
!correctionsParameters.jpeg, // boolean bpp16, // 16-bit per channel color mode for result
false, // true, // boolean saveShowIntermediate, // save/show if set globally
false, // boolean saveShowFinal, // save/show result (color image?)
iclt_fimg[ncam],
out_width,
out_height,
1.0, // scaleExposures[iAux][iSubCam], // double scaleExposure, // is it needed?
-1); // debugLevel );
}
// combine to a sliced color image
double
[]
minmax
=
parameter_scene
.
getColdHot
();
// used in linearStackToColor
int [] slice_seq = {0,1,3,2}; //clockwise
ImagePlus
[]
imp_tex
=
new
ImagePlus
[
num_slices
];
if (imps_RGB.length > 4) {
EyesisCorrectionParameters
.
CorrectionParameters
correctionsParameters
=
ref_scene
.
correctionsParameters
;
slice_seq = new int [imps_RGB.length];
for
(
int
nslice
=
0
;
nslice
<
num_slices
;
nslice
++)
{
for (int i = 0; i < slice_seq.length; i++) {
String
title
=
String
.
format
(
"%s-texture-%02d"
,
ref_scene
.
getImageName
(),
nslice
);
slice_seq[i] = i;
imp_tex
[
nslice
]
=
QuadCLTCPU
.
linearStackToColorLWIR
(
}
clt_parameters
,
// CLTParameters clt_parameters,
}
tex_palette
,
// int lwir_palette, // <0 - do not convert
int width = imps_RGB[0].getWidth();
minmax
,
// double [] minmax,
int height = imps_RGB[0].getHeight();
title
,
// String name,
ImageStack array_stack=new ImageStack(width,height);
""
,
// String suffix, // such as disparity=...
for (int i = 0; i<slice_seq.length; i++) if (imps_RGB[slice_seq[i]] != null){
tex_color
,
// boolean toRGB,
array_stack.addSlice("port_"+slice_seq[i], imps_RGB[slice_seq[i]].getProcessor().getPixels());
faded_textures
[
nslice
],
// double [][] texture_data,
}
tilesX
*
transform_size
,
// int width, // int tilesX,
ImagePlus imp_stack = new ImagePlus(image_name+sAux()+suffix, array_stack);
tilesY
*
transform_size
,
// int height, // int tilesY,
imp_stack.getProcessor().resetMinAndMax();
debug_level
);
// int debugLevel )
return imp_stack;
*/
// convert to color or apply UM,
// Add synthetic mesh only with higher resolution? or just any by a specified period?what king of mesh - vertical random, ...
// 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
// Split and save as png
}
}
// Process accumulated textures: average, apply borders, convert to color or apply UM, add synthetic mesh, ...
// Process accumulated textures: average, apply borders, convert to color or apply UM, add synthetic mesh, ...
return
null
;
// ImagePlus[] ? with alpha, to be split into png and saved with alpha.
return
imp_tex
;
// ImagePlus[] ? with alpha, to be split into png and saved with alpha.
}
}
...
...
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