2010-02-10 11 views
7

मेरी प्रोजेक्ट में, मैं (16-बिट ग्रेस्केल असंपीड़ित) gigapixel छवियों का उपयोग कर रहा हूं जो माप उद्देश्यों के लिए उच्च रिज़ॉल्यूशन स्कैनर से आते हैं। चूंकि इन बिटमैप को स्मृति में लोड नहीं किया जा सकता है (मुख्य रूप से स्मृति विखंडन के कारण) मैं टाइल्स का उपयोग कर रहा हूं (और डिस्क पर टिल्ड टीआईएफएफ)। (StackOverflow topic on this देखें)gigapixel बिटमैप्स पर पैन/ज़ूम कैसे कार्यान्वित करें?

मुझे Google मानचित्र या DeepZoom जैसे पैनिंग/ज़ूमिंग को लागू करने की आवश्यकता है। मुझे इसे स्क्रीन पर प्रस्तुत करने से पहले फ्लाई पर छवि प्रसंस्करण लागू करना है, इसलिए मैं एक सटीक लाइब्रेरी का उपयोग नहीं कर सकता जो सीधे एक छवि फ़ाइल तक पहुंचता है। ज़ूमिंग के लिए मैं अपनी फ़ाइल (पिरामिड स्टोरेज) में एक बहु-रिज़ॉल्यूशन छवि रखने का इरादा रखता हूं। सबसे उपयोगी कदम + 200%, 50% और सभी दिखाते हैं।

मेरा कोड बेस वर्तमान में सी # और .NET 3.5 है। वर्तमान में मैं प्रपत्र प्रकार मानता हूं, जब तक कि इस क्षेत्र में डब्ल्यूपीएफ मुझे बड़ा लाभ नहीं देता। मेरे पास एक विधि है जो अंतर्निहित छवि के किसी भी (संसाधित) हिस्से को वापस कर सकती है।

विशिष्ट मुद्दों:

  • संकेत या कैसे इस पैन को लागू करने/छवि भागों की मांग पर पीढ़ी के साथ ज़ूम पर संदर्भ
  • किसी भी कोड है जो एक आधार (अधिमानतः वाणिज्यिक या LGPL के रूप में इस्तेमाल किया जा सकता/बीएसडी लाइसेंस की तरह)
  • क्या इसके लिए डीपज़ूम का उपयोग किया जा सकता है (यानी क्या कोई तरीका है कि मैं वर्तमान ज़ूम स्तर के लिए सही पुनर्वसन पर टाइल प्रदान करने के लिए एक फ़ंक्शन प्रदान कर सकता हूं?) (मुझे अभी भी पिक्सेल सटीक एड्रेसिंग होना चाहिए)
+0

डीपज़ूम दृष्टिकोण की तरह दिखता है। आपको छवियों के कम-रिज़ॉल्यूशन संस्करणों को http://www.imagemagick.org/script/index.php जैसे कुछ बनाना होगा। मेरे पोकिंग से, ऐसा लगता है कि यह एक पेटेंट खानफील्ड है, इसलिए .... – kenny

उत्तर

3

मैंने स्वयं कुछ करने का फैसला किया। मैं एक सीधा जीडीआई + कोड के साथ आया, जो कि पहले से मिल चुके टाइल्स का उपयोग करता है। मैं सिर्फ उन हिस्सों को फ़िल्टर करता हूं जो वर्तमान क्लिपिंग क्षेत्र के लिए प्रासंगिक हैं। यह जादू की तरह काम करता है! कृपया नीचे अपना कोड पाएं। (फॉर्म सेटिंग्स अच्छे परिणाम के लिए डबल बफरिंग)

protected override void OnPaint(PaintEventArgs e) 
    { 
     base.OnPaint(e); 
     Graphics dc = e.Graphics; 
     dc.ScaleTransform(1.0F, 1.0F); 
     Size scrollOffset = new Size(AutoScrollPosition); 

     int start_x = Math.Min(matrix_x_size, 
          (e.ClipRectangle.Left - scrollOffset.Width)/256); 
     int start_y = Math.Min(matrix_y_size, 
          (e.ClipRectangle.Top - scrollOffset.Height)/256); 
     int end_x = Math.Min(matrix_x_size, 
         (e.ClipRectangle.Right - scrollOffset.Width + 255)/256); 
     int end_y = Math.Min(matrix_y_size, 
         (e.ClipRectangle.Bottom - scrollOffset.Height + 255)/256); 

     // start * contain the first and last tile x/y which are on screen 
     // and which need to be redrawn. 
     // now iterate trough all tiles which need an update 
     for (int y = start_y; y < end_y; y++) 
      for (int x = start_x; x < end_x; x++) 
      { // draw bitmap with gdi+ at calculated position. 
       dc.DrawImage(BmpMatrix[y, x], 
          new Point(x * 256 + scrollOffset.Width, 
            y * 256 + scrollOffset.Height)); 
      } 
    } 

