跳转到内容

分形/kallesfraktaler

来自维基教科书,开放的书籍,开放的世界

Kalles Fraktaler

参见 公共领域分类:用 Kalles Fraktaler 创建

启动

wine ./kf.x86_64.exe 



将图像大小设置为与窗口大小相同(在视图中)


只需保存您的设置 KFS(如果您想要 640x360 之外的尺寸),位置 KFR(如果您想要未缩放的 M 集之外的任何内容),调色板 KFP(可选,覆盖来自 KFR 的内容),然后调用 KF,例如

/path/to/kf.exe -s my.kfs -l my.kfr -c my.kfp -x my.exr

然后您就可以通过 OpenEXR(C++)或其他库在您的程序中加载 EXR。

对于(重新)为包含原始迭代数据的现有 EXR 文件着色,请尝试

/path/to/kf.exe -s old.exr -l old.exr -o old.exr -c new-palette.kfp  -x new.exr

参见 KF 的手册(接近末尾)以获取 EXR 通道文档,对于处理来自 KF 的 EXR 的第三方软件,请查看 zoomasm。

也支持另存为其他格式:查看 kf.exe --help 以获取详细信息。


制作视频的步骤

 mkdir ~/work
cd ~/work
wine32 ~/windows/fraktal_sft.exe
# render zoom out sequence with kalles fraktaler, saving to ~/work
for i in *.kfb ; do ~/code/maximus_kf-extras/pseudo-de < ${i} | pgmtoppm white > ${i%kfb}ppm done
# count number of kfb files, (ls *.kfb | tail -n 1) gives a hint, I had 311
ls *.kfb | ~/code/maximus_kf-extras/expmap 311 > expmap.pgm
ghc -e "100 / sqrt ( 565 * 19820 / (120 * 8000) )"
# or your favourite calculator program if you don't have ghc
# prints 29.27922435677391
# where 565 * 19820 is the size of the expmap
# 8000 is desired sample rate
# 120 is desired movie length in seconds
gimp expmap.pgm
# downscale by 29.27922435677391% (output from ghci)
# flip vertically
# make sure it's greyscale with no alpha
# save as expmap-downscaled.png
# gimp saves comments in its netpbm writers, my bad code doesn't handle it
pngtopnm < expmap-downscaled.png > expmap-downscaled.pgm
audacity
# import raw expmap-downscaled.pgm as raw unsigned 8bit PCM mono 8000Hz
# set project sample rate to 48000Hz
# select the track, mix and render
# select the track, apply filter DC Offset Removal (maybe needs a plugin)
# select the track, select amplify and apply to normalize the volume
# duplicate the track twice
# for each of the duplicates in turn, select it and apply a reverb (GVerb plugin)
# use slightly different reverb settings for each track (for stereo effect)
# normalize the duplicates by select track, select amplify, apply
# make one duplicate a left channel and the other a right channel
# set the levels of each track to -3dB
# select all tracks, mix and render
# normalize volume if needed
# select track, export as stereo wav 16bit PCM to expmap.wav
# note down the length (my test gave 1m56s)
ghc -e "1 * 60 + 56"
# to get the audio length in seconds (116)
# check the size of the kfb files (here I used 640 by 360)
# remember we have 311 kfb files
ls 00*.ppm | tac | xargs cat | ~/code/maximus_book/code/zoom 640 360 311 116 |
  avconv -f yuv4mpegpipe -i - -i expmap.wav -acodec vorbis -ab 192k -vb 2M out.ogv
# finally!
mplayer out.ogv
  • 在 Kalle's Fraktaler 中,图像每半秒钟更新一次

图像大小

[编辑 | 编辑源代码]

不考虑图像大小(像素加上原始迭代数据):[1]

对于 KF 2.15.2.2

  • 如果使用双精度:每个迭代 24 字节(到缩放深度 e300,或对于 Mandelbrot 幂 2 仅缩放双精度到 e600)
  • 如果使用长双精度:在 64 位上每个迭代 40 字节,在 32 位上每个迭代 32 字节(到缩放深度 e4900,或对于 Mandelbrot 幂 2 仅缩放长双精度到 e9800)
  • 如果使用 floatexp:每个迭代 40 字节(“无限”缩放)

对于 KF 2.15.3(正在开发中,大部分工作完成,未发布)

  • 如果使用双精度:每个迭代 24 字节(到缩放 e300)
  • 如果使用缩放的双精度:每个迭代 24 字节,加上每个迭代 48 字节,接近于 0(“无限”缩放)
  • 如果使用长双精度:在 64 位上每个迭代 48 字节;在 32 位上每个迭代可能是 36 字节(到缩放 e4900)
  • 如果使用 floatexp:每个迭代 48 字节(“无限”缩放)

对于 KF 2.15.3(可能,需要测试在实现之后是否真的有效,正在开发中,尚未发布,更不用说完成了)

  • 如果使用单精度浮点数:每个迭代 12 字节(最多缩放深度 1e38)
  • 如果使用单精度缩放浮点数:每个迭代 12 字节,加上每个迭代 24 字节,接近于 0(“无限”缩放)
  • 如果使用单精度 floatexp:每个迭代 24 字节(“无限”缩放)

KF 没有实现内存优化以仅在级数逼近后存储参考,它存储了整个轨道。但是,如果使用 OpenCL,它确实只将级数逼近后的部分上传到设备。

请注意,32 位程序的地址空间限制为 4GB,这对于 10 亿次迭代来说是不够的,每次迭代需要 4 个字节;这些数字仅供完整性参考。

要将 10 亿次迭代(10 亿)的 N 字节/像素进行转换,很简单,就是 N 吉字节。

  • T:数字类型,双精度或长双精度或 floatexp(在需要更多范围时使用)
  • Zr,Zi:最终逃逸的 Z 值
  • Jxa,Jxb,Jya,Jyb:运行导数(对于复解析公式,Jxa = Jyb 和 Jxb = - Jya,即柯西-黎曼条件)Jxa = Jyb = Re(dz/dc),Jya = -Jxb = Im(dz/dc)
  • s:像素间距
  • TK:旋转和倾斜矩阵(如果您不旋转或倾斜,则这应该是单位矩阵)
  • 设置缩放级别,CTRL-左键单击放大,右键单击缩小。

