2D packing algoritmust keresek

Fórumok

Sziasztok!

Adott a következő probléma, amire algoritmust keresek. (Hobbi projekt, nem munkához kell.)

Adott egy téglalap oldalméretekkel meghatározva, ezen a téglalapon kell elhelyezni n darab kisebb téglalapot, a következő szabályok szerint:

  • 2 <= n <= 50
  • Az elhelyezendő téglalapoknak egybevágóaknak kell lenni 
    • Közülük pontosan 1 téglalap a referencia, ennek az oldalarányát tartani kell
    • Az összess többi téglalap (n -1 darab) egyforma méretű kell legyen
    • A referencia téglalapnak ugyanakkorának (n=2 esetén) vagy nagyobbnak (n>2 esetén) kell lennie mint a többinek
  • Az elrendezésnek "mátrix jellegűnek" kell lennie, azaz pl
    • n = 2 esetén egy 1 x 2 es mátrixban lenne két egyforma téglalap
    • n = 3 esetén egy 2 x 3 as mátrixban a referencia téglalap lefoglalná az első két oszlopot teljesen, és a két kis téglalap lenne a 3. oszlop két sorában
    • n = 6 esetén egy 4 x 3 as mátrixban a referencia téglalap a bal felxő 2x2 cellát foglalná le, az 5 kis téglalap pedig a jobb oldali oszlopban, illetve a referencia téglalap alatt lennének
  • A téglalapok között kimaradt területet (értsd. üres cellák számát) kell minimalizálni
  • Eredményként a megoldásmátrix dimenziót kell kiadni, és hogy a referencia téglalap 1x1, 2x2, 3x3 stb cellát foglal e le az eredménymátrixból

Ha jól értelmezem, a probléma a 2D packing egy speciális alesete. Ezeket itt nézegettem, de szerintem minden ottani megoldás túl általános az én esetemre.

Use case: Fotózás, referencia fotóra szeretnék különféle effekteket (jelen esetben LUT-okat) applikálni, és szeretném egy képernyőn/képen nézegetni a variációkat.

Az algoritmust alighanem Rben vagy Pythonban fogom lekódolni, így ha valaki onnan tud libet vagy csomagot ajánlani, akkor extra megköszönöm.

(Nem kész szoftvert, hanem algoritmust keresek.)

Köszi előre is a tippeket,

 

Csaba

Hozzászólások

chatgpt mit mond?

Aki másnak vermet ás, az stack pointer.

Szerkesztve: 2023. 03. 17., p – 14:16

Vagy félreértek valamit, vagy a feladat a jelen, általános formájában nem megoldható.

A leírt lefedéshez szerintem teljesülnie kellene annak a  kényszerfeltételnek a "referencia téglalap" és a lefedendő téglalap oldalarányai között, hogy azok hányadosa kötelezően egész. (Tehát nem kell az oldalaránynak is azonosnak lennie, de páronként a hányados egész kell legyen.)

(Disclaimer: csupán természetes intelligenciával rendelkezem, tehát nem vagyok tévedhetetlen, és még soha nem mertem kipróbálni a bagolyfőzelék receptjét.)

Szerk.: tévedtem. Elég, ha kellően kis számokkal kifejezhető racionális szám a hányadosuk. Szóval kellene valamilyen "granularitási fokot" megállapítani, ami a kérdéses felhasználás esetén nyilván az "egy pixel" kell legyen. 

Szerk. 2: Tehát azt a szót kerestem, hogy "legnagyobb közös osztó"... Az kell hogy legyen nekik, és nem lehet túl kicsi. Na, megyek, csinálok inkább egy jó vidrapörköltet.

Köszönöm, hogy ránéztél, közben realizáltam, hogy extrém esetekben nem mindegy, hogy mekkora a lefedendő téglalap és a referencia téglalap oldalainak az aránya. Ezért annyit szigorítottam, hogy a lefedendő téglalapnak és a referencia téglalapnak is azonosnak definiáltam az oldalarányát. Ez elég nagy szigorítás, de az én felhasználási területemnél ez ok.

Csaba

A következő probléma, hogy ha csak az üresen maradó téglalapok számát minimalizálod, abból ügyesen megválasztott arányok esetén jöhetnek ki meglehetősen érdekes elrendezések, amelyek az algoritmus szerint helyesek ugyan, de ami a felhasználás célját illeti, az élvezeti értékük vetekszik egy marék szárított molylepke gasztrofizikai koefficiensével.

