中点位移算法 - 奇怪的结果

Posted

技术标签:

【中文标题】中点位移算法 - 奇怪的结果【英文标题】:Midpoint displacement algorithm - weird results 【发布时间】:2012-07-23 10:37:53 【问题描述】:

我正在编写自己的中点位移算法以用于学习目的,我决定以自己的方式实现它,看看我是否 1) 能够理解该算法,以及 2) 看看我是否可以根据自己的喜好对其进行修改。

这是生成分形的代码:

 public void Generate(Double rg, int size)
    
        Random rand = new Random();
        int min = -127;
        int max = 128;

        // Starting points of the rectangle
        MDP_Point s1 = new MDP_Point(0, 0, rand.Next(min, max));
        MDP_Point s2 = new MDP_Point(size, 0, rand.Next(min, max));
        MDP_Point s3 = new MDP_Point(size, size, rand.Next(min, max));
        MDP_Point s4 = new MDP_Point(0, size, rand.Next(min, max));

        // Lists containing the rectangles
        List<MDP_Rect> newRect = new List<MDP_Rect>();  // Newly created rectangles
        List<MDP_Rect> oldRect = new List<MDP_Rect>();  // Rectangles being divided


        // Starting rectangle is added to the list
        oldRect.Add(new MDP_Rect(s1, s2, s3, s4));

        // Distance between 2 points in a rectangle
        int h = size;

        while (h > 1)
        
            foreach (MDP_Rect r in oldRect)
            
                // Middle points of rectangle segments
                MDP_Point m1 = new MDP_Point();
                MDP_Point m2 = new MDP_Point();
                MDP_Point m3 = new MDP_Point();
                MDP_Point m4 = new MDP_Point();
                // Middle point of rectangle
                MDP_Point mm = new MDP_Point();

                m1.x = (r.C1.x + r.C2.x) / 2;
                m1.y = (r.C1.y + r.C2.y) / 2;
                m1.z = ((r.C1.z + r.C2.z) / 2) +(rand.Next(min, max) * rg);

                m2.x = (r.C2.x + r.C3.x) / 2;
                m2.y = (r.C2.y + r.C3.y) / 2;
                m2.z = ((r.C2.z + r.C3.z) / 2) +(rand.Next(min, max) * rg);

                m3.x = (r.C3.x + r.C4.x) / 2;
                m3.y = (r.C3.y + r.C4.y) / 2;
                m3.z = ((r.C3.z + r.C4.z) / 2) +(rand.Next(min, max) * rg);

                m4.x = (r.C1.x + r.C4.x) / 2;
                m4.y = (r.C1.y + r.C4.y) / 2;
                m4.z = ((r.C1.z + r.C4.z) / 2) + (rand.Next(min, max) * rg);

                mm.x = (r.C1.x + r.C2.x + r.C3.x + r.C4.x) / 4;
                mm.y = (r.C1.y + r.C2.y + r.C3.y + r.C4.y) / 4;
                mm.z = ((r.C1.z + r.C2.z + r.C3.z + r.C4.z) / 4) + (rand.Next(min, max) * rg);

                newRect.Add(new MDP_Rect(r.C1, m1, mm, m4));
                newRect.Add(new MDP_Rect(m1, r.C2, m2, mm));
                newRect.Add(new MDP_Rect(mm, m2, r.C3, m3));
                newRect.Add(new MDP_Rect(m4, mm, m3, r.C4));
            


            oldRect.Clear();
            oldRect = new List<MDP_Rect>(newRect);
            newRect.Clear();
            h /= 2;
        

        List<MDP_Rect> sorted = new List<MDP_Rect>();
        sorted = oldRect.OrderBy(y => y.C1.y).ThenBy(x => x.C1.x).ToList();

        List<MDP_Point> mapArray = new List<MDP_Point>();
        mapArray.AddRange(CreateArray(sorted));

        CreateImage(size, mapArray, rg);
    

MDP_Point 仅包含 x、y 和 z 值 MDP_Rectangle 包含 4 个点,创建一个矩形

CreateArray() 方法只获取有序的矩形列表,并以正确的顺序输出和点列表来创建图像。