状态栏

[编辑 | 编辑源代码]
  • D% 像素已使用当前参考完成
  • G% 像素通过相邻内部像素猜测
  • R% 参考迭代次数与最大迭代次数之比
  • A% 级数逼近跳过的迭代次数与最大迭代次数之比

菜单取决于 KF 的版本

  • 文件->打开 用于 KFR
  • 文件->打开地图 用于 KFB

指数映射

[编辑 | 编辑源代码]

应用 指数映射坐标变换。为了获得最佳(更保形)的结果,请使用宽纵横比(9:1 很好,窗口大小 1152x128 或 1536x170)。

您可以存储指数映射缩小序列(将缩放大小设置为 2),并将它们组合成一个使用 zoomasm 缩放视频组装器的电影。这比存储平面关键帧要高效得多。

  • 种子值
    • 对于分形类型 = Z0
  • 分形类型



对话框 迭代次数

  • "最大迭代次数"
  • "当前视图中的最小迭代次数"
  • "当前视图中的最大迭代次数"
  • "级数逼近跳过的迭代次数"
  • "迭代次数的逃逸值"
  • "曼德勃罗函数的幂"
  • "用于故障校正的额外参考的最大值"
  • "已检查级数逼近的低容差\n复数图像可能需要选中此选项才能正确渲染\n如果未选中此复选框,则渲染时间可能会更快"
  • "级数逼近的项根据要渲染的像素数量进行调整."
  • "基于曼德勃罗的分形类型的列表\n其中一些具有额外的幂选项"
  • "级数逼近的项.\n更多项通常会导致更多跳过的迭代次数和更快的渲染,\n但处理起来更耗时"
  • "显示执行的计算次数"
  • "在检查逃逸值时包含实部.\n取消选中以进行变体"
  • "在检查逃逸值时包含虚部.\n取消选中以进行变体"
  • "实数种子值(0 为标准)"
  • "虚数种子值(0 为标准)"


逃逸值和类型

[编辑 | 编辑源代码]

p-范数,带权重:[2]


所有 { a b p R } 都可配置,p = 无穷大(使用 max)为特例

分形类型的种子值

[编辑 | 编辑源代码]

要使用以下方法更改打开对话框窗口

  • 菜单/操作/迭代次数
  • 键:Ctrl+I

分形类型 = m_nFractalType

[编辑 | 编辑源代码]

可以在迭代次数菜单中更改它

  • 菜单/分形/迭代次数
  • Ctrl+I

类型

  • 0 = 曼德勃罗集(标准设置)
  • 1 = 燃烧之船
  • 2 = 水牛
  • 3 = 凯尔特
  • 4 = 曼德勃罗集共轭
  • 5 = 曼德勃罗集共轭凯尔特
  • 6 = 垂直曼德勃罗集
  • 7 = 垂直燃烧之船
  • 8 = 垂直凯尔特
  • 9 = 垂直水牛
  • 10 = 立方拟燃烧之船
  • 11 = 立方部分 BS 实部
  • 12 = 立方部分 BS 虚部
  • 13 = 立方飞翔松鼠(水牛虚部)
  • 14 = 立方拟垂直
  • 15 = 第四次燃烧之船部分虚部
  • 16 = 第四次燃烧之船部分实部
  • 17 = 第四次燃烧之船部分实部共轭
  • 18 = 第四次凯尔特燃烧之船部分虚部
  • 19 = 第四次凯尔特燃烧之船部分实部
  • 20 = 第四次凯尔特燃烧之船部分实部共轭
  • 21 = 第四次水牛部分虚部
  • 22 = 第四次凯尔特共轭
  • 23 = 第四次伪拟垂直
  • 24 = 第四次伪拟心脏
  • 25 = 第四次凯尔特伪拟垂直 25
  • 26 = 第四次凯尔特伪拟心脏 26
  • 27 = 第五次燃烧之船部分 27
  • 28 = 第五次燃烧之船部分共轭 28
  • 29 = 第五次凯尔特共轭 29
  • 30 = 第五次拟燃烧之船(燃烧之船/水牛混合体) 30
  • 31 = 第五次拟垂直 31
  • 32 = 第五次拟心脏 32
  • 33 = SimonBrot 第四次 33
  • 34 = 第四次虚部拟垂直/心脏 34
  • 35 = 第四次实部拟垂直 35
  • 36 = 第四次实部拟心脏 36
  • 37 = 第四次凯尔特虚部拟垂直/心脏 37
  • 38 = 第四次凯尔特实部拟垂直 38
  • 39 = 第四次凯尔特实部拟心脏 39
  • 40 = SimonBrot 第六次 40
  • 41 = HPDZ 水牛 : Z = |Z0|^2 - |Z| + C
  • 42 = TheRedshiftRider 1: a*z^2+z^3+c"); // 42
  • 43 = TheRedshiftRider 2: a*z^2-z^3+c"); // 43
  • 44 = TheRedshiftRider 3: 2*z^2-z^3+c"); // 44
  • 45 = TheRedshiftRider 4: a*z^2+z^4+c"); // 45
  • 46 = TheRedshiftRider 5: a*z^2-z^4+c"); // 46
  • 47 = TheRedshiftRider 6: a*z^2+z^5+c"); // 47
  • 48 = TheRedshiftRider 7: a*z^2-z^5+c"); // 48
  • 49 = TheRedshiftRider 8: a*z^2+z^6+c"); // 49
  • 50 = TheRedshiftRider 9: a*z^2-z^6+c"); // 50
  • 51 = SimonBrot2 第四次 // 51
  • KF 可以将原始迭代数据导出为 EXR(和过时的 KFB)格式,因此您可以使用其他软件对其进行着色
  • 包含迭代数据的映射文件 (*.kfb, *.exr)
  • 包含当前位置和设置的参数文件 (*.kfr)(也包含在图像元数据中)
  • fraktal_sft.exe(旧版 kf)

