You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将原始图像像素复制到新图像?代码性能问题咨询

问题分析与解决方案

一、先纠正核心逻辑错误

你当前的代码里,给新图像img1的每个像素(i,j)赋值时,内层循环遍历了整个pixels集合——这完全是无效操作,因为循环结束后这个像素只会保留pixels最后一个元素的颜色,前面的赋值全被覆盖了。

如果你的需求是给新图像的每个像素随机使用原始图像的像素颜色,应该直接随机选取pixels里的一个元素,而非遍历所有元素。

二、性能优化(解决29万像素耗时问题)

GetPixel和SetPixel方法本身性能极差,每次调用都要做大量底层安全检查。对于大规模像素操作,必须用LockBits直接操作内存,能把速度提升几十甚至上百倍。

优化后的完整代码

private void GetSetPixelsRandom()
{
    // 用using包裹Bitmap,确保资源自动释放
    using (Bitmap img = new Bitmap(@"d:\downloaded images\test.gif"))
    {
        // 步骤1:一次性读取原始图像所有像素到字节数组
        Rectangle rect = new Rectangle(0, 0, img.Width, img.Height);
        var bmpData = img.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, img.PixelFormat);
        IntPtr ptr = bmpData.Scan0;
        int bytes = Math.Abs(bmpData.Stride) * img.Height;
        byte[] rgbValues = new byte[bytes];
        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
        img.UnlockBits(bmpData);

        // 转换为Color集合(也可以直接操作字节数组,省掉这一步)
        List<Color> pixels = new List<Color>();
        int pixelSize = System.Drawing.Image.GetPixelFormatSize(img.PixelFormat) / 8;
        for (int i = 0; i < rgbValues.Length; i += pixelSize)
        {
            // 注意:24位RGB格式的通道顺序是BGR,需反转
            Color color = Color.FromArgb(rgbValues[i + 2], rgbValues[i + 1], rgbValues[i]);
            pixels.Add(color);
        }

        // 步骤2:创建新图像并快速赋值
        using (Bitmap img1 = new Bitmap(512, 512))
        {
            Random rand = new Random();
            Rectangle rect1 = new Rectangle(0, 0, img1.Width, img1.Height);
            var bmpData1 = img1.LockBits(rect1, System.Drawing.Imaging.ImageLockMode.WriteOnly, img1.PixelFormat);
            IntPtr ptr1 = bmpData1.Scan0;
            int bytes1 = Math.Abs(bmpData1.Stride) * img1.Height;
            byte[] rgbValues1 = new byte[bytes1];
            int pixelSize1 = System.Drawing.Image.GetPixelFormatSize(img1.PixelFormat) / 8;

            for (int i = 0; i < rgbValues1.Length; i += pixelSize1)
            {
                // 随机选一个原始图像的像素颜色
                Color randomColor = pixels[rand.Next(pixels.Count)];
                // 按BGR顺序写入数组(32位格式需额外写入Alpha通道)
                rgbValues1[i] = randomColor.B;
                rgbValues1[i + 1] = randomColor.G;
                rgbValues1[i + 2] = randomColor.R;
                if (pixelSize1 == 4)
                {
                    rgbValues1[i + 3] = randomColor.A;
                }
            }

            // 把处理后的字节数组写回图像内存
            System.Runtime.InteropServices.Marshal.Copy(rgbValues1, 0, ptr1, bytes1);
            img1.UnlockBits(bmpData1);

            img1.Save(@"d:\downloaded images\test3.gif");
        }
    }
}

关键优化点说明

  • 用LockBits替代GetPixel/SetPixel:直接操作内存数组,彻底避免了底层调用的性能开销,处理29万级像素毫无压力。
  • 批量读写像素数据:把整个图像的像素一次性读到字节数组,处理完再一次性写回,大幅减少IO次数。
  • 修正逻辑:用Random.Next随机选取原始像素颜色,符合“将原始图像像素设置到新图像”的需求(如果你的需求不是随机,可根据实际规则调整取值逻辑)。
  • 资源安全:所有Bitmap都用using包裹,确保程序结束后自动释放内存,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 22:30:57