2009-05-01 5 views
12

मुझे एक अल्ट्रासाउंड मशीन पर एक WPF एप्लिकेशन मिला है जो सी ++ में उत्पन्न अल्ट्रासाउंड छवियों को प्रति सेकंड 30 फ्रेम के ऊपर की गति से प्रदर्शित करता है।बड़ी मेमोरी आवंटन के बिना त्वरित अद्यतन छवियों को कैसे प्रदर्शित करें?

जो मैं समझता हूं उससे, डब्ल्यूपीएफ में छवियों को प्रदर्शित करने के लिए सामान्य प्रक्रिया आपकी छवि के लिए बिटमैप स्रोत बनाना है और अपनी छवि के लिए स्रोत सेट करना है, जो उसके बाद इसे अमान्य और प्रदर्शित करने का कारण बनता है।

चूंकि बिटमैप स्रोत IDISposable लागू नहीं करते हैं, इस विधि का उपयोग करके मुझे 30 बिटमैप स्रोतों को एक सेकंड बनाने के लिए मजबूर किया गया है। 32bppArgb प्रारूप के साथ 640x480 छवि के लिए, यह लगभग 30 एमबी/सेकेंड मेमोरी एक सेकंड आवंटित किया जा रहा है और फिर कचरा हर 10 सेकंड में निपटाया जाता है, जिससे दृश्य अंतराल होता है। स्पष्ट रूप से एक स्वीकार्य समाधान नहीं है।

मेरे वर्तमान समाधान है:

सी ++ में: मैं एक System.Drawing.Bitmap (WinForms बिटमैप) बनाने प्रबंधित C++, चित्र को भरने के लिए एक सूचक से एक memcpy कर का उपयोग ग्राफिक्स पर आपत्ति मुझे कुछ अतिरिक्त ड्राइंग की ज़रूरत है, और इसे एक छवि रिसीव किए गए ईवेंट के दौरान सी #/डब्ल्यूपीएफ में पास करें।

सी # में Image.Source BitmapBuffer द्वारा उत्पन्न एक स्रोत है, जो बिटमैप स्रोत के कच्चे डेटा तक पहुँचने का एक हैक तरह से है पर सेट है: this link. देखें मैं एक पी/CopyMemory का आह्वान डेटा की प्रतिलिपि करते हैं BitmapBcaner में Bitmap.Scan0 से। मैं फिर स्क्रीन को अद्यतन करने के लिए छवि को अमान्य कर देता हूं, और ड्रॉइंग। बिटमैप ऑब्जेक्ट को स्मृति मुक्त करने के लिए() का निपटान करता हूं।

हालांकि इस विधि ने थोड़ी देर के लिए काम किया है, यह बहुत हैकी लगता है और मुझे यह विश्वास करना मुश्किल लगता है कि प्रतिबिंब के माध्यम से ऐसा करने के लिए कोई अन्य "उचित" तरीका नहीं है।

प्रश्न: क्या कोई बेहतर तरीका है?

उत्तर

9

यहाँ कुछ कोड मैं (स्मृति साझा करने) एक WPF BitmapSource और एक GDI बिटमैप के बीच (मेरे अपने परियोजना के लिए) aliasing

जाहिर है के लिए * लिखा है, तो आप अपनी जरूरतों के लिए यह tweak करने की आवश्यकता होगी यह अंत में अंत में कम "हैकी" महसूस के साथ खत्म हो जाएगा।

class AliasedBitmapSource : BitmapSource { 
    private Bitmap source; 
    public AliasedBitmapSource(Bitmap source) { 
     this.source = source; 
     this.pixelHeight = source.Height; 
     this.pixelWidth = source.Width; 
     this.dpiX = source.HorizontalResolution; 
     this.dpiY = source.VerticalResolution; 
    } 

    public override event EventHandler DownloadCompleted; 
    public override event EventHandler<ExceptionEventArgs> DownloadFailed; 
    public override event EventHandler<ExceptionEventArgs> DecodeFailed; 

    protected override Freezable CreateInstanceCore() { 
     throw new NotImplementedException(); 
    } 

    private readonly double dpiX; 
    public override double DpiX { 
     get { 
      return dpiX; 
     } 
    } 

