Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Olena
pylene
Commits
9f3025ec
Commit
9f3025ec
authored
Oct 07, 2019
by
Edwin Carlinet
Browse files
Implement Opening By Reconstruction
parent
8d7c47c2
Changes
20
Hide whitespace changes
Inline
Side-by-side
bench/BMMorphoBase.cpp
View file @
9f3025ec
#include
<mln/core/algorithm/transform.hpp>
#include
<mln/core/algorithm/transform.hpp>
#include
<mln/core/colors.hpp>
#include
<mln/core/colors.hpp>
#include
<mln/core/image/experimental/ndimage.hpp>
#include
<mln/core/image/experimental/ndimage.hpp>
#include
<mln/core/se/disc.hpp>
#include
<mln/core/se/disc.hpp>
#include
<mln/core/se/rect2d.hpp>
#include
<mln/core/se/rect2d.hpp>
#include
<mln/core/se/mask2d.hpp>
#include
<mln/core/se/mask2d.hpp>
#include
<mln/core/neighborhood/c4.hpp>
#include
<mln/io/experimental/imread.hpp>
#include
<mln/io/experimental/imread.hpp>
#include
<mln/morpho/experimental/closing.hpp>
#include
<mln/morpho/experimental/closing.hpp>
#include
<mln/morpho/experimental/dilation.hpp>
#include
<mln/morpho/experimental/dilation.hpp>
#include
<mln/morpho/experimental/erosion.hpp>
#include
<mln/morpho/experimental/erosion.hpp>
#include
<mln/morpho/experimental/hit_or_miss.hpp>
#include
<mln/morpho/experimental/hit_or_miss.hpp>
#include
<mln/morpho/experimental/opening.hpp>
#include
<mln/morpho/experimental/median_filter.hpp>
#include
<mln/morpho/experimental/median_filter.hpp>
#include
<mln/morpho/experimental/opening.hpp>
#include
<mln/morpho/experimental/reconstruction.hpp>
#include
<benchmark/benchmark.h>
#include
<benchmark/benchmark.h>
...
@@ -151,15 +155,31 @@ BENCHMARK_F(BMMorpho, Opening_Disc)(benchmark::State& st)
...
@@ -151,15 +155,31 @@ BENCHMARK_F(BMMorpho, Opening_Disc)(benchmark::State& st)
}
}
BENCHMARK_F
(
BMMorpho
,
Median_Filter_Disc
)(
benchmark
::
State
&
st
)
BENCHMARK_F
(
BMMorpho
,
Median_Filter_Disc
)(
benchmark
::
State
&
st
)
{
int
radius
=
32
;
auto
se
=
mln
::
experimental
::
se
::
rect2d
(
2
*
radius
+
1
,
2
*
radius
+
1
);
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
experimental
::
median_filter
(
input
,
se
,
mln
::
extension
::
bm
::
mirror
{},
output
);
};
this
->
run
(
st
,
f
);
}
BENCHMARK_F
(
BMMorpho
,
Opening_By_Reconstruction_Disc
)(
benchmark
::
State
&
st
)
{
{
int
radius
=
32
;
int
radius
=
32
;
auto
se
=
mln
::
experimental
::
se
::
disc
(
radius
);
auto
se
=
mln
::
experimental
::
se
::
disc
(
radius
);
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
experimental
::
median_filter
(
input
,
se
,
mln
::
extension
::
bm
::
mirror
{},
output
);
};
auto
markers
=
mln
::
morpho
::
experimental
::
erosion
(
m_input
,
se
);
auto
f
=
[
m
=
std
::
move
(
markers
)](
const
image_t
&
input
,
image_t
&
output
)
{
output
=
mln
::
morpho
::
experimental
::
opening_by_reconstruction
(
input
,
m
,
mln
::
experimental
::
c4
);
};
this
->
run
(
st
,
f
);
this
->
run
(
st
,
f
);
}
}
BENCHMARK_F
(
BMMorpho
,
Hit_or_miss_corner
)(
benchmark
::
State
&
st
)
BENCHMARK_F
(
BMMorpho
,
Hit_or_miss_corner
)(
benchmark
::
State
&
st
)
{
{
mln
::
se
::
experimental
::
mask2d
se_hit
=
{
mln
::
se
::
experimental
::
mask2d
se_hit
=
{
...
...
bench/BMMorphoBaseRef.cpp
View file @
9f3025ec
...
@@ -4,11 +4,16 @@
...
@@ -4,11 +4,16 @@
#include
<mln/core/se/disc.hpp>
#include
<mln/core/se/disc.hpp>
#include
<mln/core/se/rect2d.hpp>
#include
<mln/core/se/rect2d.hpp>
#include
<mln/core/se/mask2d.hpp>
#include
<mln/core/se/mask2d.hpp>
#include
<mln/core/neighb2d.hpp>
#include
<mln/io/experimental/imread.hpp>
#include
<mln/io/experimental/imread.hpp>
#include
<mln/morpho/hit_or_miss.hpp>
#include
<mln/morpho/median_filter.hpp>
#include
<mln/morpho/opening_by_reconstruction.hpp>
#include
<mln/morpho/structural/closing.hpp>
#include
<mln/morpho/structural/closing.hpp>
#include
<mln/morpho/structural/dilate.hpp>
#include
<mln/morpho/structural/dilate.hpp>
#include
<mln/morpho/structural/erode.hpp>
#include
<mln/morpho/structural/erode.hpp>
#include
<mln/morpho/hit_or_miss.hpp>
#include
<mln/morpho/structural/opening.hpp>
#include
<mln/morpho/structural/opening.hpp>
// [legacy]
// [legacy]
...
@@ -103,12 +108,26 @@ BENCHMARK_REGISTER_F(BMMorpho, Dilation_Square)->RangeMultiplier(2)->Range(2, ma
...
@@ -103,12 +108,26 @@ BENCHMARK_REGISTER_F(BMMorpho, Dilation_Square)->RangeMultiplier(2)->Range(2, ma
BENCHMARK_F
(
BMMorpho
,
Opening_Disc
)(
benchmark
::
State
&
st
)
BENCHMARK_F
(
BMMorpho
,
Opening_Disc
)(
benchmark
::
State
&
st
)
{
{
int
radius
=
32
;
int
radius
=
32
;
auto
se
=
mln
::
se
::
rect2d
(
2
*
radius
+
1
,
2
*
radius
+
1
);
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
output
=
mln
::
morpho
::
structural
::
opening
(
input
,
se
,
mln
::
productorder_less
<
uint8_t
>
());
};
this
->
run
(
st
,
f
);
}
BENCHMARK_F
(
BMMorpho
,
Opening_By_Reconstruction_Disc
)(
benchmark
::
State
&
st
)
{
int
radius
=
32
;
auto
se
=
mln
::
se
::
disc
(
radius
);
auto
se
=
mln
::
se
::
disc
(
radius
);
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
structural
::
opening
(
input
,
se
,
mln
::
productorder_less
<
uint8_t
>
(),
output
);
};
auto
markers
=
mln
::
morpho
::
structural
::
erode
(
m_input_
,
se
);
auto
f
=
[
m
=
std
::
move
(
markers
)](
const
image_t
&
input
,
image_t
&
output
)
{
output
=
mln
::
morpho
::
opening_by_reconstruction
(
input
,
m
,
mln
::
c4
);
};
this
->
run
(
st
,
f
);
this
->
run
(
st
,
f
);
}
}
BENCHMARK_F
(
BMMorpho
,
Hit_or_miss_corner
)(
benchmark
::
State
&
st
)
BENCHMARK_F
(
BMMorpho
,
Hit_or_miss_corner
)(
benchmark
::
State
&
st
)
{
{
mln
::
se
::
mask2d
se_hit
=
{
mln
::
se
::
mask2d
se_hit
=
{
...
...
doc/source/images/blobs2_binary.png
0 → 100644
View file @
9f3025ec
15.3 KB
doc/source/morpho.rst
View file @
9f3025ec
...
@@ -15,7 +15,6 @@ Structural Morphological Operation
...
@@ -15,7 +15,6 @@ Structural Morphological Operation
morpho/rank_filter
morpho/rank_filter
morpho/median_filter
morpho/median_filter
morpho/opening_by_reconstruction
morpho/opening_by_reconstruction
morpho/closing_by_reconstruction
Segmentation
Segmentation
...
...
doc/source/morpho/closing_by_reconstruction.rst
deleted
100644 → 0
View file @
8d7c47c2
Closing by reconstruction
=========================
Include :file:`<mln/morpho/closing_by_reconstruction.hpp>`
.. cpp:namespace:: mln::morpho
.. cpp:function:: \
template <class InputImage1, class InputImage2, class Neighborhood> \
concrete_t<InputImage1> closing_by_reconstruction(const InputImage1& f, const InputImage2& markers, const Neighborhood& nbh)
.. cpp:function:: \
template <class InputImage1, class InputImage2, class Neighborhood, class Compare> \
concrete_t<InputImage1> closing_by_reconstruction(const InputImage1& f, const InputImage2& markers, const Neighborhood& nbh, Compare cmp)
Perform the reconstruction of the image ``markers`` over the constrain
image ``f``. Contrary to :ref:`opening-by-reconstruction`, the *background* is
reconstructed instead of the *foreground*.
:param f: Input image 𝑓
:param markers: Marker image (must have the same value type of 𝑓)
:param nbh: Fundamental structuring element.
:param cmp (optional): Comparaison function defining a strict weak ordering of values.
:return: An image whose type is deduced from the input image
:precondition: :math:`markers > f`
:exception: N/A
Notes
-----
Complexity
----------
doc/source/morpho/hit_or_miss.rst
View file @
9f3025ec
...
@@ -94,11 +94,10 @@ Hit or miss transform to detect horizontal 2px-thick line, with pattern::
...
@@ -94,11 +94,10 @@ Hit or miss transform to detect horizontal 2px-thick line, with pattern::
:width: 49%
:width: 49%
Logical or between the two previous images:
Logical or between the two previous images:
:
.. literalinclude:: /snippets/staff_lines.cpp
using mln::view::ops;
:lines: 50
auto markers = markers1 || markers2;
:language: cpp
.. image:: /images/staff_lines.png
.. image:: /images/staff_lines.png
:width: 49%
:width: 49%
...
...
doc/source/morpho/median_filter.rst
View file @
9f3025ec
...
@@ -43,7 +43,7 @@ Complexity
...
@@ -43,7 +43,7 @@ Complexity
Example 1 : Median-filter by a square on a gray-level image
Example 1 : Median-filter by a square on a gray-level image
---------------------------------------------------------
---------------------------------------------------------
--
.. code-block:: cpp
.. code-block:: cpp
...
...
doc/source/morpho/opening_by_reconstruction.rst
View file @
9f3025ec
.. _opening-by-reconstruction:
.. _opening-by-reconstruction:
Opening by reconstruction
Opening
& Closing
by reconstruction
=========================
=========================
==========
Include :file:`<mln/morpho/
opening_by_
reconstruction.hpp>`
Include :file:`<mln/morpho/reconstruction.hpp>`
.. cpp:namespace:: mln::morpho
.. cpp:namespace:: mln::morpho
.. cpp:function:: \
.. cpp:function:: \
template <class InputImage1, class InputImage2, class Neighborhood> \
Image{I1}\
concrete_t<InputImage1> opening_by_reconstruction(const InputImage1& f, const InputImage2& markers, const Neighborhood& nbh)
concrete_t<I1> opening_by_reconstruction(I1 f, I2 markers, Neighborhood nbh, Compare cmp)
Image{I1}\
Perform the reconstruction of the image ``markers`` under the constrain
concrete_t<I1> opening_by_reconstruction(I1 f, I2 markers, Neighborhood nbh)
image ``f``. The markers designate the parts of the image we want to
Image{I1}\
retain. In binary, it is equivalent to perform the *conditional*
concrete_t<I1> closing_by_reconstruction(I1 f, I2 markers, Neighborhood nbh)
dilation of the ``markers`` :math:`X`, by a structuring element 𝑩, using
the *reference* 𝑓 until reaching stability.
The opening by reconstruction performs the reconstruction of the image
``markers`` under the constrain image ``f``. The markers designate the parts
of the image we want to retain. In binary, it is equivalent to perform the
*conditional* dilation of the ``markers`` :math:`X`, by a structuring element
𝑩, using the *reference* 𝑓 until reaching stability.
.. math::
.. math::
\delta^{n+1}_{f,\mathcal{B}}(X) = \delta_\mathcal{B}(\delta^{n}_{f,\mathcal{B}}(X)) \cap f
\delta^{n+1}_{f,\mathcal{B}}(X) = \delta_\mathcal{B}(\delta^{n}_{f,\mathcal{B}}(X)) \cap f
Similarly, the closing by reconstruction reconstructs the *background* instead of the *foreground*.
:param f: Input image 𝑓
:param f: Input image 𝑓
:param markers: Marker image (must have the same value type of 𝑓)
:param markers: Marker image (must have the same value type of 𝑓)
:param nbh:
Funda
menta
l
structuring element.
:param nbh:
Ele
menta
ry
structuring element.
:return: An image whose type is deduced from the input image
:return: An image whose type is deduced from the input image
:precondition: :math:`markers
< f`
:precondition: :math:`markers
\le f` (for (3) :math:`markers \ge f`)
:exception: N/A
:exception: N/A
...
@@ -43,37 +50,88 @@ Complexity
...
@@ -43,37 +50,88 @@ Complexity
Example 1 : Staff lines reconstruction
Example 1 : Staff lines reconstruction
--------------------------------------
--------------------------------------
.. image:: /images/staff_lines.png
.. list-table::
:width: 49%
* - .. figure:: /images/staff_lines.png
.. image:: /images/staff_lines_markers.png
Original image
:width: 49%
The markers have been obtained with the :cpp:func:`hit_or_miss`.
- .. figure:: /images/staff_lines_markers.png
* Reconstruction of the objects touching staff lines; with the foundamental SE
Markers obtained by the :doc:`hit_or_miss` transform.
(4-connection). All objects that do not touch the staff lines are removed.
Given an original image and some markers obtained with the :doc:`hit_or_miss`
transform. The geodesic reconstruction (with the 4-connection) of the original
image by the markers give the objects touching staff lines. All objects that do
not touch the staff lines are removed.
.. literalinclude:: /snippets/staff_lines.cpp
.. literalinclude:: /snippets/staff_lines.cpp
:lines: 56
:start-after: M3_START
:end-before: M3_END
:language: cpp
:language: cpp
.. image:: /images/staff_lines.png
.. figure:: /images/morpho_reconstruction_1.png
:width: 49%
:figwidth: 49%
:figclass: align-center
.. image:: /images/morpho_reconstruction_1.png
Geodesic reconstruction from the markers.
:width: 49%
* Reconstruction of the lines only; with an horizontal SE `x-o-x`.
If we want to reconstruct only the staff line only, use an horizontal SE `x-o-x`.
.. literalinclude:: /snippets/staff_lines.cpp
.. literalinclude:: /snippets/staff_lines.cpp
:lines: 59
:start-after: M4_START
:end-before: M4_END
:language: cpp
:language: cpp
.. image:: /images/staff_lines.png
.. figure:: /images/morpho_reconstruction_2.png
:width: 49%
:figwidth: 49%
:figclass: align-center
Horizontal reconstruction from the markers.
Example 2 : Dense region reconstruction
---------------------------------------
.. list-table::
* - .. figure:: /images/blobs2_binary.png
(a) Original image
- .. figure:: /images/morpho_reconstruction_markers.png
(b) Markers from the :doc:`rank_filter`
- .. figure:: /images/morpho_reconstruction_dilated.png
(c) Dilated of the original image (a)
.. literalinclude:: /snippets/reconstruction.cpp
:start-after: M2_START
:end-before: M2_END
:language: cpp
Given an original image. We first start with a :doc:`rank_filter` to locate
dense region (regions with much more foreground pixels that background pixels)
that gives us markers. Then a dilation with a small disc allows to connect
objects. The reconstruction of the dilated image with a the markers gives a mask
for the dense region. Finally, we just have to mask the input with the mask to
get the objects in dense regions::
auto out = mln::clone(rec && input);
.. list-table::
* - .. figure:: /images/morpho_reconstruction_rec.png
(d) Reconstruction of (c) from the markers (b)
- .. figure:: /images/morpho_reconstruction_out.png
Input (a) restricted to the mask (d)
.. image:: /images/morpho_reconstruction_2.png
:width: 49%
doc/source/morpho/rank_filter.rst
View file @
9f3025ec
...
@@ -6,7 +6,7 @@ Include :file:`<mln/morpho/rank_filter.hpp>`
...
@@ -6,7 +6,7 @@ Include :file:`<mln/morpho/rank_filter.hpp>`
.. cpp:function:: \
.. cpp:function:: \
template <class Ratio> void rank_filter(Image image, StructuringElement se, BorderManager bm, OutputImage out)
template <class Ratio> void rank_filter(Image image, StructuringElement se, BorderManager bm, OutputImage out)
template <class Ratio
>
Image
{I}
concrete_t<I> rank_filter(I image, StructuringElement se, BorderManager bm)
template <class Ratio
,
Image
I>
concrete_t<I> rank_filter(I image, StructuringElement se, BorderManager bm)
The rank filter is non-linear filter that assigns the 𝑟-th value in a given structuring element 𝐵.
The rank filter is non-linear filter that assigns the 𝑟-th value in a given structuring element 𝐵.
...
...
doc/source/snippets/CMakeLists.txt
View file @
9f3025ec
...
@@ -28,7 +28,13 @@ add_image("erosion-cli;opening;square;21" "${PYLENE_IMAGE_DIR}/lena.pgm" morpho_
...
@@ -28,7 +28,13 @@ add_image("erosion-cli;opening;square;21" "${PYLENE_IMAGE_DIR}/lena.pgm" morpho_
add_image
(
"erosion-cli;closing;square;21"
"
${
PYLENE_IMAGE_DIR
}
/lena.pgm"
morpho_closing_1.png
)
add_image
(
"erosion-cli;closing;square;21"
"
${
PYLENE_IMAGE_DIR
}
/lena.pgm"
morpho_closing_1.png
)
add_image
(
"erosion-cli;median;square;21"
"
${
PYLENE_IMAGE_DIR
}
/lena.pgm"
morpho_median_1.png
)
add_image
(
"erosion-cli;median;square;21"
"
${
PYLENE_IMAGE_DIR
}
/lena.pgm"
morpho_median_1.png
)
add_image
(
"staff_lines"
"
${
DOCUMENTATION_IMAGE_DIR
}
/staff_lines.pbm"
add_image
(
"staff_lines"
"
${
DOCUMENTATION_IMAGE_DIR
}
/staff_lines.pbm"
morpho_hitormiss_1.png morpho_hitormiss_2.png staff_lines_markers.png morpho_reconstruction_1.png morpho_reconstruction_2.png
)
morpho_hitormiss_1.png morpho_hitormiss_2.png staff_lines_markers.png morpho_reconstruction_1.png morpho_reconstruction_2.png
)
add_image
(
"reconstruction"
"
${
DOCUMENTATION_IMAGE_DIR
}
/blobs2_binary.png"
morpho_reconstruction_dilated.png
morpho_reconstruction_markers.png
morpho_reconstruction_rec.png
morpho_reconstruction_out.png
)
add_image
(
"blobs_watershed"
"
${
DOCUMENTATION_IMAGE_DIR
}
/blobs_binary.png"
blobs_distance_transform.png blobs_segmentation.png
)
add_image
(
"blobs_watershed"
"
${
DOCUMENTATION_IMAGE_DIR
}
/blobs_binary.png"
blobs_distance_transform.png blobs_segmentation.png
)
...
@@ -42,4 +48,4 @@ add_executable(erosion-cli erosion-cli.cpp)
...
@@ -42,4 +48,4 @@ add_executable(erosion-cli erosion-cli.cpp)
add_executable
(
staff_lines staff_lines.cpp
)
add_executable
(
staff_lines staff_lines.cpp
)
add_executable
(
component_tree_1 component_tree_1.cpp
)
add_executable
(
component_tree_1 component_tree_1.cpp
)
add_executable
(
blobs_watershed blobs_watershed.cpp
)
add_executable
(
blobs_watershed blobs_watershed.cpp
)
add_executable
(
reconstruction reconstruction.cpp
)
doc/source/snippets/reconstruction.cpp
0 → 100644
View file @
9f3025ec
#include
<mln/io/experimental/imread.hpp>
#include
<mln/io/experimental/imsave.hpp>
#include
<mln/core/image/experimental/ndimage.hpp>
#include
<mln/core/neighborhood/c8.hpp>
#include
<mln/core/se/disc.hpp>
#include
<mln/core/se/rect2d.hpp>
#include
<mln/morpho/experimental/dilation.hpp>
#include
<mln/morpho/experimental/erosion.hpp>
#include
<mln/morpho/experimental/rank_filter.hpp>
#include
<mln/morpho/experimental/reconstruction.hpp>
#include
<mln/core/image/view/operators.hpp>
#include
<ratio>
int
main
(
int
argc
,
char
**
argv
)
{
if
(
argc
<
6
)
{
std
::
cerr
<<
"Usage: "
<<
argv
[
0
]
<<
" dilated.pbm markers.pbm reconstruction.pbm out.pbm
\n
"
;
return
1
;
}
using
namespace
mln
::
view
::
ops
;
mln
::
experimental
::
image2d
<
bool
>
input
;
mln
::
io
::
experimental
::
imread
(
argv
[
1
],
input
);
// #M2_START
// Make blobs connected
auto
disc
=
mln
::
experimental
::
se
::
disc
(
4
);
auto
dil
=
mln
::
morpho
::
experimental
::
dilation
(
input
,
disc
);
// Get markers for large connected components
auto
rect
=
mln
::
experimental
::
se
::
rect2d
(
20
,
20
);
auto
markers
=
mln
::
morpho
::
experimental
::
rank_filter
<
std
::
ratio
<
1
,
4
>>
(
input
,
rect
,
mln
::
extension
::
bm
::
fill
(
false
));
// Reconstruction of the large CC
auto
rec
=
mln
::
morpho
::
experimental
::
opening_by_reconstruction
(
dil
,
markers
,
mln
::
experimental
::
c8
);
// #M2_END
// Mask
auto
out
=
mln
::
clone
(
rec
&&
input
);
// Save
mln
::
io
::
experimental
::
imsave
(
dil
,
argv
[
2
]);
mln
::
io
::
experimental
::
imsave
(
markers
,
argv
[
3
]);
mln
::
io
::
experimental
::
imsave
(
rec
,
argv
[
4
]);
mln
::
io
::
experimental
::
imsave
(
out
,
argv
[
5
]);
}
doc/source/snippets/staff_lines.cpp
View file @
9f3025ec
#include
<mln/core/image/image
2d
.hpp>
#include
<mln/core/image/
experimental/nd
image.hpp>
#include
<mln/core/image/view/operators.hpp>
#include
<mln/core/image/view/operators.hpp>
#include
<mln/core/neighb2d.hpp>
#include
<mln/core/neighborhood/c4.hpp>
#include
<mln/core/neighborhood/c2_h.hpp>
#include
<mln/core/se/mask2d.hpp>
#include
<mln/core/se/mask2d.hpp>
#include
<mln/io/imread.hpp>
#include
<mln/io/
experimental/
imread.hpp>
#include
<mln/io/imsave.hpp>
#include
<mln/io/
experimental/
imsave.hpp>
#include
<mln/morpho/hit_or_miss.hpp>
#include
<mln/morpho/
experimental/
hit_or_miss.hpp>
#include
<mln/morpho/
opening_by_
reconstruction.hpp>
#include
<mln/morpho/
experimental/
reconstruction.hpp>
int
main
(
int
argc
,
char
**
argv
)
int
main
(
int
argc
,
char
**
argv
)
...
@@ -18,40 +19,43 @@ int main(int argc, char** argv)
...
@@ -18,40 +19,43 @@ int main(int argc, char** argv)
return
1
;
return
1
;
}
}
mln
::
image2d
<
bool
>
input
;
mln
::
experimental
::
image2d
<
bool
>
input
;
mln
::
io
::
imread
(
argv
[
1
],
input
);
mln
::
io
::
experimental
::
imread
(
argv
[
1
],
input
);
// Make a dual neighborhood corresponding to
// Make a dual neighborhood corresponding to
// x x x
// x x x
// o o o
// o o o
// x x x
// x x x
mln
::
image2d
<
bool
>
markers1
,
markers2
;
mln
::
experimental
::
image2d
<
bool
>
markers1
,
markers2
;
{
// #M1_START
{
// #M1_START
mln
::
se
::
mask2d
se_hit
=
{{
0
,
0
,
0
},
{
1
,
1
,
1
},
{
0
,
0
,
0
}};
mln
::
se
::
experimental
::
mask2d
se_hit
=
{{
0
,
0
,
0
},
{
1
,
1
,
1
},
{
0
,
0
,
0
}};
mln
::
se
::
mask2d
se_miss
=
{{
1
,
1
,
1
},
{
0
,
0
,
0
},
{
1
,
1
,
1
}};
mln
::
se
::
experimental
::
mask2d
se_miss
=
{{
1
,
1
,
1
},
{
0
,
0
,
0
},
{
1
,
1
,
1
}};
auto
output
=
mln
::
morpho
::
hit_or_miss
(
input
,
se_hit
,
se_miss
);
markers1
=
output
;
markers1
=
mln
::
morpho
::
experimental
::
hit_or_miss
(
input
,
se_hit
,
se_miss
)
;
mln
::
io
::
imsave
(
mln
::
l
not
(
markers1
)
,
argv
[
2
]);
mln
::
io
::
experimental
::
imsave
(
not
markers1
,
argv
[
2
]);
}
// #M1_END
}
// #M1_END
{
// #M2_START
{
// #M2_START
mln
::
se
::
mask2d
se_hit
=
{{
0
,
0
,
0
},
{
0
,
0
,
0
},
{
1
,
1
,
1
},
{
1
,
1
,
1
},
{
0
,
0
,
0
}};
mln
::
se
::
experimental
::
mask2d
se_hit
=
{{
0
,
0
,
0
},
{
0
,
0
,
0
},
{
1
,
1
,
1
},
{
1
,
1
,
1
},
{
0
,
0
,
0
}};
mln
::
se
::
mask2d
se_miss
=
{{
0
,
0
,
0
},
{
1
,
1
,
1
},
{
0
,
0
,
0
},
{
0
,
0
,
0
},
{
1
,
1
,
1
}};
mln
::
se
::
experimental
::
mask2d
se_miss
=
{{
0
,
0
,
0
},
{
1
,
1
,
1
},
{
0
,
0
,
0
},
{
0
,
0
,
0
},
{
1
,
1
,
1
}};
auto
output
=
mln
::
morpho
::
hit_or_miss
(
input
,
se_hit
,
se_miss
);
markers2
=
output
;
markers2
=
mln
::
morpho
::
experimental
::
hit_or_miss
(
input
,
se_hit
,
se_miss
)
;
mln
::
io
::
imsave
(
mln
::
l
not
(
markers2
)
,
argv
[
3
]);
mln
::
io
::
experimental
::
imsave
(
not
markers2
,
argv
[
3
]);
}
// #M2_END
}
// #M2_END
auto
markers
=
mln
::
lor
(
markers1
,
markers2
)
;
auto
markers
=
markers1
or
markers2
;
mln
::
io
::
imsave
(
mln
::
l
not
(
markers
)
,
argv
[
4
]);
mln
::
io
::
experimental
::
imsave
(
not
markers
,
argv
[
4
]);
// FIXME: add experimental version
// #M3_START
auto
markers_
=
mln
::
lor
(
markers1
,
markers2
);
auto
markers_
=
markers1
or
markers2
;
auto
all_touching
=
mln
::
morpho
::
opening_by_reconstruction
(
input
,
markers_
,
mln
::
c4
);
auto
all_touching
=
mln
::
morpho
::
experimental
::
opening_by_reconstruction
(
input
,
markers_
,
mln
::
experimental
::
c4
);
mln
::
io
::
imsave
(
mln
::
lnot
(
all_touching
),
argv
[
5
]);
mln
::
io
::
experimental
::
imsave
(
not
all_touching
,
argv
[
5
]);
// #M3_END
auto
lines_only
=
mln
::
morpho
::
opening_by_reconstruction
(
input
,
markers_
,
mln
::
c2_h
);
// #M4_START
mln
::
io
::
imsave
(
mln
::
lnot
(
lines_only
),
argv
[
6
]);
auto
lines_only
=
mln
::
morpho
::
experimental
::
opening_by_reconstruction
(
input
,
markers_
,
mln
::
experimental
::
c2_h
);
mln
::
io
::
experimental
::
imsave
(
not
lines_only
,
argv
[
6
]);
// #M4_END