อัลกอริทึมการบรรจุพื้นผิวที่ดีคืออะไร ในทางเทคนิคถังขยะนั้นบรรจุยากมากดังนั้นการเรียนรู้ด้วยตนเองจึงเป็นสิ่งที่ฉันต้องการจริงๆ
อัลกอริทึมการบรรจุพื้นผิวที่ดีคืออะไร ในทางเทคนิคถังขยะนั้นบรรจุยากมากดังนั้นการเรียนรู้ด้วยตนเองจึงเป็นสิ่งที่ฉันต้องการจริงๆ
คำตอบ:
ฉันใช้เวลาสองสามเดือนในการหางานด้วยอัลกอริธึมการบรรจุพื้นผิวที่ดีกว่า
อัลกอริทึมที่เราเริ่มต้นนั้นเรียบง่าย รวบรวมรายการอินพุตทั้งหมด จัดเรียงพวกเขาด้วยพิกเซลทั้งหมดที่บริโภคไปใหญ่ถึงเล็ก จัดวางสิ่งเหล่านี้ในพื้นผิวของคุณตามลำดับสแกนไลน์เพียงทดสอบสิ่งต่าง ๆ จากพิกเซลด้านบนสู่พิกเซลด้านบนย้ายลงบรรทัดแล้วทำซ้ำรีเซ็ตเป็นพิกเซลด้านบนหลังจากตำแหน่งที่ประสบความสำเร็จทุกตำแหน่ง
คุณต้องฮาร์ดโค้ดความกว้างหรือหาฮิวริสติกอื่นสำหรับสิ่งนี้ ในความพยายามที่จะรักษาความเป็นฉากกันอัลกอริทึมของเราจะเริ่มต้นที่ 128 จากนั้นเพิ่มขึ้นเป็น 128 วินาทีจนกว่าจะเกิดผลลัพธ์ที่ไม่ลึกกว่ากว้าง
ดังนั้นเรามีอัลกอริทึมนั้นและฉันตัดสินใจที่จะปรับปรุง ฉันลองใช้ฮิวริสติกที่แปลกประหลาด - พยายามหาวัตถุที่เข้าด้วยกันแล้วทำการลดน้ำหนักให้มากขึ้นเพื่อให้มีคุณสมบัติการบรรจุพื้นที่ที่ต้องการหมุนและพลิก หลังจากงานของฉันทั้งหมดสามเดือนฉันก็เลยประหยัดพื้นที่ได้ 3%
ใช่. 3%
และหลังจากที่เรารันรูทีนการบีบอัดมากกว่านั้นจริง ๆ แล้วมันก็ใหญ่ขึ้น(ซึ่งฉันยังอธิบายไม่ได้ไม่ได้) ดังนั้นเราจึงโยนทุกสิ่งออกไปและกลับไปที่อัลกอริธึมเก่า
เรียงลำดับรายการติดขัดในพื้นผิวตามลำดับการสแกน มีอัลกอริทึมของคุณ มันง่ายในการเขียนโค้ดเรียกใช้งานได้อย่างรวดเร็วและคุณจะไม่ดีขึ้นมากนักหากไม่มีงานที่น่าทึ่ง งานนี้ไม่คุ้มค่าเว้นแต่ บริษัท ของคุณจะมีอย่างน้อย 50 คนและอาจมากกว่านั้น
และตามบันทึกด้านข้างฉันเพิ่งใช้อัลกอริธึมนี้ (ความกว้างคงที่ 512 พิกเซล) สำหรับแอปพลิเคชันเดียวกันที่คุณกำลังทำอยู่ (ไม่ใช่ ftgles แต่เป็น glyphs แบบ opengl ที่แสดงผล) นี่คือผลลัพธ์ ดูเหมือนว่าจะพร่ามัวเพราะฉันใช้อัลกอริธึมการแสดงผลข้อความทางไกลของ Valve ซึ่งจะอธิบายถึงช่องว่างพิเศษระหว่างร่ายมนตร์ เห็นได้ชัดว่ามีพื้นที่ว่างเหลืออยู่ไม่มากนักและมันก็เป็นงานที่ดีในการยัดเยียดสิ่งต่าง ๆ สู่ที่โล่ง
ทั้งหมดรหัสสำหรับเรื่องนี้คือ BSD ได้รับใบอนุญาตและสามารถใช้ได้ที่ GitHub
วิทยานิพนธ์ปริญญาเอกของอันเดรียโลดิมีสิทธิที่อัลกอริทึมสำหรับสองมิติถังบรรจุและการกำหนดปัญหา
วิทยานิพนธ์จะผ่านรูปแบบที่ยากขึ้นของปัญหานี้ โชคดีที่การบรรจุพื้นผิวเป็นรุ่นที่ง่ายที่สุด ขั้นตอนวิธีการที่ดีที่สุดเขาก็พบว่าถูกเรียกปริมณฑลสัมผัส
อ้างจากหน้า 52:
อัลกอริทึมที่เรียกว่า Touching Perimeter (TPRF) เริ่มต้นด้วยการเรียงลำดับรายการตามพื้นที่ที่ไม่เพิ่มขึ้น (การทำลายความสัมพันธ์โดยการไม่เพิ่มค่า min {wj, hj}) และการวางแนวในแนวนอน L ขอบเขตล่างบนค่าโซลูชันที่เหมาะสมจะถูกคำนวณและถังขยะว่าง L จะเริ่มต้นได้ (ขอบเขตล่างอย่างต่อเนื่อง L0 กำหนดไว้ในส่วนก่อนหน้านี้ถูกต้องสำหรับ 2BP | R | F เช่นกันขอบเขตที่ดีกว่าถูกเสนอโดย Dell'Amico, Martello และ Vigo [56]) อัลกอริธึมบรรจุหนึ่งรายการในแต่ละครั้ง ในถังขยะที่มีอยู่หรือโดยการเริ่มต้นใหม่ รายการแรกที่บรรจุในถังขยะจะอยู่ที่มุมซ้ายล่างเสมอ แต่ละรายการที่ตามมาบรรจุในตำแหน่งปกติที่เรียกว่า (ดู Christo fi des และ Whitlock [41]) คือ
ทางเลือกของถังขยะและตำแหน่งบรรจุทำได้โดยการประเมินคะแนนซึ่งคิดเป็นเปอร์เซ็นต์ของขอบเขตรายการที่สัมผัสกับถังขยะและรายการอื่น ๆ ที่บรรจุไว้แล้ว กลยุทธ์นี้สนับสนุนรูปแบบที่รายการที่บรรจุไม่ได้“ ดักจับ” พื้นที่ขนาดเล็กซึ่งอาจใช้งานได้ยากสำหรับตำแหน่งเพิ่มเติม สำหรับตำแหน่งการบรรจุแต่ละตำแหน่งผู้สมัครคะแนนจะถูกประเมินสองครั้งสำหรับการจัดวางรายการสองรายการ (หากทั้งคู่เป็นไปได้) และเลือกค่าสูงสุด ความสัมพันธ์ของคะแนนจะแตกโดยเลือกถังที่มีพื้นที่บรรจุสูงสุด อัลกอริทึมโดยรวมมีดังนี้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
ห้องสมุดอยู่ภายใต้ MIT ดังนั้นฉันดีใจที่คุณถ้าคุณพบว่ามีประโยชน์!
การทดสอบดำเนินการกับ Intel (R) Core (TM) i7-4770K CPU @ 3.50GHz ไบนารีถูกสร้างด้วย clang 6.0.0 โดยใช้สวิตช์ -03
เวลา: 4 มิลลิวินาที
พิกเซลที่สูญเปล่า: 15538 (0.31% - เทียบเท่า 125 x 125 ตารางเมตร)
เอาต์พุต (2116 x 2382):
สี:
(สีดำเสียพื้นที่)
เวลา: 3.5 - 7 ms
พิกเซลเสีย: 9288 (1.23% - เทียบเท่า 96 x 96 ตารางเมตร)
เอาต์พุต (866 x 871):
สี:
(สีดำเสียพื้นที่)
ขั้นตอนวิธีการแก้ปัญหาที่ดีสามารถพบได้ที่นี่ เมื่อฉันพยายามทำสิ่งที่คล้ายกันเมื่อเร็ว ๆ นี้ฉันพบว่าการอ้างอิงนี้เป็นจุดเริ่มต้นพื้นฐานสำหรับการใช้งานส่วนใหญ่ที่ฉันเห็น
ใช้งานได้ดีโดยเฉพาะกับรูปทรงปกติขนาดรายการที่มีขนาดใกล้เคียงกันหรือกับภาพที่มีขนาดเล็กและใหญ่ คำแนะนำที่ดีที่สุดเพื่อให้ได้ผลลัพธ์ที่ดีคืออย่าลืมจัดเรียงอินพุตของคุณในแง่ของขนาดภาพจากนั้นแพ็คจากใหญ่ไปหาน้อยที่สุด วิธีการเรียงลำดับขึ้นอยู่กับคุณและอาจขึ้นอยู่กับเป้าหมายของคุณ ฉันใช้เส้นรอบวงมากกว่าพื้นที่เป็นลำดับที่ 1 โดยประมาณเนื่องจากฉันมองว่าภาพที่มีความสูง + บาง / สั้น + กว้าง (ซึ่งจะมีพื้นที่ที่ค่อนข้างต่ำ) จริง ๆ แล้วยากมากที่จะวางในภายหลังในแพ็คดังนั้นโดยใช้ขอบเขตที่คุณกด รูปร่างแปลก ๆ เหล่านี้ไปทางด้านหน้าของคำสั่ง
นี่คือตัวอย่าง visulization ของเอาท์พุทสำหรับ packer ของฉันในชุดภาพสุ่มจากไดเรกทอรีถ่ายโอนข้อมูลอิมเมจเว็บไซต์ของฉัน :)
ตัวเลขในช่องสี่เหลี่ยมนั้นเป็น id ของบล็อคที่มีอยู่ในทรีดังนั้นให้คุณทราบถึงลำดับของการแทรก แรกคือ ID "3" เพราะมันเป็นโหนดใบแรก(ใบเท่านั้นมีภาพ) และจึงมี 2 ผู้ปกครอง)
Root[0]
/ \
Child[1] Child[2]
|
Leaf[3]
โดยส่วนตัวฉันเพิ่งใช้ระบบแรกที่โลภมากที่สุดเหมาะกับระบบแรก มันไม่ได้ดีที่สุด แต่มันก็หลอกลวงได้
โปรดทราบว่าหากคุณมีบล็อกพื้นผิวในจำนวนที่สมเหตุสมผลคุณสามารถค้นหาการสั่งซื้อที่ดีที่สุดได้อย่างละเอียดแม้ว่าปัญหานั้นจะเป็นปัญหา
สิ่งที่ฉันใช้ซึ่งใช้งานได้ดีแม้ในแผนที่ UV ที่ผิดปกติคือการเปลี่ยนแผ่นแปะ UV ให้เป็นหน้ากากบิตแมปและรักษาหน้ากากสำหรับพื้นผิวของตัวเอง ฉันสั่งบล็อกตามฮิวริสติกแบบเรียบง่าย (ความสูงความกว้างขนาดอะไรก็ตาม) และฉันอนุญาตให้การหมุนของบล็อกลดหรือเพิ่มฮิวริสติกที่เลือกให้มากที่สุด ที่ให้พื้นที่การค้นหาที่จัดการได้สำหรับกำลังดุร้าย
หากคุณสามารถทำซ้ำที่ลองหลายฮิวริสติกและ / หรือใช้ปัจจัยสุ่มในการเลือกการสั่งซื้อและทำซ้ำจนกว่าจะถึงเวลาที่ จำกัด
ด้วยรูปแบบนี้คุณจะได้รับหมู่เกาะยูวีขนาดเล็กที่บรรจุอยู่ในช่องว่างของหมู่เกาะขนาดใหญ่และแม้กระทั่งในหลุมที่เหลืออยู่ภายในแผ่น UV ตัวเดียว
เราเพิ่งเปิดตัวสคริปต์ python ซึ่งจะบรรจุพื้นผิวเป็นไฟล์รูปภาพหลายไฟล์ในขนาดที่กำหนด
อ้างจากบล็อกของเรา:
"ในขณะที่มีผู้แบ่งบรรจุจำนวนมากที่สามารถพบได้ทั่วไปความยากลำบากของเราคือการค้นหาสิ่งใดก็ตามที่สามารถจัดการกับภาพจำนวนมากในหลาย ๆ ไดเรกทอรีดังนั้นผู้จัดทำสมุดแผนที่ของเราถือกำเนิดขึ้น!
เช่นเดียวกับสคริปต์เล็ก ๆ ของเราจะเริ่มต้นในไดเรกทอรีฐานและโหลด. PNG ทั้งหมดลงในแผนที่ หากแผนที่นั้นเต็มไปมันจะสร้างแผนที่ใหม่ จากนั้นจะลองปรับแต่งภาพส่วนที่เหลือในแผนที่ก่อนหน้าทั้งหมดก่อนที่จะหาจุดในภาพใหม่ ด้วยวิธีนี้แต่ละแผนที่มีความหนาแน่นมากที่สุด แผนที่มีชื่อตามโฟลเดอร์ที่เป็นรูปภาพ
คุณสามารถเปลี่ยนขนาดของแอตลาส (บรรทัดที่ 65) รูปแบบของภาพที่คุณต้องการแพ็ค (บรรทัดที่ 67) โหลดไดเรกทอรี (บรรทัดที่ 10) และบันทึกไดเรกทอรี (บรรทัดที่ 13) ได้อย่างง่ายดายโดยไม่ต้องใช้ Python ในฐานะที่เป็นข้อจำกัดความรับผิดชอบเล็ก ๆ น้อย ๆ สิ่งนี้ถูกรวมเข้าด้วยกันในสองสามวันเพื่อทำงานกับเครื่องยนต์ของเรา ฉันขอแนะนำให้คุณขอคุณสมบัติแสดงความคิดเห็นด้วยรูปแบบของคุณเองและรายงานข้อผิดพลาดใด ๆ แต่การเปลี่ยนแปลงใด ๆ ในสคริปต์จะเกิดขึ้นในเวลาว่างของฉัน "
อย่าลังเลที่จะตรวจสอบซอร์สโค้ดแบบเต็มได้ที่นี่: http://www.retroaffect.com/blog/159/Image_Atlas_Packer/#b
มันค่อนข้างง่ายที่จะแพ็คแบบอักษรเพราะทั้งหมด (หรือส่วนใหญ่) ของพื้นผิวสัญลักษณ์มีขนาดใกล้เคียงกัน ทำสิ่งที่ง่ายที่สุดที่เกิดขึ้นกับคุณและมันจะใกล้เคียงกับความเหมาะสมที่สุด
ความฉลาดนั้นสำคัญมากเมื่อคุณบรรจุภาพที่มีขนาดแตกต่างกันมาก จากนั้นคุณต้องการที่จะบรรจุลงในช่องว่าง ฯลฯ แม้กระนั้นอัลกอริธึมง่ายๆเช่นการค้นหาคำสั่งสแกนไลน์ที่กล่าวถึงก่อนหน้านี้จะให้ผลลัพธ์ที่สมเหตุสมผลมาก
ไม่มี algos ขั้นสูงที่เป็นเวทมนตร์ พวกมันจะไม่ได้ประสิทธิภาพมากกว่า 50% ของอัลโกทั่วไปและคุณจะไม่ได้รับผลประโยชน์ที่สม่ำเสมอจากพวกเขาเว้นแต่คุณจะมีแผ่นพื้นผิวจำนวนมาก นั่นเป็นเพราะการปรับปรุงเล็ก ๆ ที่อัลกอริทึมที่ดีกว่าจะเห็นได้ในภาพรวมเท่านั้น
ใช้ง่ายและไปยังสิ่งที่ความพยายามของคุณจะได้รับรางวัลดีกว่า
หากมันใช้กับพื้นผิวแบบอักษรโดยเฉพาะคุณอาจทำสิ่งที่ไม่เหมาะสม แต่ดีและเรียบง่าย:
จัดเรียงอักขระตามความสูงสูงสุดก่อน
เริ่มต้นที่ 0,0 วางอักขระตัวแรกที่ coords ปัจจุบันเลื่อน X วางตัวถัดไปทำซ้ำจนกว่าเราจะไม่พอดี
รีเซ็ต X เป็น 0 เลื่อน Y ลงไปตามความสูงของอักขระที่สูงที่สุดในแถวแล้วเติมอีกแถวหนึ่ง
ทำซ้ำจนกว่าเราจะหมดอักขระหรือไม่สามารถใส่แถวอื่นได้