December 16, 2022

Python向けのクリエイティブコーディングパッケージ:q5をつくったので紹介したい

素人発想・玄人実行 その2

はじめに

この記事は「Processing Advent Calendar 2022」の16日目の記事です.

今年のはじめぐらいにq5というPython用のProcessingライクなクリエイティブコーディングのパッケージを開発・公開したのでその紹介をしようと思います.本稿執筆時点での最新バージョンは v0.1.2 です.

リポジトリはこちら: https://github.com/eqs/q5

本稿はパッケージにリファレンスをつけないといけないのに文章書くのをさぼってだらだらしている状況を打破すべく,いい感じの草稿を得ることを目的として書かれました.

q5を利用するとこんな作品が作れる!!

https://sketchbook.eqseqs.work/sketch_220516a/

https://sketchbook.eqseqs.work/sketch_220220a/

https://sketchbook.eqseqs.work/sketch_220220b/

q5はどんなパッケージ

q5を用いて原点中心に円を回転させるアニメーションのPythonコードは次のようになります. ProcessingとopenFrameworksの折衷のような感じのコードになってるのがわかると思います.

import math
import q5


class App(q5.BaseApp):
    def setup(self):
        self.x = 0.0
        self.y = 0.0

    def update(self):
        t = q5.frame_count
        u = t / 60.0 * 2 * math.pi
        self.x = 100.0 * math.cos(u)
        self.y = 100.0 * math.sin(u)

    def draw(self):
        q5.background(220)
        q5.translate(self.x, self.y)
        q5.ellipse(0.0, 0.0, 100.0, 100.0)


if __name__ == '__main__':
    app = App()
    app.run()

対応プラットフォーム

Windows, Linux, macOSに対応しています. ただし,2022/12時点でM1 Macについてはユーザ自身でパッケージをビルドする必要があるのと,動作が保証できていません.動いたり動かなかったりします(著者の環境).

開発経緯

自分はProcessingやp5.jsでクリエイティブコーディング作品を作るのが趣味ですが, 数学的に凝ったアルゴリズムを作ろうとするとJavaやJavaScriptの速度の遅さや外部パッケージの導入のしづらさが障壁になりました.

数値計算や機械学習のパッケージが充実しているPythonでクリエイティブコーディングができるの理想でしたが, ProcessingのPythonモードはエンジンがJythonとよばれるPythonインタプリタのJava実装であるため, Pythonの充実したパッケージ群の恩恵を受けることができません(文法はPythonだけど中身が別物).

そこで,ネイティブのPython(CPython)にインストールして呼び出せる形のクリエイティブコーディングフレームワークを作ることで,目的を達成しようと考えました.

関連するプロジェクト

Advent Calendarに登録してから気づいたのですが,py5というProcessingからCPythonを呼び出せるようにしたプロジェクトがあるみたいです.

https://py5coding.org/

環境構築