EXR 文件通道

  • 原始迭代数据 = 归一化的迭代次数[3]
    • N = 整数迭代次数(uint32)
    • NF = 小数迭代次数,范围在 [0.0 .. 1.0) 内的浮点数
  • T = 相位 = 第一个逃逸的 Z 值的自变量,以转数计量
  • Jxa, Jxb, Jya, Jyb:运行导数
    • 对于复分析公式,Jxa = Jyb 且 Jxb = - Jya,即柯西-黎曼条件
    • Jxa = Jyb = Re(dz/dc),Jya = -Jxb = Im(dz/dc)
  • DE = 方向距离估计(在计算出导数后)
  • RGB = 颜色(半浮点数):线性光照中的一半 R、一半 G、一半 B
  • 元数据


通道名称是字符串


pnmcat -tb *.exr > *.ppm

归一化迭代次数

[编辑 | 编辑源代码]

uint32 N 整数迭代次数

0xFFFFFFFF 在标题元数据字段 int Iterations(或字符串 Iterations,因为它可以超过 int 的范围)之前未逃逸

0x00000000 未计算/故障/无可用数据。

如果实际迭代值可以为零或负数,则向每个计数添加一个偏差常数,并将其存储在标题元数据字段 int IterationsBias(或字符串 IterationsBias 中,它可以超过 int 的范围)。偏差可以为负数,这可能允许你存储高迭代次数,而无需在实际最小/最大范围足够小的情况下,特别需要两个通道。

对于迭代次数偏差高于 0xFFFFFFFE 的图像,将其拆分为两个通道

uint32 N0 最低有效 32 位

uint32 N1 最高有效 32 位

(0xFFFFFFFF, 0xFFFFFFFF) 被解释为未逃逸

对于未来的超级计算机,这可以通过 N2 等进行扩展…


  • 连续迭代次数(在逃逸时)是 N+NF-IterationsBias。为了避免在高迭代次数时丢失精度,它被单独存储
  • 希望这与 NF 对齐以给出二维外部网格单元坐标,2.15 之前的 KF 版本仅与线性平滑对齐。
  • genType NF 分数迭代次数,预计在 [0.0 .. 1.0) 之间,对于 float32 和 half(float16)来说,以及通过除以 0x100000000 对 uint32 进行归一化的整个范围。连续迭代次数(在逃逸时)是 N+NF-IterationsBias。为了避免在高迭代次数时丢失精度,它被单独存储


  • 第一个逃逸 Z 值的相位,以转数计量。
  • 基于最终迭代的自变量角度的相位通道(EXR 中的 T)
  • float T 在 [0.0 .. 1.0) 之间

方向 DE(在计算出导数后)

float DEX,float DEY 方向距离估计,以笛卡尔形式归一化,使得相邻边界像素的距离 sqrt(DEX^2 + DEY^2) 大致为 1.0。

如果一些像素没有方向 DE,则缺少的数据可以写为 (0.0, 0.0),但读取器也应该处理这种情况下的 NaN。该向量指向远离分形边界。



floatType DE 有符号距离估计,归一化使得相邻边界像素的距离对于外部距离估计大致为 1.0,对于内部距离估计大致为 -1.0。如果存在外部 de 但没有内部 de 可用(反之亦然),则缺少的数据可以写为 0.0,但读取器也应该处理这种情况下的 NaN。

floatType DEX,floatType DEY 方向距离估计,以笛卡尔形式归一化,使得相邻边界像素的距离 sqrt(DEX^2 + DEY^2) 大致为 1.0。如果一些像素没有方向 DE,则缺少的数据可以写为 (0.0, 0.0),但读取器也应该处理这种情况下的 NaN。该向量应该指向远离分形边界。

floatType ZX,floatType ZY 第一次逃逸迭代时的坐标。图像应该具有一个标题属性 floatType EscapeRadius。


轨道陷阱可以作为具有 TRAP 的路径中的层进行处理

uint32 TRAP.N 命中陷阱时的迭代次数,有关大型迭代次数,请参见上文

floatType TRAP.TD 到陷阱的距离(例如,x 轴陷阱将具有 |y 坐标|)(以你喜欢的任何方式进行归一化,因为深度图像可能具有微小的值(也许?),但应该是单调的,例如,如果你取对数以获得比 float32 更大的范围,它可能是负数。

floatType TRAP.ZX,floatType TRAP.ZY 陷阱迭代时的坐标,应该进行归一化,以使陷阱边缘的幅度为 1.0(不能仅使用 X 和 Y,因为 Y 在 EXR 中已经被用作颜色亮度)。

JPEG 是有损的

"KFC" 是 bNewFormat 1,float32 组合数据的垂直线(int32 迭代 + float32 平滑)

过时格式,参见 exr


地图文件 (.kfb) 包含

  • 计算出的分形数据
    • 迭代次数
      • N(最大迭代次数,整数)
      • NF(迭代次数,平滑部分 = 双精度)
    • 如果启用了导数计算,有时还会估计距离)
  • 它还包含一些颜色信息(但这不是完整的)

它不包含坐标。

这些文件是在

  • 保存 jpg 文件时,还会为每个图像创建一个 kfb 文件
  • 保存地图

描述

  • "KF 可以将原始迭代数据导出为 EXR(以及过时的 KFB)格式,因此你可以在其他软件中对其进行着色"
  • "KFB 文件存储原始未压缩(即巨大但高质量)的迭代数据(在应用着色之前分形计算的结果)。" FF 上的克劳德,例如原始 float32 DE 图像(按像素间距缩放)
  • "KFB 文件是图像,用作地图来存储迭代数据。没有位置、调色板等" youhn


FF 上的克劳德:[4]

