Cara Membuat Seni Generatif Dalam Kurang Dari 100 Baris Kod

Seni generatif, seperti topik pengaturcaraan, boleh menakutkan jika anda tidak pernah mencubanya sebelum ini. Saya selalu berminat dengannya kerana saya suka mencari cara baru agar pengaturcaraan dapat digunakan secara kreatif. Lebih jauh lagi, saya rasa sesiapa sahaja dapat menghayati konsep karya seni yang benar-benar mencipta.

Apa itu seni generatif?

Seni generatif adalah output dari sistem yang membuat keputusan sendiri mengenai karya itu, bukan manusia. Sistem ini bisa sesederhana program Python tunggal, asalkan memiliki peraturan dan beberapa aspek keacakan.

Dengan pengaturcaraan, cukup mudah untuk membuat peraturan dan kekangan. Itu semua pernyataan bersyarat. Setelah itu, mencari jalan untuk membuat peraturan ini membuat sesuatu yang menarik boleh menjadi sukar.

Game of Life adalah sekumpulan empat peraturan mudah yang terkenal yang menentukan "kelahiran" dan "kematian" setiap sel dalam sistem. Setiap peraturan berperanan dalam memajukan sistem melalui setiap generasi. Walaupun peraturannya mudah dan mudah difahami, corak yang kompleks dengan cepat mula muncul dan akhirnya menghasilkan hasil yang menarik.

Peraturan mungkin bertanggungjawab untuk membuat asas sesuatu yang menarik, tetapi bahkan sesuatu yang menarik seperti Game of Life Conway dapat diramalkan. Oleh kerana keempat peraturan tersebut merupakan faktor penentu bagi setiap generasi, cara untuk menghasilkan hasil yang tidak dapat diramalkan adalah dengan memperkenalkan pengacakan pada keadaan awal sel. Bermula dengan matriks rawak akan menjadikan setiap pelaksanaan unik tanpa perlu mengubah peraturan.

Contoh terbaik seni generatif adalah contoh yang dapat menemukan gabungan ramalan dan rawak untuk mencipta sesuatu yang menarik yang juga tidak dapat dihasilkan secara statistik .

Mengapa anda mesti mencubanya?

Tidak semua projek sampingan dibuat sama, dan seni generatif mungkin bukan sesuatu yang cenderung anda habiskan. Sekiranya anda memutuskan untuk mengusahakan projek, anda boleh mengharapkan faedah berikut:

  • Pengalaman - Seni generatif adalah satu lagi peluang untuk mengasah beberapa kemahiran baru dan lama. Ia dapat menjadi pintu masuk untuk mempraktikkan konsep seperti algoritma, struktur data, dan juga bahasa baru.
  • Hasil yang ketara - Dalam dunia pengaturcaraan, kita jarang dapat melihat apa-apa yang dilakukan secara fizikal daripada usaha kita, atau paling tidak. Sekarang ini saya mempunyai beberapa poster di ruang tamu saya yang memaparkan cetakan seni generatif saya dan saya suka bahawa pengaturcaraan bertanggungjawab untuk itu.
  • Projek Menarik - Kita semua mempunyai pengalaman menerangkan projek peribadi kepada seseorang, bahkan mungkin semasa wawancara, tanpa cara mudah untuk menyampaikan usaha dan hasil projek. Seni generatif bercakap dengan sendirinya, dan kebanyakan orang akan kagum dengan ciptaan anda, walaupun mereka tidak dapat memahami kaedahnya sepenuhnya.

Di mana anda harus bermula?

Memulakan seni generatif adalah proses yang sama dengan projek apa pun, langkah yang paling penting adalah mengemukakan idea atau mencari idea untuk dikembangkan. Setelah anda mempunyai tujuan, anda boleh mula menggunakan teknologi yang diperlukan untuk mencapainya.

Sebilangan besar projek seni generatif saya telah dilaksanakan di Python. Ini adalah bahasa yang cukup mudah untuk digunakan dan ia mempunyai beberapa pakej yang luar biasa untuk membantu manipulasi gambar, seperti Pillow.

