Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Perona–Malik anisotropic diffusion algorithm #500

Merged
merged 48 commits into from
Jan 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5a89ea3
Starting point
simmplecoder Jun 2, 2020
e9282ac
Working example version
simmplecoder Jun 2, 2020
0c9bec2
Stylistic changes
simmplecoder Jun 2, 2020
902fbb0
Reduce amount of warnings to zero
simmplecoder Jun 2, 2020
3fcffe3
Add rgb version and squash a bug
simmplecoder Jun 2, 2020
a27c941
Add docs
simmplecoder Jun 2, 2020
bb7d83a
Stylistical changes
simmplecoder Jun 5, 2020
dc278a4
More stylistical changes
simmplecoder Jun 5, 2020
f128ef8
Add missing include
simmplecoder Jun 5, 2020
0c486e8
Dealth with the direction enum
simmplecoder Jun 5, 2020
65ac151
All cases version
simmplecoder Jun 14, 2020
de22676
Modify example to show the properties
simmplecoder Jun 14, 2020
3b3f487
Improve documentation and static_assert
simmplecoder Jun 15, 2020
b135438
Add heat conservation test
simmplecoder Jun 15, 2020
b3a5540
Improve testing procedure, raise bar
simmplecoder Jun 15, 2020
38d7415
Add convergence to mean test
simmplecoder Jun 15, 2020
a5a8f09
4 way version
simmplecoder Jun 20, 2020
5991e21
Reduce warnings and fix bug
simmplecoder Jun 21, 2020
ce3bee4
Use transform
simmplecoder Jun 24, 2020
43bc160
Squash the damn accumulate bug
simmplecoder Jun 25, 2020
149b07d
Use 8 way nabla compute
simmplecoder Jun 25, 2020
4fe2470
Move to strategy
simmplecoder Jun 27, 2020
8628367
opencv strategy iteration
simmplecoder Jun 29, 2020
db8a326
Segment into function objects
simmplecoder Jul 5, 2020
4469ff2
Fix test
simmplecoder Jul 5, 2020
946a073
Fix distribution type bug
simmplecoder Jul 5, 2020
fcf118d
Fix distribution range
simmplecoder Jul 5, 2020
cf0ae18
Drastically decrease error threshold
simmplecoder Jul 5, 2020
1ce4264
Surround cout with ifdef
simmplecoder Jul 6, 2020
e6a6548
Matlab version
simmplecoder Jul 6, 2020
c6534fa
Add classic version
simmplecoder Jul 6, 2020
4fadad0
Add diffusivity tests
simmplecoder Jul 6, 2020
370d1b3
Add identity brightness tests
simmplecoder Jul 6, 2020
acb240b
Tested all brightness functions
simmplecoder Jul 6, 2020
cd03a9a
Add Jamfile entries
simmplecoder Jul 6, 2020
5939663
Failing laplace function tests
simmplecoder Jul 9, 2020
8c60cb4
Squash all of the bugs
simmplecoder Jul 10, 2020
abf7be7
Rename laplace stencils
simmplecoder Jul 10, 2020
6321b52
Add docs for laplace stencil indexing
simmplecoder Jul 10, 2020
8106bee
Use indexing and add offsets function
simmplecoder Jul 10, 2020
e82f2c2
Add only required stencil points
simmplecoder Jul 10, 2020
f8e382d
Add file prefix for Jamfile in tests
simmplecoder Jul 10, 2020
aaebbdb
Rename diffusivity to conductivity
simmplecoder Aug 6, 2020
b5434da
Rename _4way=>s4way and _8way=>s8way
simmplecoder Aug 6, 2020
c77ef2d
Capture this by value instead of local
simmplecoder Aug 6, 2020
b0f81f0
Add docs for Laplacian stencils
simmplecoder Aug 6, 2020
6c9b272
Use random_value from test_fixture.hpp
simmplecoder Aug 25, 2020
fbad958
Add range_min and max to random_value
simmplecoder Aug 25, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ project
local sources =
adaptive_threshold.cpp
affine.cpp
anisotropic_diffusion.cpp
convolution.cpp
convolve2d.cpp
dynamic_image.cpp
Expand Down
128 changes: 128 additions & 0 deletions example/anisotropic_diffusion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//
// Copyright 2020 Olzhas Zhumabek <anonymous.from.applecity@gmail.com>
//
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include <boost/gil/algorithm.hpp>
simmplecoder marked this conversation as resolved.
Show resolved Hide resolved
#include <boost/gil/extension/io/png.hpp>
#include <boost/gil/image.hpp>
#include <boost/gil/image_processing/diffusion.hpp>
#include <boost/gil/image_view.hpp>
#include <boost/gil/io/typedefs.hpp>
#include <boost/gil/typedefs.hpp>