They are strings found inside .kfb files (the first 3 bytes) to distinguish different versions of the data format stored in the file.

"KFB" is bNewFormat 0, vertical lines of int32 iteration plane followed by float32 smooth colouring plane.
"KFC" is bNewFormat 1, vertical lines of float32 combined data (int32 iteration + float32 smooth)
"KFD" is bNewFormat 2, horizontal lines of float32 combined data (int32 iteration + float32 smooth)

As far as I can tell, only "KFB" is actually saved by current versions of Kalles Fraktaler.

"KFB" is also the only format that preserves smooth colouring at high iteration counts, because single precision float32 can only represent integers after 2^24 = 16M, can only represent even integers after 2^25 = 33M, etc, with gradual degradation before that.




// from fractal_sftp.cpp  Kalles Fraktaler 2 © 2014-2015 Karl Runmo
void CFraktalSFT::SaveMapB(char *szFile)
{
	if (!m_nPixels)
		return;
	DWORD dw;
	HANDLE hFile = CreateFile(szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
	int x;
	WriteFile(hFile, "KFB", 3, &dw, NULL);
	WriteFile(hFile, &m_nX, sizeof(m_nX), &dw, NULL);
	WriteFile(hFile, &m_nY, sizeof(m_nY), &dw, NULL);
	for (x = 0; x<m_nX; x++)
		WriteFile(hFile, m_nPixels[x], m_nY*sizeof(int), &dw, NULL);
	int div = m_nIterDiv;
	WriteFile(hFile, &div, sizeof(m_nParts), &dw, NULL);
	WriteFile(hFile, &m_nParts, sizeof(m_nParts), &dw, NULL);
	WriteFile(hFile, m_cKeys, sizeof(COLOR14)*m_nParts, &dw, NULL);
	WriteFile(hFile, &m_nMaxIter, sizeof(int), &dw, NULL);
	for (x = 0; x<m_nX; x++)
		WriteFile(hFile, m_nTrans[x], m_nY*sizeof(float), &dw, NULL);
	CloseHandle(hFile);
}

这是 Gerrit 编写的 octave/matlab 代码:[5]

function [width,height,counts,trans,maxiter,parts,keys] = readKFB(fn)

% counts are iterations
% trans is the correction to smooth iteration count based on escape time
% (see wiki) 
% parts is number of colors, keys are the colors.
% to make a colormap(cmap):
% > cmap = reshape(keys,3,parts)'/255.;
% > cmap = flipud(fliplr(cmap));

info = dir(fn);
fid = fopen(fn,'r');
d = fread(fid, [1, info.bytes], '*uint8');
fclose(fid);
%d(1:3) == 'KFB' test skipped
k = 4;
nBytes = 4;
width = typecast(uint8(d(k:k+nBytes-1)),'uint32');
width = double(width);
k = k + nBytes;
height = typecast(uint8(d(k:k+nBytes-1)),'uint32');
height = double(height);
k = k + nBytes;
nCounts = width*height; %32 bit ints
nBytes = 4 * nCounts;
counts = typecast(uint8(d(k:k+nBytes-1)),'uint32');
counts = reshape(counts,height,width);
counts = single(counts);
k = k + nBytes;
nBytes = 4;
iterdiv = typecast(uint8(d(k:k+nBytes-1)),'uint32');
k = k + nBytes;
parts = typecast(uint8(d(k:k+nBytes-1)),'uint32');
parts = double(parts);
k = k + nBytes;
nBytes = parts * 3;
% r,g,b,... parts triples
keys = typecast(uint8(d(k:k+nBytes-1)),'uint8');
keys = double(keys);
k = k + nBytes;
nBytes = 4;
maxiter = typecast(uint8(d(k:k+nBytes-1)),'uint32');
maxiter = double(maxiter);
k = k + nBytes;
nBytes = 4 * nCounts;
trans = typecast(uint8(d(k:k+nBytes-1)),'single');
trans = reshape(trans,height,width);



十六进制编辑器中的文件头 

KFB....h.

kfp = Kalles Fraktaler 调色板文件

On the file naming convention used a file name such as
"p512bcgwmryk.kfp" is a 512 colour palette a 3bit colour cube sorted into Blue, Cyan, Green, White, Magenta, Red and yellow groups, then sub sorted within these groups to get a smooth changes in colour.
Most files will have a striping ending "p512bcgwmrykof8.kfp" shifts each 2nd colour 8 places.
"p512bcgwmrykpm4816"  is a more complex striping, the 2nd colour is shifted 4 paces, the 4th 8 places, the 6th 4 places and the 8th 16 places and so on.
"p512X2bcgwyrmkof32" duplicates the 512 colour palette into light and dark halves.
"p1024bmwmbcgyrk" the "bm" stands for bit mix a more satisfactory way of sampling the 8 bit colour cube into 1024 colours.
There are a few other oddball palettes, "LenaSoderburg.kfp" is a palette that is a 32x32 low resolution version of the famous "Lena" picture use in early image processing development.

Jeremy Thomson
ColorOffset: 0
Rotate: 0
Ratio: 363.025211
Colors: 0,0,255,0,4,255,0,8,255,0,12,255,0,16,255,0,20,255,0,24,255,0,28,255,0,32,255,0,36,255,0,40,255,0,45,255,0,49,255,0,53,255,0,57,255,0,61,255,0,65,255,0,69,255,0,73,255,0,77,255,0,81,255,0,85,255,0,89,255,0,93,255,0,97,255,0,101,255,0,105,255,0,109,255,0,113,255,0,117,255,0,121,255,0,125,255,0,130,255,0,134,255,0,138,255,0,142,255,0,146,255,0,150,255,0,154,255,0,158,255,0,162,255,0,166,255,0,170,255,0,174,255,0,178,255,0,182,255,0,186,255,0,190,255,0,194,255,0,198,255,0,202,255,0,206,255,0,210,255,0,215,255,0,219,255,0,223,255,0,227,255,0,231,255,0,235,255,0,239,255,0,243,255,0,247,255,0,251,255,0,255,255,
Smooth: 0
MultiColor: 0
BlendMC: 0
MultiColors: 
Power: 2
FractalType: 0
Slopes: 0
SlopePower: 50
SlopeRatio: 50
SlopeAngle: 45
image: 1
real: 1
SeedR: 0
SeedI: 0
FactorAR: 1
FactorAI: 0


 grep -nR "kfp"
fraktal_sft/cmdline.cpp:280:"    -c, --load-palette  [FILE.kfp]  load palette file\n"
fraktal_sft/main_color.cpp:481:			if(BrowseFile(hWnd,FALSE,"Save palette","Palette\0*.kfp\0\0",szFile))
fraktal_sft/main_color.cpp:696:			if(BrowseFile(hWnd,TRUE,"Open palette","Palette\0*.kfp\0\0",szFile)){


使用

 /path/to/kf.exe -s my.kfs -l my.kfr -c my.kfp -x my.exr
 
 

对于(重新)为包含原始迭代数据的现有 EXR 文件着色,请尝试

 /path/to/kf.exe -s old.exr -l old.exr -o old.exr -c new-palette.kfp  -x new.exr
  • 文本文件
  • 包含参数

加载地图文件之前,可以使用参数文件 (.kfr) 进行更进一步的导航。你可以将 .kfr 重命名为 .kfp,并在颜色对话框中加载它。

Re: -1.252075014867735555974940801848588674907763636282052371316271536003707048655691466436892204807423486911208873753204122
Im: -0.008791858755657632997049331233776536713263464347924936644487037690633902732242296004830894920786698063372255536046170 
Zoom: 2.9333318059216862E91 
Iterations: 31394 
IterDiv: 0.010000 
SmoothMethod: 0 
ColorMethod: 7 
Differences: 3 
ColorOffset: 0 
Rotate: 0.000000 
Ratio: 383.431953 
Colors: 195,192,201,41,59,47,31,230,221,54,211,5,239,241,216,219,206,62,238,205,241,9,21,23, 
InteriorColor: 0,0,0, 
Smooth: 1 
MultiColor: 0 
BlendMC: 0 
MultiColors: 
Power: 2 
FractalType: 0 
Slopes: 1 
SlopePower: 50 
SlopeRatio: 20 
SlopeAngle: 45 
imag: 1 
real: 1 
SeedR: -0.5 
SeedI: 0 
FactorAR: 1 
FactorAI: 0 
Period: 0 
ZoomSize: 2 
MaxReferences: 10000 
GlitchLowTolerance: 0 
ApproxLowTolerance: 0 
AutoApproxTerms: 1 
ApproxTerms: 63 
WindowWidth: 640 
WindowHeight: 360 
WindowTop: 318 
WindowLeft: 630 
WindowBottom: 445 
WindowRight: 660 
ImageWidth: 8000 
ImageHeight: 4500 
ThreadsPerCore: 1 
AnimateZoom: 1 
ArbitrarySize: 1 
ReuseReference: 0 
AutoSolveGlitches: 1 
Guessing: 1 
SolveGlitchNear: 0 
NoApprox: 0 
Mirror: 0 
LongDoubleAlways: 0 
FloatExpAlways: 0 
AutoIterations: 1 
ShowGlitches: 1 
NoReuseCenter: 1 
IsolatedGlitchNeighbourhood: 4 
JitterSeed: 0 
JitterShape: 0 
JitterScale: 1 
Derivatives: 0 
ShowCrossHair: 0 
UseNanoMB1: 0 
UseNanoMB2: 0 
OrderM: 16 
OrderN: 16 
InteriorChecking: 0
RadiusScale: 0.100000000000000006

示例

此文件类型用于设置 (.kfs),有助于配置命令行渲染或保存预设。

程序可以打开和保存带有注释的 pang


/*
Kalles Fraktaler 2
Copyright (C) 2013-2017 Karl Runmo
Copyright (C) 2017-2018 Claude Heiland-Allen

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <string>
#include <png.h>
#include <zlib.h>

#include "png.h"

static void kf_png_error_handler(png_structp png, png_const_charp msg)
{
	// FIXME make this display in the GUI or something
	fprintf(stderr, "PNG ERROR: %s\n", msg);
	longjmp(*static_cast<jmp_buf *>(png_get_error_ptr(png)), 1);
}

static void kf_png_warning_handler(png_structp png, png_const_charp msg)
{
	(void) png;
	// FIXME make this display in the GUI or something
	fprintf(stderr, "PNG WARNING: %s\n", msg);
}

static bool skip_png_image(png_structp png, png_infop info);

extern int SavePNG(const std::string &szFileName, char *Data, int nHeight, int nWidth, int nColors, const std::string &comment)
{
	jmp_buf jmpbuf;
	if (nColors != 3)
		return 0;
	FILE *file = fopen(szFileName.c_str(), "wb");
	if (! file)
		return 0;
	png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, &jmpbuf, kf_png_error_handler, kf_png_warning_handler);
	if (! png)
		return 0;
	png_infop info = png_create_info_struct(png);
	if (! info)
	{
		png_destroy_write_struct(&png, 0);
		fclose(file);
		return 0;
	}
	if (setjmp(jmpbuf))
	{
		png_destroy_write_struct(&png, &info);
		fclose(file);
		return 0;
	}
	png_init_io(png, file);
	png_set_compression_level(png, Z_BEST_COMPRESSION);
	png_set_IHDR(png, info, nWidth, nHeight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_ADAM7, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
	png_time mtime;
	png_convert_from_time_t(&mtime, time(0));
	png_set_tIME(png, info, &mtime);
	png_text text;
	text.compression = PNG_TEXT_COMPRESSION_NONE;
	const std::string &key = "Comment";
	text.key = const_cast<char *>(key.c_str());
	text.text = const_cast<char *>(comment.c_str());
	png_set_text(png, info, &text, 1);
	png_write_info(png, info);
	png_bytepp row = new png_bytep[nHeight];
	for (int y = 0; y < nHeight; ++y)
		row[y] = (png_bytep)(Data + nWidth * nColors * y);
	png_write_image(png, row);
	png_write_end(png, 0);
	delete [] row;
	fclose(file);
	return 1;
}

extern std::string ReadPNGComment(const std::string &filename)
{
	jmp_buf jmpbuf;
	FILE *file = fopen(filename.c_str(), "rb");
	if (! file)
		return "";
	png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, &jmpbuf, kf_png_error_handler, kf_png_warning_handler);
	if (! png)
	{
		fclose(file);
		return "";
	}
	png_infop info = png_create_info_struct(png);
	if (! info)
	{
		png_destroy_read_struct(&png, 0, 0);
		fclose(file);
		return "";
	}
	png_infop enfo = png_create_info_struct(png);
	if (! enfo)
	{
		png_destroy_read_struct(&png, &info, 0);
		fclose(file);
		return "";
	}
	if (setjmp(jmpbuf))
	{
		png_destroy_read_struct(&png, &info, 0);
		fclose(file);
		return "";
	}
	png_init_io(png, file);
	png_read_info(png, info);
	png_textp text;
	int count = 0;
	std::string comment = "";
	if (png_get_text(png, info, &text, &count) > 0)
		for (int t = 0; t < count; t++)
			// we save as capitalized, but processing with ImageMagick downcases
			if (0 == stricmp("Comment", text[t].key))
				comment = text[t].text; // copy
	if (comment == "")
	{
		if (skip_png_image(png, info))
		{
			png_read_end(png, enfo);
			png_textp etext;
			int ecount = 0;
			if (png_get_text(png, enfo, &etext, &ecount) > 0)
				for (int t = 0; t < ecount; t++)
					// we save as capitalized, but processing with ImageMagick downcases
					if (0 == stricmp("Comment", etext[t].key))
						comment = etext[t].text; // copy
		}
	}
	png_destroy_read_struct(&png, &info, &enfo);
	fclose(file);
	return comment;
}

采样 代码 : https://code.mathr.co.uk/kalles-fraktaler-2/blob/d685883599f7ae795bd7667834b0d2a47c00c7ef:/fraktal_sft/fraktal_sft.cpp#l3314 第 3314 行到 3379 行 KF 会这样做

  • 为每个 dx、dy 偏移量生成 (i,j,seed) 的哈希值(种子对于 x 和 y 不同)
  • 使用它进行抖动。

着色方法

[编辑 | 编辑源代码]

KF 可以将原始迭代数据导出为 EXR(以及过时的 KFB)格式,因此您可以使用其他软件对其进行着色,但学习 GLSL 并编写 KF 中的着色器可能与编写其他软件一样容易。Zoomasm 4(未发布的 WIP)中的着色器比 KF 更强大,因为您可以在代码中添加额外的均匀变量,并从 GUI 控制它们,这使得调整事物变得更容易。但仍然只有数字输入字段,这有点笨拙,并且真正设计用于具有指数映射序列的动画。

Pauldelbrot 使用了一个复杂的“多波”着色算法,它不同于(并且优于)默认 KFP 着色算法中的调色板波。查看论坛中他在 LISP 变体(可能是 Clojure?)中发布的源代码。也许它也存在于 UF 公式数据库中的某个地方?关键是拥有多个不同速率的 RGB 或 HSV 波,可能与分形的结构(周期等)相关联,这些波以复杂的方式相互影响(这绝对不仅仅是 R G B 或 H S V 的单独波,而是 3D 色彩的波)。此外,这在不同的色彩空间中完成,因为混合 sRGB 值(如图像文件中的那样)是错误的(它们必须首先转换为线性以使混合有意义)。

Claude 在他的分形探索机器人 Rodney 中实现了一些可能类似的东西(但可能不如它好)。



可以更改它 

  • 主菜单 / 操作/ 设置颜色
  • 键:Ctrl+C


可用的颜色方法是(在 main.cpp 文件第 256 行,变量 m_nColorMethod) 

  • 0 = 标准 = 距离(线性):标准迭代带着色
  • 1 = 平方根:颜色应用之前对迭代进行平方
  • 2 = 立方根:颜色应用之前应用立方根
  • 3 = 对数:颜色应用之前应用对数 = ColorMethod_Logarithm [6]:“ColorMethod_Logarithm 根本不是 DEM,而是具有非线性传递函数的逃逸时间。”
  • 4 = 拉伸:调色板在最小-最大迭代值上拉伸
  • 5 = 距离:距离估计 :“ColorMethod_Distance* 有一些图像处理(查找相邻像素的迭代值)来生成伪去着色。它不是真正的 DEM,但在某些情况下看起来很接近。”
  • 6 = DE+标准




描述方法的数字(变量 m_nColorMethod)在版本之间变化[7]


代码

  • 文件 fraktal_sft.cpp
  • 变量 m_nColorMethod
  • 函数
    • CFraktalSFT::SetColorMethod
    • void CFraktalSFT::SetColor
    • CFraktalSFT::OpenFile
    • CFraktalSFT::SaveFile


// fraktal_sft.h
enum ColorMethod
{
	ColorMethod_Standard = 0,
	ColorMethod_SquareRoot = 1,
	ColorMethod_CubicRoot = 2,
	ColorMethod_Logarithm = 3,
	ColorMethod_Stretched = 4,
	ColorMethod_DistanceLinear = 5,
	ColorMethod_DEPlusStandard = 6,
	ColorMethod_DistanceLog = 7,
	ColorMethod_DistanceSqrt = 8,
	ColorMethod_LogLog = 9,
	ColorMethod_ATan = 10,
	ColorMethod_FourthRoot = 11
};

enum Differences
{
	Differences_Traditional = 0,
	Differences_Forward3x3 = 1,
	Differences_Central3x3 = 2,
	Differences_Diagonal2x2 = 3,
	Differences_LeastSquares2x2 = 4,
	Differences_LeastSquares3x3 = 5,
	Differences_Laplacian3x3 = 6,
	Differences_Analytic = 7
};




//fraktal_sft.cpp
void CFraktalSFT::SetColor(int nIndex, int nIter, double offs, int x, int y)
{
	if (nIter<0 || (!g_bShowGlitches && offs==2))
		return;
	if (nIter == m_nMaxIter)
		m_lpBits[nIndex] = m_lpBits[nIndex + 1] = m_lpBits[nIndex + 2] = 0;
	{
		double iter = (double)nIter + (double)1 - offs; // m_nColorMethod = 0;

		if (m_nColorMethod == 1){
			iter = sqrt(iter);
		}
		else if (m_nColorMethod == 2){
			iter = pow(iter, (double)1 / (double)3);
		}
		else if (m_nColorMethod == 3){
			iter = log(iter);
		}
		else if (m_nColorMethod == 4){
			int nMin, nMax;
			GetIterations(nMin, nMax,NULL,NULL,TRUE);
			iter = (double)1024 * ((double)iter - (double)nMin) / ((double)nMax - (double)nMin);
		}
		else if (m_nColorMethod == 5 || m_nColorMethod == 6){
			double p1, p2, p3, p4;
			iter=0;
			if (x){
				p1 = (double)m_nPixels[x - 1][y] + (double)1 - m_nTrans[x - 1][y];
				p2 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
			}
			else if (x<m_nX - 1){
				p1 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
				p2 = (double)m_nPixels[x + 1][y] + (double)1 - m_nTrans[x + 1][y];
			}
			else
				p1 = p2 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
			double _abs_val;
			iter += _abs(p1 - p2)*1.414;

			if (x && y){
				p1 = (double)m_nPixels[x - 1][y - 1] + (double)1 - m_nTrans[x - 1][y - 1];
				p2 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
			}
			else if (x<m_nX - 1 && y<m_nY - 1){
				p1 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
				p2 = (double)m_nPixels[x + 1][y + 1] + (double)1 - m_nTrans[x + 1][y + 1];
			}
			else
				p1 = p2 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
			iter += _abs(p1 - p2);

			if (y){
				p1 = (double)m_nPixels[x][y - 1] + (double)1 - m_nTrans[x][y - 1];
				p2 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
			}
			else if (y<m_nY - 1){
				p1 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
				p2 = (double)m_nPixels[x][y + 1] + (double)1 - m_nTrans[x][y + 1];
			}
			else
				p1 = p2 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
			iter += _abs(p1 - p2)*1.414;

			if (y && x<m_nX-1){
				p1 = (double)m_nPixels[x + 1][y - 1] + (double)1 - m_nTrans[x + 1][y - 1];
				p2 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
			}
			else if (x && y<m_nY - 1){
				p1 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
				p2 = (double)m_nPixels[x - 1][y + 1] + (double)1 - m_nTrans[x - 1][y + 1];
			}
			else
				p1 = p2 = (double)m_nPixels[x][y] + (double)1 - m_nTrans[x][y];
			iter += _abs(p1 - p2);
//			iter/=4;
//			iter*=iter;
			iter*=(double)m_nX / (double)640;
			iter=sqrt(iter);
			/*iter=log(iter);
			if(iter<0)
				iter=0;*/
			if(iter>1024)
				iter=1024;
			if(m_nColorMethod == 6 && iter>m_nIterDiv)
				iter = (double)nIter + (double)1 - offs;
		}
		if (m_nIterDiv != 1){
			iter /= m_nIterDiv;
		}
		if (m_nColorOffset)
			iter += m_nColorOffset;// = (nIter+m_nColorOffset)%1024;
		nIter = (int)iter;
		offs = 1 - (iter - (double)nIter);
		if (m_bITrans)
			offs = 1 - offs;
		if (m_bMW){
			double nH = 0, nS = 0, nB = 0;
			int nDR = 0, nDG = 0, nDB = 0;
			int i;
			for (i = 0; i<m_nMW; i++){
				double nPeriod;
				nPeriod = m_MW[i].nPeriod;
				double g;
				if (m_bTrans)
					g = sin((pi*iter) / nPeriod) / 2 + .5;
				else
					g = sin((pi*((int)iter)) / nPeriod) / 2 + .5;
				if (nPeriod<0)
					g = -(double)nPeriod / (double)100;
				if (m_MW[i].nType == 0){
					nH += g;
					nDR++;
				}
				if (m_MW[i].nType == 1){
					nS += g;
					nDG++;
				}
				if (m_MW[i].nType == 2){
					nB += g;
					nDB++;
				}
			}
			if (nDR)
				nH /= nDR;
			if (nDG)
				nS /= nDG;
			if (nDB)
				nB /= nDB;
			COLOR14 cPos;
			HSVToRGB(nH, nS, nB, cPos);

			m_lpBits[nIndex] = cPos.r;
			m_lpBits[nIndex + 1] = cPos.g;
			m_lpBits[nIndex + 2] = cPos.b;

			if (m_bBlend){
				int nR, nG, nB;
				if (m_bTrans && offs){
					double g1 = (1 - offs);
					int col = nIter % 1024;
					int ncol = (col + 1) % 1024;
					nR = m_cPos[col].r*offs + m_cPos[ncol].r*g1;
					nG = m_cPos[col].g*offs + m_cPos[ncol].g*g1;
					nB = m_cPos[col].b*offs + m_cPos[ncol].b*g1;
				}
				else{
					int col = nIter % 1024;
					nR = m_cPos[col].r;//+n;
					nG = m_cPos[col].g;//+n;
					nB = m_cPos[col].b;//+n;
				}
				m_lpBits[nIndex] = (m_lpBits[nIndex] + nR) / 2;
				m_lpBits[nIndex + 1] = (m_lpBits[nIndex + 1] + nG) / 2;
				m_lpBits[nIndex + 2] = (m_lpBits[nIndex + 2] + nB) / 2;
			}
		}
		else{
			if (m_bTrans && offs){
				double g1 = (1 - offs);
				int col = nIter % 1024;
				int ncol = (col + 1) % 1024;
				m_lpBits[nIndex] = m_cPos[col].r*offs + m_cPos[ncol].r*g1;
				m_lpBits[nIndex + 1] = m_cPos[col].g*offs + m_cPos[ncol].g*g1;
				m_lpBits[nIndex + 2] = m_cPos[col].b*offs + m_cPos[ncol].b*g1;
			}
			else{
				int col = nIter % 1024;
				m_lpBits[nIndex] = m_cPos[col].r;//+n;
				m_lpBits[nIndex + 1] = m_cPos[col].g;//+n;
				m_lpBits[nIndex + 2] = m_cPos[col].b;//+n;
			}
		}
	}


