C# 字节数组映像裁剪性能问题

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

有两个指向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++) 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;
    }
}