Teszem azt az optimális elrendezésnél az jön ki, hogy lesz egy nagy kép (referencia) és mellette egy oszlopban 49 darab 1x2 pixeles feldolgozott változat. Fogsz te ennek örülni? ;-)

Hogy klasszikusat idézzek, jogos a pont.

Azt hiszem, le kell redukálnom a problémát úgy, hogy a téglalapjaimat egy mátrix celláiként értelmezem. A referencia képet egy m x m cella méretű mátrix fogja reprezentálni, míg az összes többi 1x1 cella méretűek lesznek. Kikötöm, hogy a referencia kép mérete nem lehet nagyobb, mint az összes többi cella. Azaz m ^2 <= n.

Azokat az elrendezéseket preferálom, ahol a teljes elrendezés közel azonos számú sorból és oszlopból áll. Még ki kell sakkoznom, hogy hány üres cellát engedjek meg betenni. Gyanítom, hogy a gyakorlati megoldások esetén viszonylag keveset. Miután 7x7 = 49 elég közel van a felső korlátnak használt 50 téglalaphoz, ezért maximum 6 üres cellát fogok engedélyezni.

Addig már megvagyok, hogy fix cellaszám esetén megkapom a legjobb referencia képméretet, illetve a leginkább "négyzet szerű" mátrix méreteket, most még az üres cellák számával kell játszadoznom.

Köszönöm a tippeket, asszem ezzel már elboldogulok.

Csaba

Szerkesztve: 2023. 03. 18., szo – 06:52

Lehet benéztem a feladatot, de nekem első körben x,y prímfelbontása lenne a kiindulópontom, majd lnko.

Ps.: Benéztem. Én csak felosztottam. ;)

az nem egy megoldas, hogy az alap teglalap Ax*Ay, ekkor n x(Ax * Ay/n) egymas alatt szepen, matrix-szeru is, ki is tolti az alap A dolgot. 

Warhol? :))

Az nem megoldás, hogy erre a < 50 esetre kézzel készítesz elrendezéseket? Tudom, ez nem tudományos...

Debian - The "What?!" starts not!
http://nyizsa.blogspot.com

Szerkesztve: 2023. 03. 19., v – 00:19

Akkor lehet lefedni teljesen a játékteret, ha az is egybevágó. Ez ugye nem feltétlen lesz egybevágó a monitoroddal, ezért vagy jobb szélen, vagy alul lesz fekete csík oldalaránytól függően.

(Szerk: itt volt egy marhaság, javítva)

Ha a monitorod mérete pixelben X*Y, a referencia képed oldalaránya 'r' (oldalai a,b és így b=r*a), akkor az egybevágó játéktér mérete:

Xm = X if r * X < Y else Y / r

Ym = Y if Y / r < X else X * r

Ezt hézagmentesen lefedni egybevágó téglalapokkal négyezetesen lehet (1x1, 2x2, 3x3...)

Ebben a referenciakép a bal felső sarokban szintén csak akkor lesz egybevágó, ha négyzetesen foglal el helyet. Innentől kezdve ideális fedés ezekben az esetekben lehetséges:

