diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/gil/example/hessian.cpp | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/gil/example/hessian.cpp')
-rw-r--r-- | src/boost/libs/gil/example/hessian.cpp | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/src/boost/libs/gil/example/hessian.cpp b/src/boost/libs/gil/example/hessian.cpp new file mode 100644 index 00000000..d12f51dd --- /dev/null +++ b/src/boost/libs/gil/example/hessian.cpp @@ -0,0 +1,208 @@ +#include <boost/gil/image.hpp> +#include <boost/gil/image_view.hpp> +#include <boost/gil/image_processing/numeric.hpp> +#include <boost/gil/image_processing/hessian.hpp> +#include <boost/gil/extension/io/png.hpp> +#include <vector> +#include <functional> +#include <set> +#include <iostream> +#include <fstream> + +namespace gil = boost::gil; + +// some images might produce artifacts +// when converted to grayscale, +// which was previously observed on +// canny edge detector for test input +// used for this example. +// the algorithm here follows sRGB gamma definition +// taken from here (luminance calculation): +// https://en.wikipedia.org/wiki/Grayscale +gil::gray8_image_t to_grayscale(gil::rgb8_view_t original) +{ + gil::gray8_image_t output_image(original.dimensions()); + auto output = gil::view(output_image); + constexpr double max_channel_intensity = (std::numeric_limits<std::uint8_t>::max)(); + for (long int y = 0; y < original.height(); ++y) + { + for (long int x = 0; x < original.width(); ++x) + { + // scale the values into range [0, 1] and calculate linear intensity + auto& p = original(x, y); + double red_intensity = p.at(std::integral_constant<int, 0>{}) + / max_channel_intensity; + double green_intensity = p.at(std::integral_constant<int, 1>{}) + / max_channel_intensity; + double blue_intensity = p.at(std::integral_constant<int, 2>{}) + / max_channel_intensity; + auto linear_luminosity = 0.2126 * red_intensity + + 0.7152 * green_intensity + + 0.0722 * blue_intensity; + + // perform gamma adjustment + double gamma_compressed_luminosity = 0; + if (linear_luminosity < 0.0031308) + { + gamma_compressed_luminosity = linear_luminosity * 12.92; + } else + { + gamma_compressed_luminosity = 1.055 * std::pow(linear_luminosity, 1 / 2.4) - 0.055; + } + + // since now it is scaled, descale it back + output(x, y) = gamma_compressed_luminosity * max_channel_intensity; + } + } + + return output_image; +} + +void apply_gaussian_blur(gil::gray8_view_t input_view, gil::gray8_view_t output_view) +{ + constexpr static auto filter_height = 5ull; + constexpr static auto filter_width = 5ull; + constexpr static double filter[filter_height][filter_width] = + { + 2, 4, 6, 4, 2, + 4, 9, 12, 9, 4, + 5, 12, 15, 12, 5, + 4, 9, 12, 9, 4, + 2, 4, 5, 4, 2, + }; + constexpr double factor = 1.0 / 159; + constexpr double bias = 0.0; + + const auto height = input_view.height(); + const auto width = input_view.width(); + for (std::ptrdiff_t x = 0; x < width; ++x) + { + for (std::ptrdiff_t y = 0; y < height; ++y) + { + double intensity = 0.0; + for (std::ptrdiff_t filter_y = 0; filter_y < filter_height; ++filter_y) + { + for (std::ptrdiff_t filter_x = 0; filter_x < filter_width; ++filter_x) + { + int image_x = x - filter_width / 2 + filter_x; + int image_y = y - filter_height / 2 + filter_y; + if (image_x >= input_view.width() || image_x < 0 || + image_y >= input_view.height() || image_y < 0) + { + continue; + } + const auto& pixel = input_view(image_x, image_y); + intensity += pixel.at(std::integral_constant<int, 0>{}) + * filter[filter_y][filter_x]; + } + } + auto& pixel = output_view(gil::point_t(x, y)); + pixel = (std::min)((std::max)(int(factor * intensity + bias), 0), 255); + } + + } +} + +std::vector<gil::point_t> suppress( + gil::gray32f_view_t harris_response, + double harris_response_threshold) +{ + std::vector<gil::point_t> corner_points; + for (gil::gray32f_view_t::coord_t y = 1; y < harris_response.height() - 1; ++y) + { + for (gil::gray32f_view_t::coord_t x = 1; x < harris_response.width() - 1; ++x) + { + auto value = [](gil::gray32f_pixel_t pixel) { + return pixel.at(std::integral_constant<int, 0>{}); + }; + double values[9] = { + value(harris_response(x - 1, y - 1)), + value(harris_response(x, y - 1)), + value(harris_response(x + 1, y - 1)), + value(harris_response(x - 1, y)), + value(harris_response(x, y)), + value(harris_response(x + 1, y)), + value(harris_response(x - 1, y + 1)), + value(harris_response(x, y + 1)), + value(harris_response(x + 1, y + 1)) + }; + + auto maxima = *std::max_element( + values, + values + 9, + [](double lhs, double rhs) + { + return lhs < rhs; + } + ); + + if (maxima == value(harris_response(x, y)) + && std::count(values, values + 9, maxima) == 1 + && maxima >= harris_response_threshold) + { + corner_points.emplace_back(x, y); + } + } + } + + return corner_points; +} + +int main(int argc, char* argv[]) { + if (argc != 5) + { + std::cout << "usage: " << argv[0] << " <input.png> <odd-window-size>" + " <hessian-response-threshold> <output.png>\n"; + return -1; + } + + std::size_t window_size = std::stoul(argv[2]); + long hessian_determinant_threshold = std::stol(argv[3]); + + gil::rgb8_image_t input_image; + + gil::read_image(argv[1], input_image, gil::png_tag{}); + + auto input_view = gil::view(input_image); + auto grayscaled = to_grayscale(input_view); + gil::gray8_image_t smoothed_image(grayscaled.dimensions()); + auto smoothed = gil::view(smoothed_image); + apply_gaussian_blur(gil::view(grayscaled), smoothed); + gil::gray16s_image_t x_gradient_image(grayscaled.dimensions()); + gil::gray16s_image_t y_gradient_image(grayscaled.dimensions()); + + auto x_gradient = gil::view(x_gradient_image); + auto y_gradient = gil::view(y_gradient_image); + auto scharr_x = gil::generate_dx_scharr(); + gil::detail::convolve_2d(smoothed, scharr_x, x_gradient); + auto scharr_y = gil::generate_dy_scharr(); + gil::detail::convolve_2d(smoothed, scharr_y, y_gradient); + + gil::gray32f_image_t m11(x_gradient.dimensions()); + gil::gray32f_image_t m12_21(x_gradient.dimensions()); + gil::gray32f_image_t m22(x_gradient.dimensions()); + gil::compute_hessian_entries( + x_gradient, + y_gradient, + gil::view(m11), + gil::view(m12_21), + gil::view(m22) + ); + + gil::gray32f_image_t hessian_response(x_gradient.dimensions()); + auto gaussian_kernel = gil::generate_gaussian_kernel(window_size, 0.84089642); + gil::compute_hessian_responses( + gil::view(m11), + gil::view(m12_21), + gil::view(m22), + gaussian_kernel, + gil::view(hessian_response) + ); + + auto corner_points = suppress(gil::view(hessian_response), hessian_determinant_threshold); + for (auto point: corner_points) { + input_view(point) = gil::rgb8_pixel_t(0, 0, 0); + input_view(point).at(std::integral_constant<int, 1>{}) = 255; + } + gil::write_view(argv[4], input_view, gil::png_tag{}); +} |