C# 字节数组映像裁剪性能问题
有两个指向1的指针(字节*)。B8G8R8A8像素数据2。字节缓冲区用来放置裁剪后的像素数据,非常简单的问题。以下是我的实现:C# 字节数组映像裁剪性能问题,c#,.net,bytearray,unsafe,imaging,C#,.net,Bytearray,Unsafe,Imaging,有两个指向1的指针(字节*)。B8G8R8A8像素数据2。字节缓冲区用来放置裁剪后的像素数据,非常简单的问题。以下是我的实现: private unsafe void Crop(byte* src, byte* dst, Rectangle rSrc, Rectangle rDst) { int sSrc = 4 * rSrc.Width, sDst = 4 * rDst.Width; // stride for (int x = 0; x < rDst.Width; x
private unsafe void Crop(byte* src, byte* dst, Rectangle rSrc, Rectangle rDst)
{
int sSrc = 4 * rSrc.Width, sDst = 4 * rDst.Width; // stride
for (int x = 0; x < rDst.Width; x++) for (int y = 0; y < rDst.Height; y++)
{
dst[(x * 4 + y * (sDst)) + 0] = src[((rDst.X + x) * 4 + (rDst.Y + y) * (sSrc)) + 0];
dst[(x * 4 + y * (sDst)) + 1] = src[((rDst.X + x) * 4 + (rDst.Y + y) * (sSrc)) + 1];
dst[(x * 4 + y * (sDst)) + 2] = src[((rDst.X + x) * 4 + (rDst.Y + y) * (sSrc)) + 2];
dst[(x * 4 + y * (sDst)) + 3] = src[((rDst.X + x) * 4 + (rDst.Y + y) * (sSrc)) + 3];
}
}
私有不安全无效裁剪(字节*src,字节*dst,矩形rSrc,矩形rDst)
{
int sSrc=4*rSrc.Width,sDst=4*rDst.Width;//步幅
for(int x=0;x
它可以工作:~100ms用于1920x1080,但需要~10-15ms。有可能使它更快吗?例如,纯拷贝(无裁剪)提供了更好的性能8毫秒(对于相同的分辨率),功能如下:
private unsafe void Copy(void* dst, void* src, long count)
{
long block; block = count >> 3;
long* pDst = (long*)dst; long* pSrc = (long*)src;
{
for (int i = 0; i < block; i++) { *pDst = *pSrc; pDst++; pSrc++; }
}
}
private不安全的无效副本(void*dst、void*src、长计数)
{
长块;块=计数>>3;
长*pDst=(长*)dst;长*pSrc=(长*)src;
{
对于(inti=0;i
需要你的想法
谢谢。实际上,你可以让它在3毫秒内运行,而且不需要不安全
void Main()
{
int width;
int height;
int border;
byte[] src;
using (var bm = new Bitmap(@"C:\Data\sample-photo.jpg"))
{
width = bm.Width;
height = bm.Height;
border = width / 10;
src = new byte[width * height * 4];
for (var y = 0; y < bm.Height; y++)
for (var x = 0; x < bm.Width; x++)
{
var pixel = bm.GetPixel(x,y);
var i = GetIndex(width, x,y);
src[i + 1] = pixel.R;
src[i + 2] = pixel.G;
src[i + 3] = pixel.B;
}
}
var sw = Stopwatch.StartNew();
byte[] dst = null;
dst = Crop(src, width, border, width - border, border, height - border);
sw.Stop();
Console.WriteLine(sw.Elapsed);
using (var dstBmp = new Bitmap(width - border * 2, height - border * 2, PixelFormat.Format32bppArgb))
{
for (var y = 0; y < (height - border * 2); y++)
for (var x = 0; x < (width - border * 2); x++)
{
var i = GetIndex(dstBmp.Width, x, y);
var r = dst[i + 1];
var g = dst[i + 2];
var b = dst[i + 3];
dstBmp.SetPixel(x, y, Color.FromArgb(255, r, g, b));
}
dstBmp.Save(@"C:\Data\sample-photo-cropped.jpg");
}
}
byte[] Crop(byte[] src, int srcWidth, int xStart, int xEnd, int yStart, int yEnd)
{
var width = xEnd - xStart;
var height = yEnd - yStart;
var dst = new byte[width * height * 4];
for (var iY = yStart; iY < yEnd; iY++)
{
Array.Copy(src, GetIndex(srcWidth, xStart, iY), dst, GetIndex(width, 0, iY - yStart), width * 4);
}
return dst;
}
int GetIndex(int width, int x, int y)
{
return (x + (width * y)) * 4;
}
要使用指针,可以使用封送
类,该类有一系列用于复制内存的重载或
private static unsafe void Crop(byte* src, byte* dst, Rectangle rSrc, Rectangle rDst)
{
int* pDst = (int*)dst, pSrc = (int*)src + (rDst.Y * rSrc.Width + rDst.X);
int srcSkip = rSrc.Width - rDst.Width;
int rowCount = rDst.Height, colCount = rDst.Width;
for (int row = 0; row < rowCount; row++)
{
for (int col = 0; col < colCount; col++) *pDst++ = *pSrc++;
pSrc += srcSkip;
}
}
私有静态不安全无效裁剪(字节*src,字节*dst,矩形rSrc,矩形rDst)
{
int*pDst=(int*)dst,pSrc=(int*)src+(rDst.Y*rSrc.Width+rDst.X);
int srcSkip=rSrc.Width-rDst.Width;
int rowCount=rDst.Height,colCount=rDst.Width;
对于(int row=0;row
您是否尝试过.NET framework裁剪方法,从现有位图和矩形创建新位图?它可能没有你想象的那么糟糕。否则,通过一次复制整行而不是逐像素逐字节复制,有一些非托管的位位屏蔽方法可能会更快。是。很有可能使它更快。预先计算循环中可以使用的内容,并找到一种方法让.NET使用一些SIMD指令。在变量中存储((rDst.X+X)*4+(rDst.Y+Y)*(sSrc))
,并使用它4次,而不是计算它4次。对于(x*4+y*(sDst))
您的目标是什么版本的.NET Framework?@IvanStoev 4.5是targetThanks,请快速回复!“不安全”(指针)是外部系统的一个限制,我从设备上获取“图像”,需要应用一些转换并对mp4进行编码。确定可以通过IntPtr获取数组,然后应用crop,但不确定这是一个好主意。无论如何,修复了更完整示例的代码并修复了错误。现在它实际上在大约毫秒的时间内裁剪出一个位图。这是一个很好的例子。我将通过使用位移位而不是乘法来进一步优化它,并跳过对目标地址的循环中GetIndex的调用,因为它始终是连续的,并跳过对循环中GetIndex的调用,在循环外预初始化它,并使用add跳过未使用的字节。很好的示例,谢谢。但我不认为可以使用任何封送处理重载或缓冲区来替换Array.Copy。
private static unsafe void Crop(byte* src, byte* dst, Rectangle rSrc, Rectangle rDst)
{
int* pDst = (int*)dst, pSrc = (int*)src + (rDst.Y * rSrc.Width + rDst.X);
int srcSkip = rSrc.Width - rDst.Width;
int rowCount = rDst.Height, colCount = rDst.Width;
for (int row = 0; row < rowCount; row++)
{
for (int col = 0; col < colCount; col++) *pDst++ = *pSrc++;
pSrc += srcSkip;
}
}