🧑🎨
Goでジェネレーティブアート
Goでジェネレーティブアート風な動画を作ってみます。
使用するpackage
-
fogleman/gg
Goには図形描画の標準ライブラリが無いようなので適当なpackageを使います。 -
icza/mjpeg
MotionJEPGのavi動画を生成するpackageです。画像を連結して1つの動画ファイルにするために使います。
ステップ1: 1枚の画像を生成してみる
まずggを使って1枚の画像を生成してみます。
package main
import (
"github.com/fogleman/gg"
)
func main() {
c := gg.NewContext(1000, 500)
c.SetRGB(1, 0, 0)
c.DrawCircle(500, 250, 10)
c.Fill()
c.SavePNG("image.png")
}
こんな感じの画像が出力されます。
ステップ2: 画像を動画ファイルにしてみる
先ほどのソースをちょっと書き換えて、動画ファイルを生成するようにします。
ここでは1枚のjpg画像をAddFrameして、1秒間1フレームだけの動画ファイルにしています。
実行するとaviファイルが生成され、1秒間だけですが動画再生できるはずです。
package main
import (
"bytes"
"image/jpeg"
"math/rand"
"github.com/fogleman/gg"
"github.com/icza/mjpeg"
)
func main() {
const (
W = 1000 // 解像度 : 高さ
H = 500 // 解像度 : 幅
FRAME_RATE = 1 // 1秒間のフレーム数
)
aw, _ := mjpeg.New("single_frame.avi", W, H, FRAME_RATE)
c := gg.NewContext(W, H)
c.SetRGB(1, 0, 0)
c.DrawCircle(rand.Float64()*W, rand.Float64()*H, 50)
c.Fill()
buf := &bytes.Buffer{}
_ = jpeg.Encode(buf, c.Image(), nil)
_ = aw.AddFrame(buf.Bytes())
_ = aw.Close()
}
ステップ3: 複数の画像を動画ファイルに追加してみる
先ほどの動画は1フレームしかなかったので、動画と言えるものではありませんでした。
今度はさらに書き換えて、複数の画像を動画ファイルに追加してみます。
package main
import (
"bytes"
"image/jpeg"
"math/rand"
"github.com/fogleman/gg"
"github.com/icza/mjpeg"
)
func main() {
const (
W = 1000 // 解像度 : 高さ
H = 500 // 解像度 : 幅
FRAME_RATE = 1 // 1秒間のフレーム数
SECONDS = 10 // 動画の長さ(秒)
)
aw, _ := mjpeg.New("multi_frames.avi", W, H, FRAME_RATE)
for i := 0; i < FRAME_RATE*SECONDS; i++ {
c := gg.NewContext(W, H)
c.SetRGB(1, 0, 0)
c.DrawCircle(rand.Float64()*W, rand.Float64()*H, 50)
c.Fill()
buf := &bytes.Buffer{}
_ = jpeg.Encode(buf, c.Image(), nil)
_ = aw.AddFrame(buf.Bytes())
}
_ = aw.Close()
}
出来上がる動画はこんな感じです。
このサンプルでは円を描画する座標をランダムにしてあるので、あちこちに円が瞬間移動しているように見えますが、たとえば座標を1ピクセルずつ動くように書き変えると、もっとアニメーションっぽく見えるはずです。
発展
ここまでできれば、あとは出力する画像をもう少しちゃんとしたものに差し替えれば終わりです。
私はこんな画像を生成してみました。
この画像をちょっとずつ動かして動画にしたものはこちら。
2万パーティクルを動かしているので1枚1枚の画像生成に時間はかかってしまいますが、(当たり前ではありますが)1度動画になってしまえスムースに動きます。
以上です。
ソースは下記にありますので、興味ある方はお試しください。
Discussion