This is a follow-up question for im2double and im2uint8 Functions Implementation for Image in C++, conv2 Template Function Implementation for Image in C++ and An Updated Multi-dimensional Image Data Structure with Variadic Template Functions in C++. I am trying to implement imgaussfilt
template function like Matlab's imgaussfilt to perform Gaussian blur in this post.
The experimental implementation
imgaussfilt
template function implementation (in fileimage_operations.h
)namespace TinyDIP { // imgaussfilt template function implementation template<typename ElementT> constexpr static auto imgaussfilt(const Image<ElementT>& input, double sigma = 0.5, bool is_size_same = true) { if (input.getDimensionality()!=2) { throw std::runtime_error("Unsupported dimension!"); } return imgaussfilt(input, sigma, static_cast<int>(2 * std::ceil(2 * sigma) + 1), is_size_same); } // imgaussfilt template function implementation template<typename ElementT, typename SigmaT = double, std::integral SizeT = int> requires(std::floating_point<SigmaT> || std::integral<SigmaT>) constexpr static auto imgaussfilt(const Image<ElementT>& input, SigmaT sigma, SizeT filter_size, bool is_size_same = true) { if (input.getDimensionality()!=2) { throw std::runtime_error("Unsupported dimension!"); } return imgaussfilt(input, sigma, sigma, filter_size, is_size_same); } // imgaussfilt template function implementation template<typename ElementT, typename SigmaT = double, std::integral SizeT = int> requires(std::floating_point<SigmaT> || std::integral<SigmaT>) constexpr static auto imgaussfilt(const Image<ElementT>& input, SigmaT sigma1, SigmaT sigma2, SizeT filter_size, bool is_size_same = true) { if (input.getDimensionality()!=2) { throw std::runtime_error("Unsupported dimension!"); } auto filter_mask = gaussianFigure2D( filter_size, filter_size, (static_cast<double>(filter_size) + 1.0) / 2.0, (static_cast<double>(filter_size) + 1.0) / 2.0, sigma1, sigma2); auto sum_result = sum(filter_mask); filter_mask = divides(filter_mask, sum_result); // Normalization return conv2(input, filter_mask, is_size_same); } }
gaussianFigure2D
template function implementation (in fileimage_operations.h
)namespace TinyDIP { // multiple standard deviations template<class InputT> constexpr static Image<InputT> gaussianFigure2D( const std::size_t xsize, const std::size_t ysize, const std::size_t centerx, const std::size_t centery, const InputT standard_deviation_x, const InputT standard_deviation_y) { auto output = Image<InputT>(xsize, ysize); auto row_vector_x = Image<InputT>(xsize, std::size_t{1}); for (std::size_t x = 0; x < xsize; ++x) { row_vector_x.at(x, 0) = normalDistribution1D(static_cast<InputT>(x) - static_cast<InputT>(centerx), standard_deviation_x); } auto row_vector_y = Image<InputT>(ysize, std::size_t{1}); for (std::size_t y = 0; y < ysize; ++y) { row_vector_y.at(y, 0) = normalDistribution1D(static_cast<InputT>(y) - static_cast<InputT>(centery), standard_deviation_y); } for (std::size_t y = 0; y < ysize; ++y) { for (std::size_t x = 0; x < xsize; ++x) { output.at(x, y) = row_vector_x.at(x, 0) * row_vector_y.at(y, 0); } } return output; } }
conv2
template function implementation (in fileimage_operations.h
)namespace TinyDIP { // conv2 template function implementation template<typename ElementT> requires(std::floating_point<ElementT> || std::integral<ElementT> || is_complex<ElementT>::value) constexpr auto conv2(const Image<ElementT>& x, const Image<ElementT>& y, bool is_size_same = false) { auto output = Image<ElementT>(x.getWidth() + y.getWidth() - 1, x.getHeight() + y.getHeight() - 1); for (std::size_t y1 = 0; y1 < x.getHeight(); ++y1) { auto* x_row = &(x.at(0, y1)); for (std::size_t y2 = 0; y2 < y.getHeight(); ++y2) { auto* y_row = &(y.at(0, y2)); auto* out_row = &(output.at(0, y1 + y2)); for (std::size_t x1 = 0; x1 < x.getWidth(); ++x1) { for (std::size_t x2 = 0; x2 < y.getWidth(); ++x2) { out_row[x1 + x2] += x_row[x1] * y_row[x2]; } } } } if(is_size_same) { output = subimage(output, x.getWidth(), x.getHeight(), static_cast<double>(output.getWidth()) / 2.0, static_cast<double>(output.getHeight()) / 2.0); } return output; } // conv2 template function implementation template<typename ElementT, typename ElementT2> requires (((std::same_as<ElementT, RGB>) || (std::same_as<ElementT, RGB_DOUBLE>) || (std::same_as<ElementT, HSV>)) && (std::floating_point<ElementT2> || std::integral<ElementT2> || is_complex<ElementT2>::value)) constexpr static auto conv2(const Image<ElementT>& input1, const Image<ElementT2>& input2, bool is_size_same = false) { return apply_each(input1, [&](auto&& planes) { return conv2(planes, input2, is_size_same); }); } }
The usage of imgaussfilt
function:
void imgaussfiltTest(std::string_view input_image_path = "InputImages/1", std::string_view output_image_path = "OutputImages/imgaussfiltTest")
{
auto input_img = TinyDIP::bmp_read(std::string(input_image_path).c_str(), false);
for(int sigma = 1; sigma < 10; ++sigma)
{
auto output_img = TinyDIP::im2uint8(
TinyDIP::imgaussfilt(TinyDIP::im2double(input_img), sigma)
);
TinyDIP::bmp_write(
(std::string(output_image_path) + std::string("_sigma=") + std::to_string(sigma)).c_str(),
output_img);
}
}
int main(int argc, char* argv[])
{
auto start = std::chrono::system_clock::now();
imgaussfiltTest();
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
return EXIT_SUCCESS;
}
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
im2double and im2uint8 Functions Implementation for Image in C++,
conv2 Template Function Implementation for Image in C++ and
An Updated Multi-dimensional Image Data Structure with Variadic Template Functions in C++
What changes has been made in the code since last question?
I am trying to implement
imgaussfilt
template function like Matlab's imgaussfilt to perform Gaussian blur in this post.Why a new review is being asked for?
Please review the implementation of
imgaussfilt
template function and its tests.