C#byte数组转化成Bitmap图像 像素错位

问题:c# 中 由于项目需要,图像保存在byte数组中,图像格式为8bit灰度图像,原图如下所示:

img

然后对图像进行缩放,缩放的代码为:

public static byte[] ResizeNearestNeighbor(byte[] srcByte, Size srcSize, Size dstSize)
{
    int bytesPerPixel = 1;
    byte[] dstDataBuffer = new byte[dstSize.Width * dstSize.Height];
    int dstDataLen = dstSize.Width * dstSize.Height * bytesPerPixel;
    if (dstDataBuffer.Length < dstDataLen)
    {
        Array.Resize(ref dstDataBuffer, dstDataLen);
    }
    float scale_x = (float)srcSize.Width / dstSize.Width;
    float scale_y = (float)srcSize.Height / dstSize.Height;
    int dstStep = dstSize.Width * bytesPerPixel;
    int srcStep = srcSize.Width * bytesPerPixel;
    int ny, nx, nc;
    int sy, sx;
    for (ny = 0; ny < dstSize.Height; ++ny)
    {
        sy = Convert.ToInt32(Math.Floor(ny * scale_y));
        sy = Math.Min(sy, srcSize.Height - 1);
        for (nx = 0; nx < dstSize.Width; ++nx)
        {
            sx = Convert.ToInt32(Math.Floor(nx * scale_x));
            sx = Math.Min(sx, srcSize.Width - 1);
            for (nc = 0; nc < bytesPerPixel; nc++)
            {
                dstDataBuffer[ny * dstStep + nx * bytesPerPixel + nc] =
                    srcByte[sy * srcStep + sx * bytesPerPixel + nc];
            }
        }
    }
    return dstDataBuffer;
}

最后需要将缩放完的图像再转为bitmap去保存,保存的图像出现像素错位现象,byte转bitmap代码如下:

public static Bitmap ByteArrayToBitmap(byte[] byteArray, Size size)
{
    Bitmap bmp = new Bitmap(size.Width, size.Height, PixelFormat.Format8bppIndexed);
    BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),ImageLockMode.WriteOnly, bmp.PixelFormat);
    //用Marshal的Copy方法,将刚才得到的内存字节数组复制到BitmapData中
    Marshal.Copy(byteArray, 0, bmpData.Scan0, size.Width * size.Height);
    //解锁内存区域  
    bmp.UnlockBits(bmpData);

    //使PixelFormat.Format8bppIndexed(八位颜色索引)生效,在调色板中设置每个索引到具体的颜色映射
    ColorPalette palette = bmp.Palette;
    for (int i = 0; i < 256; i++)
    {
        palette.Entries[i] = Color.FromArgb(i, i, i);
    }
    bmp.Palette = palette;

    return bmp;
}

错位图像如下所示,哪位能够帮忙解惑一下

img

这篇有讲你这个问题的,你看看,应该对你有用:

 用这个可以缩放:           

                // 原始图像路径
                string imagePath = "D:\\07842857109619.png";

                // 读取原始图像
                Bitmap originalImage = new Bitmap(imagePath);

                // 缩放倍数
                double scale = 0.5;

                // 计算缩放后的图像宽度和高度
                int scaledWidth = (int)(originalImage.Width * scale);
                int scaledHeight = (int)(originalImage.Height * scale);

                // 创建缩放后的图像
                Bitmap scaledImage = new Bitmap(scaledWidth, scaledHeight);

                // 使用 Graphics 对象进行绘制,实现图像缩放
                using (Graphics graphics = Graphics.FromImage(scaledImage))
                {
                    graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    graphics.DrawImage(originalImage, 0, 0, scaledWidth, scaledHeight);
                }

                // 保存缩放后的图像
                scaledImage.Save("D:\\path_to_scaled_image.png");

                // 释放资源
                originalImage.Dispose();
                scaledImage.Dispose();

当图像尺寸小于100时似乎是正确的,若设置为200, 错位很明显
用以下代码创建虚拟图像

 byte[] bytes = new byte[10000];
 int k = 0;
for (int i = 0; i < 100; i++)
{
  for (int j = 0; j < 100; j++)
  {
       bytes[k++] = (byte)(i + j);
  }
}

你的缩放代码是最近邻插值法缩放,这个是会导致像素位置偏移的,要用更高级的插值法,可以试试双线性插值或双三次插值

它本质就是矩阵嘛,看一看中途的矩阵发生了什么变化。可以一步一步debug输出一下核心的部分。。

参考如下代码试一下

using System;
using System.Drawing;
using System.Windows.Forms;

namespace WinFormGui
{
    public class Utility
    {
        /// <summary>
        /// 保证宽高比例的一种压缩方式
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="targetHeight"></param>
        /// <returns></returns>
        public static Bitmap Resize(Bitmap bitmap, int targetHeight)
        {
            int targetWidth = bitmap.Width * targetHeight / bitmap.Height;
            return Resize(bitmap, targetWidth, targetHeight);
        }

        /// <summary>
        /// 直接Resize到给定大小
        /// </summary>
        /// <param name="input"></param>
        /// <param name="targetWidth"></param>
        /// <param name="targetHeight"></param>
        /// <returns></returns>
        public static Bitmap Resize(Bitmap input, int targetWidth, int targetHeight)
        {
            try
            {
                var actualBitmap = new Bitmap(targetWidth, targetHeight);

                var g = Graphics.FromImage(actualBitmap);
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default; //设定插值方式

                g.DrawImage(input, 
                    new Rectangle(0, 0, targetWidth, targetHeight),
                    new Rectangle(0, 0, input.Width, input.Height), 
                    GraphicsUnit.Pixel);
                g.Dispose();
                return actualBitmap;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"图片压缩异常{ex.Message}");
                return null;
            }
        }
    }
}