q5はPyPIで各プラットフォーム向けにビルド済みのバイナリを配布しているので( https://pypi.org/project/q5/ ),下記のようにpipコマンドでインストールすることができます.

pip install q5

M1 Macの場合は上記コマンドを実行するとパッケージのソースコードがダウンロードされ,自動でビルドが開始されます(Rust言語の環境とPythonの setuptools-rust パッケージが無いとエラーで止まります).

サンプルコードと機能紹介

画像をクリックするとリポジトリ内のサンプルコードのページに飛べます. リポジトリにサンプルが無いものはコードを記事内に示しています.

図形の描画

円,楕円,矩形,直線,折れ線,多角形,矢印といったProcessingの2D図形描画関数に相当するものは一通り用意しています.

プロパティ

描画領域のサイズを表す q5.width , q5.height とか, フレーム数が入る q5.frame_count が用意されています.

アフィン変換と行列スタック

Processingでいう translatepushMatrix, popMatrix に相当する機能です.

画像の描画

q5.QImage.from_ndarray 関数にNumpyの配列を渡すことでq5のキャンバスに描画可能な画像を作成できます.下記サンプルはプログラムで自動的に作成した画像を from_ndarray で読み込んでいます.

from_ndarray の代わりに from_path 関数に文字列を渡すことでファイルから直接画像を直接読み込むことも可能です.

テキストの描画

リポジトリにサンプルコードはまだ無いですが,q5.text 関数でテキストを描画することが可能です.

import q5
import numpy as np
import math


class App(q5.BaseApp):
    def setup(self):
        q5.title('q5 app')

        t = np.linspace(0, 2*np.pi, 1000)
        x = 100.0 * np.cos(t)
        y = 100.0 * np.sin(t)
        self.pts = np.vstack([x, y]).T
        self.s = 1.0

    def update(self):
        t = np.linspace(0, 2*np.pi, 1500)
        r = 200.0 + 50.0 * np.sin(t * 32.0 + q5.frame_count / 60.0)
        x = r * np.cos(t)
        y = r * np.sin(t)
        self.pts = np.vstack([x, y]).T

        self.s = 1.0 + 0.125 * np.sin(q5.frame_count / 60.0 * 2.0)

    def draw(self):
        q5.background(220)

        q5.scale(self.s)

        q5.stroke(0)
        q5.fill(255)
        q5.stroke_weight(1.0)
        q5.circle(0.0, 0.0, 100.0)

        q5.stroke(255, 0, 0)
        q5.fill(0, 255, 0)
        q5.stroke_weight(5.0)
        q5.polygon(self.pts)

        q5.font_size(128)
        q5.fill(0, 0, 255)
        # q5.text_leading(32.0 + 16.0 * math.sin(q5.frame_count / 60.0 * 10.0))
        q5.text("Hello\nWorld", 0.0, 0.0, 500.0, 500.0)


if __name__ == '__main__':
    app = App()
    app.run()

フォントの読み込み

これもリポジトリにサンプルコードはまだ無いですが,フォントのファイルを読み込んで利用することが可能です(標準のフォントだと日本語を描画できません).

import os
import q5

class App(q5.BaseApp):
    def setup(self):
        q5.title('q5 app')

        font_root = r'C:\Users\<username>\AppData\Local\Microsoft\Windows\Fonts'
        font_names = [
            'migmix-1m-regular.ttf',
            'migmix-1m-bold.ttf',
            'PixelMplus10-Regular.ttf',
            'PixelMplus10-Bold.ttf',
            'PixelMplus12-Regular.ttf',
            'PixelMplus12-Bold.ttf',
        ]
        self.fonts = [q5.QFont(os.path.join(font_root, name)) for name in font_names]

    def update(self):
        pass

    def draw(self):
        q5.background(220, 220, 220)

        q5.font_size(20)
        q5.text_padding(20.0)
        q5.fill(32, 32, 32)

        for k, font in enumerate(self.fonts):
            q5.text_font(font)
            q5.text('Windows でコンピューターの世界が広がります。1234567890',
                    0.0, 256.0 - k * 64.0, q5.width, 128.0)

    def key_pressed(self):
        q5.save_frame('font.png')

if __name__ == '__main__':
    app = App()
    app.run()

発展的な例

機械学習パッケージの利用

q5はCPython上にインストールされるため,同じPythonにインストールされているパッケージを利用可能です.上記のサンプル内で数値計算のパッケージであるNumpyを利用していたのもその例のひとつです.

冒頭でも紹介したスライムがぐねぐね動く動画↓は, ガウス過程と呼ばれる機械学習の応用的なモデルを利用して作成しています. ガウス過程の計算は非常に巨大な行列の掛け算を行う必要がありますが,Pythonから利用可能なガウス過程の高速な実装である GPy を用いることでリアルタイムでの実行も可能にしています.

https://sketchbook.eqseqs.work/sketch_220220b/

また,以下のCircle Packingの作品も見た目はよくある技法に見えますが,中身はPyTorchという深層学習でよく利用されているパッケージを利用して作成しています.具体的には,キャンバス上に円をランダムに配置し,円と円の重複の総和を目的関数としてそれを最小化する問題を自動微分と勾配降下法で解いてます.アニメーション作ってないのがもったいないのですが重なりが消えていくまでの過程を眺めるのが楽しい作品です.

https://sketchbook.eqseqs.work/sketch_220516a/

データ・アルゴリズムの可視化

q5 はクリエイティブコーディング用に開発したパッケージですが, 用途はクリエイティブコーディングに限定されません.

下記の例は,2次元の空間上に分布しているデータから意味のある構造を抽出する操作であるクラスタリングの過程を示しています. 具体的には,混合ガウスモデルによるクラスタリングをギプスサンプリングによって解いていて,そのサンプリングの過程をq5でプロットしています. このプログラムでは画面をクリックするとサンプリングをランダムな値で初期化するため,様々な初期値におけるアルゴリズムの挙動を確認することが可能です.

https://sketchbook.eqseqs.work/sketch_220421a/

q5の実装について

q5はPythonのパッケージですが,中身はほとんどRust言語で書かれています. 具体的には,ウインドウの表示や描画処理はRust製のクリエイティブコーディングフレームワークであるNannouの機能を利用していて,これらの機能をPythonから呼び出す部分はPyO3というパッケージを利用しています. RustとPythonはかなりパラダイムの異なるプログラミング言語ですが(例えば,Rustにはクラスが無い), Pythonでプログラムを書く際にProcessingやp5.jsに近い書き心地になるようにバックエンド側を工夫しています. パラダイムの違いをうまく吸収する設計はPython向けレトロゲームエンジンであるPyxelの設計を参考にしています.

まとめ

Python向けのクリエイティブコーディングパッケージであるq5の概要やできることをざっと紹介しました.

自分がほしい機能が思いついたときに開発を進めているので進行ペースがかなり歪なプロジェクトですが, GitHubのIssuesやTwitterの #q5 ハッシュタグでアイデアや作品を投稿していただけると開発のモチベになります.

今後の方針は特に決まってないですが,3D図形やシェーダはほしくなってきたのでとりあえずそのへんを強化していこうかなと思ってます.

おわり!!!!

© eqs 2021