问题:c# 中 由于项目需要,图像保存在byte数组中,图像格式为8bit灰度图像,原图如下所示:
然后对图像进行缩放,缩放的代码为:
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;
}
错位图像如下所示,哪位能够帮忙解惑一下
用这个可以缩放:
// 原始图像路径
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;
}
}
}
}