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
01518ab1
Commit
01518ab1
authored
Dec 24, 2019
by
Edwin Carlinet
Browse files
Added vector impl of hierarchical queues + benchmark.
parent
9fcc818e
Pipeline
#15487
passed with stages
in 10 minutes and 51 seconds
Changes
13
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
bench/BMMorphoMaxtree.cpp
0 → 100644
View file @
01518ab1
#include <mln/core/algorithm/transform.hpp>
#include <mln/core/colors.hpp>
#include <mln/core/image/experimental/ndimage.hpp>
#include <mln/core/neighborhood/c4.hpp>
#include <mln/core/neighb2d.hpp>
#include <mln/io/experimental/imread.hpp>
#include <mln/morpho/experimental/maxtree.hpp>
#include <mln/morpho/maxtree/maxtree.hpp>
#include <benchmark/benchmark.h>
#include <fixtures/ImagePath/image_path.hpp>
class
BMMorpho
:
public
benchmark
::
Fixture
{
public:
using
image_t
=
mln
::
experimental
::
image2d
<
uint8_t
>
;
using
image_ref_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
)
>
callback
)
{
for
(
auto
_
:
st
)
callback
(
m_input
);
st
.
SetBytesProcessed
(
int64_t
(
st
.
iterations
())
*
int64_t
(
m_size
));
}
void
run2
(
benchmark
::
State
&
st
,
std
::
function
<
void
(
const
image_ref_t
&
input
)
>
callback
)
{
for
(
auto
_
:
st
)
callback
(
m_input_
);
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
;
std
::
size_t
m_size
;
mln
::
image2d
<
uint8_t
>
m_input_
;
mln
::
image2d
<
uint8_t
>
m_output_
;
};
bool
BMMorpho
::
g_loaded
=
false
;
mln
::
experimental
::
image2d
<
uint8_t
>
BMMorpho
::
g_input
;
BENCHMARK_F
(
BMMorpho
,
MaxtreeNew
)(
benchmark
::
State
&
st
)
{
auto
f
=
[](
const
image_t
&
input
)
{
mln
::
morpho
::
experimental
::
maxtree
(
input
,
mln
::
experimental
::
c4
);
};
this
->
run
(
st
,
f
);
}
BENCHMARK_F
(
BMMorpho
,
MaxtreeRef
)(
benchmark
::
State
&
st
)
{
auto
f
=
[](
const
image_ref_t
&
input
)
{
mln
::
morpho
::
maxtree_indexes
(
input
,
mln
::
c4
);
};
this
->
run2
(
st
,
f
);
}
BENCHMARK_MAIN
();
bench/CMakeLists.txt
View file @
01518ab1
...
...
@@ -66,6 +66,7 @@ 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
(
BMMorphoMaxtree BMMorphoMaxtree.cpp
)
add_benchmark
(
BMMorphoBase BMMorphoBase.cpp
)
add_benchmark
(
BMMorphers BMMorphers.cpp BMMorphers_main.cpp
)
add_benchmark
(
BMReference_Linear BMReference_Linear.cpp BMReference_Linear_Reversed.cpp BMReference_Linear_main.cpp
)
...
...
pylene/CMakeLists.txt
View file @
01518ab1
...
...
@@ -63,6 +63,7 @@ target_sources(Pylene PRIVATE
src/io/imprint.cpp
src/morpho/maxtree.cpp
src/morpho/component_tree.cpp
src/morpho/hvector.cpp
)
# Compiler configurations
...
...
pylene/include/mln/data/experimental/histogram.hpp
0 → 100644
View file @
01518ab1
#pragma once
#include <mln/core/algorithm/for_each.hpp>
#include <vector>
#include <concepts/concepts.hpp>
#include <range/v3/algorithm/fill.hpp>
#include <range/v3/view/span.hpp>
namespace
mln
::
data
::
experimental
{
template
<
class
I
,
class
OutputRng
>
[[
gnu
::
noinline
]]
void
histogram
(
I
image
,
OutputRng
histogram
);
template
<
class
I
>
[[
gnu
::
noinline
]]
std
::
vector
<
std
::
size_t
>
histogram
(
I
image
);
/******************************************/
/**** Implementation ****/
/******************************************/
namespace
impl
{
template
<
class
I
,
class
OutputRng
>
void
histogram
(
I
&&
image
,
OutputRng
hist
)
{
using
V
=
image_value_t
<
std
::
remove_reference_t
<
I
>>
;
static_assert
(
::
concepts
::
unsigned_integral
<
V
>
);
::
ranges
::
fill
(
hist
,
0
);
mln
::
for_each
(
std
::
forward
<
I
>
(
image
),
[
&
hist
](
int
x
)
{
hist
[
x
]
++
;
});
}
}
template
<
class
I
,
class
OutputRng
>
[[
gnu
::
noinline
]]
void
histogram
(
I
image
,
OutputRng
histogram
)
{
impl
::
histogram
(
image
,
histogram
);
}
template
<
class
I
>
[[
gnu
::
noinline
]]
std
::
vector
<
std
::
size_t
>
histogram
(
I
image
)
{
using
V
=
image_value_t
<
I
>
;
static_assert
(
::
concepts
::
unsigned_integral
<
V
>
);
std
::
vector
<
std
::
size_t
>
histogram
;
histogram
.
resize
(
std
::
numeric_limits
<
V
>::
max
()
+
1
);
impl
::
histogram
(
image
,
::
ranges
::
make_span
(
histogram
.
data
(),
histogram
.
size
()));
return
histogram
;
}
}
pylene/include/mln/morpho/experimental/canvas/depthfirst.hpp
View file @
01518ab1
...
...
@@ -34,7 +34,12 @@ namespace mln::morpho::experimental::canvas
template
<
class
I
,
class
N
,
class
DFVisitor
,
class
Proj
>
void
depthfirst
(
I
&
f
,
N
nbh
,
DFVisitor
&
viz
,
image_point_t
<
I
>
start
)
{
enum
st
{
NONE
=
0
,
INQUEUE
=
1
,
DONE
=
2
};
enum
st
{
NONE
=
0
,
INQUEUE
=
1
,
DONE
=
255
,
};
using
P
=
image_point_t
<
I
>
;
//using V = image_value_t<I>;
...
...
@@ -52,7 +57,8 @@ namespace mln::morpho::experimental::canvas
status
.
extension
().
fill
(
DONE
);
mln
::
morpho
::
experimental
::
details
::
pqueue_fifo
<
I
>
queue
(
f
);
constexpr
auto
impl_type
=
mln
::
morpho
::
experimental
::
details
::
pqueue_impl
::
vector
;
mln
::
morpho
::
experimental
::
details
::
pqueue_fifo
<
I
,
impl_type
>
queue
(
f
);
queue
.
push
(
f
(
start
),
start
);
status
(
start
)
=
INQUEUE
;
...
...
@@ -62,33 +68,39 @@ namespace mln::morpho::experimental::canvas
{
P
p
=
start
;
auto
current_level
=
f
(
start
);
int
pstatus
;
flood:
viz
.
on_flood_start
(
current_level
,
p
);
pstatus
=
0
;
keep_flooding:
for
(
auto
n
:
nbh
(
p
))
for
(
int
k
=
1
;
auto
n
:
nbh
(
p
))
{
if
(
status
.
at
(
n
)
!=
NONE
)
int
mask
=
1
<<
k
++
;
if
((
pstatus
&
mask
)
||
status
.
at
(
n
)
!=
NONE
)
continue
;
// Insert n INQUEUE
auto
nval
=
f
(
n
);
status
(
n
)
=
INQUEUE
;
queue
.
push
(
nval
,
n
);
pstatus
|=
mask
;
// If the neighbor is lower, postpone the neighbor
if
(
nval
<=
current_level
)
continue
;
// Otherwise, process it, (do not remove p from stack)
status
(
p
)
=
pstatus
;
current_level
=
nval
;
p
=
n
;
goto
flood
;
}
// All the neighbors have been seen, p is DONE
status
(
p
)
=
DONE
;
//
status(p) = DONE;
viz
.
on_done
(
current_level
,
p
);
queue
.
pop
();
...
...
@@ -99,6 +111,7 @@ namespace mln::morpho::experimental::canvas
{
auto
old_level
=
current_level
;
std
::
tie
(
current_level
,
p
)
=
queue
.
top
();
pstatus
=
status
(
p
);
if
(
current_level
==
old_level
)
goto
keep_flooding
;
viz
.
on_flood_end
(
old_level
,
current_level
);
...
...
pylene/include/mln/morpho/experimental/maxtree.hpp
View file @
01518ab1
...
...
@@ -14,6 +14,7 @@ namespace mln::morpho::experimental
{
template
<
class
I
,
class
N
>
[[
gnu
::
noinline
]]
//
std
::
pair
<
component_tree
<
image_value_t
<
I
>>
,
image_ch_value_t
<
I
,
component_tree
<>::
node_id_type
>>
//
maxtree
(
I
input
,
N
nbh
);
...
...
@@ -132,6 +133,7 @@ namespace mln::morpho::experimental
}
// namespace details
template
<
class
I
,
class
N
>
[[
gnu
::
noinline
]]
//
std
::
pair
<
component_tree
<
image_value_t
<
I
>>
,
image_ch_value_t
<
I
,
component_tree
<>::
node_id_type
>>
//
maxtree
(
I
input
,
N
nbh
)
{
...
...
pylene/include/mln/morpho/experimental/private/hlinked_lists.hpp
0 → 100644
View file @
01518ab1
#pragma once
#include <mln/core/concept/new/images.hpp>
#include <mln/core/assert.hpp>
namespace
mln
::
morpho
::
experimental
::
details
{
/// \brief Set of points ordered hierarchically into a list of points
///
/// \tparam N Number of levels
/// \tparam P Type of point
/// \tparam LinkImage Type of the link image
template
<
int
N
,
class
P
,
class
LinkImage
>
class
hlinked_lists
{
static_assert
(
N
<=
(
1
<<
24
),
"Too many numbers of level"
);
static_assert
(
std
::
is_convertible_v
<
P
,
image_point_t
<
LinkImage
>>
);
template
<
class
J
>
hlinked_lists
(
J
&&
f
);
void
push_front
(
int
level
,
P
p
)
noexcept
;
void
push_back
(
int
level
,
P
p
)
noexcept
;
P
pop_front
(
int
level
)
noexcept
;
P
back
(
int
level
)
const
noexcept
;
P
front
(
int
level
)
const
noexcept
;
bool
empty
(
int
level
)
const
noexcept
;
private:
struct
node_t
{
P
head
;
P
tail
;
int
size
=
0
;
};
std
::
array
<
node_t
,
N
>
m_lists
;
LinkImage
m_next
;
};
/******************************************/
/**** Implementation ****/
/******************************************/
template
<
int
N
,
class
P
,
class
LinkImage
>
template
<
class
J
>
inline
hlinked_lists
<
N
,
P
,
LinkImage
>::
hlinked_lists
(
J
&&
f
)
:
m_next
(
std
::
forward
<
J
>
(
f
),
image_build_params
{})
{
}
template
<
int
N
,
class
P
,
class
LinkImage
>
inline
bool
hlinked_lists
<
N
,
P
,
LinkImage
>::
empty
(
int
level
)
const
noexcept
{
mln_precondition
(
level
<
N
);
return
m_lists
[
level
].
size
==
0
;
}
template
<
int
N
,
class
P
,
class
LinkImage
>
inline
void
hlinked_lists
<
N
,
P
,
LinkImage
>::
push_front
(
int
level
,
P
p
)
noexcept
{
mln_precondition
(
level
<
N
);
if
(
m_lists
[
level
].
size
==
0
)
{
m_lists
[
level
].
head
=
p
;
m_lists
[
level
].
tail
=
p
;
}
else
{
m_next
(
p
)
=
m_lists
[
level
].
head
;
m_lists
[
level
].
head
=
p
;
}
m_lists
[
level
].
size
++
;
}
template
<
int
N
,
class
P
,
class
LinkImage
>
inline
void
hlinked_lists
<
N
,
P
,
LinkImage
>::
push_back
(
int
level
,
P
p
)
noexcept
{
mln_precondition
(
level
<
N
);
if
(
m_lists
[
level
].
size
==
0
)
{
m_lists
[
level
].
head
=
p
;
m_lists
[
level
].
tail
=
p
;
}
else
{
m_next
(
m_lists
[
level
].
tail
)
=
p
;
m_lists
[
level
].
tail
=
p
;
}
m_lists
[
level
].
size
++
;
}
template
<
int
N
,
class
P
,
class
LinkImage
>
inline
P
hlinked_lists
<
N
,
P
,
LinkImage
>::
pop_front
(
int
level
)
noexcept
{
mln_precondition
(
level
<
N
);
mln_precondition
(
m_lists
[
level
].
size
>
0
&&
"Empty list"
);
P
head
=
m_lists
[
level
].
head
;
m_lists
[
level
].
head
=
m_next
(
head
);
m_lists
[
level
].
size
--
;
return
head
;
}
template
<
int
N
,
class
P
,
class
LinkImage
>
inline
P
hlinked_lists
<
N
,
P
,
LinkImage
>::
front
(
int
level
)
const
noexcept
{
mln_precondition
(
level
<
N
);
mln_precondition
(
m_lists
[
level
].
size
>
0
&&
"Empty list"
);
return
m_lists
[
level
].
head
;
}
template
<
int
N
,
class
P
,
class
LinkImage
>
inline
P
hlinked_lists
<
N
,
P
,
LinkImage
>::
back
(
int
level
)
const
noexcept
{
mln_precondition
(
level
<
N
);
mln_precondition
(
m_lists
[
level
].
size
>
0
&&
"Empty list"
);
return
m_lists
[
level
].
tail
;
}
}
// namespace mln::morpho::experimental::detail
pylene/include/mln/morpho/experimental/private/hpqueue.hpp
View file @
01518ab1
#pragma once
#include <mln/morpho/experimental/private/h
vector
.hpp>
#include <mln/morpho/experimental/private/h
linked_lists
.hpp>
namespace
mln
::
morpho
::
experimental
::
detail
{
...
...
@@ -12,15 +12,15 @@ namespace mln::morpho::experimental::detail
/// \tparam N Number of levels
/// \tparam P Type of point
/// \tparam LinkImage Type of the link image
template
<
int
N
,
class
P
,
class
LinkImage
,
bool
reverse
>
class
hpqueue
:
private
hlinked_lists
<
N
,
P
,
LinkImage
>
template
<
int
N
,
class
P
,
class
Impl
,
bool
reverse
>
class
hpqueue
:
private
Impl
{
using
base
=
hlinked_lists
<
N
,
P
,
LinkImage
>
;
using
base
=
Impl
;
public:
template
<
class
J
>
hpqueue
(
J
&&
f
)
:
hlinked_lists
<
N
,
P
,
LinkImage
>
(
std
::
forward
<
J
>
(
f
))
:
base
(
std
::
forward
<
J
>
(
f
))
{
}
...
...
@@ -36,7 +36,10 @@ namespace mln::morpho::experimental::detail
m_current_level
=
std
::
max
(
m_current_level
,
level
);
}
// Push in first position at givel level
// Not supported by all implementation
/*
void push_first(int level, P p) noexcept
{
mln_precondition(0 <= level && level < N);
...
...
@@ -47,6 +50,7 @@ namespace mln::morpho::experimental::detail
else
m_current_level = std::max(m_current_level, level);
}
*/
bool
has_key
(
int
level
)
const
noexcept
{
return
!
base
::
empty
(
level
);
}
bool
empty
()
const
noexcept
{
return
base
::
empty
(
m_current_level
);
}
...
...
pylene/include/mln/morpho/experimental/private/hvector.hpp
View file @
01518ab1
#pragma once
#include <mln/core/assert.hpp>
#include <mln/core/concept/new/images.hpp>
#include <mln/data/experimental/histogram.hpp>
#include <algorithm>
#include <numeric>
#include <mln/core/assert.hpp>
namespace
mln
::
morpho
::
experimental
::
detail
namespace
mln
::
morpho
::
experimental
::
detail
s
{
/// \brief Set of points ordered hierarchically into a list of points
/// \brief Set of points ordered hierarchically into a list of points
(vector implemented)
///
/// \tparam N Number of levels
/// \tparam P Type of point
/// \tparam LinkImage Type of the link image
template
<
int
N
,
class
P
,
class
LinkImage
>
class
hlinked_lists
template
<
class
P
>
class
hvectors
;
/// \brief Base implementation
template
<
>
class
hvectors
<
void
>
{
static_assert
(
N
<=
(
1
<<
24
),
"Too many numbers of level"
);
static_assert
(
std
::
is_convertible_v
<
P
,
image_point_t
<
LinkImage
>>
);
public:
bool
empty
(
int
level
)
const
noexcept
;
protected:
/// \param count Number of elements in the histogram
/// \param size Size in bytes of an element
hvectors
()
=
default
;
~
hvectors
();
void
init
(
const
std
::
size_t
*
cumulated_histogram
,
std
::
size_t
count
,
std
::
size_t
size
);
struct
vector_t
{
void
*
begin
;
void
*
end
;
};
vector_t
*
m_lists
;
/* List of unitialized storage */
};
template
<
class
P
>
class
hvectors
:
public
hvectors
<
void
>
{
template
<
class
J
>
hlinked_lists
(
J
&&
f
);
hvectors
(
J
&&
f
);
~
hvectors
()
=
default
;
hvectors
(
const
hvectors
&
)
=
delete
;
hvectors
(
hvectors
&&
)
=
delete
;
hvectors
&
operator
=
(
const
hvectors
&
)
=
delete
;
hvectors
&
operator
=
(
hvectors
&&
)
=
delete
;
void
push_front
(
int
level
,
P
p
)
noexcept
;
void
push_back
(
int
level
,
P
p
)
noexcept
;
P
pop_back
(
int
level
)
noexcept
;
P
pop_front
(
int
level
)
noexcept
;
P
back
(
int
level
)
const
noexcept
;
P
front
(
int
level
)
const
noexcept
;
bool
empty
(
int
level
)
const
noexcept
;
}
;
private:
struct
node_t
{
P
head
;
P
tail
;
int
size
=
0
;
};
std
::
array
<
node_t
,
N
>
m_lists
;
LinkImage
m_next
;
};
/******************************************/
/**** Implementation ****/
/******************************************/
template
<
int
N
,
class
P
,
class
LinkImage
>
template
<
class
P
>
template
<
class
J
>
inline
hlinked_lists
<
N
,
P
,
LinkImage
>::
hlinked_lists
(
J
&&
f
)
:
m_next
(
std
::
forward
<
J
>
(
f
),
image_build_params
{})
inline
hvectors
<
P
>::
hvectors
(
J
&&
f
)
{
auto
hist
=
mln
::
data
::
experimental
::
histogram
(
std
::
forward
<
J
>
(
f
));
std
::
partial_sum
(
hist
.
begin
(),
hist
.
end
(),
hist
.
begin
());
this
->
init
(
hist
.
data
(),
hist
.
size
(),
sizeof
(
P
));
}
template
<
int
N
,
class
P
,
class
LinkImage
>
inline
bool
hlinked_lists
<
N
,
P
,
LinkImage
>::
empty
(
int
level
)
const
noexcept
inline
bool
hvectors
<
void
>::
empty
(
int
level
)
const
noexcept
{
mln_precondition
(
level
<
N
);
return
m_lists
[
level
].
size
==
0
;
return
m_lists
[
level
].
begin
==
m_lists
[
level
].
end
;
}
template
<
int
N
,
class
P
,
class
LinkImage
>
inline
void
h
linked_lists
<
N
,
P
,
LinkImage
>::
push_
front
(
int
level
,
P
p
)
noexcept
template
<
class
P
>
inline
void
h
vectors
<
P
>::
push_
back
(
int
level
,
P
p
)
noexcept
{
mln_precondition
(
level
<
N
);
if
(
m_lists
[
level
].
size
==
0
)
{
m_lists
[
level
].
head
=
p
;
m_lists
[
level
].
tail
=
p
;
}
else
{
m_next
(
p
)
=
m_lists
[
level
].
head
;
m_lists
[
level
].
head
=
p
;
}
m_lists
[
level
].
size
++
;
P
*&
end
=
reinterpret_cast
<
P
*&>
(
m_lists
[
level
].
end
);
new
((
void
*
)
end
++
)
P
(
p
);
}
template
<
int
N
,
class
P
,
class
LinkImage
>
inline
void
hlinked_lists
<
N
,
P
,
LinkImage
>::
push_back
(
int
level
,
P
p
)
noexcept
template
<
class
P
>
inline
P
hvectors
<
P
>::
pop_front
(
int
level
)
noexcept