This is a follow-up question for Tests for the operators of image template class in C++, Image pixelwise operation function with multiple inputs in C++ and An Updated Multi-dimensional Image Data Structure with Variadic Template Functions in C++. In order to generate random complex type (std::complex) image, I create a template function named generate_complex_image in this post.
The experimental implementation
generate_complex_imagetemplate function implementation (in fileimage_operations.h)// generate_complex_image template function implementation template<class ElementT> requires(std::floating_point<ElementT> || std::integral<ElementT>) constexpr static auto generate_complex_image(const Image<ElementT>& real, const Image<ElementT>& imaginary) { if (real.getSize() != imaginary.getSize()) { throw std::runtime_error("Size mismatched!"); } return pixelwiseOperation( [&](auto&& real_element, auto&& imaginary_element) { return std::complex{ real_element, imaginary_element }; }, real, imaginary ); }pixelwiseOperationtemplate function implementation (in fileimage_operations.h)// pixelwiseOperation template function implementation template<std::size_t unwrap_level = 1, class... Args> constexpr static auto pixelwiseOperation(auto op, const Args&... inputs) { auto transformed_data = recursive_transform<unwrap_level>( op, inputs.getImageData()...); auto output = Image<recursive_unwrap_type_t<unwrap_level, decltype(transformed_data)>>( transformed_data, first_of(inputs...).getSize()); return output; } // pixelwiseOperation template function implementation template<std::size_t unwrap_level = 1, class ExPo, class InputT> requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>) constexpr static auto pixelwiseOperation(ExPo&& execution_policy, auto op, const Image<InputT>& input1) { auto transformed_data = recursive_transform<unwrap_level>( std::forward<ExPo>(execution_policy), op, (input1.getImageData())); auto output = Image<recursive_unwrap_type_t<unwrap_level, decltype(transformed_data)>>( transformed_data, input1.getSize()); return output; }randtemplate function implementation (in fileimage_operations.h)// rand template function implementation template<image_element_standard_floating_point_type ElementT = double, typename Urbg, class... Sizes> requires(std::uniform_random_bit_generator<std::remove_reference_t<Urbg>> and ((std::same_as<Sizes, std::size_t>&&...) or (std::same_as<Sizes, int>&&...))) constexpr static auto rand(Urbg&& urbg, Sizes... sizes) { // Reference: https://stackoverflow.com/a/23143753/6667035 // Reference: https://codereview.stackexchange.com/a/294739/231235 auto dist = std::uniform_real_distribution<ElementT>{}; return generate([&dist, &urbg]() { return dist(urbg); }, sizes...); } // rand template function implementation template<image_element_standard_floating_point_type ElementT = double, class... Size> requires((std::same_as<Size, std::size_t>&&...) or (std::same_as<Size, int>&&...)) inline auto rand(Size... size) { return rand<ElementT>(std::mt19937{std::random_device{}()}, size...); } // rand template function implementation template<image_element_standard_floating_point_type ElementT = double, typename Urbg> requires std::uniform_random_bit_generator<std::remove_reference_t<Urbg>> constexpr auto rand(Urbg&& urbg) { auto dist = std::uniform_real_distribution<ElementT>{}; return Image<ElementT>(std::vector{ dist(urbg) }, 1, 1); } // rand template function implementation template<image_element_standard_floating_point_type ElementT = double> inline auto rand() { return rand<ElementT>(std::mt19937{std::random_device{}()}); }
The usage of generate_complex_image template function (To generate random complex image):
/* Developed by Jimmy Hu */
#include <chrono>
#include <execution>
#include <map>
#include <omp.h>
#include <sstream>
#include <tbb/global_control.h>
#include "../base_types.h"
#include "../basic_functions.h"
#include "../image.h"
#include "../image_io.h"
#include "../image_operations.h"
#include "../timer.h"
// remove_extension Function Implementation
// Copy from: https://stackoverflow.com/a/6417908/6667035
std::string remove_extension(const std::string& filename)
{
size_t lastdot = filename.find_last_of(".");
if (lastdot == std::string::npos) return filename;
return filename.substr(0, lastdot);
}
void generate_complex_image_tests()
{
auto random_complex_image1 =
TinyDIP::generate_complex_image(
TinyDIP::rand(10, 10),
TinyDIP::rand(10, 10));
std::cout << "Random complex image size: " << random_complex_image1.getWidth() << "x" << random_complex_image1.getHeight() << '\n';
std::cout << "Random complex image dimensionality: " << random_complex_image1.getDimensionality() << '\n';
random_complex_image1.print();
}
int main(int argc, char* argv[])
{
TinyDIP::Timer timer1;
generate_complex_image_tests();
return EXIT_SUCCESS;
}
The output of the test code above:
Random complex image size: 10x10
Random complex image dimensionality: 2
(0.0309802,0.207745) (0.7672,0.982068) (0.1391,0.384014) (0.58921,0.962672) (0.0835206,0.482384) (0.964937,0.110899) (0.992883,0.60257) (0.0421169,0.690975) (0.97506,0.362581) (0.415112,0.650993)
(0.85862,0.540162) (0.435931,0.26674) (0.0340822,0.939691) (0.0646598,0.407043) (0.102873,0.489902) (0.51485,0.983734) (0.784026,0.881374) (0.550912,0.416697) (0.71402,0.0934162) (0.936469,0.98452)
(0.868887,0.000198707) (0.576647,0.407503) (0.18223,0.800446) (0.630022,0.26426) (0.495893,0.6303) (0.675096,0.0886127) (0.273139,0.197433) (0.846047,0.671209) (0.160573,0.406575) (0.078908,0.429751)
(0.338148,0.728895) (0.339481,0.430446) (0.359749,0.0122478) (0.304211,0.142009) (0.962339,0.174089) (0.574091,0.0177569) (0.399281,0.283194) (0.973445,0.416701) (0.0839186,0.334491) (0.627023,0.148123)
(0.193928,0.16015) (0.906759,0.579312) (0.114695,0.622613) (0.198024,0.39291) (0.27091,0.945753) (0.802529,0.441601) (0.714487,0.764121) (0.065839,0.229243) (0.589151,0.831745) (0.0613892,0.952846)
(0.0656263,0.481777) (0.770057,0.617461) (0.791546,0.83214) (0.00609061,0.617163) (0.245474,0.963633) (0.0709438,0.243092) (0.138417,0.736006) (0.223,0.5196) (0.0154476,0.377757) (0.0899701,0.20117)
(0.499435,0.182347) (0.316292,0.761439) (0.810907,0.923709) (0.361648,0.0705249) (0.657706,0.526143) (0.863371,0.803923) (0.211954,0.253455) (0.694857,0.914313) (0.983336,0.220962) (0.122613,0.633516)
(0.387504,0.201909) (0.411941,0.516121) (0.807016,0.0558608) (0.391722,0.387649) (0.421397,0.502398) (0.0419318,0.923201) (0.156964,0.639464) (0.166985,0.660141) (0.340207,0.677165) (0.036271,0.611554)
(0.746185,0.631796) (0.167071,0.942087) (0.452643,0.0341877) (0.786094,0.241459) (0.355874,0.0868275) (0.158459,0.130438) (0.587968,0.0338624) (0.37882,0.620195) (0.0410965,0.666004) (0.0018716,0.951475)
(0.736898,0.613944) (0.630904,0.494962) (0.579905,0.593296) (0.0643072,0.907601) (0.156467,0.407707) (0.19433,0.0602593) (0.216056,0.84544) (0.905882,0.0748013) (0.336258,0.163358) (0.655664,0.165356)
Computation finished at Thu Jun 19 14:59:56 2025
elapsed time: 0.0555367 seconds.
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
Tests for the operators of image template class in C++,
Image pixelwise operation function with multiple inputs 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 implemented
generate_complex_imagetemplate function in this post.Why a new review is being asked for?
Please review the implementation of
generate_complex_imagetemplate function and its tests.