@color[int(($iteration/$divide_constant)%pallet_size)] -- (Perl code, % is the modulo operator)

其中除数(divide_constant)小于 1,如 0.1 或 0.01。


如何从命令行着色 KFB? 

这是一个小的 shell 脚本,用于执行颜色循环

#!/bin/bash
f=0
for i in $(seq 0 32 1023)
do
  t=$((i * 360 / 1024))
  echo $f $i $t
  cat template.kfp |
  sed "s/ColorOffset: 0/ColorOffset: $i/" |
  sed "s/SlopeAngle: 45/SlopeAngle: $t/" > tmp.kfp
  ./kf.exe -o input.kfb -c tmp.kfp -p "$(printf %02d $f).png"
  f=$((f + 1))
done
for i in *.png
do
  convert $i -colorspace RGB -geometry 320x180 -colorspace sRGB $i.gif
done
gifsicle --colors 256 --delay 4 --loop --optimize *.png.gif > output.gif


这是另一个示例

  • 找到一个不错的 位置
  • 在您的 OpenGL GLSL 着色器中使用 KFP_ColorOffset
  • 找出使颜色循环与分形对齐的魔数(此示例使用 30.0)
vec3 colour()
{
  if (getInterior()) { return KFP_InteriorColor; }
  float49 N = getN();
  N = div(N, 30.0);
  N = add(N, KFP_ColorOffset / 1024.0);
  return mix(vec3(0.0), texture(KFP_Palette, to_float(N)).rgb,
    tanh(clamp(0.25 * length(getDE()), 0.0, 4.0)));
}
  • 将分形保存为 EXR 映射文件,尺寸为所需大小(可能比最终输出大,用于超采样以进行抗锯齿)。
  • 运行一个 bash 脚本,以动画化 KFP_ColorOffset 并保存帧
