अनंत बिटमैप [बंद]


10

मैं रनटाइम के दौरान एक बिटमैप बनाना चाहता हूं। बिटमैप सभी पक्षों पर स्केलेबल होना चाहिए और पिक्सेल एक्सेस शांत कुशल होना चाहिए।

कुछ चित्रण http://img546.imageshack.us/img546/4995/maptm.jpg

चित्र में दिखाए गए आदेशों के बीच और बाद में, Map.setPixel () और Map.getPixel () को बिटमैप में सहेजे गए डेटा को सेट / वापस करना चाहिए।

मैं एक कार्यान्वयन की अपेक्षा नहीं करता हूं कि बस एक अवधारणा है कि मेमोरी को इस तरह से कैसे आवंटित किया जाए कि सेटपिक्सल () / गेटपिक्सल जितनी जल्दी हो सके।


क्या ग्रे फ़ील्ड हमेशा बिंदु (0,0) है या यह एक अन्य समन्वय भी हो सकता है?
फॉल्कन

2
अधिक जानकारी की आवश्यकता है। क्या सेट पिक्सेल विरल हो रहे हैं? कितनी तेजी से आप extendXतरीके बनाने के लिए तैयार कर रहे हैं ताकि setPixelऔर getPixelतेजी से हो?
पीटर टेलर

1
क्या मेमोरी में फिट होने के लिए बिटमैप बहुत बड़ा होगा? तेजी से संचालन - विस्तार, सेटपिक्सल (), गेटपिकेल () क्या होना चाहिए?

1
@ फाल्कन: नहीं, पर्याप्त समय उपलब्ध है
SecStone

3
मैं इस प्रश्न को ऑफ-टॉपिक के रूप में बंद करने के लिए मतदान कर रहा हूं क्योंकि यह प्रश्न शामिल छवि पर बहुत अधिक निर्भर करता है, जिसे बाद में हटा दिया गया है। जैसा कि वर्तमान में लिखा गया है, यह बहुत मायने नहीं रखता है।

जवाबों:


9

यदि extend()ऑपरेशन को तेजी से करने की आवश्यकता है, तो क्वाडट्री एक अच्छा फिट हो सकता है; यह वास्तव में भी स्पष्ट विस्तार ऑपरेशन की आवश्यकता नहीं होगी। बेशक, यह अलग-अलग पिक्सेल के लिए रैंडम एक्सेस के लिए अनुकूलतम प्रदर्शन प्राप्त होते हैं नहीं है, लेकिन अपनी टिप्पणी का कहना है कि अपनी प्राथमिक ऑपरेशन है बार-बार दोहराना जो एक quadtree एक मैट्रिक्स आधारित कार्यान्वयन के रूप में बहुत तेजी से शायद लगभग के रूप में तेजी से कर सकता है,, पिक्सल से अधिक (और तेजी से यदि पुनरावृत्ति हमेशा उसी तरह से नहीं होती है जिस तरह से मैट्रिक्स रखी गई है)।

आपकी आवश्यकताओं को वास्तव में लगता है जैसे कि आप सेलुलर ऑटोमेटन को गेम ऑफ लाइफ की तरह लागू करने की कोशिश कर रहे हैं। आप होशलाइफ पर एक नज़र डाल सकते हैं , एक अनंत ग्रिड पर गेम ऑफ लाइफ को लागू करने के लिए एक उच्च प्रदर्शन वाला तरीका है। ध्यान दें कि यह एक Quadtree पर आधारित है, लेकिन खेल के नियमों की स्थानीयता के आधार पर कुछ बहुत ही स्मार्ट अतिरिक्त अनुकूलन करता है।


इस विचार के लिए धन्यवाद! मैं कुछ परीक्षण करूंगा और परिणामों की रिपोर्ट करूंगा।
15

2

@SecStone ने कहा कि विस्तार ऑपरेशन के लिए पर्याप्त समय उपलब्ध है, इसलिए पिक्सल को स्टोर करने का सबसे आसान और सबसे कुशल तरीका एक ही फ्लैट सरणी या दो आयामी सरणी का उपयोग करना है, क्योंकि पिक्सल को निरंतर समय में एक्सेस किया जा सकता है।


