分形/複平面中的迭代/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
- ↑ 分形論壇 : 使用距離和梯度著色的經典曼德博集合