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
b5e6686b
Commit
b5e6686b
authored
Sep 12, 2019
by
Edwin Carlinet
Browse files
Implement opening/closing/hit or miss operators
parent
96399c86
Changes
24
Hide whitespace changes
Inline
Side-by-side
.vscode/settings.json
View file @
b5e6686b
{}
\ No newline at end of file
{
}
\ No newline at end of file
bench/Aerial_view_of_Olbia.jpg.md5
0 → 100644
View file @
b5e6686b
3b29ff3e51f04aac090f78e7fd96b8a6
bench/BM
Dilation
.cpp
→
bench/BM
MorphoBase
.cpp
View file @
b5e6686b
#include
<mln/core/algorithm/transform.hpp>
#include
<mln/core/colors.hpp>
#include
<mln/core/image/experimental/ndimage.hpp>
#include
<mln/io/experimental/imread.hpp>
#include
<benchmark/benchmark.h>
#include
<mln/core/se/disc.hpp>
#include
<mln/core/se/rect2d.hpp>
#include
<mln/core/se/mask2d.hpp>
#include
<mln/io/experimental/imread.hpp>
#include
<mln/morpho/experimental/closing.hpp>
#include
<mln/morpho/experimental/dilation.hpp>
#include
<mln/morpho/experimental/erosion.hpp>
#include
<mln/morpho/experimental/hit_or_miss.hpp>
#include
<mln/morpho/experimental/opening.hpp>
#include
<fixtures/ImagePath/image_path.hpp>
#include
<benchmark/benchmark.h>
#include
<fixtures/ImagePath/image_path.hpp>
class
BM
Dilation
:
public
benchmark
::
Fixture
class
BM
Morpho
:
public
benchmark
::
Fixture
{
public:
BMDilation
()
using
image_t
=
mln
::
experimental
::
image2d
<
uint8_t
>
;
BMMorpho
()
{
mln
::
io
::
experimental
::
imread
(
fixtures
::
ImagePath
::
concat_with_filename
(
"lena.pgm"
),
m_input
);
if
(
!
g_loaded
)
{
const
char
*
filename
=
"Aerial_view_of_Olbia.jpg"
;
mln
::
experimental
::
image2d
<
mln
::
rgb8
>
input
;
mln
::
io
::
experimental
::
imread
(
filename
,
input
);
g_input
=
mln
::
transform
(
input
,
[](
mln
::
rgb8
x
)
->
uint8_t
{
return
x
[
0
];
});
g_loaded
=
true
;
}
m_input
=
g_input
;
int
nr
=
m_input
.
width
();
int
nc
=
m_input
.
height
();
mln
::
resize
(
m_output
,
m_input
);
...
...
@@ -25,19 +39,24 @@ public:
}
void
run
(
benchmark
::
State
&
st
,
std
::
function
<
void
()
>
callback
)
void
run
(
benchmark
::
State
&
st
,
std
::
function
<
void
(
const
image_t
&
input
,
image_t
&
output
)
>
callback
)
{
for
(
auto
_
:
st
)
callback
();
callback
(
m_input
,
m_output
);
st
.
SetBytesProcessed
(
int64_t
(
st
.
iterations
())
*
int64_t
(
m_size
));
}
protected:
mln
::
experimental
::
image2d
<
uint8_t
>
m_input
;
mln
::
experimental
::
image2d
<
uint8_t
>
m_output
;
std
::
size_t
m_size
;
static
bool
g_loaded
;
static
mln
::
experimental
::
image2d
<
uint8_t
>
g_input
;
mln
::
experimental
::
image2d
<
uint8_t
>
m_input
;
mln
::
experimental
::
image2d
<
uint8_t
>
m_output
;
std
::
size_t
m_size
;
};
bool
BMMorpho
::
g_loaded
=
false
;
mln
::
experimental
::
image2d
<
uint8_t
>
BMMorpho
::
g_input
;
class
slow_disc
:
public
mln
::
se_facade
<
slow_disc
>
{
using
Base
=
mln
::
experimental
::
se
::
disc
;
...
...
@@ -75,48 +94,81 @@ private:
};
BENCHMARK_DEFINE_F
(
BMDilation
,
EuclideanDisc_naive
)(
benchmark
::
State
&
st
)
BENCHMARK_DEFINE_F
(
BMMorpho
,
Dilation_EuclideanDisc_naive
)(
benchmark
::
State
&
st
)
{
int
radius
=
st
.
range
(
0
);
slow_disc
se
(
radius
,
mln
::
experimental
::
se
::
disc
::
EXACT
);
auto
f
=
[
&
](
)
{
mln
::
morpho
::
experimental
::
dilation
(
m_
input
,
se
,
m_
output
);
};
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
experimental
::
dilation
(
input
,
se
,
output
);
};
this
->
run
(
st
,
f
);
}
BENCHMARK_DEFINE_F
(
BMDilation
,
EuclideanDisc_incremental
)(
benchmark
::
State
&
st
)
BENCHMARK_DEFINE_F
(
BM
Morpho
,
Dilation
_
EuclideanDisc_incremental
)(
benchmark
::
State
&
st
)
{
int
radius
=
st
.
range
(
0
);
auto
se
=
mln
::
experimental
::
se
::
disc
(
radius
,
mln
::
experimental
::
se
::
disc
::
EXACT
);
auto
f
=
[
&
](
)
{
mln
::
morpho
::
experimental
::
dilation
(
m_
input
,
se
,
m_
output
);
};
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
experimental
::
dilation
(
input
,
se
,
output
);
};
this
->
run
(
st
,
f
);
}
BENCHMARK_DEFINE_F
(
BMDilation
,
ApproximatedDisc
)(
benchmark
::
State
&
st
)
BENCHMARK_DEFINE_F
(
BM
Morpho
,
Dilation
_
ApproximatedDisc
)(
benchmark
::
State
&
st
)
{
int
radius
=
st
.
range
(
0
);
auto
se
=
mln
::
experimental
::
se
::
disc
(
radius
,
mln
::
experimental
::
se
::
disc
::
PERIODIC_LINES_8
);
auto
f
=
[
&
](
)
{
mln
::
morpho
::
experimental
::
dilation
(
m_
input
,
se
,
m_
output
);
};
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
experimental
::
dilation
(
input
,
se
,
output
);
};
this
->
run
(
st
,
f
);
}
BENCHMARK_DEFINE_F
(
BMDilation
,
Square
)(
benchmark
::
State
&
st
)
BENCHMARK_DEFINE_F
(
BM
Morpho
,
Dilation
_
Square
)(
benchmark
::
State
&
st
)
{
int
radius
=
st
.
range
(
0
);
auto
se
=
mln
::
experimental
::
se
::
rect2d
(
2
*
radius
+
1
,
2
*
radius
+
1
);
auto
f
=
[
&
](
)
{
mln
::
morpho
::
experimental
::
dilation
(
m_
input
,
se
,
m_
output
);
};
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
experimental
::
dilation
(
input
,
se
,
output
);
};
this
->
run
(
st
,
f
);
}
constexpr
int
max_range
=
2
<<
6
;
constexpr
int
max_range
=
128
;
BENCHMARK_REGISTER_F
(
BMMorpho
,
Dilation_ApproximatedDisc
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
max_range
);
BENCHMARK_REGISTER_F
(
BMMorpho
,
Dilation_EuclideanDisc_naive
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
16
);
BENCHMARK_REGISTER_F
(
BMMorpho
,
Dilation_EuclideanDisc_incremental
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
max_range
);
BENCHMARK_REGISTER_F
(
BMMorpho
,
Dilation_Square
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
max_range
);
BENCHMARK_REGISTER_F
(
BMDilation
,
ApproximatedDisc
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
max_range
);
BENCHMARK_REGISTER_F
(
BMDilation
,
EuclideanDisc_naive
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
max_range
);
BENCHMARK_REGISTER_F
(
BMDilation
,
EuclideanDisc_incremental
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
max_range
);
BENCHMARK_REGISTER_F
(
BMDilation
,
Square
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
max_range
);
BENCHMARK_F
(
BMMorpho
,
Opening_Disc
)(
benchmark
::
State
&
st
)
{
int
radius
=
32
;
auto
se
=
mln
::
experimental
::
se
::
disc
(
radius
);
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
experimental
::
opening
(
input
,
se
,
output
);
};
this
->
run
(
st
,
f
);
}
BENCHMARK_F
(
BMMorpho
,
Hit_or_miss_corner
)(
benchmark
::
State
&
st
)
{
mln
::
se
::
experimental
::
mask2d
se_hit
=
{
{
0
,
0
,
0
,
0
,
0
},
{
0
,
0
,
0
,
0
,
0
},
{
0
,
0
,
1
,
1
,
1
},
{
0
,
0
,
1
,
1
,
1
},
{
0
,
0
,
1
,
1
,
1
},
};
mln
::
se
::
experimental
::
mask2d
se_miss
=
{
{
1
,
1
,
1
,
1
,
1
},
{
1
,
1
,
1
,
1
,
1
},
{
1
,
1
,
0
,
0
,
0
},
{
1
,
1
,
0
,
0
,
0
},
{
1
,
1
,
0
,
0
,
0
},
};
auto
f
=
[
se_hit
,
se_miss
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
experimental
::
hit_or_miss
(
input
,
se_hit
,
se_miss
,
output
);
};
this
->
run
(
st
,
f
);
}
BENCHMARK_MAIN
();
bench/BMMorphoBaseRef.cpp
0 → 100644
View file @
b5e6686b
#include
<mln/core/algorithm/transform.hpp>
#include
<mln/core/colors.hpp>
#include
<mln/core/image/experimental/ndimage.hpp>
#include
<mln/core/se/disc.hpp>
#include
<mln/core/se/rect2d.hpp>
#include
<mln/core/se/mask2d.hpp>
#include
<mln/io/experimental/imread.hpp>
#include
<mln/morpho/structural/closing.hpp>
#include
<mln/morpho/structural/dilate.hpp>
#include
<mln/morpho/structural/erode.hpp>
#include
<mln/morpho/hit_or_miss.hpp>
#include
<mln/morpho/structural/opening.hpp>
// [legacy]
#include
<mln/core/image/image2d.hpp>
#include
<benchmark/benchmark.h>
class
BMMorpho
:
public
benchmark
::
Fixture
{
public:
using
image_t
=
mln
::
image2d
<
uint8_t
>
;
BMMorpho
()
{
if
(
!
g_loaded
)
{
const
char
*
filename
=
"Aerial_view_of_Olbia.jpg"
;
mln
::
experimental
::
image2d
<
mln
::
rgb8
>
input
;
mln
::
io
::
experimental
::
imread
(
filename
,
input
);
g_input
=
mln
::
transform
(
input
,
[](
mln
::
rgb8
x
)
->
uint8_t
{
return
x
[
0
];
});
g_loaded
=
true
;
}
m_input
=
g_input
;
int
nr
=
m_input
.
width
();
int
nc
=
m_input
.
height
();
mln
::
resize
(
m_output
,
m_input
);
m_size
=
nr
*
nc
;
m_input
.
to
(
m_input_
,
false
);
m_output
.
to
(
m_output_
,
false
);
}
void
run
(
benchmark
::
State
&
st
,
std
::
function
<
void
(
const
image_t
&
input
,
image_t
&
output
)
>
callback
)
{
for
(
auto
_
:
st
)
callback
(
m_input_
,
m_output_
);
st
.
SetBytesProcessed
(
int64_t
(
st
.
iterations
())
*
int64_t
(
m_size
));
}
protected:
static
bool
g_loaded
;
static
mln
::
experimental
::
image2d
<
uint8_t
>
g_input
;
mln
::
experimental
::
image2d
<
uint8_t
>
m_input
;
mln
::
experimental
::
image2d
<
uint8_t
>
m_output
;
mln
::
image2d
<
uint8_t
>
m_input_
;
mln
::
image2d
<
uint8_t
>
m_output_
;
std
::
size_t
m_size
;
};
bool
BMMorpho
::
g_loaded
=
false
;
mln
::
experimental
::
image2d
<
uint8_t
>
BMMorpho
::
g_input
;
BENCHMARK_DEFINE_F
(
BMMorpho
,
Dilation_EuclideanDisc_incremental
)(
benchmark
::
State
&
st
)
{
int
radius
=
st
.
range
(
0
);
auto
se
=
mln
::
se
::
disc
(
radius
,
0
);
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
structural
::
dilate
(
input
,
se
,
output
,
mln
::
productorder_less
<
uint8_t
>
());
};
this
->
run
(
st
,
f
);
}
BENCHMARK_DEFINE_F
(
BMMorpho
,
Dilation_ApproximatedDisc
)(
benchmark
::
State
&
st
)
{
int
radius
=
st
.
range
(
0
);
auto
se
=
mln
::
se
::
disc
(
radius
,
8
);
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
structural
::
dilate
(
input
,
se
,
output
,
mln
::
productorder_less
<
uint8_t
>
());
};
this
->
run
(
st
,
f
);
}
BENCHMARK_DEFINE_F
(
BMMorpho
,
Dilation_Square
)(
benchmark
::
State
&
st
)
{
int
radius
=
st
.
range
(
0
);
auto
se
=
mln
::
se
::
rect2d
(
2
*
radius
+
1
,
2
*
radius
+
1
);
auto
f
=
[
se
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
structural
::
dilate
(
input
,
se
,
output
,
mln
::
productorder_less
<
uint8_t
>
());
};
this
->
run
(
st
,
f
);
}
constexpr
int
max_range
=
128
;
BENCHMARK_REGISTER_F
(
BMMorpho
,
Dilation_ApproximatedDisc
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
max_range
);
BENCHMARK_REGISTER_F
(
BMMorpho
,
Dilation_EuclideanDisc_incremental
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
max_range
);
BENCHMARK_REGISTER_F
(
BMMorpho
,
Dilation_Square
)
->
RangeMultiplier
(
2
)
->
Range
(
2
,
max_range
);
BENCHMARK_F
(
BMMorpho
,
Opening_Disc
)(
benchmark
::
State
&
st
)
{
int
radius
=
32
;
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
);
};
this
->
run
(
st
,
f
);
}
BENCHMARK_F
(
BMMorpho
,
Hit_or_miss_corner
)(
benchmark
::
State
&
st
)
{
mln
::
se
::
mask2d
se_hit
=
{
{
0
,
0
,
0
,
0
,
0
},
{
0
,
0
,
0
,
0
,
0
},
{
0
,
0
,
1
,
1
,
1
},
{
0
,
0
,
1
,
1
,
1
},
{
0
,
0
,
1
,
1
,
1
},
};
mln
::
se
::
mask2d
se_miss
=
{
{
1
,
1
,
1
,
1
,
1
},
{
1
,
1
,
1
,
1
,
1
},
{
1
,
1
,
0
,
0
,
0
},
{
1
,
1
,
0
,
0
,
0
},
{
1
,
1
,
0
,
0
,
0
},
};
auto
f
=
[
se_hit
,
se_miss
](
const
image_t
&
input
,
image_t
&
output
)
{
mln
::
morpho
::
hit_or_miss
(
input
,
se_hit
,
se_miss
,
output
);
};
this
->
run
(
st
,
f
);
}
BENCHMARK_MAIN
();
bench/CMakeLists.txt
View file @
b5e6686b
...
...
@@ -18,6 +18,7 @@ ExternalData_Expand_Arguments(
fetch-external-data
images
DATA{Space1_20MB.jpg}
DATA{Aerial_view_of_Olbia.jpg}
)
# Extra compiler options
...
...
@@ -65,7 +66,8 @@ set_source_files_properties(${src_standalone} PROPERTIES COMPILE_FLAGS ${STANDAL
add_benchmark
(
BMAlgorithms BMAlgorithms.cpp BMAlgorithms_main.cpp
)
add_benchmark
(
BMNeighborhood BMNeighborhood.cpp BMNeighborhood_main.cpp
)
add_benchmark
(
BMRotation BMRotation.cpp
)
add_benchmark
(
BMDilation BMDilation.cpp
)
add_benchmark
(
BMMorphoBase BMMorphoBase.cpp
)
add_benchmark
(
BMMorphoBaseRef BMMorphoBaseRef.cpp
)
add_benchmark
(
BMMorphers BMMorphers.cpp BMMorphers_main.cpp
)
add_benchmark
(
BMReference_Linear BMReference_Linear.cpp BMReference_Linear_Reversed.cpp BMReference_Linear_main.cpp
)
add_benchmark
(
BMReference_Neighborhood BMReference_Neighborhood_main.cpp
)
...
...
doc/source/morpho/closing.rst
View file @
b5e6686b
...
...
@@ -3,19 +3,13 @@ Closing
Include :file:`<mln/morpho/structural/closing.hpp>`
.. cpp:namespace:: mln::morpho
::structural
.. cpp:namespace:: mln::morpho
#. .. cpp:function:: \
template <class InputImage, class StructuringElement> \
concrete_t<InputImage> closing(const InputImage& ima, const StructuringElement& se)
#. .. cpp:function:: \
template <class InputImage, class StructuringElement, class Compare> \
concrete_t<InputImage> closing(const InputImage& ima, const StructuringElement& se, Compare cmp)
#. .. cpp:function:: \
template <class InputImage, class StructuringElement, class OutputImage, class Compare> \
void closing(const InputImage& ima, const StructuringElement& se, Compare cmp, OutputImage& output)
.. cpp:function:: \
Image{I} concrete_t<I> closing(I image, StructuringElement se)
Image{I} concrete_t<I> closing(I image, StructuringElement se, BorderManager bm)
void closing(Image image, StructuringElement se, OutputImage out)
void closing(Image image, StructuringElement se, BorderManager bm, OutputImage out)
Closing by a structuring element.
...
...
@@ -25,21 +19,20 @@ Include :file:`<mln/morpho/structural/closing.hpp>`
.. math::
\gamma(f) = \varepsilon_\mathcal{B}(\delta_\mathcal{B}(f))
* (2,3) If a optional \p cmp function is provided, the algorithm will internally do
an unqualified call to ``inf(x, y,cmp)``.The default is the product-order so
that it works for vectorial type as well.
* (3) If the optional ``output`` image is provided, it must be wide enough to store
the results (the function does not perform any resizing).
* An optional border management may be used to manage border side-effects.
Only *fill* and *user* are currently supported.
* If the optional ``output`` image is provided, it must be wide enough to store
the result (the function does not perform any resizing).
:param ima: Input image 𝑓
:param se: Structuring element 𝐵
:param
cmp
(optional):
Comparison function
:param
bm
(optional):
Border management policy
:param output (optional): Output image
:return:
* (1,2) An image whose type is deduced from the input image
* (3
\
) Nothing (the output image is passed as an argument)
* (3
,4
) Nothing (the output image is passed as an argument)
:exception: N/A
...
...
@@ -58,13 +51,13 @@ Example 1 : Closing by a square on a gray-level image
.. code-block:: cpp
#include <mln/morpho/
structural/
closing.hpp>
#include <mln/core/
wind
2d.hpp>
#include <mln/morpho/closing.hpp>
#include <mln/core/
se/rect
2d.hpp>
// Define a square SE of size 21x21
auto input = ...;
auto rect = mln::
make_rectangle
2d(21,21);
auto output = mln::morpho::
structural::
closing(input, rect);
auto rect = mln::
se::rect
2d(21,21);
auto output = mln::morpho::closing(input, rect);
.. image:: /images/lena_gray.jpg
...
...
doc/source/morpho/dilation.rst
View file @
b5e6686b
...
...
@@ -57,7 +57,7 @@ Example 1 : Dilation by a square on a gray-level image
.. code-block:: cpp
#include <mln/morpho/dilation.hpp>
#include <mln/core/
wind
2d.hpp>
#include <mln/core/
se/rect
2d.hpp>
// Define a square SE of size 21x21
auto input = ...;
...
...
doc/source/morpho/hit_or_miss.rst
View file @
b5e6686b
Hit or Miss
===========
#. .. cpp:function:: \
template <class InputImage, class StructuringElement1, class StructuringElement2> \
concrete_t<InputImage> hit_or_miss(const InputImage& ima, const StructuringElement1& se_hit, const StructuringElement1& se_miss)
#. .. cpp:function:: \
template <class InputImage, class StructuringElement1, class StructuringElement2, class OutputImage> \
void hit_or_miss(const InputImage& ima, const StructuringElement1& se_hit, const StructuringElement1& se_miss, OutputImage& output)
Include :file:`<mln/morpho/hit_or_miss.hpp>`
.. cpp:namespace:: mln::morpho
.. cpp:function:: \
Image{I} concrete_t<I> hit_or_miss(I image, StructuringElement se_hit, StructuringElement se_miss)
void hit_or_miss(Image image, StructuringElement se_hit, StructuringElement se_miss, OutputImage out)
The hit-or-miss transform is non-linerar filter used to detect pattern in
images. It is defined as:
...
...
doc/source/morpho/opening.rst
View file @
b5e6686b
...
...
@@ -3,19 +3,13 @@ Opening
Include :file:`<mln/morpho/structural/opening.hpp>`
.. cpp:namespace:: mln::morpho
::structural
.. cpp:namespace:: mln::morpho
#. .. cpp:function:: \
template <class InputImage, class StructuringElement> \
concrete_t<InputImage> opening(const InputImage& ima, const StructuringElement& se)
#. .. cpp:function:: \
template <class InputImage, class StructuringElement, class Compare> \
concrete_t<InputImage> opening(const InputImage& ima, const StructuringElement& se, Compare cmp)
#. .. cpp:function:: \
template <class InputImage, class StructuringElement, class OutputImage, class Compare> \
void opening(const InputImage& ima, const StructuringElement& se, Compare cmp, OutputImage& output)
.. cpp:function:: \
Image{I} concrete_t<I> opening(I image, StructuringElement se)
Image{I} concrete_t<I> opening(I image, StructuringElement se, BorderManager bm)
void opening(Image image, StructuringElement se, OutputImage out)
void opening(Image image, StructuringElement se, BorderManager bm, OutputImage out)
Opening by a structuring element.
...
...
@@ -25,22 +19,21 @@ Include :file:`<mln/morpho/structural/opening.hpp>`
.. math::
\gamma(f) = \delta_\mathcal{B}(\varepsilon_\mathcal{B}(f))
* (2,3) If a optional \p cmp function is provided, the algorithm will internally do
an unqualified call to ``inf(x, y,cmp)``.The default is the product-order so
that it works for vectorial type as well.
* (3) If the optional ``output`` image is provided, it must be wide enough to store
the results (the function does not perform any resizing).
* An optional border management may be used to manage border side-effects.
Only *fill* and *user* are currently supported.
* If the optional ``output`` image is provided, it must be wide enough to store
the result (the function does not perform any resizing).
:param ima: Input image 𝑓
:param se: Structuring element 𝐵
:param
cmp
(optional):
Comparison function
:param
bm
(optional):
Border management policy
:param output (optional): Output image
:return:
* (1,2) An image whose type is deduced from the input image
* (3
\
) Nothing (the output image is passed as an argument)
* (3
,4
) Nothing (the output image is passed as an argument)
:exception: N/A
...
...
@@ -58,13 +51,13 @@ Example 1 : Opening by a square on a gray-level image
.. code-block:: cpp
#include <mln/morpho/
structural/
opening.hpp>
#include <mln/core/
wind
2d.hpp>
#include <mln/morpho/opening.hpp>
#include <mln/core/
se/rect
2d.hpp>
// Define a square SE of size 21x21
auto input = ...;
auto rect = mln::
make_rectangle
2d(21,21);
auto output = mln::morpho::
structural::
opening(input, rect);
auto rect = mln::
se::rect
2d(21,21);
auto output = mln::morpho::opening(input, rect);
.. image:: /images/lena_gray.jpg
...
...
pylene/include/mln/core/canvas/local_accumulation.hpp
View file @
b5e6686b
...
...
@@ -3,6 +3,8 @@
#include
<mln/core/canvas/local_algorithm.hpp>
#include
<mln/core/box.hpp>
//#include <boost/container/small_vector.hpp>
namespace
mln
::
canvas
{
...
...
@@ -12,12 +14,15 @@ namespace mln::canvas
template
<
class
Accu
,
class
SE
,
class
I
,
class
J
>
class
LocalAccumulation
<
Accu
,
SE
,
I
,
J
,
false
>
:
public
LocalAlgorithm
<
SE
,
I
,
J
>
class
LocalAccumulation
<
Accu
,
SE
,
I
,
J
,
false
>
:
public
LocalAlgorithm
<
SE
,
I
,
J
,
LocalAccumulation
<
Accu
,
SE
,
I
,
J
,
false
>>
{
private:
using
ba
se_t
=
LocalA
lgorithm
<
SE
,
I
,
J
>
;
Accu
m_accu
;
using
se
lf
_t
=
LocalA
ccumulation
;
using
base_t
=
LocalAlgorithm
<
SE
,
I
,
J
,
self_t
>
;
Accu
m_accu
;
friend
base_t
;
public:
LocalAccumulation
(
Accu
accu
,
SE
se
,
I
&
f
,
J
&
g
)
...
...
@@ -42,14 +47,58 @@ namespace mln::canvas
{
m_accu
.
take
(
nval_i
);
}
public:
/*
void ExecuteWithIndexes()
{
mln_entering("LocalAlgorithm::Execute (Non-incremental)");
std::size_t se_size = ::ranges::size(this->m_se.offsets());
// Make a local copy to prevent aliasing
std::vector<std::ptrdiff_t> offsets(se_size);
std::vector<image_point_t<I>> dps(se_size);
{
std::size_t i = 0;
for (auto dp : this->m_se.offsets())
{
offsets[i] = this->m_i.delta_index(dp);
dps[i] = dp;
i++;
}
}
auto zz = ranges::view::zip(this->m_i.new_pixels(), this->m_j.new_pixels());
for (auto rows : ranges::rows(zz))
{
this->ExecuteAtLineStart();
for (auto [px_i, px_j] : rows)
{
this->EvalBeforeLocalLoop(px_i.val(), px_j.val());
for (size_t i = 0; i < se_size; ++i)
{
auto tmp = px_i; tmp.ishift(dps[i], offsets[i]);
this->EvalInLocalLoop(tmp.val(), px_i.val(), px_j.val());
}
this->EvalAfterLocalLoop(px_i.val(), px_j.val());
}
}
}
*/
};
template
<
class
Accu
,
class
SE
,
class
I
,
class
J
>
class
LocalAccumulation
<
Accu
,
SE
,
I
,
J
,
true
>
:
public
IncrementalLocalAlgorithm
<
SE
,
I
,
J
>
class
LocalAccumulation
<
Accu
,
SE
,
I
,
J
,
true
>
:
public
IncrementalLocalAlgorithm
<
SE
,
I
,
J
,
LocalAccumulation
<
Accu
,
SE
,
I
,
J
,
true
>>
{
private:
using
base_t
=
IncrementalLocalAlgorithm
<
SE
,
I
,
J
>
;
using
self_t
=
LocalAccumulation
;
using
base_t
=
IncrementalLocalAlgorithm
<
SE
,
I
,
J
,
LocalAccumulation
>
;
using
base_2_t
=
LocalAlgorithm
<
SE
,
I
,
J
,
LocalAccumulation
>
;
Accu
m_accu
;
public:
...
...
@@ -59,6 +108,8 @@ namespace mln::canvas
{
}
friend
base_t
;
friend
base_2_t
;