通过最近邻居缩放图像字节阵列

本文关键字:图像 字节 阵列 缩放 邻居 最近 | 更新日期: 2023-09-27 18:22:03

我正在尝试使用字节数组缩放图像。我的计划是使用最近的邻居来找到新字节数组的像素数据,但在转换图像的源数据时遇到了一些问题。srcImage的类型是Image,我能够成功地将其转换为字节数组并将其转换回图像,但我在使用其字节数组缩放图像时遇到了问题。我使用MemoryStream(在我的byteArrayToImage方法中)将trgData转换回Image,但我收到一个ArgumentException,告诉我"new MemoryStream(byteArray)"参数无效。

有人知道可能是什么问题,或者如何从图像中正确缩放字节数组吗?目前,我们可以假设我只是在缩放和保存png文件,但我希望最终将其扩展到其他图像格式。

这是我用于复制和缩放图像数据的代码:

byte[] srcData = ImageToByteArraybyImageConverter(srcImage);
// data transformations here
//
float srcRatio = srcImage.Width / srcImage.Height;
int bitsPerPixel = ((int)srcImage.PixelFormat & 0xff00) >> 8;
int bytesPerPixel = (bitsPerPixel + 7) / 8;
int srcStride = 4 * ((srcImage.Width * bytesPerPixel + 3) / 4);
// find max scale value
int scale = 3; // NOTE: temporary
// create new byte array to store new image
int width = srcImage.Width * scale;
int height = srcImage.Height * scale;
int stride = width;
byte[] trgData = new byte[height * stride];
// update the progress bar
progressBar1.Value = 10;
int i = -1; // index for src data
// copy pixel data 
for (int n = 0; n < trgData.Length; n++)
{
    if (n % stride == 0)
    {
        i++;
    }
    trgData[n] = srcData[i];
}
progressBar1.Value = 60;
// convert the pixel data to image
Image newImage = byteArrayToImage(trgData);
progressBar1.Value = 70;
if (newImage != null)
{
    // save the image to disk
    newImage.Save(newFileName);
    progressBar1.Value = 100;
}

如果您还有任何问题,请告诉我,谢谢!

编辑:以下是加载和保存字节数组的方法

private byte[] ImageToByteArraybyImageConverter(System.Drawing.Image image)
{
    ImageConverter imageConverter = new ImageConverter();
    byte[] imageByte = (byte[])imageConverter.ConvertTo(image, typeof(byte[]));
    return imageByte;
}

private Image byteArrayToImage(byte[] byteArrayIn)
{
    Image returnImage = null;
    using (MemoryStream ms = new MemoryStream(byteArrayIn))
    {
        returnImage = Image.FromStream(ms);
    }
    return returnImage;
}

通过最近邻居缩放图像字节阵列

您在这里做了一件非常奇怪的事情:

int i = -1; // index for src data
// copy pixel data 
for (int n = 0; n < trgData.Length; n++)
{
    if (n % stride == 0)
    {
        i++;
    }
    trgData[n] = srcData[i];
}

在每次width迭代之后(因为stride == width),将递增原始索引。也就是说,新图像的整个第一行将用原始图像的第一个字节填充,第二行用第二个字节填充等等。

试试这个:

int targetIdx = 0;
for (int i = 0; i < height; ++i)
{
    int iUnscaled = i / scale;
    for (int j = 0; j < width; ++j) {
        int jUnscaled = j / scale;
        trgData[targetIdx++] = srcData[iUnscaled * origWidth + jUnscaled];
    }
}

注意,它假定BPP=1,即它水平和垂直地复制每个字节scale次。修改BPP大于1并不困难。

这是一个演示,说明了这两种算法(评论第一行以查看算法的行为)