4
अगर आप सोचते हैं कि विस्तार से निपटा जाना चाहिए, तो आप एक अच्छा सुझाव देते हैं, तो मैं इसे वोट करूंगा।
Doc Brown

@ डॉक ब्राउन: अगर पर्याप्त समय है तो सिर्फ एरे को शिफ्ट करें। या हो सकता है कि आप ऐरे और चंक इंडेक्स के लिए चंक्स और अनुवादक फ़ंक्शन के साथ कुछ काम कर सकते हैं (जो लगातार समय में भी चलता है)।
फाल्कन

2

हाथ से

यदि स्मृति बहुत विरल संसाधन नहीं है, तो मैं बड़ी मात्रा में काम करने पर विचार करता हूं।
यहाँ कुछ छद्म कोड है।

class Chunk {
    Chunk new(int size) {...}
    void setPixel(int x, int y, int value) {...}
    int getPixel(int x, int y) {...}
}

class Grid {
    Map<int, Map<Chunk>> chunks;
    Grid new(int chunkSize) {...}
    void setPixel(int x, int y, int value) {
         getChunk(x,y).setPixel(x % chunkSize, y % chunkSize, value);//actually the modulo could be right in Chunk::setPixel and getPixel for more safety
    }
    int getPixel(int x, int y) { /*along the lines of setPixel*/ }
    private Chunk getChunk(int x, int y) {
         x /= chunkSize;
         y /= chunkSize;
         Map<Chunk> row = chunks.get(y);
         if (row == null) chunks.set(y, row = new Map<Chunk>());
         Chunk ret = row.get(x);
         if (ret == null) row.set(x, ret = new Chunk(chunkSize));
         return ret;
    }
}

यह कार्यान्वयन काफी भोला है।
एक के लिए, यह getPixel में विखंडू बनाता है (मूल रूप से यह केवल 0 या तो वापस करने के लिए ठीक होगा, यदि उस स्थिति के लिए कोई विखंडू परिभाषित नहीं किया गया था)। दूसरे यह धारणा पर आधारित है, कि आपके पास मैप का पर्याप्त तेज़ और स्केलेबल कार्यान्वयन है। मेरी जानकारी में हर सभ्य भाषा एक है।

साथ ही आपको चंक साइज़ के साथ खेलना होगा। घने बिटमैप्स के लिए, एक बड़े चंक आकार अच्छा है, विरल बिटमैप्स के लिए एक छोटा हिस्सा आकार बेहतर है। वास्तव में बहुत विरल लोगों के लिए, 1 का "चंक साइज़" सबसे अच्छा है, "चंक्स" को खुद को अप्रचलित करना और डेटा संरचना को पिक्सेल के एक आंतरिक मानचित्र के एक आंतरिक मानचित्र पर कम करना है।

शेल्फ से

एक और समाधान कुछ ग्राफिक्स पुस्तकालयों को देखने के लिए हो सकता है। वे वास्तव में एक 2 डी बफर को दूसरे में खींचने में काफी अच्छे हैं। इसका मतलब है कि आप बस एक बड़ा बफर आवंटित करेंगे और मूल को निर्देशांक के अनुसार इसमें शामिल करेंगे।

एक सामान्य रणनीति के रूप में: जब "गतिशील रूप से बढ़ते मेमोरी ब्लॉक" होते हैं, तो इसका उपयोग करने के बाद, इसमें से कई को आवंटित करना एक अच्छा विचार है। यह बल्कि स्मृति गहन है, लेकिन आवंटन और नकल की लागत में काफी कटौती करता है । अधिकांश वेक्टर कार्यान्वयन दो बार उनके आकार को आवंटित करते हैं, जब यह अधिक हो जाता है। इसलिए विशेष रूप से अगर आप ऑफ-द-शेल्फ समाधान के साथ जाते हैं, तो आप केवल 1 पिक्सेल से बफर का विस्तार न करें, क्योंकि केवल एक पिक्सेल का अनुरोध किया गया था। आवंटित स्मृति सस्ती है। Reallocating, नकल और जारी करना महंगा है।


1

