c#设置像素颜色的更快方法
我选择了一个使用c#设置像素颜色的更快方法,c#,image,pointers,noise-generator,C#,Image,Pointers,Noise Generator,我选择了一个使用setPixel()创建噪波贴图的项目。这个应用程序的大部分运行时间都花在setPixel()函数中,因此我希望提高函数的执行速度 我对此做了一些研究,发现: int index = x + (y * Width); int col = color.ToArgb(); if (this.Bits == null) { this.Bits = new Int32[Width * Height]; } Bits[index] = col; 已被推荐为一种更快的方法。但是
setPixel()
创建噪波贴图的项目。这个应用程序的大部分运行时间都花在setPixel()
函数中,因此我希望提高函数的执行速度
我对此做了一些研究,发现:
int index = x + (y * Width);
int col = color.ToArgb();
if (this.Bits == null)
{
this.Bits = new Int32[Width * Height];
}
Bits[index] = col;
已被推荐为一种更快的方法。但是,这会生成一个完全黑色的图像
我不完全理解图像处理和内存指针是如何工作的,以便能够完全理解代码并将其重构为更好的东西
以下是实施前的原始代码:
unsafe
{
var scan0 = (byte*)Iptr;
int bitmapStride = Stride;
int bitmapPixelFormatSize = Depth / 8;
index = (bitmapStride * y) + (x * bitmapPixelFormatSize);
if (bitmapPixelFormatSize == 4)
{
scan0[index + 3] = color.A;
scan0[index + 2] = color.R;
scan0[index + 1] = color.G;
scan0[index] = color.B;
}
else if (bitmapPixelFormatSize == 1)
{
scan0[index] = color.R;
}
else
{
scan0[index + 2] = color.R;
scan0[index + 1] = color.G;
scan0[index] = color.B;
}
}
Iptr
只是一个IntPtr
Stride
是一个int,我能找到的唯一设置该值的地方是Stride=(像素计数/高度)*(深度/8)
x
是宽度
y
是高度
我能解释一下原始代码块中发生了什么,并能帮助理解如何将其转换为执行速度更快的代码块吗,目前,由于宽度*高度的嵌套for循环,完成此功能需要大约500000毫秒。注意:以下信息最初由Bob Powell创建。原来的链接不再起作用,所以我从位于的Internet存档中复制了此信息。它有点长,但我认为它值得保存 我不确定这是否能直接回答你的问题,但也许能帮助你找到解决办法
使用锁定位方法访问图像数据 通过直接访问像素数据阵列,而不是依赖GetPixel和SetPixel或其他方法,可以加速许多图像处理任务甚至文件类型转换,例如从每像素32位到每像素8位 您会注意到.NET是一个托管代码系统,它通常使用托管数据,因此我们不再经常需要访问存储在内存中的字节,当托管数据访问速度太慢时,图像操作是为数不多的几次之一,因此我们需要再次深入研究查找数据和操作数据的棘手问题 在开始讨论本主题之前,我只想提醒您,用于访问任何非托管数据的方法将因编写程序所用的语言而异。C#开发人员有机会通过不安全的关键字和指针直接访问内存中的数据。VisualBasic程序员应该通过封送处理类方法访问这些数据,这也可能会显示少量的性能损失 锁定您的位 位图类提供锁定位和相应的解锁位方法,使您能够修复内存中位图像素数据数组的一部分,直接访问它,最后用修改后的数据替换位图中的位。LockBits返回一个BitmapData类,该类描述锁定数组中数据的布局和位置 BitmapData类包含以下重要属性:
- Scan0固定数据阵列内存中的地址
- 步长一行像素数据的宽度(以字节为单位)。这个宽度 是的像素尺寸的倍数,或者可能是次倍数 图像和可能会被填充以包含更多的字节。我将 请尽快解释原因
- PixelFormat数据的实际像素格式。这很重要 用于查找正确的字节
- 宽度锁定图像的宽度
- 高度锁定图像的高度
- Format32BppArgb给定X和Y坐标,第一个 像素中的元素是Scan0+(y*stride)+(x*4)。这就指向了 蓝色字节。以下三个字节包含绿色、红色和alpha 字节
- Format24BppRgb给定X和Y坐标,第一个
像素中的元素是Scan0+(yStride)+(x3)。这就指向了
蓝色字节,后跟
BitmapData bmd=bm.LockBits(new Rectangle(0, 0, 10, 10), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat); int PixelSize=4; for(int y=0; y<bmd.Height; y++) { byte* row = (byte *)bmd.Scan0+(y*bmd.Stride); for(int x = 0; x<bmd.Width; x++) { row[x * PixelSize] = 255; } }
Dim x As Integer Dim y As Integer Dim PixelSize As Integer = 4 Dim bmd As BitmapData = bm.LockBits(new Rectangle(0, 0, 10, 10), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat) For y = 0 To bmd.Height - 1 For x = 0 To bmd.Width - 1 Marshal.WriteByte(bmd.Scan0, (bmd.Stride * y) + (4 * x) , 255) Next Next
byte* p=(byte*)bmd.Scan0.ToPointer(); int index=y*bmd.Stride+(x>>3); byte mask=(byte)(0x80>>(x&0x7)); if(pixel) p[index]|=mask; else p[index]&=(byte)(mask^0xff);
Dim mask As Byte = 128 >> (x And 7) Dim offset As Integer = (y * bmd.Stride) + (x >> 3) Dim currentPixel As Byte = Marshal.ReadByte(bmd.Scan0, offset) If pixel = True Then Marshal.WriteByte(bmd.Scan0, offset, currentPixel Or mask) Else Marshal.WriteByte(bmd.Scan0, offset, CByte(currentPixel And (mask Xor 255))) End If
int offset = (y * bmd.Stride) + (x >> 1); byte currentByte = ((byte *)bmd.Scan0)[offset]; if((x&1) == 1) { currentByte &= 0xF0; currentByte |= (byte)(colorIndex & 0x0F); } else { currentByte &= 0x0F; currentByte |= (byte)(colorIndex << 4); } ((byte *)bmd.Scan0)[offset]=currentByte;
Dim offset As Integer = (y * bmd.Stride) + (x >> 1) Dim currentByte As Byte = Marshal.ReadByte(bmd.Scan0, offset) If (x And 1) = 1 Then currentByte = currentByte And &HF0 currentByte = currentByte Or (colorIndex And &HF) Else currentByte = currentByte And &HF currentByte = currentByte Or (colorIndex << 4) End If Marshal.WriteByte(bmd.Scan0, offset, currentByte)
Dim bmd As BitmapData = bm.LockBits(New Rectangle(0, 0, 10, 10), ImageLockMode.ReadWrite, bm.PixelFormat) ' do operations here bm.UnlockBits(bmd)