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 file- image_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 file- image_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 file- image_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(const int size = 10)
{
    auto random_complex_image1 =
        TinyDIP::generate_complex_image(
            TinyDIP::rand(size, size),
            TinyDIP::rand(size, size));
    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.349134,0.058453)     (0.204941,0.103249)     (0.489626,0.0430718)    (0.0287181,0.309311)    (0.0399393,0.696768)   (0.91164,0.191862)       (0.654913,0.866517)     (0.297313,0.0406738)    (0.363457,0.0659715)    (0.0282682,0.226641)
(0.0992994,0.654607)    (0.925208,0.580786)     (0.40913,0.589028)      (0.0422619,0.938065)    (0.659919,0.568031)    (0.693528,0.305793)      (0.324341,0.534812)     (0.915293,0.892706)     (0.841049,0.443242)     (0.926701,0.71971)
(0.161231,0.124854)     (0.167118,0.970151)     (0.183368,0.808257)     (0.0906341,0.37105)     (0.435765,0.394986)    (0.944431,0.556207)      (0.0509784,0.307722)    (0.281926,0.368342)     (0.373103,0.138894)     (0.274492,0.901984)
(0.143554,0.523027)     (0.821683,0.303483)     (0.994244,0.806173)     (0.204999,0.783978)     (0.0343751,0.984009)   (0.769188,0.0920548)     (0.29764,0.896474)      (0.15807,0.133722)      (0.271,0.631517)        (0.206615,0.978604)
(0.771288,0.935558)     (0.865369,0.592532)     (0.617183,0.649661)     (0.224174,0.118173)     (0.546682,0.898015)    (0.0634438,0.84084)      (0.902093,0.633853)     (0.774141,0.607455)     (0.852407,0.123795)     (0.065525,0.662438)
(0.976416,0.557757)     (0.0463527,0.999983)    (0.715594,0.494586)     (0.494334,0.471223)     (0.537649,0.822234)    (0.2264,0.657272)        (0.303286,0.488968)     (0.779682,0.114182)     (0.535423,0.701713)     (0.653509,0.594488)
(0.421601,0.0335276)    (0.741846,0.312825)     (0.724597,0.0421256)    (0.22976,0.271366)      (0.101608,0.340671)    (0.564151,0.30981)       (0.157958,0.731453)     (0.513171,0.492235)     (0.543436,0.957366)     (0.884459,0.575114)
(0.999732,0.683494)     (0.526455,0.456438)     (0.107317,0.688305)     (0.343426,0.880514)     (0.965521,0.20274)     (0.867809,0.573529)      (0.355845,0.103756)     (0.292168,0.00579886)   (0.969953,0.931475)     (0.389777,0.0103169)
(0.325895,0.238896)     (0.831035,0.63367)      (0.201822,0.954049)     (0.654814,0.841531)     (0.300335,0.424942)    (0.859326,0.247792)      (0.840811,0.0560384)    (0.961937,0.155272)     (0.853906,0.145131)     (0.807052,0.398518)
(0.0649945,0.0106254)   (0.898195,0.442709)     (0.579019,0.310179)     (0.853074,0.899483)     (0.3355,0.694544)      (0.135638,0.326269)      (0.945633,0.888922)     (0.687101,0.579121)     (0.13002,0.951442)      (0.278428,0.125251)
Computation finished at Mon Jun 23 15:25:57 2025
 elapsed time: 0.035017 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.
