Hogyan lehet generatív művészetet létrehozni kevesebb, mint 100 kódsorban

A generatív művészet, mint bármely programozási téma, megfélemlítő lehet, ha még soha nem próbálta ki. Mindig is érdekelt, mert szeretek új módszereket találni a programozás kreatív felhasználására. Továbbá azt gondolom, hogy bárki képes értékelni azt a műalkotást, amely szó szerint megalkotja önmagát.

Mi az a generatív művészet?

A generatív művészet annak a rendszernek a kimenete, amely az ember helyett maga dönti el a darabot. A rendszer olyan egyszerű lehet, mint egy Python program, amennyiben vannak szabályai és a véletlenszerűség bizonyos aspektusai .

A programozással meglehetősen egyszerű szabályokkal és korlátozásokkal előállni. Ennyi a feltételes állítás. Ennek ellenére trükkös lehet megtalálni azokat a módszereket, amelyekkel ezek a szabályok valami érdekeset hozhatnak létre.

Az Élet játéka négy egyszerű szabály híres halmaza, amelyek meghatározzák a rendszer egyes sejtjeinek „születését” és „halálát”. A szabályok mindegyike szerepet játszik a rendszer előrehaladásában minden generáción keresztül. Bár a szabályok egyszerűek és könnyen érthetők, a bonyolult minták gyorsan kezdenek megjelenni és végül lenyűgöző eredményeket alkotnak.

A szabályok felelősek lehetnek valami érdekes megalapozásáért, de még olyan izgalmas dolog is, mint a Conway Életjátéka, kiszámítható. Mivel a négy szabály a meghatározó tényező minden generáció számára, az előre nem látható eredmények előállításának módja a randomizálás bevezetése a sejtek kiindulási állapotában. Véletlenszerű mátrixszal kezdve minden végrehajtás egyedivé válik a szabályok megváltoztatása nélkül.

A generatív művészet legjobb példái azok, amelyek a kiszámíthatóság és a véletlenszerűség kombinációját találják annak érdekében, hogy valami érdekeset hozzanak létre, amely statisztikailag is reprodukálhatatlan .

Miért érdemes kipróbálni?

Nem minden mellékprojekt jön létre egyenlően, és a generatív művészet nem biztos, hogy hajlandó időt tölteni. Ha mégis úgy dönt, hogy egy projekten dolgozik, akkor számíthat ezekre az előnyökre:

  • Tapasztalat - A generatív művészet csak egy újabb lehetőség új és régi készségek csiszolására. Átjáróként szolgálhat olyan fogalmak gyakorlásához, mint algoritmusok, adatstruktúrák és akár új nyelvek is.
  • Kézzelfogható eredmények - A programozási világban ritkán tapasztalhatunk fizikai erőfeszítéseket, vagy legalábbis én nem. Jelenleg a nappalimban van néhány plakát, amelyen generatív művészetem nyomatai láthatók, és imádom, hogy a programozás felelős ezért.
  • Vonzó projektek - Mindannyiunknak megvolt a tapasztalata arról, hogy elmagyarázzunk valakinek egy személyes projektet, esetleg még egy interjú során is, anélkül, hogy egyszerű módon átadnánk a projekt erőfeszítéseit és eredményeit. A generatív művészet önmagáért beszél, és a legtöbb embert lenyűgözi alkotása, még akkor is, ha nem tudja teljesen megérteni a módszereket.

Hol kell kezdeni?

A generatív művészet megkezdése ugyanolyan folyamat, mint bármely projekt, a legfontosabb lépés egy ötlet előállítása vagy megtalálása, amelyre építeni lehet. Miután szem előtt tartotta a célját, elkezdheti dolgozni az eléréséhez szükséges technológiát.

A legtöbb generatív művészeti projektem a Pythonban valósult meg. Ez egy meglehetősen könnyen megszokható nyelv, és hihetetlen csomagok állnak rendelkezésre a képkezeléshez, például a Párna.

Szerencsédre nem kell nagyon messzire keresni a kiindulópontot, mert az alábbiakban biztosítottam néhány kódot, amellyel játszhatsz.

Sprite Generator

Ez a projekt akkor kezdődött, amikor láttam egy bejegyzést, amely egy sprite generátort mutat be, Javascriptben írva. A program 5x5 pixeles art-spritteket készített néhány véletlenszerű színbeállítással, és a kimenete többszínű űrbe betolakodókra hasonlított.

Tudtam, hogy a képmanipulációt szeretnék gyakorolni a Pythonban, ezért arra gondoltam, hogy megpróbálhatom egyedül létrehozni ezt a koncepciót. Ezenkívül úgy gondoltam, hogy kibővíthetem, mivel az eredeti projekt annyira korlátozott volt a spritek méretében. Nem csak a méretet, hanem azok számát és még a kép méretét is meg akartam tudni adni.

Íme egy pillantás a megoldás két különböző kimenetére:

Ez a két kép egyáltalán nem hasonlít egymásra, de mindkettő ugyanazon rendszer eredménye. Nem is beszélve arról, hogy a kép bonyolultsága és a sprite generáció véletlenszerűsége miatt rendkívül nagy a valószínűsége annak, hogy ugyanezen érvek mellett is ezek a képek örökké egyfajtaak lesznek. Szeretem.

A környezet

