c++opencv

I'm writing a c++ mandelbrot generator but I need to work with HSV


I'm starting with a black cv::Mat image but I would like to add HSV to it. How do I achieve this??

int RE_START = -2;
int RE_END = 1;
int IM_START = -1;
int IM_END = 1;

int MAX_ITER = 80;

int mandelbrot(std::complex<double> c){
    std::complex<double> z{0,0};
    int n = 0;
    while (abs(z) <= 2 && n < MAX_ITER){
        z = z*z + c;
        n += 1;
    }   
    return n;
}
int m;
int main()
{
    //! [mandelbrot-transformation]
    Mat mandelbrotImg(width, height,CV_8UC3, cv::Scalar(0, 0, 0));
    Mat mandelHSV(width, height,COLOR_BGR2HSV);
    float wid = (float)width;
    float hei = (float)height;
    int count = 0;
    for (int x=0; x < width; x++){
        for (int y=0; y<height; y++){
            
            std::complex<double> c( RE_START + (x / wid) * (RE_END - RE_START),
                    IM_START + (y / hei) * (IM_END - IM_START));

            m = mandelbrot(c);
            
            double hue = (255 * m / (float)MAX_ITER);
            double saturation = 255.0;
            double value;
            if (m < MAX_ITER) {
                value = 255;
            }else {
               value = 0;
            }
            mandelbrotImg.at<cv::Vec3b>(x,y) = ((uchar)hue, (uchar)saturation, (uchar)value);
            
            count++;
            
        }
    }
    cv::cvtColor(mandelbrotImg, mandelbrotImg, COLOR_BGR2HSV);
    imwrite("../img/mandle.png", mandelbrotImg);
    
    }
    
};

This is what I have so far! I dont know if I need to convert it or assign the HSV value at the pixel location.

The image output is now:

IMAGE OUTPUT

Expected output:

EXPECTED OUTPUT


Solution

  • There were numerous issues in your original code, and there are still quite a few in your current one.

    To name some:

    1. cv::Mat constructor expects first the height, then the width.
    2. cv::Mat::at method expects first the y coordinate, then the x.
    3. The final color conversion should be COLOR_HSV2BGR not COLOR_BGR2HSV.
    4. mandelbrot should better accept the parameter by const& to avoid copy (an efficiency issue).
    5. Instead of checking abs(z) <= 2, it's better to use norm(z) <= 4 since it avoids calculating the sqrt (an efficiency issue).
    6. Since your main calculations are in doubles, I swapped all the floats to doubles.
    7. There's no need to initialize the cv::Mat to a zero value upon construction, because later on we fill all the pixel values anyway.

    See fixed version:

    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <complex>
    
    
    static const int RE_START = -2;
    static const int RE_END = 1;
    static const int IM_START = -1;
    static const int IM_END = 1;
    static const int MAX_ITER = 80;
    
    
    int mandelbrot(std::complex<double> const & c) 
    {
        std::complex<double> z{ 0,0 };
        int n = 0;
        while (std::norm(z) <= 4 && n < MAX_ITER) 
        {
            z = z*z + c;
            n += 1;
        }
        return n;
    }
    
    
    int main()
    {
        int width = 960;
        int height = 640;
    
        cv::Mat mandelbrotImg(height, width, CV_8UC3);
        double wid = (double)width;
        double hei = (double)height;
        double reWidth = RE_END - RE_START;
        double imWidth = IM_END - IM_START;
        for (int x = 0; x < width; x++) 
        {
            for (int y = 0; y < height; y++) 
            {
                std::complex<double> c(RE_START + (x / wid) * reWidth, IM_START + (y / hei) * imWidth);
                int m = mandelbrot(c);
    
                double hue = (255 * m / (float)MAX_ITER);
                double saturation = 255.0;
                double value = (m < MAX_ITER) ? 255.0 : 0;
    
                mandelbrotImg.at<cv::Vec3b>(y, x) = cv::Vec3b((uchar)hue, (uchar)saturation, (uchar)value);
            }
        }
        cv::cvtColor(mandelbrotImg, mandelbrotImg, cv::COLOR_HSV2BGR);
        cv::imwrite("../img/mandle.png", mandelbrotImg);
    }
    

    Output: enter image description here