    private readonly double dpiY; 
    public override double DpiY { 
     get { 
      return dpiY; 
     } 
    } 

    private readonly int pixelHeight; 
    public override int PixelHeight { 
     get { 
      return pixelHeight; 
     } 
    } 

    private readonly int pixelWidth; 
    public override int PixelWidth { 
     get { 
      return pixelWidth; 
     } 
    } 

    public override System.Windows.Media.PixelFormat Format { 
     get { 
      return PixelFormats.Bgra32; 
     } 
    } 

    public override BitmapPalette Palette { 
     get { 
      return null; 
     } 
    } 

    public unsafe override void CopyPixels(Int32Rect sourceRect, Array pixels, int stride, int offset) { 
     BitmapData sourceData = source.LockBits(
     sourceRect.ToRectangle(), 
     ImageLockMode.ReadWrite, 
     System.Drawing.Imaging.PixelFormat.Format32bppArgb); 

     fixed (byte* _ptr = &((byte[])pixels)[0]) { 
      byte* dstptr = _ptr; 
      byte* srcptr = (byte*)sourceData.Scan0; 

      for (int i = 0; i < pixels.Length; ++i) { 
       *dstptr = *srcptr; 
       ++dstptr; 
       ++srcptr; 
      } 
     } 

     source.UnlockBits(sourceData); 
    } 
} 

public static class Extensions { 
    public static Rectangle ToRectangle(this Int32Rect me) { 
     return new Rectangle(
     me.X, 
     me.Y, 
     me.Width, 
     me.Height); 
    } 

    public static Int32Rect ToInt32Rect(this Rectangle me) { 
     return new Int32Rect(
     me.X, 
     me.Y, 
     me.Width, 
     me.Height); 
    } 
} 

* द्वारा "लिखा था" मेरा मतलब है आप WriteableBitmap की जाँच नवीनतम WPF बिट्स का उपयोग कर रहे हैं, तो आप पैर काम के अधिक करना होगा

+0

मार्शल का उपयोग करना। कॉपी के बजाय असुरक्षित कोड भी तेज़ है और असुरक्षित ब्लॉक की आवश्यकता नहीं है। – Andreas

12

"10 मिनट में एक साथ फेंक दिया" लेकिन आप वास्तव में तेजी से अपडेट करेंगे।

एक त्वरित Google करें और आपको कुछ नमूने मिलेंगे।

+0

आप अधिक मेमोरी और सीपीयू चक्र का उपयोग कर समाप्त हो जाएंगे। चूंकि वांछित स्रोत एक जीडीआई बिटमैप है, इसलिए इसे अद्यतन होने पर इसे लिखने योग्य बिटमैप में प्रतिलिपि बनाना होगा। उपरोक्त AliasedBitmap दृष्टिकोण स्वचालित रूप से दूसरे में बिटमैप में किए गए परिवर्तनों को स्वचालित रूप से प्रतिबिंबित करेगा। – bsneeze

+0

एकमात्र अतिरिक्त मेमोरी जिसे आप उपभोग करेंगे, बैक बफर के लिए है; लेकिन फायदा यह है कि आप फाड़ने से बचेंगे। जहां तक ​​सीपीयू चक्र, स्मृति प्रतिलिपि मेरे बारे में समान प्रतीत होती है, आपको अपने ऐप से बिटमैप डेटा को डिस्प्ले पर प्राप्त करना होगा - और CopyPixels तर्क लगभग किसी भी में समान है। – Scott

+2

इस पर एक नज़र डालने पर, मुझे विश्वास है कि सालों बाद, मैं इस समाधान की ओर बढ़ रहा था। मैंने अल्ट्रासाउंड मशीन के इमेज बफर से बैकबफर को एक बफर.ब्लॉककॉपी कर एक सिंगल लिखित बीटमैप रखा।नतीजतन, समय के साथ कोई स्मृति उपयोग नहीं था (आवंटित नहीं किया जा रहा था) और यहां तक ​​कि एक धीमी दोहरी कोर प्रोसेसर के साथ, 60FPS के आसपास विश्वसनीय प्रदर्शन था। –

संबंधित मुद्दे