使用位图.LockBits函数访问的底层缓冲区在C#中处理位图
我需要对任意图像进行分析。我想从最简单的例子开始——只需将图像复制到picturebox使用位图.LockBits函数访问的底层缓冲区在C#中处理位图,c#,.net,image-processing,system.drawing,lockbits,C#,.net,Image Processing,System.drawing,Lockbits,我需要对任意图像进行分析。我想从最简单的例子开始——只需将图像复制到picturebox Bitmap foreImg = new Bitmap("input.jpg"); //output image Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height); unsafe { BitmapData oneBits = foreImg.LockBits(new Rectangle(0, 0, foreImg.Width, for
Bitmap foreImg = new Bitmap("input.jpg");
//output image
Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height);
unsafe
{
BitmapData oneBits = foreImg.LockBits(new Rectangle(0, 0, foreImg.Width, foreImg.Height), ImageLockMode.ReadOnly, foreImg.PixelFormat);
BitmapData thrBits = resImg.LockBits(new Rectangle(0, 0, resImg.Width, resImg.Height), ImageLockMode.WriteOnly, resImg.PixelFormat);
System.Threading.Tasks.Parallel.For(0, foreImg.Width * foreImg.Height, j =>
{
Pixel* pxOne = (Pixel*)((byte*)oneBits.Scan0 + j * sizeof(Pixel));
Pixel* pxRes = (Pixel*)((byte*)thrBits.Scan0 + j * sizeof(Pixel));
pxRes->Green = pxOne->Green;
pxRes->Red = pxOne->Red;
pxRes->Blue = pxOne->Blue;
});
foreImg.UnlockBits(oneBits);
resImg.UnlockBits(thrBits);
}
在我的程序中,图像被扭曲了
原件:
之后:。我做错什么了?谢谢!问题是输入图像的像素格式与我的结构像素不匹配。事实上,我没有添加alpha字节,在本例中,我假设使用Format24bppRgb。您的图像复制代码有两个错误,这是由于对所复制的特定图像的假设不成立。首先假设,当您为复制操作创建新的目标图像时,它将具有与源图像完全相同的像素表示形式,这有时可能是正确的,但在许多情况下不会:
Bitmap resImg=新位图(foreImg.Width、foreImg.Height)代码>
应改为:
Bitmap resImg=新位图(foreImg.Width、foreImg.Height、foreImg.PixelFormat)代码>
根据图像的不同,下一个假设可能会出错,也可能不会出错,这是一个隐式假设,即源图像PixelFormat
的大小正好是3个字节,对应于PixelFormat.Format24bppRgb
格式(或3个字节的倍数,因为我不知道像素结构中红色、绿色或蓝色通道的大小,可能是PixelFormat.Format48bppRgb
format),因此基于此假设,字节从源图像复制到目标图像
要执行精确复制,必须将相同数量的字节从源图像复制到目标图像,并且不需要使用底层的像素
结构,而是可以基于整数复制。最后但并非最不重要的一点是,如果目标是复制图像而不是逐像素分析其内容,则方法是使用专门的内存复制功能:
System.Buffer.MemoryCopy((void*)oneBits.Scan0,(void*)thrBits.Scan0,byteLength,byteLength);
下面是一个代码列表,其中包含使用ulong
作为carrier
复制图像的代码。我添加了返回Pixel
大小(以字节为单位)的函数,用于计算图像大小(以字节为单位)并执行精确复制。但是,它可以用于选择匹配的Pixel
结构,而不是可以使用的结构d分析图像数据。例如,如果图像具有PixelFormat.Format24bppRgb
格式,则可以使用3字节大小和RGB颜色的Pixel
结构。对于其他格式,需要定义其他直接复制图像Pixel
格式的Pixel
结构
using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace DrawingImagingOperations
{
class Program
{
static void Main(string[] args)
{
Bitmap foreImg = new Bitmap(@"..\..\YaHI9.jpg");
//output image
Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height, foreImg.PixelFormat);
unsafe
{
BitmapData oneBits = foreImg.LockBits(new Rectangle(0, 0, foreImg.Width, foreImg.Height), ImageLockMode.ReadOnly, foreImg.PixelFormat);
BitmapData thrBits = resImg.LockBits(new Rectangle(0, 0, resImg.Width, resImg.Height), ImageLockMode.WriteOnly, resImg.PixelFormat);
int pixelSize = GetPixelSize(foreImg.PixelFormat);
var byteLength = foreImg.Width * foreImg.Height * pixelSize;
var length = byteLength / sizeof(UInt64);
var reminder = byteLength % sizeof(UInt64);
System.Threading.Tasks.Parallel.For(0, length, j =>
{
ulong* pxOne = (ulong*)((byte*)oneBits.Scan0 + j * sizeof(UInt64));
ulong* pxRes = (ulong*)((byte*)thrBits.Scan0 + j * sizeof(UInt64));
*pxRes = *pxOne;
});
if (reminder > 0)
{
byte* pSrc = (byte*)oneBits.Scan0 + (pixelSize * length);
byte* pDst = (byte*)thrBits.Scan0 + (pixelSize * length);
for (int j = length; j < byteLength; j++)
*pDst++ = *pSrc++;
}
foreImg.UnlockBits(oneBits);
resImg.UnlockBits(thrBits);
}
resImg.Save(@"..\..\imgCopy.jpg");
}
internal static int GetPixelSize(PixelFormat data)
{
switch (data)
{
case PixelFormat.Format8bppIndexed:
return 1;
case PixelFormat.Format16bppGrayScale:
case PixelFormat.Format16bppRgb555:
case PixelFormat.Format16bppRgb565:
case PixelFormat.Format16bppArgb1555:
return 2;
case PixelFormat.Format24bppRgb:
return 3;
case PixelFormat.Canonical:
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
case PixelFormat.Format32bppRgb:
return 4;
case PixelFormat.Format48bppRgb:
return 6;
case PixelFormat.Format64bppArgb:
case PixelFormat.Format64bppPArgb:
return 8;
}
throw new FormatException("Unsupported image format: " + data);
}
}
}
使用系统;
使用系统图;
使用系统、绘图、成像;
命名空间DrawingImagingOperations
{
班级计划
{
静态void Main(字符串[]参数)
{
位图foreImg=新位图(@.\..\YaHI9.jpg);
//输出图像
位图大小=新位图(foreImg.Width、foreImg.Height、foreImg.PixelFormat);
不安全的
{
BitmapData oneBits=foreImg.LockBits(新矩形(0,0,foreImg.Width,foreImg.Height),ImageLockMode.ReadOnly,foreImg.PixelFormat);
BitmapData thrBits=resImg.LockBits(新矩形(0,0,resImg.Width,resImg.Height),ImageLockMode.WriteOnly,resImg.PixelFormat);
int pixelSize=GetPixelSize(foreImg.PixelFormat);
var byteLength=前景宽度*前景高度*像素大小;
var长度=byteLength/sizeof(UInt64);
var提醒=通过发送长度%sizeof(UInt64);
System.Threading.Tasks.Parallel.For(0,length,j=>
{
ulong*pxOne=(ulong*)((字节*)oneBits.Scan0+j*sizeof(UInt64));
ulong*pxRes=(ulong*)((字节*)thrBits.Scan0+j*sizeof(UInt64));
*pxRes=*pxOne;
});
如果(提醒>0)
{
byte*pSrc=(byte*)oneBits.Scan0+(像素大小*长度);
字节*pDst=(字节*)thrBits.Scan0+(像素大小*长度);
对于(int j=长度;j
你能解释一下你在做什么样的图像处理吗?什么是像素
?我猜你的像素结构缺少字母的一个字节。在任何情况下,不要锁定未知的格式,选择与你的处理相匹配的格式,看起来你假设格式24bpprgb
你总是非常非常关心像素f当您直接操作位图数据时,ormat。所以