सलाह के सिर्फ कुछ बिंदु:

  • यदि आप इसे कुछ अभिन्न प्रकार के सरणी के रूप में कार्यान्वित करते हैं (या सारणी का एक सरणी ...) तो आपको शायद बिट्स को स्थानांतरित करने से बचने के लिए प्रत्येक बार बिट्स / पिक्सेल की कुछ संख्या से बैकिंग सरणी बढ़नी चाहिए। डाउन-साइड यह है कि आप अधिक स्थान का उपयोग करते हैं, लेकिन बिटमैप के रूप में व्यर्थ अंतरिक्ष के अनुपात में गिरावट आती है।

  • यदि आप एक मैप-आधारित डेटा संरचना का उपयोग करते हैं, तो आप केवल x, y getPixelऔर setPixelकॉल के तर्कों को समन्वयित करके बिटमैप के बढ़ने की समस्या पर ध्यान केंद्रित कर सकते हैं।

  • यदि आप मानचित्र-आधारित डेटा संरचना का उपयोग करते हैं, तो आपको केवल "लोगों" के लिए मानचित्र प्रविष्टियों की आवश्यकता होती है। "शून्य" एक प्रविष्टि की अनुपस्थिति से संकेत दिया जा सकता है। यह अंतरिक्ष की एक महत्वपूर्ण राशि को बचाता है, खासकर अगर बिटमैप ज्यादातर शून्य है।

  • आपको मानचित्रों के मानचित्र का उपयोग करने की आवश्यकता नहीं है। आप intएक एकल के रूप में एक x, y युग्म को एनकोड कर सकते हैं long। एक अनुरूप प्रक्रिया का उपयोग सरणी के सरणी को सरणी में मैप करने के लिए किया जा सकता है।


अंत में, आपको 3 चीजों को संतुलित करने की आवश्यकता है:

  1. के प्रदर्शन getPixelऔर setPixel,
  2. extend*संचालन का प्रदर्शन , और
  3. अंतरिक्ष उपयोग।

1

किसी और चीज को और अधिक जटिल बनाने की कोशिश करने से पहले, और जब तक आप सब कुछ स्मृति में नहीं रख सकते, चीजों को सरल रखें और अपने समन्वय प्रणाली की उत्पत्ति के बारे में जानकारी के साथ एक दो आयामी सरणी का उपयोग करें। इसका विस्तार करने के लिए, समान रणनीति का उपयोग करें, उदाहरण के लिए, C ++ std :: वेक्टर करता है: अपने सरणी के वास्तविक आकार और सरणी की क्षमता के बीच अंतर करें, और जब भी सीमा पूरी हो जाए, तो विखंडू में क्षमता का विस्तार करें। यहां "क्षमता" को अंतराल (from_x, to_x), (from_y, to_y) के संदर्भ में परिभाषित किया जाना चाहिए।

इसके लिए समय-समय पर मेमोरी को पूर्ण रूप से पुन: उपयोग करने की आवश्यकता हो सकती है, लेकिन जब तक ऐसा अक्सर नहीं होता है, तब तक यह आपके उद्देश्य के लिए पर्याप्त तेज़ हो सकता है (वास्तव में, आपको यह प्रयास करना होगा / प्रोफ़ाइल करना होगा)।


1

पिक्सेल एक्सेस करने का सबसे तेज़ तरीका व्यक्तिगत-पता योग्य पिक्सेल का दो-आयामी सरणी है।

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

यदि प्रोफाइलिंग से पुन: आवंटन की संख्या को कम रखने की आवश्यकता का पता चलता है और आप स्मृति-विवश नहीं हैं, तो प्रत्येक दिशा में एक प्रतिशत से अधिक आवंटन पर विचार करें और एक ऑफसेट को मूल में संग्रहीत करें। (जैसे, यदि आप 1x1 पर एक नया बिटमैप शुरू करते हैं और इसे धारण करने के लिए एक 9x9 सरणी आवंटित करते हैं, तो प्रारंभिक xऔर yऑफ़सेट्स होंगे 4।) ऑफसेट को लागू करने के लिए पिक्सेल से एक्सेस के दौरान यहां व्यापार-बंद को अतिरिक्त गणित करना पड़ता है।

यदि एक्सटेंशन वास्तव में महंगे हैं, तो आप इनमें से एक या दोनों को आजमा सकते हैं:

  • ऊर्ध्वाधर और क्षैतिज एक्सटेंशन को अलग-अलग तरीके से हैंडल करें। किसी भी दिशा में लंबवत रूप से एक सरणी का विस्तार एक नया ब्लॉक आवंटित करके और पूरे मौजूदा सरणी की एक ही प्रतिलिपि को नई मेमोरी में उपयुक्त ऑफसेट करने के लिए पूरा किया जा सकता है। इसकी तुलना क्षैतिज विस्तार से करें, जहां आपको प्रति पंक्ति एक बार उस ऑपरेशन को करना होगा क्योंकि मौजूदा डेटा नए ब्लॉक में सन्निहित नहीं है।

  • सबसे लगातार राशि और विस्तार की दिशा का ध्यान रखें। एक नए आकार और ऑफसेट का चयन करने के लिए उस जानकारी का उपयोग करें जो किसी भी एक्सटेंशन के लिए फिर से आवंटित और कॉपी करने की संभावना को कम कर देगा।

व्यक्तिगत रूप से, मुझे संदेह है कि जब तक पिक्सेल-एक्सेस-टू-एक्सटेंशन अनुपात कम नहीं हो जाता है, तब तक आपको उन दोनों की आवश्यकता होगी।


1
  • लगातार आकार टाइलिंग (कहते हैं, 256x256, लेकिन अनंत संख्या में टाइलों के साथ)
  • एक बिटमैप आवरण प्रदान करें जो नकारात्मक पिक्सेल निर्देशांक देता है (यह धारणा देने के लिए कि मौजूदा समन्वय मूल्यों के संदर्भों को फिर से शुरू / सिंक्रनाइज़ करने के बिना किसी छवि को चारों दिशाओं में विस्तारित किया जा सकता है)
    • वास्तविक बिटमैप वर्ग (आवरण के नीचे काम करना), हालांकि, केवल पूर्ण (गैर-नकारात्मक) निर्देशांक का समर्थन करना चाहिए।
  • आवरण के नीचे, मैमोरी-मैप्ड I / O का उपयोग करके टाइल-लेवल (ब्लॉक-लेवल) एक्सेस प्रदान करें
  • इसके अलावा Map.setPixel()और Map.getPixel()जो एक समय में एकल पिक्सेल को संशोधित करता है, वे विधियाँ भी प्रदान करता है जो एक बार में पिक्सेल के एक आयत को कॉपी और संशोधित करता है । इससे कॉल करने वाले को उपलब्ध सूचना के आधार पर कॉल करने वाले को अधिक कुशल रूप चुनने की सुविधा मिलेगी।
    • व्यावसायिक लाइब्रेरीज़ अपडेट करने के तरीके भी प्रदान करती हैं: पिक्सल की एक पंक्ति, पिक्सेल का एक कॉलम, स्कैटर / इकट्ठा अपडेट, और एक चरण में (अंक डेटा को कम करने के लिए) अंकगणितीय / तर्क ब्लिटर संचालन।

(आइए उल्लसित उत्तर पर ध्यान न दें ...)


0

सबसे लचीला और शायद विश्वसनीय कार्यान्वयन x- समन्वय, y- समन्वय और बिट मूल्य देने वाली संरचनाओं के साथ एक लिंक की गई सूची है। मैं इसे पहले बनाऊंगा और इसे काम करूंगा।

फिर, यदि यह बहुत धीमा और / या बड़ा है, तो इसे तेज करने के सामान्य तरीकों को आज़माएं: सरणी, मैट्रिक्स, बिटमैप, संपीड़न, कैशिंग, उलटा, केवल '1' मानों को संग्रहीत करना, आदि।

बग्गी के तेजी से क्रियान्वयन को ठीक करने की तुलना में धीमी गति से सही कार्यान्वयन करना आसान है। और अपने 'तेज़' दूसरे कार्यान्वयन का परीक्षण करते समय आपको इसके खिलाफ तुलना करने के लिए एक रेफ़रेंस मानक मिला है।

और, कौन जानता है, आपको पता चल जाएगा कि धीमी संस्करण पर्याप्त तेजी से है। जब तक पूरी संरचना स्मृति में फिट होती है, तब तक चीजें आश्चर्यजनक रूप से पहले से ही तेज होती हैं।


3
-1: "इसे तेजी से बनाने से पहले काम करें" सबसे खराब संभव कार्यान्वयन के साथ शुरू करने का एक अच्छा कारण नहीं है। इसके अलावा, व्यावहारिक रूप से कोई भी कोड नहीं होगा जिसे अंतर्निहित डेटा संरचना के साथ पूरी तरह से बदलने की आवश्यकता नहीं होगी, इसलिए उस स्तर पर पुनरावृत्ति यहाँ पूरी तरह से असाइन सुझाव है।
माइकल Borgwardt

इसलिए आपके पास एक एपीआई है। एपीआई अंतर्निहित कार्यान्वयन को छुपाता है। SetValue (MyMatrix, X, Y, Value) और GetValue (MyMatrix, X, Y) छुपाता है कि क्या MyMatrix 1 या 2 डिमैन्सिअल ऐरे, या लिंक्ड लिस्ट, या डिस्क पर कैश्ड है, या SQL टेबल, या जो भी है। कॉलर को फिर से शुरू करने की आवश्यकता हो सकती है, लेकिन कोड बदलने के लिए नहीं।
एंडी कैनफील्ड

0

मैं पायथन में निम्नलिखित कार्यान्वयन का प्रस्ताव करता हूं:

class Map(dict): pass

इसके निम्नलिखित फायदे हैं:

  1. प्राप्त / सेट एक्सेस के माध्यम map[(1,2)]से विचार किया जा सकता है O(1)
  2. ग्रिड गायब होने का स्पष्ट रूप से विस्तार करने की आवश्यकता है।
  3. कीड़े के लिए बहुत कम जगह है।
  4. यदि आवश्यक हो, तो इसे आसानी से 3 डी में अपग्रेड किया जाता है।

0

यदि आपको वास्तव में किसी भी मनमाने आकार के बिटमैप की आवश्यकता है - और मुझे 1x1 से 1000000x1000000 तक के कुछ भी मतलब है, और यह मांग पर विस्तार योग्य है ... एक संभव तरीका एक डेटाबेस का उपयोग करना है। यह पहली बार में सहज ज्ञान युक्त लग सकता है, लेकिन आपके पास वास्तव में एक भंडारण समस्या है। एक डेटाबेस आपको अलग-अलग पिक्सेल तक पहुँचने और निबंधित रूप से किसी भी डेटा को संग्रहीत करने देगा। मैं जरूरी एक SQL db, btw मतलब नहीं है।

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

कहा जा रहा है, मैं मदद नहीं कर सकता, लेकिन आश्चर्य है कि अगर आप कुछ गलत कर रहे हैं। क्या आपको शायद वेक्टर आधारित ग्राफिक का उपयोग करके और स्मृति में व्यक्तिगत प्रवेश पर नज़र रखने के बजाय, और फिर स्क्रीन के लिए केवल आवश्यकतानुसार एक बिटमैप प्रदान करना चाहिए?


शायद एक OSGeo मानचित्र सर्वर।
रवांग

0

यहाँ यह ठीक से काम करने के लिए कदम है:

  1. वस्तुओं के एक पेड़ का निर्माण करने के लिए एक इंटरफ़ेस से दूसरे में अग्रेषण का उपयोग करें जो एक साथ बिटमैप का प्रतिनिधित्व करते हैं
  2. बिटमैप का हर "एक्सटेंशन" यह स्वयं की मेमोरी आवंटित करेगा और इसके लिए एक और इंटरफ़ेस प्रदान करेगा
  3. उदाहरण कार्यान्वयन होगा:

    template<class T, class P>
    class ExtendBottom {
    public:
       ExtendBottom(T &t, int count) : t(t), count(count),k(t.XSize(), count) { }
       P &At(int x, int y) const { if (y<t.YSize()) return t.At(x,y); else return k.At(x, y-t.YSize()); }
       int XSize() const { return t.XSize(); }
       int YSize() const { return t.YSize()+count; }
    private:
       T &t;
       int count;
       MemoryBitmap k;
    };
    

स्पष्ट रूप से वास्तविक कार्यान्वयन के लिए, XSize () और YSize () काम नहीं करेगा, लेकिन आपको सूचकांक संख्या को बनाए रखने के लिए MinX (), MaxX (), MinY (), MaxY () या ऐसा कुछ चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.