Ha el akarsz kezdeni játszani a sprite generátorral, előbb egy kis alapozási munkát kell elvégezni.

Megfelelő környezet beállítása a Python segítségével bonyolult. Ha korábban nem dolgozott a Python-nal, akkor valószínűleg le kell töltenie a Python 2.7.10-et. Kezdetben gondjaim voltak a környezet beállításával, így ha problémákba ütközik, megteheti, amit tettem, és belenézhet a virtuális környezetekbe. Végül, de nem utolsósorban, győződjön meg arról, hogy telepítette a Párnát is.

Miután beállította a környezetet, átmásolhatja a kódomat egy .py kiterjesztésű fájlba, és a következő paranccsal hajthatja végre:

python spritething.py [SPRITE_DIMENSIONS] [NUMBER] [IMAGE_SIZE]

Például a parancs az első tömb mátrix fentről történő létrehozására a következő:

python spritething.py 7 30 1900

A kód

import PIL, random, sysfrom PIL import Image, ImageDraw
origDimension = 1500
r = lambda: random.randint(50,215)rc = lambda: (r(), r(), r())
listSym = []
def create_square(border, draw, randColor, element, size): if (element == int(size/2)): draw.rectangle(border, randColor) elif (len(listSym) == element+1): draw.rectangle(border,listSym.pop()) else: listSym.append(randColor) draw.rectangle(border, randColor)
def create_invader(border, draw, size): x0, y0, x1, y1 = border squareSize = (x1-x0)/size randColors = [rc(), rc(), rc(), (0,0,0), (0,0,0), (0,0,0)] i = 1
 for y in range(0, size): i *= -1 element = 0 for x in range(0, size): topLeftX = x*squareSize + x0 topLeftY = y*squareSize + y0 botRightX = topLeftX + squareSize botRightY = topLeftY + squareSize
 create_square((topLeftX, topLeftY, botRightX, botRightY), draw, random.choice(randColors), element, size) if (element == int(size/2) or element == 0): i *= -1; element += i
def main(size, invaders, imgSize): origDimension = imgSize origImage = Image.new('RGB', (origDimension, origDimension)) draw = ImageDraw.Draw(origImage)
 invaderSize = origDimension/invaders padding = invaderSize/size
 for x in range(0, invaders): for y in range(0, invaders): topLeftX = x*invaderSize + padding/2 topLeftY = y*invaderSize + padding/2 botRightX = topLeftX + invaderSize - padding botRightY = topLeftY + invaderSize - padding
 create_invader((topLeftX, topLeftY, botRightX, botRightY), draw, size)
 origImage.save("Examples/Example-"+str(size)+"x"+str(size)+"-"+str(invaders)+"-"+str(imgSize)+".jpg")
if __name__ == "__main__": main(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))

Ez a megoldás messze van a tökéletestől, de azt mutatja, hogy a generatív művészet létrehozása nem igényel rengeteg kódot. Igyekszem minden erőmmel elmagyarázni a legfontosabb darabokat.

A funkció a kezdeti kép elkészítésével és a sprittek méretének meghatározásával indul. A kettő a hurkokért felelős azért, hogy meghatározzon minden sprite határát, alapvetően elosztva a kép méreteit a kért sprite-ek számával. Ezeket az értékeket használjuk az egyes koordináták meghatározásához.

Hagyjuk figyelmen kívül a párnázást, és nézzük meg az alábbi képet. Képzelje el, hogy a négy négyzet mindegyike egy sprite-t jelent, amelynek mérete 1. A következő függvénynek átadott határ a bal és a jobb alsó koordinátára vonatkozik. Tehát a bal felső sprite duplája (0,0,1,1), míg a jobb felső sarka (1,0,2,1) lenne. Ezeket fogják használni az egyes sprite négyzeteinek méreteiként és alapkoordinátáiként.

A create_invader függvény határozza meg a sprite minden egyes négyzetének határát. Ugyanezt a folyamatot határozza meg itt, és az alábbiakban ábrázoljuk, csak a teljes kép helyett egy előre meghatározott szegélyt használunk a munkához. Ezeket a négyzetek végső koordinátáit a következő függvényben használjuk a sprite tényleges megrajzolásához.

To determine the color, a simple array of three random RGB tuples and three blacks are used to simulate a 50% chance of being drawn. The lambda functions near the top of the code are responsible for generating the RGB values.

The real trick of this function is creating symmetry. Each square is paired with an element value. In the image below you can see the element values increment as they reach the center and then decrement. Squares with matching element values are drawn with the same color.

As create_square receives its parameters from create_invader, it uses a queue and the element values from before to ensure symmetry. The first occurrence of the values have their colors pushed onto the queue and the mirrored squares pop the colors off.

I realize how difficult it is to read through and understand someone else’s solution for a problem, and the roughness of the code certainly does not help with its complexity, but hopefully you’ve got a pretty good idea for how it works. Ultimately it would be incredible if you are able to scrap my code altogether and figure out an entirely different solution.

Conclusion

Generative art takes time to fully appreciate, but it’s worth it. I love being able to combine programming with a more traditional visual, and I have definitely learned a lot in every one of my projects.

Overall there may be more useful projects to pursue and generative art may not be something you need experience with, but it’s a ton of fun and you never know how it might separate you from the crowd.

Thank you for reading!