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.
- I've added floating point division
- I've added norm(z) into mandelbrot
The image output is now:
Expected output:
CodePudding user response:
There were numerous issues in you original code, and there are still quite a few in your current one. To name some:
cv::Mat
constructor expects first the height, then the width.cv::Mat::at
method expects first the y coordinate, then the x.- The final color conversion should be
COLOR_HSV2BGR
notCOLOR_BGR2HSV
. mandelbrot
should better accept the parameter byconst&
to avoid copy (an efficiency issue).- Instead of checking
abs(z) <= 2
, it's better to usenorm(z) <= 4
since it avoids calculating the sqrt (an efficiency issue). - Since your main calculations are in
double
s, I swapped all thefloat
s todouble
s. - 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);
}