字节数组图像裁剪性能问题

时间:2015-09-28 15:48:35

标签: c# .net bytearray unsafe imaging

有两个指针(byte *)为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];
    }
}

它的工作原理:1920x1080约为100ms,但需要~10 - 15 ms。有可能让它更快吗?例如,普通副本(没有裁剪)提供了更好的性能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++; }
    }
}

需要你的想法!

感谢。

2 个答案:

答案 0 :(得分:0)

实际上你可以让它在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;
}

输出:

00:00:00.0007131

要使用指针,您可以使用Marshal类,它有一堆重载用于复制内存或Buffer.MemoryCopy Method

答案 1 :(得分:0)

你去了

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;
    }
}