Boost GIL


numeric.hpp
1 //
2 // Copyright 2019 Olzhas Zhumabek <anonymous.from.applecity@gmail.com>
3 // Copyright 2021 Pranam Lashkari <plashkari628@gmail.com>
4 //
5 // Use, modification and distribution are subject to the Boost Software License,
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 #ifndef BOOST_GIL_IMAGE_PROCESSING_NUMERIC_HPP
10 #define BOOST_GIL_IMAGE_PROCESSING_NUMERIC_HPP
11 
12 #include <boost/gil/image_processing/kernel.hpp>
13 #include <boost/gil/image_processing/convolve.hpp>
14 #include <boost/gil/image_view.hpp>
15 #include <boost/gil/typedefs.hpp>
16 #include <boost/gil/detail/math.hpp>
17 // fixes ambigious call to std::abs, https://stackoverflow.com/a/30084734/4593721
18 #include <cstdlib>
19 #include <cmath>
20 
21 namespace boost { namespace gil {
22 
34 inline double normalized_sinc(double x)
35 {
36  return std::sin(x * boost::gil::detail::pi) / (x * boost::gil::detail::pi);
37 }
38 
46 inline double lanczos(double x, std::ptrdiff_t a)
47 {
48  // means == but <= avoids compiler warning
49  if (0 <= x && x <= 0)
50  return 1;
51 
52  if (static_cast<double>(-a) < x && x < static_cast<double>(a))
53  return normalized_sinc(x) / normalized_sinc(x / static_cast<double>(a));
54 
55  return 0;
56 }
57 
58 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
59 #pragma warning(push)
60 #pragma warning(disable:4244) // 'argument': conversion from 'const Channel' to 'BaseChannelValue', possible loss of data
61 #endif
62 
63 inline void compute_tensor_entries(
64  boost::gil::gray16s_view_t dx,
65  boost::gil::gray16s_view_t dy,
66  boost::gil::gray32f_view_t m11,
67  boost::gil::gray32f_view_t m12_21,
68  boost::gil::gray32f_view_t m22)
69 {
70  for (std::ptrdiff_t y = 0; y < dx.height(); ++y) {
71  for (std::ptrdiff_t x = 0; x < dx.width(); ++x) {
72  auto dx_value = dx(x, y);
73  auto dy_value = dy(x, y);
74  m11(x, y) = dx_value * dx_value;
75  m12_21(x, y) = dx_value * dy_value;
76  m22(x, y) = dy_value * dy_value;
77  }
78  }
79 }
80 
81 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
82 #pragma warning(pop)
83 #endif
84 
91 template <typename T = float, typename Allocator = std::allocator<T>>
93 {
94  if (side_length % 2 != 1)
95  throw std::invalid_argument("kernel dimensions should be odd and equal");
96  const float entry = 1.0f / static_cast<float>(side_length * side_length);
97 
98  detail::kernel_2d<T, Allocator> result(side_length, side_length / 2, side_length / 2);
99  for (auto& cell: result) {
100  cell = entry;
101  }
102 
103  return result;
104 }
105 
110 template <typename T = float, typename Allocator = std::allocator<T>>
112 {
113  if (side_length % 2 != 1)
114  throw std::invalid_argument("kernel dimensions should be odd and equal");
115 
116  detail::kernel_2d<T, Allocator> result(side_length, side_length / 2, side_length / 2);
117  for (auto& cell: result) {
118  cell = 1.0f;
119  }
120 
121  return result;
122 }
123 
129 template <typename T = float, typename Allocator = std::allocator<T>>
130 inline detail::kernel_2d<T, Allocator> generate_gaussian_kernel(std::size_t side_length, double sigma)
131 {
132  if (side_length % 2 != 1)
133  throw std::invalid_argument("kernel dimensions should be odd and equal");
134 
135 
136  const double denominator = 2 * boost::gil::detail::pi * sigma * sigma;
137  auto middle = side_length / 2;
138  std::vector<T, Allocator> values(side_length * side_length);
139  for (std::size_t y = 0; y < side_length; ++y)
140  {
141  for (std::size_t x = 0; x < side_length; ++x)
142  {
143  const auto delta_x = middle > x ? middle - x : x - middle;
144  const auto delta_y = middle > y ? middle - y : y - middle;
145  const double power = (delta_x * delta_x + delta_y * delta_y) / (2 * sigma * sigma);
146  const double nominator = std::exp(-power);
147  const float value = static_cast<float>(nominator / denominator);
148  values[y * side_length + x] = value;
149  }
150  }
151 
152  return detail::kernel_2d<T, Allocator>(values.begin(), values.size(), middle, middle);
153 }
154 
162 template <typename T = float, typename Allocator = std::allocator<T>>
163 inline detail::kernel_2d<T, Allocator> generate_dx_sobel(unsigned int degree = 1)
164 {
165  switch (degree)
166  {
167  case 0:
168  {
169  return detail::get_identity_kernel<T, Allocator>();
170  }
171  case 1:
172  {
173  detail::kernel_2d<T, Allocator> result(3, 1, 1);
174  std::copy(detail::dx_sobel.begin(), detail::dx_sobel.end(), result.begin());
175  return result;
176  }
177  default:
178  throw std::logic_error("not supported yet");
179  }
180 
181  //to not upset compiler
182  throw std::runtime_error("unreachable statement");
183 }
184 
192 template <typename T = float, typename Allocator = std::allocator<T>>
194 {
195  switch (degree)
196  {
197  case 0:
198  {
199  return detail::get_identity_kernel<T, Allocator>();
200  }
201  case 1:
202  {
203  detail::kernel_2d<T, Allocator> result(3, 1, 1);
204  std::copy(detail::dx_scharr.begin(), detail::dx_scharr.end(), result.begin());
205  return result;
206  }
207  default:
208  throw std::logic_error("not supported yet");
209  }
210 
211  //to not upset compiler
212  throw std::runtime_error("unreachable statement");
213 }
214 
222 template <typename T = float, typename Allocator = std::allocator<T>>
223 inline detail::kernel_2d<T, Allocator> generate_dy_sobel(unsigned int degree = 1)
224 {
225  switch (degree)
226  {
227  case 0:
228  {
229  return detail::get_identity_kernel<T, Allocator>();
230  }
231  case 1:
232  {
233  detail::kernel_2d<T, Allocator> result(3, 1, 1);
234  std::copy(detail::dy_sobel.begin(), detail::dy_sobel.end(), result.begin());
235  return result;
236  }
237  default:
238  throw std::logic_error("not supported yet");
239  }
240 
241  //to not upset compiler
242  throw std::runtime_error("unreachable statement");
243 }
244 
252 template <typename T = float, typename Allocator = std::allocator<T>>
254 {
255  switch (degree)
256  {
257  case 0:
258  {
259  return detail::get_identity_kernel<T, Allocator>();
260  }
261  case 1:
262  {
263  detail::kernel_2d<T, Allocator> result(3, 1, 1);
264  std::copy(detail::dy_scharr.begin(), detail::dy_scharr.end(), result.begin());
265  return result;
266  }
267  default:
268  throw std::logic_error("not supported yet");
269  }
270 
271  //to not upset compiler
272  throw std::runtime_error("unreachable statement");
273 }
274 
284 template <typename GradientView, typename OutputView>
286  GradientView dx,
287  GradientView dy,
288  OutputView ddxx,
289  OutputView dxdy,
290  OutputView ddyy)
291 {
292  auto sobel_x = generate_dx_sobel();
293  auto sobel_y = generate_dy_sobel();
294  detail::convolve_2d(dx, sobel_x, ddxx);
295  detail::convolve_2d(dx, sobel_y, dxdy);
296  detail::convolve_2d(dy, sobel_y, ddyy);
297 }
298 
299 }} // namespace boost::gil
300 
301 #endif
boost::gil::generate_dy_sobel
detail::kernel_2d< T, Allocator > generate_dy_sobel(unsigned int degree=1)
Generates Sobel operator in vertical direction.
Definition: numeric.hpp:223
std::copy
BOOST_FORCEINLINE auto copy(boost::gil::pixel< T, CS > *first, boost::gil::pixel< T, CS > *last, boost::gil::pixel< T, CS > *dst) -> boost::gil::pixel< T, CS > *
Copy when both src and dst are interleaved and of the same type can be just memmove.
Definition: algorithm.hpp:145
boost::gil::generate_dx_scharr
detail::kernel_2d< T, Allocator > generate_dx_scharr(unsigned int degree=1)
Generate Scharr operator in horizontal direction.
Definition: numeric.hpp:193
boost::gil::generate_unnormalized_mean
detail::kernel_2d< T, Allocator > generate_unnormalized_mean(std::size_t side_length)
Generate kernel with all 1s.
Definition: numeric.hpp:111
boost::gil::compute_hessian_entries
void compute_hessian_entries(GradientView dx, GradientView dy, OutputView ddxx, OutputView dxdy, OutputView ddyy)
Compute xy gradient, and second order x and y gradients.
Definition: numeric.hpp:285
boost::gil::generate_normalized_mean
detail::kernel_2d< T, Allocator > generate_normalized_mean(std::size_t side_length)
Generate mean kernel.
Definition: numeric.hpp:92
boost::gil::generate_gaussian_kernel
detail::kernel_2d< T, Allocator > generate_gaussian_kernel(std::size_t side_length, double sigma)
Generate Gaussian kernel.
Definition: numeric.hpp:130
boost::gil::generate_dx_sobel
detail::kernel_2d< T, Allocator > generate_dx_sobel(unsigned int degree=1)
Generates Sobel operator in horizontal direction.
Definition: numeric.hpp:163
boost::gil::detail::kernel_2d
variable-size kernel
Definition: kernel.hpp:272
boost::gil::generate_dy_scharr
detail::kernel_2d< T, Allocator > generate_dy_scharr(unsigned int degree=1)
Generate Scharr operator in vertical direction.
Definition: numeric.hpp:253
boost::gil::lanczos
double lanczos(double x, std::ptrdiff_t a)
Lanczos response at point x.
Definition: numeric.hpp:46