Board: 2x2, Index: 1x1, n = 3
Board: 3x3, Index: 1x1, n = 8
Board: 3x3, Index: 2x2, n = 5
Board: 4x4, Index: 1x1, n = 15
Board: 4x4, Index: 2x2, n = 12
Board: 4x4, Index: 3x3, n = 7
Board: 5x5, Index: 1x1, n = 24
Board: 5x5, Index: 2x2, n = 21
Board: 5x5, Index: 3x3, n = 16
Board: 5x5, Index: 4x4, n = 9
Board: 6x6, Index: 1x1, n = 35
Board: 6x6, Index: 2x2, n = 32
Board: 6x6, Index: 3x3, n = 27
Board: 6x6, Index: 4x4, n = 20
Board: 6x6, Index: 5x5, n = 11
Board: 7x7, Index: 1x1, n = 48
Board: 7x7, Index: 2x2, n = 45
Board: 7x7, Index: 3x3, n = 40
Board: 7x7, Index: 4x4, n = 33
Board: 7x7, Index: 5x5, n = 24
Board: 7x7, Index: 6x6, n = 13
Board: 8x8, Index: 4x4, n = 48
Board: 8x8, Index: 5x5, n = 39
Board: 8x8, Index: 6x6, n = 28
Board: 8x8, Index: 7x7, n = 15
Board: 9x9, Index: 6x6, n = 45
Board: 9x9, Index: 7x7, n = 32
Board: 9x9, Index: 8x8, n = 17
Board: 10x10, Index: 8x8, n = 36
Board: 10x10, Index: 9x9, n = 19
Board: 11x11, Index: 9x9, n = 40
Board: 11x11, Index: 10x10, n = 21
Board: 12x12, Index: 10x10, n = 44
Board: 12x12, Index: 11x11, n = 23
Board: 13x13, Index: 11x11, n = 48
Board: 13x13, Index: 12x12, n = 25
Board: 14x14, Index: 13x13, n = 27
Board: 15x15, Index: 14x14, n = 29
Board: 16x16, Index: 15x15, n = 31
Board: 17x17, Index: 16x16, n = 33
Board: 18x18, Index: 17x17, n = 35
Board: 19x19, Index: 18x18, n = 37
Board: 20x20, Index: 19x19, n = 39
Board: 21x21, Index: 20x20, n = 41
Board: 22x22, Index: 21x21, n = 43
Board: 23x23, Index: 22x22, n = 45
Board: 24x24, Index: 23x23, n = 47
Board: 25x25, Index: 24x24, n = 49

for board in range(2, 101):
    for index in range(1, board):
        if(board * board - index * index < 50):
            print(f"Board: {board}x{board}, Index: {index}x{index}, n = {board * board - index * index}")

Kifejezetten érdekes, hogy melyik 'n' értékekre nem lehet megoldani: 4,6,10,14,18,22,26,30,34,38,42,46,50

n =  3, Board:  2x 2, Index:  1x 1
n =  5, Board:  3x 3, Index:  2x 2
n =  7, Board:  4x 4, Index:  3x 3
n =  8, Board:  3x 3, Index:  1x 1
n =  9, Board:  5x 5, Index:  4x 4
n = 11, Board:  6x 6, Index:  5x 5
n = 12, Board:  4x 4, Index:  2x 2
n = 13, Board:  7x 7, Index:  6x 6
n = 15, Board:  8x 8, Index:  7x 7
n = 16, Board:  5x 5, Index:  3x 3
n = 17, Board:  9x 9, Index:  8x 8
n = 19, Board: 10x10, Index:  9x 9
n = 20, Board:  6x 6, Index:  4x 4
n = 21, Board: 11x11, Index: 10x10
n = 23, Board: 12x12, Index: 11x11
n = 24, Board:  7x 7, Index:  5x 5
n = 25, Board: 13x13, Index: 12x12
n = 27, Board: 14x14, Index: 13x13
n = 28, Board:  8x 8, Index:  6x 6
n = 29, Board: 15x15, Index: 14x14
n = 31, Board: 16x16, Index: 15x15
n = 32, Board:  9x 9, Index:  7x 7
n = 33, Board: 17x17, Index: 16x16
n = 35, Board: 18x18, Index: 17x17
n = 36, Board: 10x10, Index:  8x 8
n = 37, Board: 19x19, Index: 18x18
n = 39, Board: 20x20, Index: 19x19
n = 40, Board: 11x11, Index:  9x 9
n = 41, Board: 21x21, Index: 20x20
n = 43, Board: 22x22, Index: 21x21
n = 44, Board: 12x12, Index: 10x10
n = 45, Board: 23x23, Index: 22x22
n = 47, Board: 24x24, Index: 23x23
n = 48, Board: 13x13, Index: 11x11
n = 49, Board: 25x25, Index: 24x24

Kiegészítés: Teljes sor vagy oszlop kihagyásával az alap algoritmus szerint teljes fedéssel nem megoldható N esetére is van megoldás, de "vastagabb lesz a fekete csík"

Példa:

N=45, abból egy sor vagy oszlop 23 elem, annak elvétele esetén 22 kiskép marad. Pár példára megnéztem, a többi hiányzóra is működik.

Általános megoldást nem ismerek, Google OR Tools-ba megpróbálnám felvenni a constraint-eket, aztán lesni mit hoz ki belőle.