C# 使用指针实现图像像素级放大( nearest neighbor)
本文介绍了在 C# 中利用指针和 LockBits 机制实现图像像素级放大的具体方法。该方法通过直接访问内存数据,以最近邻域的方式复制像素,适用于需要对图片进行快速放大处理的场景。
准备工作与注意事项
实现该功能需要使用 System.Drawing 和 System.Drawing.Imaging 命名空间。由于代码涉及不安全的内存操作(unsafe),项目必须允许不安全代码编译。
- 启用不安全代码:在项目属性中,切换到“生成”选项卡,勾选“允许不安全代码”复选框;或者直接在
.csproj文件中添加<AllowUnsafeBlocks>true</AllowUnsafeBlocks>。 - 引用类库:确保项目中已引入
System.Drawing.dll。
核心实现逻辑
第1步:定义放大方法签名
创建一个接受源位图和放大倍数的静态方法,返回处理后的新位图。
public Bitmap Magnifier(Bitmap srcbitmap, int multiple)
第2步:参数校验与目标图像初始化
首先检查放大倍数是否合法(需大于0)。随后根据放大倍数计算新图像的宽度和高度,并实例化一个新的 Bitmap 对象作为缓冲区。
if (multiple <= 0) { return srcbitmap; }
Bitmap bitmap = new Bitmap(srcbitmap.Size.Width * multiple, srcbitmap.Size.Height * multiple);
第3步:锁定图像内存获取指针
使用 LockBits 方法同时锁定源图像和目标图像的数据区。设置格式为 PixelFormat.Format32bppArgb,以便每个像素占用 4 个字节(R、G、B、Alpha)。获取指向内存首地址的指针。
BitmapData srcdata = srcbitmap.LockBits(new Rectangle(0, 0, srcbitmap.Width, srcbitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe {
byte* ps = (byte*)srcdata.Scan0.ToPointer();
byte* pd = (byte*)bmpdata.Scan0.ToPointer();
}
第4步:执行像素复制循环
这是核心算法部分。遍历目标图像的每一个像素位置,计算其在原图中的对应坐标。由于是简单放大,直接使用最近的源像素填充目标像素。因为格式为 32 位 ARGB,每个像素由 4 个字节组成,所以步长为 4。
for (int y = 0; y < bmpdata.Height; y++) {
for (int x = 0; x < bmpdata.Width; x++) {
// 计算源图像中的对应索引
long index = (x / multiple) * 4 + (y / multiple) * srcdata.Stride;
// 逐字节拷贝 RGBA
pd[0] = ps[index]; // Blue
pd[1] = ps[index + 1]; // Green
pd[2] = ps[index + 2]; // Red
pd[3] = ps[index + 3]; // Alpha
pd += 4; // 移动到下一个目标像素位置
}
}
第5步:释放资源
操作完成后,务必调用 UnlockBits 解锁图像数据,防止内存泄漏或图像损坏。
srcbitmap.UnlockBits(srcdata);
bitmap.UnlockBits(bmpdata);
return bitmap;
完整代码汇总
将上述步骤整合,完整的 C# 实现代码如下:
using System;
using System.Drawing;
using System.Drawing.Imaging;
public class ImageScaler
{
public static Bitmap Magnifier(Bitmap srcbitmap, int multiple)
{
if (multiple <= 0) return srcbitmap;
// 创建放大后的新位图
Bitmap bitmap = new Bitmap(
srcbitmap.Size.Width * multiple,
srcbitmap.Size.Height * multiple
);
// 锁定源图片和目标图片的内存
BitmapData srcData = srcbitmap.LockBits(
new Rectangle(0, 0, srcbitmap.Width, srcbitmap.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb
);
BitmapData bmpData = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb
);
unsafe
{
byte* ps = (byte*)srcData.Scan0.ToPointer();
byte* pd = (byte*)bmpData.Scan0.ToPointer();
// 遍历目标图像的所有像素
for (int y = 0; y < bmpData.Height; y++)
{
for (int x = 0; x < bmpData.Width; x++)
{
// 找到对应的源像素索引
long index = (x / multiple) * 4 + (y / multiple) * srcData.Stride;
// 复制 RGBA 四个通道
pd[0] = ps[index]; // B
pd[1] = ps[index + 1]; // G
pd[2] = ps[index + 2]; // R
pd[3] = ps[index + 3]; // A
pd += 4; // 指针前进一个像素
}
}
}
// 解锁内存
srcbitmap.UnlockBits(srcData);
bitmap.UnlockBits(bmpData);
return bitmap;
}
}
总结
以上便是关于 C# 使用指针和 LockBits 实现图像最简单像素放大的详细内容。此方法效率较高,但由于采用最近邻插值,边缘可能会有锯齿感,适合对性能要求高于画质平滑度的应用场景。更多关于 C# 图像处理的技术资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









