分形/复平面中的迭代/demm
此算法有 2 个版本
- 外部
- 内部
与动态平面和 Julia 集版本:DEM/J 进行比较
曼德勃罗集的距离估计方法 (DEM/M) 估计点 (在曼德勃罗集的外部)到曼德勃罗集最近点的距离。[1][2]
名称
- (方向)距离估计公式
它可用于从 BOF 创建黑白图像:[3]
- 第 84 页的 41 图
- 第 85 页的 43 图
- 第 188 页的无编号图
- 解析 DE = DEM = 真实 DE
- Claude DE = 假 DE (FDE):当 g>0 时 FDE=1/(g*log(2)),当 g=0 时未定义(即在内部)[4]
其中
是 关于 c 的一阶导数,它可以通过从以下开始的迭代找到
然后在每个连续步骤中替换
- "你需要将“If mag > 2”更改为增加逃逸半径。附件是一个比较,显示当半径增加时,“带子”会减少,没有问题可以将其增加到像 R = 1e6 这样的大小,因为一旦它逃逸了 2,它就会快速增长。半径越大,距离估计越准确。” Claude [8]
- 基本上,在测试幅度平方与逃逸值时
- 如果你的逃逸值是 10^4,那么你的 DE 估计值精确到两位小数,例如,如果你的 DE 是 0.01,那么它只精确到 +/-0.0001,
- 如果你的逃逸值是 10^6,那么你的 DE 估计值精确到三位小数(David Makin 在 fractalforums.com 上说)
"对于外部距离估计,你需要一个大的逃逸半径,例如 100100。迭代次数限制是任意的,在有限的限制下,某些像素将始终被归类为“未知”。" Claude Heiland-Allen[9]
- 分形的美丽
- 分形图像科学,第 198 页,
- 由 Robert P. Munafo 编写的距离估计器[10]
由 Claude Heiland-Allen 编写的伪代码[11]
foreach pixel c while not escaped and iteration limit not reached dc := 2 * z * dc + 1 z := z^2 + c de := 2 * |z| * log(|z|) / |dz| d := de / pixel_spacing plot_grey(tanh(d))
代码 [12]
double _Complex m_exterior_distance(int N, double R, double _Complex c)
{
double _Complex z = 0;
double _Complex dc = 0;
for (int n = 0; n < N; ++n)
{
if (cabs(z) > R)
return 2 * z * log(cabs(z)) / dc;
dc = 2 * z * dc + 1;
z = z * z + c;
}
return -1;
}
"分形的美丽" 为右侧图像中显示的距离估计提供了几乎正确的计算机程序。该方法没有获得支持的一个可能原因是该程序中的过程存在严重缺陷: 的计算是在 计算之前(并完成),而不是之后,它应该是在之后( 使用 ,而不是 )。为了避免重新计算 (k = 0, 1, 2, ...),此序列被保存在一个数组中。使用此数组, 被计算到最后一个迭代次数,并指出可能发生溢出。如果发生溢出,则该点被认为属于边界(逃逸条件)。如果未发生溢出,则可以执行距离计算。除了发生溢出并非事实之外,该方法使用了不必要的存储和迭代重复,使其变得不必要地更慢且吸引力更低。本书中的以下评论也不是令人鼓舞的:“事实证明,图像对各种选择非常敏感”(逃逸半径、最大迭代次数、溢出、边界厚度和放大系数)。是这种无稽之谈让人们对使用和推广该方法失去了所有兴趣吗?" Gertbuschmann
所以
- 在循环中,导数 应该在新的 z 之前计算
"我终于生成了让我满意的 DEM(距离估计方法)图像。事实证明,我的代码中存在一些错误。新的代码运行速度相当快,即使计算距离估计值需要额外的数学运算。
S of F I(“分形图像科学”)中的算法使用从白色到黑色的锐利截止,当像素足够靠近集合时,但我发现这会导致图像看起来参差不齐。我已经实现了一个非线性颜色渐变,效果很好。
对于 DE 值为 threshold>=DE>=0 的像素,我将 DE 值缩放到 1>=DE>=0,然后进行计算:gradient_value = 1 - (1-DE)^n,(“^n”表示 n 次方。我希望我能使用上标!)
"n" 是一个调整因子,它允许我更改渐变曲线的形状。值“gradient_value”决定像素的颜色。如果它为 0,则像素以起始颜色(对于黑白图像,为白色)着色。如果“gradient_value”为 1,则像素获得结束颜色(例如,
黑色) 对于 n>1 的值,这将导致远离集合的像素颜色发生快速变化,并且随着 DE 接近 0,值的变化速度会变慢。对于 n<1 的值,它会导致远离集合的像素颜色发生缓慢变化,并且靠近集合的像素颜色发生快速变化。对于 n=1,我得到一个线性
颜色梯度。非线性梯度允许我使用 DE 值来反锯齿我的绘图。通过调整我的阈值和调整值,我可以为各种图像获得良好的效果。”Duncan C [13]
“我们上面列出的所有 DE 公式都只是近似值——在 n→∞ 的极限情况下有效,而且一些公式也只适用于靠近分形边界点的点。当您开始渲染这些结构时,这一点会变得非常明显——您通常会遇到噪点和伪影。
将 DE 估计值乘以小于 1 的数字可以用来减少噪点(这就是 Fragmentarium 中的“ Fudge Factor”)。
另一种常见的方法是 **过采样**——或以较大的尺寸渲染图像并缩小尺寸。”Mikael Hvidtfeldt Christensen [14]
示例代码
[edit | edit source]
两种算法,在两个循环中
[edit | edit source]- Inigo Quilez 在 shadertoy : Distance estimation to the Mandelbrot set by Inigo Quilez 中提供的曼德布罗特集合距离估计方法
这是一个 Java 函数。它在一个循环中同时计算 : 迭代 和 导数 。如果(在动态平面中)临界点
- 没有逃逸到无穷远(跳出条件),那么它属于曼德布罗特集合的内部,并具有最大颜色值,
- 逃逸则它可能在外部或边界附近。它的颜色与点 c 与曼德布罗特集合中最近点的距离“成比例”。它也使用颜色循环((int)R % maxColor)。
// Java function by Evgeny Demidov from http://www.ibiblio.org/e-notes/MSet/DEstim.htm
// based on code by Robert P. Munafo from http://www.mrob.com/pub/muency/distanceestimator.html
public int iterate(double cr, double ci, double K, double f) {
double Cr,Ci, I=0, R=0, I2=I*I, R2=R*R, Dr=0,Di=0,D; int n=0;
if (f == 0){ Cr = cr; Ci = ci;}
else{ Cr = ci; Ci = cr;}
do {
D = 2*(R*Dr - I*Di) +1; Di = 2*(R*Di + I*Dr); Dr = D;
I=(R+R)*I+Ci; R=R2-I2+Cr; R2=R*R; I2=I*I; n++;
} while ((R2+I2 < 100.) && (n < MaxIt) );
if (n == MaxIt) return maxColor; // interior
else{ // boundary and exterior
R = -K*Math.log(Math.log(R2+I2)*Math.sqrt((R2+I2)/(Dr*Dr+Di*Di))); // compute distance
if (R < 0) R=0;
return (int)R % maxColor; };
}
这是一个 cpp 函数。它将颜色的整数索引作为输出。
/*
this function is from program mandel ver 5.10 by Wolf Jung
see file mndlbrot.cpp
http://www.mndynamics.com/indexp.html
It is checked first (in pixcolor)
that the point escapes before calling this function.
So we do not compute the derivative and the logarithm
when it is not escaping.
This would not be a good idea if most points escape anyway.
*/
int mndlbrot::dist(double a, double b, double x, double y)
{ uint j;
double xp = 1, yp = 0; // zp = xp+yp*i = 1 ; derivative
double nz, nzp;
// iteration
for (j = 1; j <= maxiter; j++)
{ // zp
nz = 2*(x*xp - y*yp);
yp = 2*(x*yp + y*xp);
xp = nz; //zp = 2*z*zp; on the dynamic plane
// if sign is positive it is parameter plane, if negative it is dynamic plane.
if (sign > 0) xp++; //zp = 2*z*zp + 1 ; on the parameter plane
//z = z*z + c;
nz = x*x - y*y + a;
y = 2*x*y + b;
x = nz;
//
nz = x*x + y*y;
nzp = xp*xp + yp*yp;
// 2 conditions for stopping the iterations
if (nzp > 1e40 || nz > bailout) break;
}
// 5 types of points but 3 colors
/* not escaping, rare
Is it not simply interior ???
This should not be necessary. I do not know why I included it,
because in this case pixcolor should not call dist. If you do not
have pixcolor before, you should return 0 here. */
if (nz < bailout) return 1; // not escaping, rare
/* If The Julia set is disconnected and the orbit of z comes close to
z = 0 before escaping, nzp will be small */
if (nzp < nz) return 10; // includes escaping through 0
// compute estimated distance = x
x = log(nz);
x = x*x*nz / (temp[1]*nzp); //4*square of dist/pixelwidth
if (x < 0.04) return 1; // exterior but very close to the boundary
if (x < 0.24) return 9; // exterior but close to the boundary
return 10; //exterior : escaping and not close to the boundary
} //dist
两种算法,在一个循环中
[edit | edit source]- ińigo quilez 在 c++ 中提供的分形距离渲染方法[15]
CPU 单线程 DEM/M 8 位的 C 源代码 - 点击右侧查看 |
---|
/*
c console program, for CPU, one thread. numbers type : double
It can be compiled and run under Linux, windows, Mac
It needs gcc
draw :
* check 2 algorithms :
** binary escape time
** add boundary computed by DEM/M
* save it to the pgm file
-----------------------------------------
1.pgm file code is based on the code of Claudio Rocchini
http://en.wikipedia.org/wiki/Image:Color_complex_plot.jpg
create 8 bit color graphic file , portable gray map file = pgm
see http://en.wikipedia.org/wiki/Portable_pixmap
to see the file use external application ( graphic viewer)
I think that creating graphic can't be simpler
---------------------------
2. first it creates data array which is used to store color values of pixels,
fills the array with data and after that writes the data from array to pgm file.
It allows free ( non sequential) access to "pixels"
-------------------------------------------
Adam Majewski fraktal.republika.pl
to compile :
gcc m.c -lm -Wall -march=native
to run ( Linux console) :
time ./a.out
convert h6.650000m6650.pgm -resize 800x120 c.png
convert b6.650000m6650.pgm -resize 1600x240 cbig.png
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
/* iXmax/iYmax = 1 */
unsigned int iSide = 1000; /* side of rectangle in pixels */
unsigned int iXmax; // ((int)(m*iSide)) /* height of image in pixels */
unsigned int iYmax ; //= iSide;
unsigned int iLength; // = (iXmax*iYmax) /* number of pixels */
/* world ( double) coordinate */
double dSide = 1.5;
double CxMin ; // = 0.0;
double CxMax ; // =(m*dSide);
double CyMin ; //= dSide;
double CyMax ; // = dSide;
/* (CxMax-CxMin)/(CyMax-CyMin)==iXmax/iYmax = 1 */
unsigned int IterationMax; // = (iXmax*100) /* proportional to resolution of picture */
double PixelWidth; //= ((CxMax-CxMin)/iXmax)
double PixelHeight ;//= ((CyMax-CyMin)/iYmax)
double CDistanceMax ; //= PixelWidth; /* proportional to pixel size */
/* fc(z) = z*z + c */
double EscapeRadius = 33.0; /* radius of circle around origin; its complement is a target set for escaping points */
double ER2 ; //= (EscapeRadius*EscapeRadius)
/* colors = shades of gray from 0=black to 255=white */
unsigned char iExterior = 255; /* exterior of Julia set */
unsigned char iBoundary = 0; /* border , boundary*/
unsigned char iInterior = 0;
unsigned int f(unsigned int _iX, unsigned int _iY)
/*
gives position of point (iX,iY) in 1D array ; uses also global variables
it does not check if index is good so memory error is possible
*/
{return (_iX + (iYmax-_iY-1)*iXmax );}
/*
estimates distance from point c to nearest point in Julia set
for Fc(z)= z*z + c
z(n+1) = Fc(zn)
this function is based on function mndlbrot::dist from mndlbrot.cpp
from program mandel by Wolf Jung (GNU GPL )
http://www.mndynamics.com/indexp.html
Hyunsuk Kim :
For Julia sets, z is the variable and c is a constant. Therefore df[n+1](z)/dz = 2*f[n]*f'[n] -- you don't add 1.
For the Mandelbrot set on the parameter plane, you start at z=0 and c becomes the variable. df[n+1](c)/dc = 2*f[n]*f'[n] + 1.
http://iquilezles.org/www/articles/distancefractals/distancefractals.htm
double EscapeRadius = 33.0;
*/
// boolean Escape time and DEM/M in one loop
double GiveDistance( double Cx, double Cy, int iMax, double DistanceMax)
{
// C = Cx + Cy* I = point of parameter c-plane
int i; /* iteration number */
double Zx, Zy; /* Z = Zx + Zy*I point of dynamical plane */
double Zx2, Zy2; /* Zx2=Zx*Zx; Zy2=Zy*Zy */
double temp;
double absZ2;
// http://en.wikipedia.org/wiki/Complex_quadratic_polynomial
// first derivative of fc(zcr) with respect to c = dZ = dfc(zcr)/dc = 2*Z*dZ = dZx + dZy*I
double dZx = 0.0;
double dZy = 0.0;
double absdZ2; // = abs(dZ)* abs(dZ) = dZx*dZx + dZy*dZy
double distance;
/* initial value of orbit = critical point zcr = 0 */
Zx=0.0;
Zy=0.0;
//
Zx2 = Zx*Zx;
Zy2 = Zy*Zy;
absZ2= Zx*Zx + Zy*Zy;
absdZ2= dZx*dZx + dZy*dZy;
// iteration of critical point z= 0 on the dynamical z-plane
for (i=0; i<iMax; i++)
{ // check if not escaping : abs(z)>ER
if (absZ2 > ER2 ) break ; // exterior when escapes
//if (absdZ2 > 1e60) { i=iMax; } // interior when derivative explodes
// in the loop, the derivative should be calculated before the new z
/* first derivative zp = 2*z*zp = xp + yp*i; */
temp = 2*(Zx*dZx - Zy*dZy) + 1.0 ; /* */
dZy = 2*(Zx*dZy + Zy*dZx);
dZx = temp;
// z = fc(z) = z*z + c
Zy=2*Zx*Zy + Cy;
Zx=Zx2-Zy2 +Cx;
// abs
Zx2 = Zx*Zx;
Zy2 = Zy*Zy;
absZ2= Zx2 + Zy2; // nz = x*x + y*y;
absdZ2= dZx*dZx + dZy*dZy; //
};
// compute distance
if (i<iMax) // exterior
{
// based on https://www.shadertoy.com/view/lsX3W4 shadertoy : Distance estimation to the Mandelbrot set by Inigo Quilez
distance = sqrt(absZ2/absdZ2)*log(absZ2); //
distance = pow( 4.0*distance, 0.25 );
}
else distance=0.0; // interior
// if (nz < bailout) return 1; //still not escaping after iteration , rare
// if (absdZ2 < absZ2) color= iExterior; //includes escaping through 0 // som eiterior points are coded as exterior = error
return distance;
} //0.000007
// color is proportional to distance between point c and nearest point in Mandelbrot set
unsigned char GiveColor( double Cx, double Cy, int iMax, double DistanceMax)
{
double distance ;
unsigned char color ;
distance = GiveDistance( Cx, Cy, iMax, DistanceMax);
if (distance > 0.0)
{ if (distance<DistanceMax*333.0) // = clamp(distance, 0.0, 1.0) to remove level sets effect !!!!!
color = (int)(255.0*distance); // boundary and near boundary = shades of gray
else color = iExterior; // exterior far away from boundary
}
else color = iInterior;
return color;
}
/* --------------------------------------------------------------------------------------------------------- */
int main(){
unsigned int iX,iY, /* indices of 2D virtual array (image) = integer coordinate */
i; /* index of 1D array */
double Cx, Cy;
//int ExtLastIteration; //
unsigned char color;
printf(" Setup \n");
iXmax = iSide; /* height of image in pixels */
iYmax = iSide;
iLength = iXmax*iYmax; /* number of pixels */
CxMin = -2.25;
CxMax = 0.75 ;
CyMin = -dSide;
CyMax = dSide;
IterationMax = 1000 ;
PixelWidth= (CxMax-CxMin)/iXmax;
PixelHeight = (CyMax-CyMin)/iYmax;
ER2 = EscapeRadius*EscapeRadius;
/* dynamic 1D array for colors ( shades of gray ) */
unsigned char *data;
data = malloc( iLength * sizeof(unsigned char) );
if (data == NULL )
{
fprintf(stderr," Could not allocate memory");
return 1;
}
printf(" compute color for every pixel : scan c-plane \n");
for(iY=0;iY<iYmax;++iY){
Cy=CyMin + iY*PixelHeight; /* */
printf("row %u from %u \n",iY, iYmax);
for(iX=0;iX<iXmax;++iX){
Cx=CxMin + iX*PixelWidth;
color=GiveColor(Cx, Cy, IterationMax, PixelWidth);
i= f(iX,iY); /* compute index of 1D array from indices of 2D array */
data[i]=color; /* change the color */
}
}
printf(" save data array to the pgm file \n");
unsigned int length = 30;
char filename[length] ;
snprintf(filename, length, "%.0fe%u%s", EscapeRadius,iXmax , ".pgm");
char *comment="# ";/* comment should start with # */
const unsigned int MaxColorComponentValue=255; /* color component is coded from 0 to 255 ; it is 8 bit color file */
FILE * fp;
fp = fopen(filename,"wb"); /*create new file,give it a name and open it in binary mode */
fprintf(fp,"P5\n %s\n %u\n %u\n %u\n",comment,iXmax,iYmax,MaxColorComponentValue); /*write header to the file*/
fwrite(data,iLength,1,fp); /*write image data bytes to the file in one step */
printf("File %s saved. \n", filename);
fclose(fp);
printf(" save graphic data to the text file \n");
char tfilename[length] ;
snprintf(tfilename, length, "%.0fe%u%s",EscapeRadius, iXmax, ".txt");
fp = fopen(tfilename,"wb"); /*create new file,give it a name and open it in binary mode */
fprintf(fp,"IterationMax = %d \n", IterationMax);
fprintf(fp,"EscapeRadius = %f ER2 = %f \n", EscapeRadius, ER2);
fprintf(fp,"\n" ); /* */
fprintf(fp,"C plane : \n" ); /* */
fprintf(fp,"dWidth = %f ; dHeight = %f \n",CxMax- CxMin, CyMax - CyMin );
fprintf(fp,"PixelWidth = %f ; PixelHeight = %f \n", PixelHeight, PixelWidth);
fprintf(fp," CxMin = %f \n", CxMin); /* */
fprintf(fp," CxMax = %f \n", CxMax); /* */
fprintf(fp," CyMin = %f \n", CyMin); /* */
fprintf(fp," CyMax = %f \n", CyMax); /* */
fprintf(fp," center of image : C = %f ; %f \n",CxMax -(CxMax-CxMin)/2.0, CyMax - (CyMax-CyMin)/2.0); /* */
fprintf(fp,"\n" );
printf("File %s saved. \n", tfilename);
fclose(fp);
printf(" allways free memory \n ");
free(data);
return 0;
}
|
CPU 单线程 DEM/M 32 位色的 C 源代码 - 点击右侧查看 |
---|
/*
c console program, for CPU, one thread. numbers type : double
It can be compiled and run under Linux, windows, Mac
It needs gcc
draw :
* check 2 algorithms :
** binary escape time
** add boundary computed by DEM/M
* save it to the ppm file
-----------------------------------------
1.pgm file code is based on the code of Claudio Rocchini
http://en.wikipedia.org/wiki/Image:Color_complex_plot.jpg
create 24 bit color graphic file , portable pixel map file = ppm
see http://en.wikipedia.org/wiki/Portable_pixmap
to see the file use external application ( graphic viewer)
I think that creating graphic can't be simpler
---------------------------
2. first it creates data array which is used to store color values of pixels,
fills the array with data and after that writes the data from array to pgm file.
It allows free ( non sequential) access to "pixels"
-------------------------------------------
Adam Majewski fraktal.republika.pl
to compile :
gcc m.c -lm -Wall -march=native
to run ( Linux console) :
time ./a.out
convert h6.650000m6650.pgm -resize 800x120 c.png
convert b6.650000m6650.pgm -resize 1600x240 cbig.png
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
double g=100.0;
/* iXmax/iYmax = 1 */
unsigned int iSide = 1000; /* side of rectangle in pixels */
unsigned int iXmax; // ((int)(m*iSide)) /* height of image in pixels */
unsigned int iYmax ; //= iSide;
unsigned int iLength; // = (iXmax*iYmax) /* number of pixels */
/* world ( double) coordinate */
double dSide = 1.5;
double CxMin ; // = 0.0;
double CxMax ; // =(m*dSide);
double CyMin ; //= dSide;
double CyMax ; // = dSide;
/* (CxMax-CxMin)/(CyMax-CyMin)==iXmax/iYmax = 1 */
unsigned int IterationMax; // = (iXmax*100) /* proportional to resolution of picture */
double PixelWidth; //= ((CxMax-CxMin)/iXmax)
double PixelHeight ;//= ((CyMax-CyMin)/iYmax)
double CDistanceMax ; //= PixelWidth; /* proportional to pixel size */
/* fc(z) = z*z + c */
double EscapeRadius = 33.0; /* radius of circle around origin; its complement is a target set for escaping points */
double ER2 ; //= (EscapeRadius*EscapeRadius)
/* colors = shades of gray from 0=black to 255=white */
unsigned char iExterior = 255; /* exterior of Julia set */
unsigned char iBoundary = 0; /* border , boundary*/
unsigned char iInterior = 0;
unsigned int f(unsigned int _iX, unsigned int _iY)
/*
gives position of point (iX,iY) in 1D array ; uses also global variables
it does not check if index is good so memory error is possible
*/
{return ((_iX + (iYmax-_iY-1)*iXmax)*3 );}
// ((iYmax-iY-1)*iXmax+iX)*3;
/* based on Delphi function by Witold J.Janik */
void GiveRainbowColor(double position,unsigned char Color32[])
{
/* if position > 1 then we have repetition of colors it maybe useful */
if (position>1.0){if (position-(int)position==0.0)position=1.0; else position=position-(int)position;}
unsigned char nmax=6; /* number of color segments */
double m=nmax* position;
int n=(int)m; // integer of m
double f=m-n; // fraction of m
unsigned char t=(int)(f*255);
switch( n){
case 0: {
Color32[0] = 255;
Color32[1] = t;
Color32[2] = 0;
break;
};
case 1: {
Color32[0] = 255 - t;
Color32[1] = 255;
Color32[2] = 0;
break;
};
case 2: {
Color32[0] = 0;
Color32[1] = 255;
Color32[2] = t;
break;
};
case 3: {
Color32[0] = 0;
Color32[1] = 255 - t;
Color32[2] = 255;
break;
};
case 4: {
Color32[0] = t;
Color32[1] = 0;
Color32[2] = 255;
break;
};
case 5: {
Color32[0] = 255;
Color32[1] = 0;
Color32[2] = 255 - t;
break;
};
default: {
Color32[0] = 255;
Color32[1] = 0;
Color32[2] = 0;
break;
};
}; // case
}
/*
estimates distance from point c to nearest point in Julia set
for Fc(z)= z*z + c
z(n+1) = Fc(zn)
this function is based on function mndlbrot::dist from mndlbrot.cpp
from program mandel by Wolf Jung (GNU GPL )
http://www.mndynamics.com/indexp.html
Hyunsuk Kim :
For Julia sets, z is the variable and c is a constant. Therefore df[n+1](z)/dz = 2*f[n]*f'[n] -- you don't add 1.
For the Mandelbrot set on the parameter plane, you start at z=0 and c becomes the variable. df[n+1](c)/dc = 2*f[n]*f'[n] + 1.
http://iquilezles.org/www/articles/distancefractals/distancefractals.htm
double EscapeRadius = 33.0;
*/
// boolean Escape time and DEM/M in one loop
double GiveDistance( double Cx, double Cy, int iMax, double DistanceMax)
{
// C = Cx + Cy* I = point of parameter c-plane
int i; /* iteration number */
double Zx, Zy; /* Z = Zx + Zy*I point of dynamical plane */
double Zx2, Zy2; /* Zx2=Zx*Zx; Zy2=Zy*Zy */
double temp;
double absZ2;
// http://en.wikipedia.org/wiki/Complex_quadratic_polynomial
// first derivative of fc(zcr) with respect to c = dZ = dfc(zcr)/dc = 2*Z*dZ = dZx + dZy*I
double dZx = 0.0;
double dZy = 0.0;
double absdZ2; // = abs(dZ)* abs(dZ) = dZx*dZx + dZy*dZy
double distance;
/* initial value of orbit = critical point zcr = 0 */
Zx=0.0;
Zy=0.0;
//
Zx2 = Zx*Zx;
Zy2 = Zy*Zy;
absZ2= Zx*Zx + Zy*Zy;
absdZ2= dZx*dZx + dZy*dZy;
// iteration of critical point z= 0 on the dynamical z-plane
for (i=0; i<iMax; i++)
{ // check if not escaping : abs(z)>ER
if (absZ2 > ER2 ) break ; // exterior when escapes
//if (absdZ2 > 1e60) { i=iMax; } // interior when derivative explodes
// in the loop, the derivative should be calculated before the new z
/* first derivative zp = 2*z*zp = xp + yp*i; */
temp = 2*(Zx*dZx - Zy*dZy) + 1.0 ; /* */
dZy = 2*(Zx*dZy + Zy*dZx);
dZx = temp;
// z = fc(z) = z*z + c
Zy=2*Zx*Zy + Cy;
Zx=Zx2-Zy2 +Cx;
// abs
Zx2 = Zx*Zx;
Zy2 = Zy*Zy;
absZ2= Zx2 + Zy2; // nz = x*x + y*y;
absdZ2= dZx*dZx + dZy*dZy; //
};
// compute distance
if (i<iMax) // exterior
{
distance = sqrt(absZ2/absdZ2)*log(absZ2); //
distance = pow( g*distance, 0.25 );
}
else distance=0.0; // interior
// if (nz < bailout) return 1; //still not escaping after iteration , rare
// if (absdZ2 < absZ2) color= iExterior; //includes escaping through 0 // som eiterior points are coded as exterior = error
return distance;
} //0.000007
// gives width in estimated distance of near boundary strip around Mandelbrot set
// true boundary is = DistanceMax*0.1
double GiveDistanceMax(double PixelWidth, int iSide)
{
return PixelWidth*iSide*0.0333; // = 0.1
}
// color is proportional to distance between point c and nearest point in Mandelbrot set
int ComputeColor32( double Cx, double Cy, int iMax, double DistanceMax, unsigned char color32[3] )
{
double distance ;
distance = GiveDistance( Cx, Cy, iMax, DistanceMax);
if (distance > 0.0)
{
if (distance<DistanceMax) // boundary
{ // boundary
color32[0] = 255-(int)(255.0*distance);
color32[1] = 255-(int)(255.0*distance);
color32[2] = 255-(int)(255.0*distance);
}
else { // exterior far away from boundary
GiveRainbowColor(distance, color32); // gradient of 32 rgb color
}
}
else { // interior
color32[0] = 0;
color32[1] = 0;
color32[2] = 0;
}
return 0;
}
/* --------------------------------------------------------------------------------------------------------- */
int main(){
unsigned int iX,iY, /* indices of 2D virtual array (image) = integer coordinate */
i; /* index of 1D array */
double Cx, Cy;
//int ExtLastIteration; //
unsigned char color32[3];
printf(" Setup \n");
iXmax = iSide; /* height of image in pixels */
iYmax = iSide;
iLength = iXmax*iYmax*3; /* number of pixels* number of bytes per color */
CxMin = -2.25;
CxMax = 0.75 ;
CyMin = -dSide;
CyMax = dSide;
IterationMax = 1000 ;
PixelWidth= (CxMax-CxMin)/iXmax;
PixelHeight = (CyMax-CyMin)/iYmax;
ER2 = EscapeRadius*EscapeRadius;
CDistanceMax = GiveDistanceMax( PixelWidth, iSide);
/* dynamic 1D array for colors ( shades of gray ) */
unsigned char *data;
data = malloc( iLength * sizeof(unsigned char) );
if (data == NULL )
{
fprintf(stderr," Could not allocate memory");
return 1;
}
printf(" compute color for every pixel : scan c-plane \n");
for(iY=0;iY<iYmax;++iY){
Cy=CyMin + iY*PixelHeight; /* */
printf("row %u from %u \n",iY, iYmax);
for(iX=0;iX<iXmax;++iX){
Cx=CxMin + iX*PixelWidth;
ComputeColor32(Cx, Cy, IterationMax, CDistanceMax, color32);
i= f(iX,iY); /* compute index of 1D array from indices of 2D array */
/* change the color */
data[i] = color32[0];
data[i+1] = color32[1];
data[i+2] = color32[2];
}
}
printf(" save data array to the pgm file \n");
unsigned int length = 30;
char filename[length] ;
snprintf(filename, length, "%fg%.0fe%u%s",g, EscapeRadius,iXmax , ".ppm");
char *comment="# ";/* comment should start with # */
const unsigned int MaxColorComponentValue=255; /* color component is coded from 0 to 255 ; it is 8 bit color file */
FILE * fp;
fp = fopen(filename,"wb"); /*create new file,give it a name and open it in binary mode */
fprintf(fp,"P6\n %s\n %u\n %u\n %u\n",comment,iXmax,iYmax,MaxColorComponentValue); /*write header to the file*/
fwrite(data,iLength,1,fp); /*write image data bytes to the file in one step */
printf("File %s saved. \n", filename);
fclose(fp);
printf(" save graphic data to the text file \n");
char tfilename[length] ;
snprintf(tfilename, length, "%fg%.0fe%u%s",g, EscapeRadius,iXmax , ".txt");
fp = fopen(tfilename,"wb"); /*create new file,give it a name and open it in binary mode */
fprintf(fp,"IterationMax = %d \n", IterationMax);
fprintf(fp,"EscapeRadius = %f ER2 = %f \n", EscapeRadius, ER2);
fprintf(fp,"\n" ); /* */
fprintf(fp,"C plane : \n" ); /* */
fprintf(fp,"dWidth = %f ; dHeight = %f \n",CxMax- CxMin, CyMax - CyMin );
fprintf(fp,"PixelWidth = %f ; PixelHeight = %f \n", PixelHeight, PixelWidth);
fprintf(fp," CxMin = %f \n", CxMin); /* */
fprintf(fp," CxMax = %f \n", CxMax); /* */
fprintf(fp," CyMin = %f \n", CyMin); /* */
fprintf(fp," CyMax = %f \n", CyMax); /* */
fprintf(fp," center of image : C = %f ; %f \n",CxMax -(CxMax-CxMin)/2.0, CyMax - (CyMax-CyMin)/2.0); /* */
fprintf(fp,"\n" );
fprintf(fp,"g= %f used for distance = pow( g*distance, 0.25 ); \n", g);
printf("File %s saved. \n", tfilename);
fclose(fp);
printf(" always free memory \n ");
free(data);
return 0;
}
|
Function GiveDistance(xy2,eDx,eDy:extended):extended;
begin
result:=2*log2(sqrt(xy2))*sqrt(xy2)/sqrt(sqr(eDx)+sqr(eDy));
end;
//------------------------------------
Function PointIsInCardioid (Cx,Cy:extended):boolean;
//Hugh Allen
// http://homepages.borland.com/ccalvert/Contest/MarchContest/Fractal/Source/HughAllen.zip
var DeltaX,DeltaY:extended;
//
PDeltyX,PDeltyY:extended;
//
ZFixedX,ZFixedY:extended;
begin
result:=false;
// cardioid checkig - thx to Hugh Allen
//sprawdzamy Czy punkt C jest w głównej kardioidzie
//Cardioid in squere :[-0.75,0.4] x [ -0.65,0.65]
if InRange(Cx,-0.75,0.4)and InRange(Cy,-0.65,065) then
begin
// M1= all C for which Fc(z) has attractive( = stable) fixed point
// znajdyjemy punkt staly z: z=z*z+c
// czyli rozwiazujemy rownanie kwadratowe
// zmiennej zespolonej o wspolczynnikach zespolonych
// Z*Z - Z + C = 0
//Delta:=1-4*a*c; Delta i C sa liczbami zespolonymi
DeltaX:=1-4*Cx;
DeltaY:=-4*Cy;
// Pierwiastek zespolony z delty
CmplxSqrt(DeltaX,DeltaY,PDeltyX,PDeltyY);
// obliczmy punkt staly jeden z dwóch, ten jest prawdopodobnie przycišgajšcy
ZFixedX:=1.0-PDeltyX; //0.5-0.5*PDeltyX;
ZFixedY:=PDeltyY; //-0.5*PDeltyY;
// jesli punkt stały jest przycišgajšcy
// to należy do M1
If (ZfixedX*ZFixedX + ZFixedY*ZFixedY)<1.0
then result:=true;
// ominięcie iteracji M1 przyspiesza 3500 do 1500 msek
end; // if InRange(Cx ...
end;
//------------------------------------
Function PointIsInComponent (Cx,Cy:extended):boolean;
//Hugh Allen
// http://homepages.borland.com/ccalvert/Contest/MarchContest/Fractal/Source/HughAllen.zip
var Dx:extended;
begin
result:=false;
// czy punkt C nalezy do koła na lewo od kardioidy
// circle: center = -1.0 and radius 1/4
dx:=Cx+1.0;
if (Dx*Dx+Cy*Cy) < 0.0625
then result:=true;
end;
//------------------------------
Procedure DrawDEM_DazibaoTrueColor;
// draws Mandelbrot set in black and its complement in true color
// see http://ibiblio.org/e-notes/MSet/DEstim.htm
// by Evgeny Demidov
//
// see also
//http://www.mandelbrot-dazibao.com/Mset/Mset.htm
// translation ( with modification) of Q-Basic program:
// http://www.mandelbrot-dazibao.com/Mset/Mdb3.bas
//
// see also my page http://republika.pl/fraktal/mset_dem.html
var iter:integer;
iY,iX:integer;
eCy ,eCx:extended; // C:=eCx + eCy*i
eX,eY:extended; // Zn:=eX+eY*i
eTempX,eTempY:extended;
eX2,eY2:extended; //x2:=eX*eX; y2:=eY*eY;
eXY2:extended; // xy2:=x2+y2;
eXY4:extended;
eTempDx,eTempDy:extended;
eDx,eDy:extended; // derivative
distance:extended;
color:TColor;
begin
//compute bitmap
for iY:= iYmin to iYMax do
begin
eCy:=Convert_iY_to_eY(iY);
for iX:= iXmin to iXmax do
begin
eCx:=Convert_iX_to_eX(iX);
If not PointIsInCardioid (eCx,eCy) and not PointIsInComponent(eCx,eCy)
then
begin
// Z0:=0+0*i
eX:=0;
eY:=0;
eTempX:=0;
eTempY:=0;
//
eX2:=0;
eY2:=0;
eXY2:=0;
//
eDx:=0;
eDy:=0;
eTempDx:=0;
eTempDy:=0;
//
iter:=0;
// iteration of Z ; Z= Z*z +c
while ((iter<IterationMax) and (eXY2<=BailOut2)) do
begin
inc(iter);
//
eTempY:=2*eX*eY + eCy;
eTempX:=eX2-eY2 + eCx;
//
eX2:=eTempX*eTempX;
eY2:=eTempY*eTempY;
//
eTempDx:=1+2*(eX*eDx-eY*eDy);
eTempDy:=2*(eX*eDY+eY*eDx);
//
eXY2:=eX2+eY2;
//
eX:=ETempX;
eY:=eTempY;
//
eDx:=eTempDx;
eDy:=eTempDy;
end; // while
// drawing procedure
if (iter<IterationMax)
then
begin
distance:= GiveDistance(eXY2,eDx,eDy);
color:=Rainbow(1,500,Abs(Round(100*Log10(distance)) mod 500));
with Bitmap1.FirstLine[iY*Bitmap1.LineLength+iX] do
begin
B := GetBValue(color);
G := GetGValue(color);
R := GetRValue(color);
//A := 0;
end; // with FirstLine[Y*LineLength+X]
end // if (iter<IterationMax) then
else with Bitmap1.FirstLine[iY*Bitmap1.LineLength+iX] do
begin
B := 0;
G := 0;
R := 0;
//A := 0;
end;
//--- end of drawing procedure ---
end // If not PointIsInCardioid ... then
else with Bitmap1.FirstLine[iY*Bitmap1.LineLength+iX] do
begin
B := 0;
G := 0;
R := 0;
//A := 0;
end;
//--- If not PointIsInCardioid ...
end; // for iX
end; // for iY
end;
//------------------------------------------------------
修改/优化
[edit | edit source]可以通过使用 来改进 DEM 图像的创建
- 柯比 1/4 定理[16]
- 基于距离的灰度图[17][18]
- 分形论坛 : 跳出条件与解析 DE 精度之间的关系
- DEM/M 中的权重
- 如果你看到主天线有双重轮廓
- 提高分辨率并不能解决问题
- 在高度上增加一个像素,或更改 CyMax 或 CyMin(增加一个像素大小)。
均衡
[edit | edit source]距离估计均衡[19]
程序 exrdeeq[20]
- 读取 DEX 和 DEY 通道
- 输出 Y 通道
- DE 小于 0 则变为 0
- DE 大于 1 则变为 1
- 否则 Y 为 DE 在排序数组中的索引,缩放到 0 到 1 的范围内
exrdeeq in.exr out.exr
示例
[edit | edit source]- Duncan Champney 绘制的 B of F 地图 43 DEM[21]
- 该图以 -0.7436636773584340, 0.1318632143960234i 为中心,宽度约为 6.25E-11
- Duncan Champney 绘制的微笑万花筒 [22]
height=800 width=800 max_iterations=10000 center_r=-1.74920463346 center_i=-0.000286846601561 r_width=3.19E-10
内部距离估计
[edit | edit source]估计极限周期点 (在曼德布罗特集合的内部)到曼德布罗特集合边界的距离。
描述 :[23]
- 书籍 : The Science of Fractal Images, Springer Verlag, Tokyo, Springer, New York, 1988 by Heinz-Otto Peitgen , D. Saupe, page 294
- Albert Lobo Cusidó 关于曼德布罗特集合的内部和外部距离边界
- R Munafo 的内部距离估计方法
- mandelbrot-numerics 库 : m_d_interior by Claude
// https://mathr.co.uk/mandelbrot/book-draft/#interior-distance
// Claude Heiland-Allen
#include <complex.h>
#include <math.h>
double cnorm(double _Complex z)
{
return creal(z) * creal(z) + cimag(z) * cimag(z);
}
double m_interior_distance
(double _Complex z0, double _Complex c, int p)
{
double _Complex z = z0;
double _Complex dz = 1;
double _Complex dzdz = 0;
double _Complex dc = 0;
double _Complex dcdz = 0;
for (int m = 0; m < p; ++m)
{
dcdz = 2 * (z * dcdz + dz * dc);
dc = 2 * z * dc + 1;
dzdz = 2 * (dz * dz + z * dzdz);
dz = 2 * z * dz;
z = z * z + c;
}
return (1 - cnorm(dz))
/ cabs(dcdz + dzdz * dc / (1 - dz));
}
double m_distance(int N, double R, double _Complex c)
{
double _Complex dc = 0;
double _Complex z = 0;
double m = 1.0 / 0.0;
int p = 0;
for (int n = 1; n <= N; ++n)
{
dc = 2 * z * dc + 1;
z = z * z + c;
if (cabs(z) > R)
return 2 * cabs(z) * log(cabs(z)) / cabs(dc);
if (cabs(z) < m)
{
m = cabs(z);
p = n;
double _Complex z0 = m_attractor(z, c, p);
double _Complex w = z0;
double _Complex dw = 1;
for (int k = 0; k < p; ++k)
{
dw = 2 * w * dw;
w = w * w + c;
}
if (cabs(dw) <= 1)
return m_interior_distance(z0, c, p);
}
}
return 0;
}
数学描述
[edit | edit source]该估计值由 给出
其中
是要估计的 参数平面 中的点
是 复二次多项式
是 -次迭代
是构成周期轨道(极限环) 的 个点中的任意一个
在 处计算的 的 4 个 导数
关于 z 的一阶偏导数
[edit | edit source]它必须通过应用链式法则递归地计算
起点:
第一次迭代:
第二次迭代:
第p次迭代的一般规则:
它必须通过应用链式法则递归地计算
起始点:
第一次迭代:
第二次迭代:
p 次迭代的一般规则:
关于 z 的二阶偏导数
[edit | edit source]它必须计算
- 与: 和 一起
- 递归地应用链式法则
起点:
第一次迭代:
第二次迭代:
p 迭代的一般规则:
- 选择 c
- 检查给定 c 的临界点是否为周期性的(内部)或非周期性的(外部或接近边界或周期过大)
- 如果非周期性,则不要使用此算法(使用外部版本)
- 如果周期性,则计算周期和周期点
- 使用 计算 p 迭代的距离
- Albert Lobo Cusidó 的 Java 代码[24]
- Claude 的 Haskell 代码[25] 和图像[26]
- tit_toinou 的 processing 代码[27] 和描述[28]
内部距离估计有两个实际问题
- 首先,我们需要精确找到 ,
- 其次,我们需要精确找到 。
的问题是,理论上,通过迭代 来收敛到 需要无限次的操作。
周期的问题是,有时由于舍入误差,会错误地将周期识别为真实周期的整数倍(例如,检测到 86 的周期,而真实周期只有 43=86/2)。在这种情况下,距离被高估,即报告的半径可能包含曼德尔布罗特集合之外的点。
对于内部距离估计,您需要周期,然后需要一些(可能 10 个左右,通常就足够了)牛顿步来找到极限环。
内部检查代码绝对要求参考点位于岛的核心中(不是它的任何子圆盘,当然也不是随机点)
- 与外部情况类似,一旦找到b,我们就知道距离c 的b/4 内的所有点都在曼德尔布罗特集合内。
- 使用距离估计的自适应超采样 Claude Heiland-Allen 使用距离估计的自适应超采样
- Claude Heiland-Allen 2020-04-23 的混合逃逸时间分形距离估计
- Milnor "曼德尔布罗特集合中的自相似性和毛发",1989 年的几何与拓扑学中的计算机。
- ↑ A Cheritat wiki-draw: Mandelbrot_set
- ↑ fractalforums : m-set-distance-estimation
- ↑ fractalforums discussion : How are B&W images from "Beauty of Fractals" created?
- ↑ fractalforums.org : m-brot-distance-estimation-versus-claudes-fake-de
- ↑ Milnor (在单个复变量中的动力学,附录 G)
- ↑ Heinz-Otto Peitgen(编辑、贡献者),Dietmar Saupe(编辑、贡献者),Yuval Fisher(贡献者),Michael McGuire(贡献者),Richard F. Voss(贡献者),Michael F. Barnsley(贡献者),Robert L. Devaney(贡献者),Benoit B. Mandelbrot(贡献者) : 分形图像的科学。施普林格;第一版(1988 年 7 月 19 日),第 199 页
- ↑ ińigo quilez 的分形距离渲染
- ↑ fractalforums : mandelbrot-distance-estimation-problem
- ↑ fractalforums.org : list-of-numbers-with-fixed-digit-length-in-the-mandelbrot-set
- ↑ Robert P. Munafo 的距离估计器
- ↑ math.stackexchange 问题:如何绘制具有连接细丝的曼德尔布罗特集合
- ↑ 曼德尔布罗特书籍
- ↑ Fractal forum : 如何从 "Beauty of Fractals" 中创建黑白图像?
- ↑ Mikael Hvidtfeldt Christensen 的距离估计 3D 分形(V):曼德尔球体和不同的 DE 近似
- ↑ ińigo quilez 的分形距离渲染
- ↑ Claude Heiland-Allen 的距离估计
- ↑ ińigo quilez 的分形距离渲染
- ↑ fractalforums 画廊,作者 Pauldelbrot
- ↑ fractalforums.org : histogram-de-coloring
- ↑ Claude Heiland-Allen 的距离估计均衡
- ↑ Duncan Champney 的 B of F 地图 43 DEM
- ↑ Duncan Champney 的 Smily Kaleidoscope
- ↑ 曼德博集合的内部和外部距离界限,作者 Albert Lobo Cusidó
- ↑ 曼德博集合的内部和外部距离界限,作者 Albert Lobo Cusidó
- ↑ 曼德博集合中的内部坐标,作者 Claude
- ↑ 分形论坛 : 曼德博集合内部点的着色
- ↑ ttoinou 编写的 Processing 中的 MandelbrotDE
- ↑ 分形论坛 : 使用距离和梯度着色的经典曼德博集合