Commit 7c86c7a1 authored by Edwin Carlinet's avatar Edwin Carlinet
Browse files

Merge branch 'development/next' of gitlab.lrde.epita.fr:olena/pylene into development/cpp20

parents 8e261b8c 5e281a21
Pipeline #14186 passed with stages
in 31 minutes and 2 seconds
......@@ -51,8 +51,6 @@ build-docker-automatic:
- cmake -G Ninja .. -DCMAKE_BUILD_TYPE=$PYLENE_CONFIGURATION -DPYLENE_CODE_COVERAGE=OFF -DSANITIZE_ADDRESS=$ASAN -DSANITIZE_MEMORY=$MSAN -DSANITIZE_UNDEFINED=$UBSAN $OTHER_CMAKE_ARGS
- cmake --build . --target build-fixtures --config $PYLENE_CONFIGURATION
- cmake --build . --target Pylene --config $PYLENE_CONFIGURATION
- cmake --build . --target build-apps --config $PYLENE_CONFIGURATION
- cmake --build . --target build-cli --config $PYLENE_CONFIGURATION
- cmake --build . --target build-tests --config $PYLENE_CONFIGURATION
- ctest -L UnitTests --schedule-random --output-on-failure
- cmake --build . --target dist --config $PYLENE_CONFIGURATION
......@@ -70,8 +68,6 @@ build-docker-automatic:
- cmake -G Ninja .. -DCMAKE_BUILD_TYPE=$PYLENE_CONFIGURATION -DPYLENE_CODE_COVERAGE=ON -DGCOV_PATH=$COV -DSANITIZE_ADDRESS=$ASAN -DSANITIZE_MEMORY=$MSAN -DSANITIZE_UNDEFINED=$UBSAN $OTHER_CMAKE_ARGS
- cmake --build . --target build-fixtures --config $PYLENE_CONFIGURATION
- cmake --build . --target Pylene --config $PYLENE_CONFIGURATION
- cmake --build . --target build-apps --config $PYLENE_CONFIGURATION
- cmake --build . --target build-cli --config $PYLENE_CONFIGURATION
- cmake --build . --target build-tests --config $PYLENE_CONFIGURATION
- ctest -L UnitTests --schedule-random --output-on-failure
- cmake --build . --target run-tests_coverage-gcovr-html --config $PYLENE_CONFIGURATION
......@@ -105,9 +101,9 @@ build-docker-automatic:
# MSAN: "OFF"
# UBSAN: "OFF"
# OTHER_CMAKE_ARGS: "-DCMAKE_CXX_EXTENSIONS=OFF" # This fixes a GCC ICE
# distcheck-linux-gcc8-debug-cov-asan-ubsan:
# <<: *distcheck-linux-coverage
#
# distcheck-linux-gcc8-debug:
# <<: *distcheck-linux-base
# image: ${FEDORA_29}
# variables:
# PYLENE_CONFIGURATION: "Debug"
......@@ -155,9 +151,9 @@ distcheck-linux-gcc9-debug-cov-asan-ubsan:
# MSAN: "OFF"
# UBSAN: "OFF"
# OTHER_CMAKE_ARGS: ""
# distcheck-linux-clang7-debug-cov-asan-ubsan:
# <<: *distcheck-linux-coverage
#
# distcheck-linux-clang7-debug:
# <<: *distcheck-linux-base
# image: ${FEDORA_29}
# variables:
# PYLENE_CONFIGURATION: "Debug"
......@@ -180,9 +176,9 @@ distcheck-linux-gcc9-debug-cov-asan-ubsan:
# MSAN: "OFF"
# UBSAN: "OFF"
# OTHER_CMAKE_ARGS: ""
# distcheck-linux-clang8-debug-cov-asan-ubsan:
# <<: *distcheck-linux-coverage
#
# distcheck-linux-clang8-debug:
# <<: *distcheck-linux-base
# image: ${FEDORA_30}
# variables:
# PYLENE_CONFIGURATION: "Debug"
......
......@@ -141,10 +141,6 @@ if (NOT PYLENE_BUILD_LIBS_ONLY)
add_custom_target(build-doc)
add_subdirectory(doc EXCLUDE_FROM_ALL)
add_custom_target(build-apps)
add_subdirectory(apps EXCLUDE_FROM_ALL)
add_custom_target(build-cli)
add_subdirectory(cli EXCLUDE_FROM_ALL)
endif ()
......
#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/core/neighb2d.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/dilate.hpp>
#include <mln/morpho/structural/erode.hpp>
#include <mln/morpho/structural/opening.hpp>
#include <mln/morpho/watershed.hpp>
#include <mln/labeling/local_extrema.hpp>
#include <mln/transform/chamfer_distance_transform.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::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 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);
}
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_F(BMMorpho, minima)(benchmark::State& st)
{
auto f = [](const image_t& input, image_t&) {
int nlabel;
mln::labeling::local_minima<int8_t>(input, mln::c4, nlabel);
return nlabel;
};
this->run(st, f);
}
BENCHMARK_F(BMMorpho, cdt_2_3)(benchmark::State& st)
{
auto f = [](const image_t& input, image_t&) {
auto tmp = mln::transform(input, [](uint8_t x) { return x < 128; });
auto out = mln::transforms::chamfer_distance_transform<int16_t>(tmp, mln::c8);
return out;
};
this->run(st, f);
}
BENCHMARK_F(BMMorpho, watershed)(benchmark::State& st)
{
auto f = [](const image_t& input, image_t&) {
int nlabel;
mln::morpho::watershed<int8_t>(input, mln::c4, nlabel);
return nlabel;
};
this->run(st, f);
}
BENCHMARK_MAIN();
......@@ -67,7 +67,6 @@ add_benchmark(BMAlgorithms BMAlgorithms.cpp BMAlgorithms_main.cpp)
add_benchmark(BMNeighborhood BMNeighborhood.cpp BMNeighborhood_main.cpp)
add_benchmark(BMRotation BMRotation.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)
......
add_executable(area_close area_close.cpp)
add_executable(closing_by_reconstruction closing_by_reconstruction.cpp)
add_executable(dilate-cli dilate.cpp)
add_executable(leveling leveling.cpp)
add_executable(area_fast_close area_fast_close.cpp)
# add_executable(grain_filter grain_filter.cpp)
add_executable(decompose_channels decompose_channels.cpp)
add_executable(recompose_channels recompose_channels.cpp)
add_executable(rgb2lab rgb2lab.cpp)
add_executable(lab2rgb lab2rgb.cpp)
set_target_properties(dilate-cli PROPERTIES OUTPUT_NAME dilate)
target_link_libraries(area_close ${FreeImage_LIBRARIES} Pylene::Pylene)
target_link_libraries(area_fast_close ${FreeImage_LIBRARIES} Pylene::Pylene)
target_link_libraries(decompose_channels ${FreeImage_LIBRARIES} Pylene::Pylene)
target_link_libraries(recompose_channels ${FreeImage_LIBRARIES} Pylene::Pylene)
# target_link_libraries(grain_filter ${FreeImage_LIBRARIES} Pylene::Pylene)
target_link_libraries(closing_by_reconstruction ${FreeImage_LIBRARIES} Pylene::Pylene)
target_link_libraries(dilate-cli ${FreeImage_LIBRARIES} Pylene::Pylene)
target_link_libraries(leveling ${FreeImage_LIBRARIES} Pylene::Pylene)
target_link_libraries(rgb2lab ${FreeImage_LIBRARIES} Pylene::Pylene)
target_link_libraries(lab2rgb ${FreeImage_LIBRARIES} Pylene::Pylene)
add_dependencies(build-cli area_close closing_by_reconstruction dilate-cli leveling
area_fast_close decompose_channels recompose_channels rgb2lab lab2rgb)
#include <mln/core/image/image2d.hpp>
#include <mln/core/neighb2d.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <mln/accu/accumulators/count.hpp>
#include <mln/morpho/component_tree/accumulate.hpp>
#include <mln/morpho/component_tree/filtering.hpp>
#include <mln/morpho/component_tree/reconstruction.hpp>
#include <mln/morpho/maxtree/maxtree.hpp>
#include <iostream>
#include <mln/io/imprint.hpp>
int main(int argc, char** argv)
{
using namespace mln;
if (argc < 5)
{
std::cerr << "Usage: " << argv[0] << " input(gray) connectivity lambda output(gray)" << std::endl
<< "connectivity: 4 / 8" << std::endl;
std::exit(1);
}
image2d<uint8> ima;
io::imread(argv[1], ima);
typedef image2d<uint8>::size_type size_type;
morpho::component_tree<size_type, image2d<size_type>> tree;
if (argv[2][0] == '4')
tree = morpho::maxtree_indexes(ima, c4, std::greater<uint8>());
else
tree = morpho::maxtree_indexes(ima, c8, std::greater<uint8>());
auto areamap = morpho::paccumulate(tree, ima, accu::features::count<>());
unsigned lambda = std::atoi(argv[3]);
auto criterion =
make_functional_property_map<size_type>([&areamap, lambda](size_type x) { return areamap[x] >= lambda; });
morpho::filter_direct_inplace(tree, criterion);
auto valuemap = morpho::make_attribute_map_from_image(tree, ima);
image2d<uint8> out;
resize(out, ima);
morpho::reconstruction(tree, valuemap, out);
io::imsave(out, argv[4]);
}
#include <mln/core/image/image2d.hpp>
#include <mln/core/neighb2d.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <iostream>
#include <mln/core/algorithm/transform.hpp>
#include <mln/morpho/algebraic_filter.hpp>
int main(int argc, char** argv)
{
using namespace mln;
if (argc < 5)
{
std::cerr << "Usage: " << argv[0] << " input(gray) connectivity lambda output(gray)" << std::endl
<< "connectivity: 4 / 8" << std::endl;
std::exit(1);
}
image2d<uint8> ima;
io::imread(argv[1], ima);
image2d<uint8> out;
unsigned lambda = std::atoi(argv[3]);
if (argv[2][0] == '4')
out = morpho::area_closing(ima, c4, lambda);
else
out = morpho::area_closing(ima, c8, lambda);
io::imsave(out, argv[4]);
}
#include <mln/core/image/image2d.hpp>
#include <mln/core/neighb2d.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <mln/morpho/closing_by_reconstruction.hpp>
#include <iostream>
int main(int argc, char** argv)
{
using namespace mln;
if (argc < 5)
{
std::cerr << "Usage: " << argv[0] << " input(gray) markers(gray) connectivity output(gray)" << std::endl
<< "connectivity: 4 / 8" << std::endl;
std::exit(1);
}
image2d<uint8> ima;
image2d<uint8> markers;
image2d<uint8> out;
io::imread(argv[1], ima);
io::imread(argv[2], markers);
if (argv[3][0] == '4')
out = morpho::closing_by_reconstruction(ima, markers, c4);
else
out = morpho::closing_by_reconstruction(ima, markers, c8);
io::imsave(out, argv[4]);
}
#include <boost/format.hpp>
#include <mln/colors/rgba.hpp>
#include <mln/core/colors.hpp>
#include <mln/core/image/image2d.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
int main(int argc, char** argv)
{
if (argc != 3)
{
std::cerr << "Usage: " << argv[0]
<< " input.ppm out.tiff\n"
"Decompose a color image intro individual channel out-0.tiff out-1.tiff out-2.tiff...\n";
std::exit(1);
}
using namespace mln;
std::string oname = argv[2];
int pos = oname.rfind('.');
std::string fmt = oname.substr(0, pos) + "-%i" + oname.substr(pos);
try
{
image2d<colors::rgba8> f;
io::imread(argv[1], f);
for (int i = 0; i < 4; ++i)
io::imsave(channel(f, i), (boost::format(fmt) % i).str());
}
catch (...)
{
image2d<rgb8> f;
io::imread(argv[1], f);
for (int i = 0; i < 3; ++i)
io::imsave(channel(f, i), (boost::format(fmt) % i).str());
}
}
#include <mln/core/image/image2d.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <iostream>
#include <mln/core/se/disc.hpp>
#include <mln/core/win2d.hpp>
#include <mln/morpho/structural/dilate.hpp>
int main(int argc, char** argv)
{
using namespace mln;
if (argc < 4)
{
std::cerr << "Usage: " << argv[0] << " input ball_radius output(gray)" << std::endl;
std::exit(1);
}
image2d<uint8> ima;
io::imread(argv[1], ima);
int radius = std::atoi(argv[2]);
auto w = se::disc(radius + 0.3f);
image2d<uint8> out = morpho::structural::dilate(ima, w);
io::imsave(out, argv[3]);
}
#include <mln/core/image/image2d.hpp>
#include <mln/core/neighb2d.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <mln/accu/accumulators/accu_if.hpp>
#include <mln/accu/accumulators/count.hpp>
#include <mln/morpho/component_tree/accumulate.hpp>
#include <mln/morpho/component_tree/filtering.hpp>
#include <mln/morpho/component_tree/reconstruction.hpp>
#include <mln/morpho/tos/tos.hpp>
#include <apps/tos/Kinterpolate.hpp>
#include <apps/tos/addborder.hpp>
#include <apps/tos/topology.hpp>
#include <iostream>
int main(int argc, char** argv)
{
using namespace mln;
if (argc < 4)
{
std::cerr << "Usage: " << argv[0] << " input(gray) lambda output(gray)" << std::endl;
std::exit(1);
}
image2d<uint8> f;
io::imread(argv[1], f);
image2d<uint8> ima = addborder(f);
image2d<uint8> Ima = immerse_k1(ima);
typedef image2d<uint8>::size_type size_type;
typedef morpho::component_tree<size_type, image2d<size_type>> tree_t;
tree_t tree;
tree = morpho::cToS(ima, c4);
// tree._reorder_pset();
auto isface2 = [](const point2d& p) { return K1::is_face_2(p); };
typedef accu::accumulators::accu_if<accu::accumulators::count<>, decltype(isface2), point2d> ACC;
ACC accu(accu::accumulators::count<>(), isface2);
auto areamap = morpho::paccumulate(tree, Ima, accu, false);
unsigned lambda = std::atoi(argv[2]);
auto criterion = make_functional_property_map<tree_t::node_type>(
[&areamap, lambda](tree_t::node_type x) { return areamap[x] >= lambda; });
image2d<uint8> out;
resize(out, tree._get_data()->m_pmap);
auto valuemap = morpho::make_attribute_map_from_image(tree, Ima);
morpho::filter_direct_and_reconstruct(tree, criterion, valuemap, out);
// {
// morpho::filter_min_inplace(tree, criterion);
// morpho::reconstruction(tree, valuemap, out);
// }
image2d<uint8> res;
resize(res, f);
copy(out | sbox2d{out.domain().pmin + point2d{2, 2}, out.domain().pmax - point2d{2, 2}, point2d{2, 2}}, res);
io::imsave(res, argv[3]);
}
#include <mln/colors/lab.hpp>
#include <mln/core/algorithm/transform.hpp>
#include <mln/core/colors.hpp>
#include <mln/core/image/image2d.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
int main(int argc, char** argv)
{
if (argc != 3)
{
std::cerr << "Usage: " << argv[0]
<< " input.ppm out.tiff\n"
"Convert a 8-bit Lab* image ot a 8-bit RGB image (inverse of rgb2lab)\n";
std::exit(1);
}
using namespace mln;
image2d<rgb8> f;
io::imread(argv[1], f);
auto h = transform(f, [](rgb8 x) -> rgb8 {
lab<float> v = {x[0] * 100.0f / 256.0f, x[1] * 220.0f / 256.0f - 110.0f, x[2] * 220.0f / 256.0f - 110.0f};
return lab2rgb<uint8>(v);
});
io::imsave(h, argv[2]);
}
#include <mln/core/image/image2d.hpp>
#include <mln/core/neighb2d.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <mln/morpho/closing_by_reconstruction.hpp>
#include <iostream>
int main(int argc, char** argv)
{
using namespace mln;
if (argc < 5)
{
std::cerr << "Usage: " << argv[0] << " input(gray) markers(gray) connectivity output(gray)" << std::endl
<< "connectivity: 4 / 8" << std::endl;
std::exit(1);