#include <cmath>
#include <iostream>
#include <string>
#include <type_traits>

namespace gil = boost::gil;

void gray_version(std::string const& input_path, std::string const& output_path,
unsigned int iteration_count, float kappa)
{
gil::gray8_image_t input;
gil::read_image(input_path, input, gil::png_tag{});
auto input_view = gil::view(input);

gil::gray32f_image_t gray(input.dimensions());
auto gray_view = gil::view(gray);

gil::transform_pixels(input_view, gray_view, [](const gil::gray8_pixel_t& p) { return p[0]; });
double sum_before = 0;
gil::for_each_pixel(gray_view, [&sum_before](gil::gray32f_pixel_t p) { sum_before += p[0]; });
gil::gray32f_image_t output(gray.dimensions());
auto output_view = gil::view(output);

// gil::anisotropic_diffusion(gray_view, output_view, iteration_count, {kappa, delta_t});
gil::default_anisotropic_diffusion(gray_view, output_view, iteration_count, kappa);
double sum_after = 0;
gil::for_each_pixel(output_view, [&sum_after](gil::gray32f_pixel_t p) { sum_after += p[0]; });

gil::gray8_image_t true_output(output.dimensions());
gil::transform_pixels(output_view, gil::view(true_output),
[](gil::gray32f_pixel_t p) { return static_cast<gil::uint8_t>(p[0]); });

gil::write_view(output_path, gil::view(true_output), gil::png_tag{});

std::cout << "sum of intensity before diffusion: " << sum_before << '\n'
<< "sum of intensity after diffusion: " << sum_after << '\n'
<< "difference: " << sum_after - sum_before << '\n';
}

void rgb_version(const std::string& input_path, const std::string& output_path,
unsigned int iteration_count, float kappa)
{
gil::rgb8_image_t input;
gil::read_image(input_path, input, gil::png_tag{});
auto input_view = gil::view(input);

gil::rgb32f_image_t gray(input.dimensions());
auto gray_view = gil::view(gray);

gil::transform_pixels(input_view, gray_view, [](const gil::rgb8_pixel_t& p) {
return gil::rgb32f_pixel_t(p[0], p[1], p[2]);
});
double sum_before[3] = {};
gil::for_each_pixel(gray_view, [&sum_before](gil::rgb32f_pixel_t p) {
sum_before[0] += p[0];
sum_before[1] += p[1];
sum_before[2] += p[2];
});
gil::rgb32f_image_t output(gray.dimensions());
auto output_view = gil::view(output);

// gil::anisotropic_diffusion(gray_view, output_view, iteration_count, {kappa, delta_t});
gil::default_anisotropic_diffusion(gray_view, output_view, iteration_count, kappa);
double sum_after[3] = {};
gil::for_each_pixel(output_view, [&sum_after](gil::rgb32f_pixel_t p) {
sum_after[0] += p[0];
sum_after[1] += p[1];
sum_after[2] += p[2];
});

gil::rgb8_image_t true_output(output.dimensions());
gil::transform_pixels(output_view, gil::view(true_output), [](gil::rgb32f_pixel_t p) {
return gil::rgb8_pixel_t(static_cast<gil::uint8_t>(p[0]), static_cast<gil::uint8_t>(p[1]),
static_cast<gil::uint8_t>(p[2]));
});

gil::write_view(output_path, gil::view(true_output), gil::png_tag{});
std::cout << "sum of intensity before diffusion: (" << sum_before[0] << ", " << sum_before[1]
<< ", " << sum_before[2] << ")\n"
<< "sum of intensity after diffusion: (" << sum_after[0] << ", " << sum_after[1]
<< ", " << sum_after[2] << ")\n"
<< "difference: (" << sum_after[0] - sum_before[0] << ", "
<< sum_after[1] - sum_before[1] << ", " << sum_after[2] - sum_before[2] << ")\n";
}

int main(int argc, char* argv[])
{
if (argc != 6)
{
std::cerr << "usage: " << argv[0]
<< " <input.png> <output.png>"
" <colorspace: gray|rgb> <positive iteration count> <positive kappa~30>\n";
return -1;
}
std::string input_path = argv[1];
std::string output_path = argv[2];
std::string colorspace = argv[3];

unsigned int iteration_count = static_cast<unsigned int>(std::stoul(argv[4]));
float kappa = std::stof(argv[5]);
if (colorspace == "gray")
{
gray_version(input_path, output_path, iteration_count, kappa);
}
else if (colorspace == "rgb")
{
rgb_version(input_path, output_path, iteration_count, kappa);
}
else
{
std::cerr << "unknown colorspace option passed (did you type gray with A?)\n";
}
}
Loading