#!/bin/bash
seq 0 32 1023 |
cat -n |
while read frame ColorOffset
do
  echo -e "ColorOffset: ${ColorOffset}\r" > palette.kfp
  /path/to/kf.x86_64.exe -s map.exr -l map.exr -o map.exr -c palette.kfp -t "$(printf %04d "${frame}").tif"
done

这将渲染 32 帧,对于 16 帧,将 0 32 1023 更改为 0 64 1023,对于 64 帧,更改为 0 16 1023 - 通常二的幂将是最平滑的循环

  • 使用 ImageMagick 将帧转换为带有伽马校正降尺度的 GIF
for i in *.tif
do
   convert "${i}" -colorspace RGB -geometry 256x256 -colorspace sRGB "${i}.gif"
done
  • 将帧组装到动画 GIF:gifsicle --delay 5 --loop --optimize --colors 256 *.tif.gif > output.gif
  • 在 Firefox 或其他软件中查看 GIF

后处理效果

[edit | edit source]

斜率

[edit | edit source]
  "Slopes rendering is originally a screen-space post-processing effect, using differences between neighbouring pixels' smooth iteration counts.  
   More recently it can use directional distance estimate (normalized by pixel spacing) instead, which I think gerrit proved is equivalent in the   limit of infinitely fine pixel grid. 
   Relevant part of the source code: https://code.mathr.co.uk/kalles-fraktaler- 2/blob/c78c224a4a3ae7f10ed03aa3948f0cd6b740adcb:/fraktal_sft/fraktal_sft.cpp#l933 lines 933 to 998 " Claude