यह परीक्षण करने के लिए, मैं 256 के 80x80 टाइल (420 MPixel) के एक मैट्रिक्स बना लिया है। बेशक मुझे वास्तविक जीवन में कुछ स्थगित लोडिंग जोड़नी होगी। अगर वे अभी तक लोड नहीं हुए हैं तो मैं टाइल्स को छोड़ सकता हूं (खाली)। असल में, मैंने अपने क्लाइंट से अपनी मशीन में 8 जीबीटीटी चिपकने के लिए कहा है, इसलिए मुझे प्रदर्शन के बारे में परेशान करने की ज़रूरत नहीं है। एक बार लोड टाइल्स स्मृति में रह सकते हैं।

public partial class Form1 : Form 
{ 
    bool dragging = false; 
    float Zoom = 1.0F; 
    Point lastMouse; 
    PointF viewPortCenter; 

    private readonly Brush solidYellowBrush = new SolidBrush(Color.Yellow); 
    private readonly Brush solidBlueBrush = new SolidBrush(Color.LightBlue); 
    const int matrix_x_size = 80; 
    const int matrix_y_size = 80; 
    private Bitmap[,] BmpMatrix = new Bitmap[matrix_x_size, matrix_y_size]; 
    public Form1() 
    { 
     InitializeComponent(); 

     Font font = new Font("Times New Roman", 10, FontStyle.Regular); 
     StringFormat strFormat = new StringFormat(); 
     strFormat.Alignment = StringAlignment.Center; 
     strFormat.LineAlignment = StringAlignment.Center; 
     for (int y = 0; y < matrix_y_size; y++) 
      for (int x = 0; x < matrix_x_size; x++) 
      { 
       BmpMatrix[y, x] = new Bitmap(256, 256, PixelFormat.Format24bppRgb); 
       //     BmpMatrix[y, x].Palette.Entries[0] = (x+y)%1==0?Color.Blue:Color.White; 

       using (Graphics g = Graphics.FromImage(BmpMatrix[y, x])) 
       { 
        g.FillRectangle(((x + y) % 2 == 0) ? solidBlueBrush : solidYellowBrush, new Rectangle(new Point(0, 0), new Size(256, 256))); 
        g.DrawString("hello world\n[" + x.ToString() + "," + y.ToString() + "]", new Font("Tahoma", 8), Brushes.Black, 
         new RectangleF(0, 0, 256, 256), strFormat); 
        g.DrawImage(BmpMatrix[y, x], Point.Empty); 
       } 
      } 

     BackColor = Color.White; 

     Size = new Size(300, 300); 
     Text = "Scroll Shapes Correct"; 

     AutoScrollMinSize = new Size(256 * matrix_x_size, 256 * matrix_y_size); 
    } 

बाहर निकला यह आसान हिस्सा था।बैकग्राउंड में एसिंक मल्टीथ्रेड किए गए I/O को प्राप्त करना बहुत कठिन था। फिर भी, मैं इसे यहां वर्णित तरीके से काम कर रहा हूं। हल करने के लिए मुद्दे इस विषय से संबंधित .NET/Form multithreading थे।

छद्म कोड में यह इस तरह काम करता है:

after onPaint (and on Tick) 
    check if tiles on display need to be retrieved from disc 
     if so: post them to an async io queue 
     if not: check if tiles close to display area are already loaded 
      if not: post them to an async io/queue 
    check if bitmaps have arrived from io thread 
     if so: updat them on screen, and force repaint if visible 

परिणाम: मैं अब जो मनमाने ढंग से आकार (टाइलों) TIFF फ़ाइलों के लिए बहुत तेजी से पहुँच के लिए लगभग 50 MByte का उपयोग करता है अपने खुद के कस्टम नियंत्रण है।

+0

एक कंपाइलर ध्वज जोड़ना सुनिश्चित करें कि यह केवल 64 बिट है, अन्यथा यह एक बाह्य स्वर्ग बन जाता है। – Dykam

3

यह CodeProject article: Generate...DeepZoom Image Collection एक उपयोगी पढ़ा जा सकता है क्योंकि यह एक DeepZoom छवि स्रोत उत्पन्न करने के बारे में बात करता है। । भागो समय और इस Mandelbrot Explorer के लिंक पर छवि पिक्सल की आपूर्ति जो थोड़े 'तुम क्या करने की कोशिश कर रहे हैं क्या करने के लिए इसी तरह की लग रहा है (यानी वह के विशिष्ट भागों पैदा कर रहा है:

यह MSDN article एक वर्ग गतिशील दीप ज़ूम है mandelbrot ऑन-डिमांड सेट; आप मांग पर अपनी गिगापिक्सेल छवि के विशिष्ट हिस्सों को पुनर्प्राप्त करना चाहते हैं)।

