|
| 1 | +#include "convolution.h" |
| 2 | +#include <exception> |
| 3 | + |
| 4 | +Matrix convolve(const Matrix& image, const Matrix& kernel) { |
| 5 | + if (kernel.rows() % 2 != 1 || kernel.cols() % 2 != 1) { |
| 6 | + throw std::invalid_argument("Only odd dimensions on kernel supported"); |
| 7 | + } |
| 8 | + /* |
| 9 | + s_mid and t_mid are number of pixels between the center pixel |
| 10 | + and the edge, ie for a 5x5 filter they will be 2. |
| 11 | + |
| 12 | + The output size is calculated by adding s_mid, t_mid to each |
| 13 | + side of the dimensions of the input image. |
| 14 | + */ |
| 15 | + auto s_mid {kernel.rows()/2}; |
| 16 | + auto t_mid {kernel.cols()/2}; |
| 17 | + auto x_max {image.rows() + 2*s_mid}; |
| 18 | + auto y_max {image.cols() + 2*t_mid}; |
| 19 | + // Allocate result image. |
| 20 | + Matrix new_image(x_max, y_max); |
| 21 | + // Do convolution |
| 22 | + for (int x = 0; x < x_max; ++x) { |
| 23 | + for (int y = 0; y < y_max; ++y) { |
| 24 | + // Calculate pixel value for h at (x,y). Sum one component |
| 25 | + // for each pixel (s, t) of the filter kernel. |
| 26 | + auto s_from {std::max(s_mid - x, -s_mid)}; |
| 27 | + auto s_to {std::min((x_max - x) - s_mid, s_mid + 1)}; |
| 28 | + auto t_from {std::max(t_mid - y, -t_mid)}; |
| 29 | + auto t_to {std::min((y_max - y) - t_mid, t_mid + 1)}; |
| 30 | + double value {0.0}; |
| 31 | + for (int s = s_from; s < s_to; ++s) { |
| 32 | + for (int t = t_from; t < t_to; ++t) { |
| 33 | + auto v {x - s_mid + s}; |
| 34 | + auto w {y - t_mid + t}; |
| 35 | + value += kernel(s_mid - s, t_mid - t)*image(v, w); |
| 36 | + } |
| 37 | + } |
| 38 | + new_image(x, y) = value; |
| 39 | + } |
| 40 | + } |
| 41 | + return new_image; |
| 42 | +} |
0 commit comments