Почему мой небезопасный блок кода медленнее, чем мой безопасный код?

Я пытаюсь написать некоторый код, который целесообразно обработает видеокадры. Я принимаю кадры как a System.Windows.Media.Imaging.WriteableBitmap. Для тестирования я просто применяю простой пороговый фильтр, который обработает изображение формата BGRA и присвоит каждый пиксель, чтобы или быть черным или белым на основе среднего числа пикселей BGR.

Вот моя "Безопасная" версия:

public static void ApplyFilter(WriteableBitmap Bitmap, byte Threshold)
{
    // Let's just make this work for this format
    if (Bitmap.Format != PixelFormats.Bgr24
        && Bitmap.Format != PixelFormats.Bgr32)
    {
        return;
    }

    // Calculate the number of bytes per pixel (should be 4 for this format). 
    var bytesPerPixel = (Bitmap.Format.BitsPerPixel + 7) / 8;

    // Stride is bytes per pixel times the number of pixels.
    // Stride is the byte width of a single rectangle row.
    var stride = Bitmap.PixelWidth * bytesPerPixel;

    // Create a byte array for a the entire size of bitmap.
    var arraySize = stride * Bitmap.PixelHeight;
    var pixelArray = new byte[arraySize];

    // Copy all pixels into the array
    Bitmap.CopyPixels(pixelArray, stride, 0);

    // Loop through array and change pixels to black/white based on threshold
    for (int i = 0; i < pixelArray.Length; i += bytesPerPixel)
    {
        // i=B, i+1=G, i+2=R, i+3=A
        var brightness =
               (byte)((pixelArray[i] + pixelArray[i+1] + pixelArray[i+2]) / 3);

        var toColor = byte.MinValue; // Black

        if (brightness >= Threshold)
        {
            toColor = byte.MaxValue; // White
        }

        pixelArray[i] = toColor;
        pixelArray[i + 1] = toColor;
        pixelArray[i + 2] = toColor;
    }
    Bitmap.WritePixels(
        new Int32Rect(0, 0, Bitmap.PixelWidth, Bitmap.PixelHeight),
        pixelArray, stride, 0
    );
}

Вот то, что я думаю, прямой перевод с помощью небезопасного блока кода и WriteableBitmap Обратный Буфер вместо forebuffer:

public static void ApplyFilterUnsafe(WriteableBitmap Bitmap, byte Threshold)
{
    // Let's just make this work for this format
    if (Bitmap.Format != PixelFormats.Bgr24
        && Bitmap.Format != PixelFormats.Bgr32)
    {
        return;
    }

    var bytesPerPixel = (Bitmap.Format.BitsPerPixel + 7) / 8;

    Bitmap.Lock();

    unsafe
    {
        // Get a pointer to the back buffer.
        byte* pBackBuffer = (byte*)Bitmap.BackBuffer;

        for (int i = 0;
             i < Bitmap.BackBufferStride*Bitmap.PixelHeight;
             i+= bytesPerPixel)
        {
            var pCopy = pBackBuffer;
            var brightness = (byte)((*pBackBuffer
                                     + *++pBackBuffer
                                     + *++pBackBuffer) / 3);
            pBackBuffer++;

            var toColor =
                    brightness >= Threshold ? byte.MaxValue : byte.MinValue;

            *pCopy = toColor;
            *++pCopy = toColor;
            *++pCopy = toColor;                    
        }
    }

    // Bitmap.AddDirtyRect(
    //           new Int32Rect(0,0, Bitmap.PixelWidth, Bitmap.PixelHeight));
    Bitmap.Unlock();

}

Это - мой первый набег в небезопасные блоки кода и указатели, поэтому возможно, логика не оптимальна.

Я протестировал оба блока кода на том же использовании WriteableBitmaps:

var threshold = Convert.ToByte(op.Result);
var copy2 = copyFrame.Clone();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
BinaryFilter.ApplyFilterUnsafe(copyFrame, threshold);
stopWatch.Stop();

var unsafesecs = stopWatch.ElapsedMilliseconds;
stopWatch.Reset();
stopWatch.Start();
BinaryFilter.ApplyFilter(copy2, threshold);
stopWatch.Stop();
Debug.WriteLine(string.Format("Unsafe: {1}, Safe: {0}",
                stopWatch.ElapsedMilliseconds, unsafesecs));

Таким образом, я анализирую то же изображение. Тестовый прогон входящего потока видеокадров:

Unsafe: 110, Safe: 53
Unsafe: 136, Safe: 42
Unsafe: 106, Safe: 36
Unsafe: 95, Safe: 43
Unsafe: 98, Safe: 41
Unsafe: 88, Safe: 36
Unsafe: 129, Safe: 65
Unsafe: 100, Safe: 47
Unsafe: 112, Safe: 50
Unsafe: 91, Safe: 33
Unsafe: 118, Safe: 42
Unsafe: 103, Safe: 80
Unsafe: 104, Safe: 34
Unsafe: 101, Safe: 36
Unsafe: 154, Safe: 83
Unsafe: 134, Safe: 46
Unsafe: 113, Safe: 76
Unsafe: 117, Safe: 57
Unsafe: 90, Safe: 41
Unsafe: 156, Safe: 35

Почему моя небезопасная версия всегда медленнее? Действительно ли это происходит из-за использования заднего буфера? Или я делаю что-то не так?

Спасибо

7
задан Michael Myers 3 May 2010 в 19:31
поделиться

3 ответа

Может быть, потому что ваша небезопасная версия выполняет умножение и доступ к свойствам:

Bitmap.BackBufferStride*Bitmap.PixelHeight

На каждой итерации цикла. Сохраните результат в переменной.

9
ответ дан 6 December 2019 в 15:19
поделиться

Еще одна оптимизация, в безопасном или небезопасном коде: Перестаньте делить на 3 внутри цикла. Умножьте порог на 3 один раз, вне цикла. Вам придется использовать какой-то тип, отличный от byte, но это не должно быть проблемой. На самом деле, вы уже используете больший тип данных, чем byte :)

5
ответ дан 6 December 2019 в 15:19
поделиться

Трудно сказать без профилирования кода, тем более что код сильно отличается (хотя на первый взгляд выглядит похожим) некоторые ключевые моменты (и все они лишь предположения)

условие остановки, если вычисляется if. в небезопасной версии, а не в сейфе

  • , индексы для массива pixelArray могут быть вычислены только один раз , хотя они используются дважды.
  • даже если они не "кэшированы", сложение чисел вместе без сохранения их (в отличие от ++ p) все равно будет быстрее (меньше инструкций и { {1}} меньше доступа к памяти)
  • вы не блокируете растровое изображение в безопасной версии
  • pixelArray [i], pixelArray [i + 1], pixelArray [i + 2] {{1 }} может храниться в локальных жителях, что делает доступ к ним во второй раз потенциально быстрее, чем повторение указателя снова.
  • у вас есть дополнительное назначение в небезопасном коде (pCOpy = pBackBuffer) и дополнительное приращение (pBackBuffer ++;)

Это все идеи, которые я могу придумать. Надеюсь, это поможет

0
ответ дан 6 December 2019 в 15:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: