एक अच्छा बनावट पैकिंग एल्गोरिथ्म क्या है? तकनीकी तौर पर, बिन पैकिंग है एनपी कठिन तो एक अनुमानी क्या मैं वास्तव में के बाद कर रहा हूँ है।
एक अच्छा बनावट पैकिंग एल्गोरिथ्म क्या है? तकनीकी तौर पर, बिन पैकिंग है एनपी कठिन तो एक अनुमानी क्या मैं वास्तव में के बाद कर रहा हूँ है।
जवाबों:
मैंने कुछ महीने एक बेहतर बनावट पैकिंग एल्गोरिदम के साथ आने में बिताए।
हमने जो एल्गोरिथ्म शुरू किया वह सरल था। सभी इनपुट आइटम लीजिए। छोटे, बड़े-से-छोटे उपभोग किए गए कुल पिक्सेल द्वारा उन्हें क्रमबद्ध करें। स्कैनलाइन ऑर्डर में उन्हें अपनी बनावट में रखें, बस टॉपलेट पिक्सेल से टॉप पिक्सेल तक सामान का परीक्षण करना, एक रेखा नीचे जाना, और दोहराना, हर सफल प्लेसमेंट के बाद टॉपलेफ्ट पिक्सेल पर रीसेट करना।
आपको या तो एक चौड़ाई को हार्डकोड करना होगा या इसके लिए किसी अन्य अनुमान के साथ आना होगा। स्क्वैरिटी को संरक्षित करने के प्रयास में, हमारा एल्गोरिथ्म 128 पर शुरू होता है, फिर 128 के दशक तक बढ़ जाता है जब तक कि यह एक परिणाम के साथ नहीं आया, जो किसी भी गहन से व्यापक नहीं था।
इसलिए, हमारे पास वह एल्गोरिथम था, और मैंने इसे सुधारने का निर्णय लिया। मैंने निराला उत्तराधिकारियों के एक समूह की कोशिश की - उन वस्तुओं को खोजने की कोशिश की जो एक साथ फिट होती हैं, वांछित अंतरिक्ष पैकिंग गुणों के एक गुच्छा पर कुछ भारित करना, घूमना और फ्लिप करना। मेरे सभी काम के बाद, सचमुच तीन महीने के काम के बाद, मैंने 3% स्थान की बचत की।
हाँ। 3%।
और जब हमने इस पर अपनी संपीड़न दिनचर्या चलाई, तो यह वास्तव में बड़ा हो गया (जिसे मैं अभी भी समझा नहीं सकता) इसलिए हमने पूरी चीज को बाहर फेंक दिया और पुराने एल्गोरिथ्म में वापस चला गया।
आइटम क्रमबद्ध करें, स्कैनलाइन ऑर्डर में बनावट में जाम करें। आपका एल्गोरिथम है। यह कोड के लिए आसान है, तेजी से चलाने के लिए, और आप काम की एक अद्भुत राशि के बिना बहुत बेहतर नहीं मिलेगा। यह काम तब तक सार्थक नहीं है जब तक आपकी कंपनी कम से कम 50 लोगों की बड़ी, और शायद अधिक नहीं हो।
और एक साइड नोट के रूप में, मैंने अभी-अभी इस एल्गोरिथ्म (निश्चित चौड़ाई 512 पिक्सल्स) को लागू किया है, जो कि वास्तव में ठीक उसी अनुप्रयोग के लिए है जो आप कर रहे हैं (कोई फुट नहीं है, लेकिन opengl-freetype ग्लिफ़्स।) यहां इसका परिणाम है। यह धुंधला दिखता है क्योंकि खान वाल्व की दूरी-क्षेत्र आधारित पाठ रेंडरिंग एल्गोरिथ्म का उपयोग कर रहा है , जो ग्लिफ़ के बीच अतिरिक्त स्थान के लिए भी खाता है। जाहिर है, बहुत सारी खाली जगह नहीं बची है, और यह खुले स्थानों में चीजों को समेटने का अच्छा काम करती है।
इसके लिए सभी कोड BSD- लाइसेंस प्राप्त है और github पर उपलब्ध है ।
एंड्रिया लोदी की पीएचडी थीसिस दो आयामी बिन पैकिंग और असाइनमेंट समस्याओं के लिए एल्गोरिदम का हकदार है ।
थीसिस इस समस्या के कुछ कठिन रूपों से अधिक है। सौभाग्य से, बनावट पैकिंग सबसे आसान संस्करण है। उन्हें मिला सबसे अच्छा एल्गोरिथ्म टचिंग परिधि कहा जाता था ।
पृष्ठ 52 से उद्धृत करने के लिए:
टचिंग परिधि (टीपीआरएफ) नामक एल्गोरिथ्म, गैर-बढ़ते क्षेत्र के अनुसार वस्तुओं को सॉर्ट करना शुरू करता है (गैर-बढ़ते मिनट {डब्ल्यूजे, एचजे} मूल्यों द्वारा संबंधों को तोड़ता है), और क्षैतिज रूप से उन्मुख करके। इष्टतम समाधान मान पर एक कम बाध्य एल तब गणना की जाती है, और एल खाली डिब्बे को आरंभीकृत किया जाता है। (पिछले खंड में निरंतर कम बाउंड L0 de continuous नेड 2BP के लिए स्पष्ट रूप से मान्य है। R | F साथ ही, बेहतर सीमाएं Dell'Amico, Martello और Vigo [56] द्वारा प्रस्तावित हैं।) एल्गोरिथ्म एक समय में एक आइटम पैक करता है, या तो। एक मौजूदा बिन में, या एक नई शुरुआत करके। बिन में पैक किए गए placed rst आइटम को हमेशा नीचे-बाएँ कोने में रखा जाता है। प्रत्येक बाद की वस्तु को तथाकथित सामान्य स्थिति में पैक किया जाता है (क्रिस्टो Whit डेस और व्हिटलॉक [41] देखें), अर्थात
बिन और पैकिंग की स्थिति का चुनाव एक स्कोर का मूल्यांकन करके किया जाता है, आइटम परिधि के प्रतिशत के रूप में डी the ned जो बिन और पहले से पैक किए गए अन्य आइटम को छूता है। यह रणनीति उन पैमानों का पक्षधर है जहाँ पैक्ड आइटम छोटे क्षेत्रों को "फँसा" नहीं करते हैं, जो आगे के प्लेसमेंट के लिए उपयोग करना कठिन हो सकता है। प्रत्येक उम्मीदवार की पैकिंग स्थिति के लिए, दो आइटम अभिविन्यास (यदि दोनों संभव हैं) के लिए, स्कोर का दो बार मूल्यांकन किया जाता है, और उच्चतम मूल्य का चयन किया जाता है। अधिकतम पैक क्षेत्र वाले बिन को चुनने से स्कोर संबंध टूट जाते हैं। समग्र एल्गोरिथ्म इस प्रकार है।touching_perimeter: sort the items by nonincreaseing w,h values, and horizontally orient them; comment: Phase 1; compute a lower bound L on the optimal solution value, and open L empty bins; comment: Phase 2; for j := 1 to n do score := 0; for each normal packing position in an open bin do let score1 and score2 be scores with tow orientations; score := max{score,score1,score2}; end for; if score > 0 then pack item j in the bin, position and orientation corresponding to score; else open a new bin and horizontally pack item j into i; end if; end for; end;
ब्याज की भी, कागज एक एल्गोरिथ्म का वर्णन करता है कि एक बेहतर ढंग से पैक बनावट नक्शे के आकार का निर्धारण किया जाता है। यह निर्धारित करना उपयोगी होगा कि क्या 1024x1024 एटलस में सभी बनावट को फिट करना संभव है।
अगर किसी को अभी भी दिलचस्पी है, तो मैंने rectpack2D लाइब्रेरी को पूरी तरह से फिर से लिखा है ताकि यह अधिक कुशल हो।
यह std::vector
कुछ प्रारंभिक अधिकतम आकार (आमतौर पर, एक विशेष GPU पर अधिकतम अनुमत बनावट आकार) के साथ शुरुआत में, पहले व्यवहार्य खाली स्थान को विभाजित करने और वेक्टर को वापस विभाजन को बचाने के साथ, एटलस में खाली स्थानों को रखकर काम करता है ।
प्रदर्शन की सफलता केवल एक वेक्टर का उपयोग करने के साथ आई थी, एक पूरे पेड़ को रखने के बजाय, जैसे कि यह पहले किया गया था।
README में प्रक्रिया का विस्तार से वर्णन किया गया है ।
पुस्तकालय एमआईटी के अधीन है, इसलिए यदि आप इसे उपयोगी पाते हैं तो मैं आपके लिए खुश हूं!
एक Intel (R) Core (TM) i7-4770K CPU @ 3.50GHz पर टेस्ट आयोजित किए गए। -03 स्विच का उपयोग करके बाइनरी को क्लैंग 6.0.0 के साथ बनाया गया था।
रनटाइम: 4 मिलीसेकंड
व्यर्थ पिक्सेल: 15538 (0.31% - 125 x 125 वर्ग के बराबर)
आउटपुट (2116 x 2382):
रंग में:
(अंतरिक्ष व्यर्थ काला है)
रनटाइम: 3.5 - 7 एमएस
व्यर्थ पिक्सेल: 9288 (1.23% - एक 96 x 96 वर्ग के बराबर)
आउटपुट (866 x 871):
रंग में:
(अंतरिक्ष व्यर्थ काला है)
एक अच्छा अनुमानी एल्गोरिथ्म यहां पाया जा सकता है । जब मैं हाल ही में कुछ इसी तरह की कोशिश कर रहा था, तो मैंने इसे सबसे अधिक कार्यान्वयन के लिए मूल शुरुआती बिंदु के रूप में संदर्भित किया।
विशेष रूप से अच्छी तरह से नियमित रूप से आकार के समान, समान आकार की वस्तुओं के साथ या छोटे और कम बड़े चित्रों के अच्छे मिश्रण के साथ अच्छी तरह से काम करता है। अच्छे परिणाम प्राप्त करने के लिए सबसे अच्छी सलाह यह है कि आप अपने इनपुट को इमेज साइज के अनुसार क्रमबद्ध करें, फिर सबसे बड़ी से छोटी तक की पैकिंग करें क्योंकि छोटी छवियां बड़ी छवियों के चारों ओर अंतरिक्ष में पैक होंगी। आप यह कैसे करते हैं और आप अपने लक्ष्यों पर निर्भर हो सकते हैं। मैंने 1 ऑर्डर सन्निकटन के रूप में क्षेत्र के बजाय परिधि का उपयोग किया क्योंकि मैंने यह विचार किया कि लम्बे + पतले / छोटे + चौड़े चित्र (जिसमें नीच क्षेत्र होगा) वास्तव में बाद में एक पैक में रखने के लिए बहुत कठिन हैं, इसलिए परिधि का उपयोग करके आप धक्का देते हैं आदेश के सामने की ओर ये विषम आकार।
यहाँ मेरी वेबसाइट छवि डंप निर्देशिका से छवियों के एक यादृच्छिक सेट पर मेरे पैकर के लिए आउटपुट का एक नमूना विज़ुअलाइज़ेशन है :)।
वर्गों में संख्या आईडी के पेड़ में ब्लॉक की है तो आप आवेषण के आदेश का एक विचार दे। पहली आईडी "3" है क्योंकि यह पहली पत्ती का नोड है (केवल पत्तियों में चित्र हैं) और परिणामस्वरूप 2 माता-पिता हैं)।
Root[0]
/ \
Child[1] Child[2]
|
Leaf[3]
मैंने जो कुछ भी उपयोग किया है, जो अनियमित यूवी मानचित्रों के लिए भी अच्छी तरह से काम करता है, यूवी पैच को बिटमैप मास्क में बदलना है, और बनावट के लिए एक मुखौटा बनाए रखना है, पहली स्थिति के लिए यूवी पैच फिट होगा। मैं कुछ सरल हेयुरिस्टिक (ऊंचाई, चौड़ाई, आकार, जो भी हो) के अनुसार ब्लॉकों का आदेश देता हूं, और मैं चुने हुए हेयुरिस्टिक को कम करने या अधिकतम करने के लिए ब्लॉकों के रोटेशन की अनुमति देता हूं। यह जानवर बल के लिए एक प्रबंधनीय खोज-स्थान देता है।
यदि आप तब कई पुनरावृत्तियों की कोशिश कर रहे हैं, और कुछ समय सीमा समाप्त होने तक आदेश देने और पुनरावृति चुनने में एक यादृच्छिक कारक लागू कर सकते हैं।
इस योजना के साथ आप छोटे यूवी द्वीपों को बड़े लोगों द्वारा बनाए गए गैप में पैक कर पाएंगे, और यहां तक कि सिंगल यूवी पैच के भीतर छोड़ दिए गए छेदों में भी।
हमने हाल ही में एक पाइथन स्क्रिप्ट जारी की है जो एक दिए गए आकार की कई छवि फ़ाइलों में बनावट पैक करेगी।
हमारे ब्लॉग से उद्धृत:
"जबकि ऐसे कई पैकर्स हैं जिन्हें ऑनलाइन पाया जा सकता है, हमारी कठिनाई किसी भी ऐसी खोज को खोजने में थी जो बड़ी संख्या में छवियों को कई निर्देशिकाओं में संभाल सके। इस प्रकार, हमारे अपने एटलस पैकर का जन्म हुआ!
जैसा कि, हमारी छोटी स्क्रिप्ट बेस डायरेक्टरी में शुरू होगी और सभी .PNG को एक एटलस में लोड करेगी। यदि वह एटलस भरा है, तो यह एक नया बनाता है। फिर, यह नए में एक स्थान खोजने से पहले सभी पिछले atlases में बाकी छवियों को फिट करने की कोशिश करेगा। इस तरह, प्रत्येक एटलस को यथासंभव कसकर पैक किया जाता है। एटलस को उस फ़ोल्डर के आधार पर नामित किया जाता है जो उनकी छवियां हैं।
आप एटलस का आकार (लाइन 65), उन छवियों के प्रारूप को बदल सकते हैं जिन्हें आप पैक करना चाहते हैं (लाइन 67), लोड निर्देशिका (लाइन 10) और सहेजें निर्देशिका (लाइन 13) पायथन में बिना किसी अनुभव के आसानी से। एक छोटे से अस्वीकरण के रूप में, यह कुछ दिनों में हमारे इंजन के साथ विशेष रूप से काम करने के लिए एक साथ मार दिया गया था। मैं आपको सुविधाओं का अनुरोध करने, अपनी खुद की विविधताओं के साथ टिप्पणी करने और किसी भी त्रुटि की रिपोर्ट करने के लिए प्रोत्साहित करता हूं, लेकिन स्क्रिप्ट में कोई भी बदलाव मेरे खाली समय में होगा। "
पूर्ण स्रोत कोड की जांच करने के लिए स्वतंत्र महसूस करें: http://www.retroaffect.com/blog/159/Image_Atlas_Packer/#b
फोंट को पैक करना बहुत आसान है क्योंकि ग्लिफ़ बनावट के सभी (या महान बहुमत) लगभग एक ही आकार के हैं। सबसे सरल काम जो आपके साथ होता है और यह इष्टतम के बहुत करीब होगा।
जब आप बहुत भिन्न आकारों की छवियों को पैक कर रहे होते हैं, तो चतुराई और अधिक महत्वपूर्ण हो जाती है। फिर आप अंतराल आदि में पैक करने में सक्षम होना चाहते हैं, फिर भी, हालांकि, पहले से चर्चा की गई स्कैनलाइन ऑर्डर खोज जैसा एक सरल एल्गोरिथ्म बहुत ही उचित परिणाम देगा।
उन्नत अल्गों में से कोई भी जादू नहीं है। वे एक simpel अहंकार की तुलना में 50% अधिक आकर्षक नहीं होंगे, और जब तक आपके पास बनावट की चादरें नहीं होंगी, तब तक आपको उनसे लगातार लाभ नहीं मिलेगा। ऐसा इसलिए है क्योंकि बेहतर एल्गोरिदम बनाने वाले छोटे सुधार केवल समुच्चय में दिखाई देंगे।
सरल जाओ, और कुछ करने के लिए आगे बढ़ें जहां आपके प्रयासों को बेहतर पुरस्कृत किया जाएगा
यदि यह विशेष रूप से फ़ॉन्ट बनावट के लिए है, तो आप शायद कुछ गैर-इष्टतम लेकिन अच्छा और सरल करते हैं:
ऊंचाई से वर्णों को क्रमबद्ध करें, सबसे पहले
0,0 पर शुरू करें वर्तमान कोर्डर्स पर पहला कैरेक्टर, एक्स को एडवांस करें, एक को अगले स्थान पर रखें, जब तक हम दूसरे को फिट नहीं कर सकते
X को 0 पर रीसेट करें, पंक्ति में सबसे ऊंचे वर्ण की ऊँचाई से Y को नीचे की ओर बढ़ाएं और दूसरी पंक्ति भरें
जब तक हम वर्णों से बाहर न हों, तब तक दोहराएं या किसी अन्य पंक्ति को फिट नहीं कर सकते।