无法使用 CImg 获得与 mandelbrot 集一起使用的颜色平滑度
Can't get color smoothness to work with mandelbrot set using CImg
因此,在学习 C++ 的过程中,我决定尝试使用 CImg 实现 mandelbrot 集。这是我的程序:
#include <cstdlib>
#include <iostream>
#include <complex>
#define cimg_use_png
#include "CImg.h"
using namespace cimg_library;
const int MAX_ITER = 80;
const int WIDTH = 600;
const int HEIGHT = 400;
const int DEPTH = 1;
const int COLOR_SPECTRUM = 3;
const int RE_START = -2;
const int RE_END = 1;
const int IM_START = -1;
const int IM_END = 1;
double mandelbrot(const std::complex<double> &value) {
std::complex<double> z(0, 0);
int n = 0;
while (abs(z) <= 2 && n < MAX_ITER){
z = (z * z) + value;
n += 1;
}
if(n == MAX_ITER) {
return n;
}
return n + 1 - log(log2(norm(z)));
}
int main() {
CImg<int> img(WIDTH, HEIGHT, DEPTH, COLOR_SPECTRUM, 0);
img.RGBtoHSV();
cimg_forXY(img, x, y) {
std::complex<double> complex(RE_START + ((double)x / WIDTH) * (RE_END - RE_START),
IM_START + ((double)y / HEIGHT) * (IM_END - IM_START));
double m = mandelbrot(complex);
int hue = (255 * m / MAX_ITER);
int saturation = 255;
int value = 0;
if (m < MAX_ITER) {
value = 255;
}
int color[] = { hue, saturation, value };
img.draw_point(x, y, color);
}
// img.HSVtoRGB().display("Mandelbrot");
img.HSVtoRGB().save_png("output/test.png");
return 0;
}
我设法画出经典的 mandelbrot 形状,但后来我尝试实施平滑以摆脱丑陋的条带。但我无法让它真正起作用。
说真的,我不知道我在做什么,因为数学很难。
这就是我得到的
保存图像时我也收到此警告
[CImg] *** Warning ***[instance(600,400,1,3,0x104800000,non-shared)]
CImg<int>::save_png(): Instance has pixel values in
[-1.65164e+07,65025], probable type overflow in file 'output/test.png'.
很明显我在某处溢出了,但我真的不知道在哪里。
如果有人能帮助我解释我在做什么,并以简单的方式指出我所做的所有错误,我将永远感激不已。
更新
因此,通过添加标准化步骤,我设法获得了更好的图像:
img.HSVtoRGB()
.normalize(0, 255)
.save_png("output/test.png");
并且溢出错误消失了。
但是HSV和RGB的转换好像有问题
所有白色的东西都应该是黑色的。
我写的 HSV 值是 255, 255, 0
但它在 RGB 中被转换为 255、255、255,这是错误的。它应该被转换成黑色。
更新 2
正如鲍勃告诉我的那样,色相和饱和度不是 0..100 之间的数字,它由 0..1 之间的数字表示。
这是我的主要失误,也是为什么我会溢出并且黑色变成白色的原因。通过更正并执行 Bob 建议的小修复,我现在得到:
在HSV颜色模型中,色调通常表示为角度[0°, 360°],而饱和度 和 value 在 [0, 1].
范围内
修复已发布代码的一种方法是调整存储在 img
中的值及其类型。
CImg<double> img(WIDTH, HEIGHT, DEPTH, COLOR_SPECTRUM, 0);
// ^^^^^^ I guess a float could be enough
// img.RGBtoHSV(); Here, is useless. CImg has no notion of the color space
cimg_forXY(img, x, y)
{
std::complex<double> c(/* Get real and imaginary part from x and y */);
double m = mandelbrot(c);
double color[] = {
// ^^^^^^
360.0 * m / MAX_ITER, // hue
1.0, // saturation
(m < MAX_ITER) ? 1.0 : 0.0 // value
};
img.draw_point(x, y, color);
}
img.HSVtoRGB().normalize(0, 255).save_png("output/test.png");
另请注意,在 mandelbrot()
中,您可以使用
while (std::norm(z) <= 4 && n < MAX_ITER) //
{ // ^^^^^^^^^^^^^^^^^ To avoid a sqrt at every iteration
// See e.g. https://linas.org/art-gallery/escape/smooth.html for this:
return n + 1 - std::log2( std::log( std::norm(z) ) * 0.5 );
}
因此,在学习 C++ 的过程中,我决定尝试使用 CImg 实现 mandelbrot 集。这是我的程序:
#include <cstdlib>
#include <iostream>
#include <complex>
#define cimg_use_png
#include "CImg.h"
using namespace cimg_library;
const int MAX_ITER = 80;
const int WIDTH = 600;
const int HEIGHT = 400;
const int DEPTH = 1;
const int COLOR_SPECTRUM = 3;
const int RE_START = -2;
const int RE_END = 1;
const int IM_START = -1;
const int IM_END = 1;
double mandelbrot(const std::complex<double> &value) {
std::complex<double> z(0, 0);
int n = 0;
while (abs(z) <= 2 && n < MAX_ITER){
z = (z * z) + value;
n += 1;
}
if(n == MAX_ITER) {
return n;
}
return n + 1 - log(log2(norm(z)));
}
int main() {
CImg<int> img(WIDTH, HEIGHT, DEPTH, COLOR_SPECTRUM, 0);
img.RGBtoHSV();
cimg_forXY(img, x, y) {
std::complex<double> complex(RE_START + ((double)x / WIDTH) * (RE_END - RE_START),
IM_START + ((double)y / HEIGHT) * (IM_END - IM_START));
double m = mandelbrot(complex);
int hue = (255 * m / MAX_ITER);
int saturation = 255;
int value = 0;
if (m < MAX_ITER) {
value = 255;
}
int color[] = { hue, saturation, value };
img.draw_point(x, y, color);
}
// img.HSVtoRGB().display("Mandelbrot");
img.HSVtoRGB().save_png("output/test.png");
return 0;
}
我设法画出经典的 mandelbrot 形状,但后来我尝试实施平滑以摆脱丑陋的条带。但我无法让它真正起作用。
说真的,我不知道我在做什么,因为数学很难。
这就是我得到的
保存图像时我也收到此警告
[CImg] *** Warning ***[instance(600,400,1,3,0x104800000,non-shared)]
CImg<int>::save_png(): Instance has pixel values in
[-1.65164e+07,65025], probable type overflow in file 'output/test.png'.
很明显我在某处溢出了,但我真的不知道在哪里。
如果有人能帮助我解释我在做什么,并以简单的方式指出我所做的所有错误,我将永远感激不已。
更新
因此,通过添加标准化步骤,我设法获得了更好的图像:
img.HSVtoRGB()
.normalize(0, 255)
.save_png("output/test.png");
并且溢出错误消失了。
但是HSV和RGB的转换好像有问题
所有白色的东西都应该是黑色的。
我写的 HSV 值是 255, 255, 0
但它在 RGB 中被转换为 255、255、255,这是错误的。它应该被转换成黑色。
更新 2
正如鲍勃告诉我的那样,色相和饱和度不是 0..100 之间的数字,它由 0..1 之间的数字表示。
这是我的主要失误,也是为什么我会溢出并且黑色变成白色的原因。通过更正并执行 Bob 建议的小修复,我现在得到:
在HSV颜色模型中,色调通常表示为角度[0°, 360°],而饱和度 和 value 在 [0, 1].
范围内修复已发布代码的一种方法是调整存储在 img
中的值及其类型。
CImg<double> img(WIDTH, HEIGHT, DEPTH, COLOR_SPECTRUM, 0);
// ^^^^^^ I guess a float could be enough
// img.RGBtoHSV(); Here, is useless. CImg has no notion of the color space
cimg_forXY(img, x, y)
{
std::complex<double> c(/* Get real and imaginary part from x and y */);
double m = mandelbrot(c);
double color[] = {
// ^^^^^^
360.0 * m / MAX_ITER, // hue
1.0, // saturation
(m < MAX_ITER) ? 1.0 : 0.0 // value
};
img.draw_point(x, y, color);
}
img.HSVtoRGB().normalize(0, 255).save_png("output/test.png");
另请注意,在 mandelbrot()
中,您可以使用
while (std::norm(z) <= 4 && n < MAX_ITER) //
{ // ^^^^^^^^^^^^^^^^^ To avoid a sqrt at every iteration
// See e.g. https://linas.org/art-gallery/escape/smooth.html for this:
return n + 1 - std::log2( std::log( std::norm(z) ) * 0.5 );
}