Estoy intentando escribir algún código que procese oportunamente los marcos de video. Estoy recibiendo los marcos como System.Windows.Media.Imaging.WriteableBitmap
. Para fines de prueba, solo estoy aplicando un filtro de umbral simple que procesará una imagen de formato BGRA y asignará cada píxel a ser negro o blanco en función del promedio de los píxeles de BGR.¿Por qué mi bloque de código inseguro es más lento que mi código de seguridad?
Aquí está mi versión "segura":
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
);
}
Esto es lo que que es una traducción directa utilizando un bloque de código inseguro y el WriteableBitmap Volver búfer en lugar de la 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();
}
Esta es mi primera incursión en bloques de código y punteros inseguros, por lo que quizás la lógica no sea óptima.
He probado ambos bloques de código en los mismos utilizando 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));
Así que estoy analizando la misma imagen. Una ejecución de prueba de una secuencia entrante de cuadros de video:
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
¿Por qué mi versión insegura es siempre más lenta? ¿Es debido al uso del buffer de respaldo? ¿O estoy haciendo algo mal?
Gracias
¿Está ejecutando estas pruebas en una compilación de versión? –
No, esto está en una compilación de depurador en este momento. –
Recomiendo ejecutar pruebas de rendimiento en una versión de lanzamiento para obtener resultados significativos. Puede encontrar que hay una brecha de rendimiento menor para justificar el uso de una versión "insegura" si permite que el optimizador cumpla con el código. –