创建数组():

        private List<MDP_Point> CreateArray(List<MDP_Rect> lRect)
    
        List<MDP_Point> p = new List<MDP_Point>();

        int size = (int)Math.Sqrt(lRect.Count);

        int i = 0;
        foreach (MDP_Rect r in lRect)
        
            p.Add(new MDP_Point((int)r.C1.x, (int)r.C1.y, (int)r.C1.z));

            if (i > 0 && i % size == size - 1)
            
                p.Add(new MDP_Point((int)r.C2.x, (int)r.C2.y, (int)r.C2.z));
            

            i++;
        

        for (int a = 0; a < size; a++)
        
            p.Add(new MDP_Point((int)lRect[(size * size - size) + a].C4.x,
                (int)lRect[(size * size - size) + a].C4.y,
                (int)lRect[(size * size - size) + a].C4.z));

            if (a > 0 && a % size == size - 1)
            
                p.Add(new MDP_Point((int)lRect[(size * size - size) + a].C3.x,
                    (int)lRect[(size * size - size) + a].C3.y,
                    (int)lRect[(size * size - size) + a].C3.z));
            
        

        return p;
    

这是创建图像的方法:

        private void CreateImage(int size, List<MDP_Point> arr, double roughness)
    
        Bitmap map = new Bitmap(size, size);

        int ver = 0;
        for (int i = 0; i < map.Height; i++)
        
            for (int n = 0; n < map.Width; n++ )
            
                int h = (int)arr[ver].z + 127;
                if (h < 0)
                
                    h = 0;
                
                else if (h > 255)
                
                    h = 255 ;
                
                Color c = Color.FromArgb(h, h, h);

                //map.SetPixel(n, i, c);
                map.SetPixel(i, n, c);
                ver++;
            
        

        Bitmap m = new Bitmap(map);
        bool saved = true;
        int num = 0;

        while (saved)
        
            if (File.Exists("map_S" + size + "_R" + roughness + "_" + num + ".png"))
            
                num++;
            
            else
            
                m.Save("map_S" + size + "_R" + roughness + "_" + num + ".png", System.Drawing.Imaging.ImageFormat.Png);
                saved = false;
            
        

        map.Dispose();
        m.Dispose();
    

低于 0 的任何值都设置为 0,高于 255 的任何值都设置为 255 这可能是一个大问题......不知道该怎么办。

这是代码生成的图像: 尺寸:1024 粗糙度:0.5

最明显的问题是对角线“脊线”和平铺外观。

此时,我不确定如何解决此问题以使其看起来更自然。 有什么想法吗?

【问题讨论】:

你的CreateArray方法在哪里? 添加了 CreateArray() 和 CreateImage() 的缺失部分 我的理解是中点位移算法需要从高斯分布中抽取随机数。 rand 调用将来自均匀分布(0 和 1 之间的均匀分布)。见***.com/questions/75677/… 和***.com/questions/8739851/… 我阅读了链接,但我不太确定如何将其转换为 0 到 255 之间的值。 【参考方案1】:

在这里,我认为部分问题是您使用 255 和 0 破解了 h 变量。我尝试使用以下代码:

int h = (int) arr[ver].z;
if (h < 0)

    h = Math.Abs(h);

while(h > 255)

    h -= 255;

在我的电脑上,结果是:

当我使用时:

int h = (int) arr[ver].z + 127;

注意,我只需要创建一个测试类MDP_PointMDP_Rect 来测试它...

【讨论】:

是的,我承认,破解 h 值确实是一个廉价的把戏!尽管如此,您的代码仍显示对角脊线,以及峰值/低点周围的一些噪音。我认为这可以通过像 sfstewman 建议的高斯分布来解决,但我不确定如何正确实施。 嗯,我注意到这比你的要好。随机排列线条的顺序会有所帮助,顺便说一句,这是一个比编程更复杂的问题,MIT 上实际上有一个关于生成轮廓、脊和其他 2D 绘图技术的项目。 是的,当然更好!我没有任何冒犯的意思。感谢您提供 MIT 链接!【参考方案2】:

为避免这些伪影,您应该使用 Peitgen 等人提出的两阶段方法。在“分形图像的科学”中。他们还建议在每个细分步骤之后向所有顶点添加额外的随机位移。我在这里找到了扫描的摘录(第 45 页):

http://cs455.cs.byu.edu/lectureslides/FractalsPart2.pdf

【讨论】:

以上是关于中点位移算法 - 奇怪的结果的主要内容,如果未能解决你的问题,请参考以下文章

帮助解读——模拟——查看分析结果——绘制结果图解——位移图解

DES加密,如何解决C#、Java互通时补位算法的问题

当经度 > 90 时,Python 纬度/经度中点计算给出错误结果

千题案例TypeScript获取两点之间的距离 | 中点 | 补点 | 向量 | 角度

奇怪的编译器速度优化结果——IAR编译器

R语言自定义ggpot2可视化结果中点形状大小色彩填充色边框线类型边框线色彩点样式pch(plot characters)自定义的核心函数