Skip to main content
3 of 4
Update code
JimmyHu
  • 7.6k
  • 2
  • 11
  • 48

generate_complex_image Template Function Implementation for Image in C++

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_image template 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
        );
    }
    
  • pixelwiseOperation template 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;
    }
    
  • rand template 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()
{
    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.

TinyDIP on GitHub

All suggestions are welcome.

The summary information:

JimmyHu
  • 7.6k
  • 2
  • 11
  • 48