Ich versuche, Code zu schreiben, der Videoframes zweckdienlich verarbeiten wird. Ich empfange die Rahmen als System.Windows.Media.Imaging.WriteableBitmap
. Zu Testzwecken verwende ich einfach einen einfachen Schwellenwertfilter, der ein Bild im BGRA-Format verarbeitet und jedem Pixel basierend auf dem Durchschnitt der BGR-Pixel entweder Schwarz oder Weiß zuweist.Warum ist mein unsicherer Code langsamer als mein sicherer Code?
Hier ist meine "Safe" Version:
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
);
}
Hier ist, was ich ist denke eine direkte Übersetzung ist einen unsicheren Codeblock und die Writeablebitmap Back Buffer anstelle des forebuffer mit:
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();
}
Dies ist mein erster Ausflug in unsichere Code-Blöcke und Zeiger, also ist die Logik vielleicht nicht optimal.
Ich habe beide Codeblöcke auf den gleichen WriteableBitmaps getestet mit:
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));
Ich Analyse das gleiche Bild So. Ein Testlauf eines eingehenden Videostreamerahmens:
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
Warum ist meine unsichere Version immer langsamer? Liegt es an der Verwendung des Backpuffers? Oder mache ich etwas falsch?
Dank
Führen Sie diese Tests in einem Release-Build? –
Nein, das ist jetzt in einem Debugger-Build. –
Ich empfehle, Leistungstests in einem Release-Build auszuführen, um aussagekräftige Ergebnisse zu erhalten. Sie können feststellen, dass es weniger Leistungslücken gibt, um die Verwendung einer "unsicheren" Version zu rechtfertigen, wenn Sie den Optimierer mit dem Code vertraut machen. –