首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Mandelbrot Lockbit

Mandelbrot Lockbit
EN

Stack Overflow用户
提问于 2021-09-02 17:12:43
回答 1查看 67关注 0票数 0

我正在尝试为我的Mandelbrot渲染器实现Lockbits,因为它的性能更好。然而,在尝试呈现mandelbrot函数时,我似乎得到了一个非常有趣的结果。我所做的基本上是获取每个像素的RGB值,然后将它们放入字节数组中。之后,我将它们全部复制到位图中并绘制它们。

渲染器的代码:

代码语言:javascript
复制
private void Draw(object sender, PaintEventArgs e)
{
    Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
    double minX = centerX - zoom / 2, minY = centerY - zoom / 2;
    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    System.Drawing.Imaging.BitmapData bmpData =
    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
    IntPtr ptr = bmpData.Scan0;
    int ret = 0;
    byte[] bytes = new byte[2000000];
    for (int x = 0; x < pictureBox1.Width; x++)
    {
        for (int y = 0; y < pictureBox1.Height; y++)
        {
            double a = minX + (double)x / pictureBox1.Width * zoom;
            double b = minY + (double)y / pictureBox1.Height * zoom;
            Complex c = new Complex(a, b);
            Complex z = new Complex(0, 0);
            int it = 0;
            do
            {
                it++;
                z.Square();
                z.Add(c);
                if (z.Magnitude() > 2.0)
                {
                    break;
                }
            }
            while (it < 50);
            int r = (it % 32) * 7;
            int g = (it % 16) * 14;
            int b = (it % 128) * 2;
            int l = 255;
            if (ret <= 1999997)
            {
                bytes[ret] = (byte)g;
                bytes[ret + 1] = (byte)b;
                bytes[ret + 2] = (byte)r;
                ret = ret + 3;
            }
        }
    }
    System.Runtime.InteropServices.Marshal.Copy(bytes, 0, ptr, 2000000);
    bmp.UnlockBits(bmpData);
    e.Graphics.DrawImage(bmp, 0, 0);
}

结果:

EN

回答 1

Stack Overflow用户

发布于 2021-09-02 18:51:32

这里有几个地方出了问题。为了使示例工作,我在方法中声明了一些变量。下一次,请提供一个可重现的例子,这样人们就不需要那么多的摆弄了。

我还将Complex类型更改为System.Numerics.Complex,因为您没有提到正在使用哪个库。

  1. 您正在创建一个未指定像素格式[1](https://ask.qcloudimg.com/http-save/yehe-900000/45f634c2ca290a18c4b9810c09cee798.png)的位图。这样做将使用每像素32位。您要么需要坚持该格式,要么指定要使用的格式。使用32位实际上可能是有益的,因为CPU可以很好地处理32位。不管怎样,我在这里使用24位,因为你的代码是这样写的,还有另一个原因。

位图bmp =新位图(pictureBox1.Width,pictureBox1.Height,PixelFormat.Format24bppRgb);

  1. b声明了两次,因此代码无法编译。我将后一个更改为blue.

  1. 如果使用的是24位位图,则在处理行和列时,位图的末尾可能无法很好地对齐。为了解决这种对齐问题,您必须考虑Stride。跨度在每一行的末尾添加一些字节,以便下一行从4或8的倍数开始(不确切地知道)。

这意味着:在每一行之后,必须将差值添加到ret变量中:

ret = ret + bmpData.Stride - pictureBox1.Width * 3;

  1. 现在已经完成了,您的外部循环是X,内部循环是Y,但是需要考虑行的步长,而不是列。因此,翻转循环:

for (int y= 0;y< pictureBox1.Height;y++) { for (int x= 0;x< pictureBox1.Width;x++) {

  1. 另外,字节数组的大小始终为2.000.000字节。如果图片框需要较少的像素,则您正在尝试将更多像素复制到可用的位图中。这会导致访问冲突。

通过分配您所需大小的byte[]来修复此问题。

byte[]字节=新的bytebmp.Height * bmpData.Stride;

然后更改所有边界检查。

  1. Hans Passant在评论中提到,你的颜色顺序错误。应该是

字节数=(字节)蓝色;字节数+1=(字节)g;字节数+2=(字节)r;

我不想发布完整的代码,因为我认为你犯了很多错误,应该自己修复它们。复制/粘贴不利于学习。但是,以下是使用参数运行时修复的结果

代码语言:javascript
复制
var zoom = 2.0;
var centerX = -.2;
var centerY = 0.0;

你会注意到,如果图像不是方形的,它看起来会被拉伸。您可能希望在计算中对此进行补偿。

另外:当前在Paint事件中绘制图像。你的窗口可能比你想象的要频繁的多。也许你会找到一个更好的地方。

在我的机器上,2560x1440像素的全屏更新需要大约2100ms。它可能仍然需要更多的性能:-)如果你避免使用ret,而是用一个计算来代替它,那么在外部y循环上使用Parallel.For()是可能的。这样我就可以在300ms (8个内核;16个线程)下运行。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69034592

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档