2010-05-03 11 views
7

मैं कुछ कोड लिखने का प्रयास कर रहा हूं जो तेजी से वीडियो फ्रेम को संसाधित करेगा। मैं फ्रेम को System.Windows.Media.Imaging.WriteableBitmap के रूप में प्राप्त कर रहा हूं। परीक्षण उद्देश्यों के लिए, मैं बस एक साधारण थ्रेसहोल्ड फ़िल्टर लागू कर रहा हूं जो बीजीआरए प्रारूप छवि को संसाधित करेगा और प्रत्येक पिक्सेल को बीजीआर पिक्सेल के औसत के आधार पर काला या सफेद रंग देने के लिए असाइन करेगा।मेरे सुरक्षित कोड से मेरा असुरक्षित कोड ब्लॉक धीमा क्यों है?

यहाँ मेरी "सुरक्षित" संस्करण है:

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

यहाँ है मैं क्या सोचता एक असुरक्षित कोड ब्लॉक और forebuffer के बजाय WriteableBitmap वापस बफर का उपयोग कर एक सीधा अनुवाद है:

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 

मेरा असुरक्षित संस्करण हमेशा धीमा क्यों है? क्या यह बैक बफर का उपयोग करने के कारण है? या मुझ से कुछ गलत हो रहा है?

धन्यवाद

+0

मदद करता है क्या आप इन परीक्षणों को रिलीज बिल्ड में चला रहे हैं? –

+0

नहीं यह अभी डिबगर निर्माण में है। –

+3

मैं सार्थक परिणाम प्राप्त करने के लिए रिलीज बिल्ड में प्रदर्शन परीक्षण परीक्षण की अनुशंसा करता हूं। यदि आप ऑप्टिमाइज़र को कोड के साथ अपना रास्ता देते हैं तो आप एक 'असुरक्षित' संस्करण का उपयोग करके औचित्य साबित करने के लिए प्रदर्शन प्रदर्शन कम कर सकते हैं। –

उत्तर

9

हो सकता है कि क्योंकि आपके असुरक्षित संस्करण एक गुणा और संपत्ति का उपयोग कर रहा है:

Bitmap.BackBufferStride*Bitmap.PixelHeight 

हर पाश यात्रा पर। परिणाम को एक चर में स्टोर करें।

+0

सुनिश्चित नहीं है कि यह समस्या है, लेकिन यह निश्चित रूप से इसमें योगदान देगा। – McAden

+1

आप सही हैं! मैं यह पता लगाने की कोशिश में इतना लपेट गया था कि असुरक्षित ब्लॉक कैसे काम करता है और पॉइंटर्स, कि मैं अपने इटरेटर स्थिति तर्क ऑपरेशन के लिए अंधेरा था। एक चर में यह संग्रहीत करने से वास्तव में मुझे "सुरक्षित" संस्करण से नीचे गिरा दिया गया, हालांकि गेम-चेंजर होने के लिए वास्तव में पर्याप्त नहीं है। यदि अन्य चीजें हैं जो मैं कर रहा हूं जो उप-इष्टतम हैं, तो मैं सभी कान हूं, यदि नहीं, तो त्वरित सुधार के लिए धन्यवाद! –

+1

यह गुणा नहीं है कि यह बड़ी समस्या है, यह तथ्य है कि आप गुणों तक पहुंच रहे हैं (बैकबफररटाइड और पिक्सेलहेइट, यह असली हत्यारा है। मुझे पता है कि आप डब्ल्यूपीएफ के साथ काम कर रहे हैं, लेकिन सिल्वरलाइट के लिए मैंने एक रैपर बनाया जो कैश किया गया आवश्यक प्रदर्शन प्राप्त करने के लिए बिटमैप के सभी प्रॉपर्टी वैल्यू। –

5

एक और अनुकूलन, या तो सुरक्षित या असुरक्षित कोड में: अपने लूप के अंदर 3 से विभाजित करना बंद करें। लूप के बाहर, 3 बार एक बार अपनी दहलीज गुणा करें। आपको byte के अलावा किसी अन्य प्रकार का उपयोग करने की आवश्यकता होगी, लेकिन यह कोई समस्या नहीं होनी चाहिए। असल में, आप पहले से ही byte की तुलना में एक बड़ा डेटाटाइप का उपयोग कर रहे हैं :)

+0

+1: इससे भी मदद मिली! मुझे लगभग 9 एमएस रेंज मिल रही थी पहले और अब लूप के बाहर एकल गुणा प्रदर्शन करते हुए जैसा कि आपने सुझाव दिया था कि यह 17-20 एमएस रेंज तक पहुंच गया है। सुनिश्चित नहीं है कि मैं बहुत कम नीचे उतर पाऊंगा। –

+0

@jomtois मैंने कुछ चीजों की कोशिश की है ... लेकिन यदि मेरे परीक्षण कुछ भी साबित करते हैं, तो यह है कि माइक्रो-ऑप्टिमाइज़ेशन आमतौर पर इसके लायक नहीं है। मैंने कुछ बिटमैस्क का उपयोग करने और गिनती लूप के बजाय 'while (pBackBuffer Thorarin

0

कोड को प्रोफाइलिंग के साथ कहना मुश्किल है, खासकर जब कोड बहुत अलग है (घटनाओं में यह पहली बार दिखता है) कुछ महत्वपूर्ण बिंदु (और वे हैं सब सिर्फ अटकलें तेज हो गई)

रोक हालत अगर यदि सरणी pixelArray केवल एक बार की गणना की जा सकती है eventhough वे दो बार उपयोग किया जाता है के लिए सुरक्षित

  • सूचकांकों में नहीं असुरक्षित संस्करण में गणना की जाती है।
  • भले ही वे "कैश की गई" नहीं कर रहे हैं जोड़कर मिलने एक साथ भंडारण उन्हें (के रूप में पी ++ के खिलाफ) के बिना अभी भी तेजी से (कम निर्देश और कम स्मृति का उपयोग) होगा
  • आप ताला लगा नहीं कर रहे हैं सुरक्षित संस्करण
  • pixelArray में बिटमैप [i], pixelArray [i + 1], pixelArray [i + 2] ताकि उन्हें आसानी से सूचक फिर से पुनरावृत्ति से पहुँचने के दूसरी बार संभावित बनाने के लिए स्थानीय लोगों में संग्रहीत हो सकता है।
  • आप असुरक्षित कोड (pCOpy = pBackBuffer) और एक अतिरिक्त वेतन वृद्धि में एक अतिरिक्त कार्यभार है (pBackBuffer ++;)

सभी विचारों मैं के साथ आ सकता है यही कारण है कि। उम्मीद है कि यह

+0

मुझे संदेह है कि स्टॉप हालत एक बड़ा हिटर है, जैसा ऊपर बताया गया है। मैं आपके कुछ अन्य विचारों और @ थोरिनिन के विचार को भी ऊपर देखूंगा। असल में मैं पॉइंटर को 4 बाइट भागों में ले जाना चाहता हूं जो पिक्सेल का प्रतिनिधित्व करते हैं। मुझे पहले तीन बाइट्स को खंड में पूछताछ और बदलने की जरूरत है और चौथे स्थान पर जाना है। मुझे नहीं पता कि माइक्रो-ऑप्टिमाइज़ेशन इसके लिए सबसे अच्छा क्या है। –