变量

  • m_bSlopes = FALSE; 是布尔变量
  • m_nSlopePower = 50; 是斜率阴影深度,整数
  • m_nSlopeRatio = 50; 是斜率阴影强度,整数
  • m_nSlopeAngle = 45; 是斜率阴影角度(0-360),整数


显示斜率

  • 启用斜率编码以实现 3D 效果。
  • 第一个值是斜率的放大倍数。100 的起始值适用于未缩放的视图。深视图需要高几个数量级的值。
  • 第二个值是将斜率编码应用于着色的百分比。100 是最大值,但平坦区域仍然会显示调色板颜色。


算法


 grep -nR "Slope"

工具

[edit | edit source]


KFMovieMaker

[edit | edit source]

视频

效果


混合

 grep -nR "Blend"

缩写

[edit | edit source]
  • ADE = 分析 DE = 分析距离估计
  • NDE = 数值 DE
  • DDE = 方向 DE
  • NR = 牛顿-拉夫森缩放
  • SMB
  • BLA 双线性近似加速方法
  • SA = 级数逼近
  • SSA
  • SFT = K.I. Martin 的超级分形
  • ET = 逃逸时间
  • ETA
    • 逃逸时间算法(?)

参考文献

[编辑 | 编辑源代码]
  1. fractalforums.org : 如何渲染一个超过 10 亿次迭代的图像所需内存
  2. fractalforums.org : Kalle 分形上的额外逃逸变化
  3. 迈向二维逃逸时间迭代数据的通用文件格式
  4. fractalforums org: KF 文件类型
  5. fractalforums org : matlaboctave-code-for-kfb-reading
  6. fractalforums : 距离对数测试
  7. fractalforums : kalles-fraktaler/向后兼容性
华夏公益教科书