मुझे लगता है कि "इसके लिए DeepZoom का उपयोग किया जा सकता है?" शायद "हां" है, हालांकि यह केवल सिल्वरलाइट में उपलब्ध है, यदि आपको WinForms/WPF क्लाइंट ऐप की आवश्यकता है तो आपको एम्बेडेड वेब ब्राउज़र नियंत्रण के साथ कुछ युक्तियां करनी होंगी।

क्षमा करें मैं अधिक विशिष्ट उत्तर प्रदान नहीं कर सकता - आशा है कि वे लिंक मदद करें।

पेज। मुझे यकीन नहीं है कि सिल्वरलाइट टीआईएफएफ छवियों का समर्थन करता है - यह तब तक एक मुद्दा हो सकता है जब तक कि आप किसी अन्य प्रारूप में परिवर्तित न हों।

+0

सिल्वरलाइट वर्तमान में टीआईएफएफ छवियों का समर्थन नहीं करता है, लेकिन इसमें एक लिखित योग्य बिट क्लास –

+0

धन्यवाद है। उत्तर और लिंक के लिए +1। मैं सिर्फ पैन/ज़ूम के लिए सिल्वरलाइट-थ्रू-ए-वेबसर्वर-इन-डब्ल्यूपीएफ जोड़ने की जटिलता से डरता हूं। (मेरे पास वर्तमान में मेरे एप्लिकेशन में कोई सर्वर या ब्राउज़र हिस्सा नहीं है; यह डेस्कटॉप है)। टीआईएफएफ के लिए: यह कोई समस्या नहीं है; मैं आंतरिक रूप से टीआईएफएफ से पीएनजी स्ट्रीम कर सकता हूं। बस बिट्स का 50% छोड़ दें ;-) – Adriaan

+0

जो मैंने अभी तक डीपज़ूम के बारे में सीखा है, ऐसा लगता है कि सटीक पते (मेरे आवेदन में एकाधिक विंडो के बीच ज़ूम/स्थिति का सिंक्रनाइज़ेशन) जैसी चीजें बहुत कठिन होंगी। दीपज़ूम द्वारा दी गई कार्यक्षमता उस वास्तुशिल्प जटिलता को उचित नहीं ठहराती है जो इसे लाएगी (सिल्वरलाइट जोड़कर और पैन/ज़ूम के लिए एक सर्वर जोड़ना)। मैं एक कस्टम (एक) आवेदन कर रहा हूं जहां घंटियां और सीटी की तुलना में विकास के घंटे अधिक महत्वपूर्ण हैं। मैं भविष्य के अनुप्रयोगों के लिए इसकी नजर रखूंगा (जब यह .NET xx की बात आती है तो यह दिलचस्प होगा! – Adriaan

3

मुझे लगता है कि आप इस समस्या को निम्न चरणों का पालन पता कर सकते हैं:

  1. छवि पीढ़ी:

    • instace के लिए एक छोटा सा संकल्प के कई subimages (टाइल) में अपनी छवि खंड,, 500x500 । इन छवियों को गहराई 0
    • गहराई 0 (4x4 या 6x6) के साथ टाइल्स की एक श्रृंखला गठबंधन, आकार बदलने के संयोजन 500x500 पिक्सेल के साथ एक नई टाइल पैदा गहराई में 1.
    • इस दृष्टिकोण के साथ जारी रखने के लिए जब तक केवल का उपयोग कर पूरी छवि प्राप्त कर रहे हैं कुछ टाइल्स
  2. छवि दृश्य

    • उच्चतम गहराई
    • उपयोगकर्ता छवि को खींचता है,, टाइल्स गतिशील
    • उपयोगकर्ता छवि का एक क्षेत्र ज़ूम जब लोड गहराई कमी से प्रारंभ, उच्च रिज़ॉल्यूशन में उस क्षेत्र के लिए टाइल्स लोड करना।

अंतिम परिणाम गूगल मैप्स के समान है।

+2

मैं हूं यह देखने में कठिनाई हो रही है कि आपने जो लिंक प्रदान किया है वह उपयोगी है; यह ओपी पूछ रहा था कि कैसे करना है इसका वर्णन करने के लिए यह कोई कोड/छद्म कोड प्रदान नहीं करता है। मैं लिंक को हटा रहा हूं ताकि कोई भी स्पैम के लिए इस जवाब को गलती न करे। –

+0

असल में , मेरे आवेदन को मुख्य रूप से 25-100% के ज़ूम स्तर की आवश्यकता होती है, और इसके लिए निश्चित 256x256 टाइल्स के साथ एक परत का उपयोग करके बहुत अच्छी तरह से काम किया जाता है। यह सिर्फ इतना है कि जीडीआई + वास्तव में बड़ी छवियों को संभाल नहीं सकता है और कुछ मदद (टाइल्स के गतिशील प्रदर्शन) की आवश्यकता है और टीआईएफएफ फाइलों (Tifflib.net) की लोडिंग।आपकी विधि वास्तव में terrabit छवियों के लिए आवश्यक है या यदि कोई ज़ूम कारक की आवश्यकता है। आपके योगदान के लिए धन्यवाद। – Adriaan

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