Nasib baik untuk anda, tidak perlu mencari titik permulaan, kerana saya telah memberikan beberapa kod di bawah untuk anda mainkan.

Penjana Sprite

Projek ini dimulakan ketika saya melihat catatan yang memaparkan generator sprite yang ditulis dalam Javascript. Program ini mencipta sprite seni 5x5 piksel dengan beberapa pilihan warna rawak dan outputnya menyerupai penceroboh ruang pelbagai warna.

Saya tahu bahawa saya mahu mempraktikkan manipulasi gambar di Python, jadi saya fikir saya hanya boleh mencipta konsep ini sendiri. Selain itu, saya berpendapat bahawa saya dapat mengembangkannya kerana projek asalnya sangat terhad dalam ukuran sprite. Saya ingin dapat menentukan bukan sahaja ukuran, tetapi juga jumlahnya dan juga ukuran gambar.

Berikut adalah dua output yang berbeza dari penyelesaian yang saya selesaikan:

Kedua-dua gambar ini sama sekali tidak menyerupai satu sama lain, tetapi kedua-duanya adalah hasil sistem yang sama. Belum lagi, disebabkan oleh kerumitan imej dan kerawakan generasi bidadari, terdapat kebarangkalian yang sangat tinggi bahawa walaupun dengan hujah yang sama, imej-imej ini selama-lamanya akan menjadi salah satu jenis. Saya sukakannya.

Alam sekitar

Sekiranya anda ingin mula bermain-main dengan generator sprite, ada sedikit kerja asas yang harus dilakukan terlebih dahulu.

Menyiapkan persekitaran yang sesuai dengan Python boleh menjadi sukar. Sekiranya anda belum pernah bekerja dengan Python sebelum ini, anda mungkin perlu memuat turun Python 2.7.10. Saya pada mulanya menghadapi masalah dalam mengatur persekitaran, jadi jika anda mula menghadapi masalah, anda dapat melakukan apa yang saya lakukan dan melihat persekitaran maya. Akhir sekali, pastikan anda juga memasang Pillow.

Setelah anda menyiapkan persekitaran, anda boleh menyalin kod saya ke dalam fail dengan ekstensi .py dan laksanakan dengan perintah berikut:

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

Sebagai contoh, arahan untuk membuat matriks sprite pertama dari atas adalah:

python spritething.py 7 30 1900

Kodnya

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]))

Penyelesaian ini jauh dari sempurna, tetapi menunjukkan bahawa mencipta seni generatif tidak memerlukan banyak kod. Saya akan berusaha sedaya upaya untuk menerangkan perkara-perkara penting.

Yang utama fungsi bermula dengan mewujudkan imej awal dan menentukan saiz sprites. Kedua-dua untuk gelung bertanggungjawab untuk menentukan sempadan bagi setiap bidadari, pada dasarnya membahagikan dimensi imej dengan jumlah sprites diminta. Nilai-nilai ini digunakan untuk menentukan koordinat bagi setiap satu.

Mari abaikan padding dan lihat gambar di bawah. Bayangkan bahawa setiap empat petak mewakili sprite dengan ukuran 1. Batas yang dilalui ke fungsi seterusnya merujuk kepada koordinat kiri kanan dan kanan atas. Jadi tuple untuk sprite kiri atas adalah (0,0,1,1) sedangkan tuple untuk kanan atas (1,0,2,1). Ini akan digunakan sebagai dimensi dan koordinat asas untuk kotak setiap sprite.

Fungsi create_invader menentukan sempadan untuk setiap persegi di sprite. Proses yang sama untuk menentukan sempadan diterapkan di sini dan ditunjukkan di bawah, hanya sebagai gambar penuh, kami menggunakan sempadan yang telah ditentukan untuk bekerja di dalamnya. Koordinat akhir ini untuk setiap petak akan digunakan dalam fungsi seterusnya untuk benar-benar menggambar sprite.

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!