四谷ラボ公式ブログ

四谷ラボはいつでも誰でも自由に参加・研究・交流・発信のできる街のオープンイノベーションラボ

技術とアートの融合 - シミュレーティッドアニーリング - 美しさの追求

小学4年生のとき・・・

・・・褒めることのない美術の先生が、僕の描いた「お花」の絵を褒めてくれ、「自分にはアートの道があるんだ」と将来を夢見てから40年・・・。

結局、芸術家になることはなく、技術家になって久しい。

こんにちは、やましんです。

今日のテーマは「技術とアートの融合」です。

最近では「アートサイエンス」という言葉があるらしく、芸大の学科にもなっているみたい。 確かに、数学や自然科学には、美しさがあり、洗練された工学デザインにも、技術の精緻さが織りなす優美さがあるよね。

よし、技術でアートをやってみよう。

技術をアートにし、小学4年生のときに夢見た芸術家への思いを昇華するので、応援してね。

今回技術で創り上げる芸術作品

ということで、今回はシミュレーティッドアニーリングという技術を使って、この三次元アートをつくるよ。

ある瞬間だけこの世で最も大切なものが見えるでしょ?

大切なモノって刹那なんだねぇ。

プログラム

コードのありか

こちらにコードがあるので、触ってみて。

ドキュメントよりコード重視派の皆さんにはもちろんだけど、計算に1時間弱かかるので、 効率重視派の皆さんも、最初に走らせておいて、文章を読み進めながら結果を待つことをお勧めします。 処理中の画像がフリーズしているように見えるかもしれなけど、我慢して待ってみて。

計算用のプログラムコードはわずか200行程度なので、興味ある方はいろいろ遊んでみて。

そうそう、今回はGPUは不要です。

github.com

動かし方

コンソールから次のコマンドを打って、60分程度待てばアートが完成します。

git clone https://github.com/428lab/simulated_annealing_3d_art.git
cd simulated_annealing_3d_art
./run.sh

動作原理

このプログラムでは、ある組合せ最適化問題をシミュレーティッドアニーリングという技術を使って解いてます。

最適化する問題

「3D空間にある立方体を動かして、特定の角度から見たときに、あらかじめ決められた画像に似た形になるように、立方体の位置、大きさ、回転の角度を変えて配置する」という最適化問題

シミュレーティッドアニーリングって?

とても面白い考え方なので、ぜひ、この機会に理解を深めてちょうだい。

真っ赤に熱した日本刀を水の中に入れて急激に冷やすシーンってみたことあるでしょ?

あれって「焼入れ」っていうんだけど、これは金属を固くする目的があるんだ。

逆に、高温の金属を、ゆっくり徐々に温度を下げることで、柔らかく、加工しやすくなるんだ。 このことを「焼きなまし」と言って、かっこよく英語でいうと「アニーリング」って言うんだね。

シミュレーティッドアニーリングを日本語に訳すと「疑似焼きなまし」になるんだけど、高温の金属を、徐々に温度を下げることで、最小エネルギー状態を保持した秩序ある構造の状態を作り出す過程をコンピュータ上で疑似的に再現した技術です。略してSA法と言ったりします。

実際にはコンピューターの温度は全く関係なく、温度と見立てた変数を徐々に下げていき、問題の解を探していると考えるんだ。

この「温度」とは、どれだけ探索の範囲を広くするか、どれだけ新しい解を受け入れるかを示す数値のことなんだよね。

最初にこの温度は高く設定されていて、コンピュータは多くの異なる解を試すことができるから、最適な解を見つける確率が高いんだけど、その分無駄な試行も多くなるんだ。

でも、時間が経つにつれて、温度は徐々に下がっていくんだ。これによって、コンピュータはだんだんと探索範囲を狭め、より良い解に焦点を当てるようになる。

シミュレーテッドアニーリングでは、「温度」が下がるにつれて、新しい解を受け入れる確率も下がっていく。だから、最初は全然違う解も試すけど、段々と目的の解に近い解を探すようになる。これが、金属の「焼きなまし」の過程に似ているから、この名前が付けられたんだ。

この方法のいいところは、局所的な最適解に囚われずに、より良い全体的な最適解を見つける可能性が高いということ。逆に言えば、時間がかかることや、最適解を保証するものではないというデメリットもあるんだけどね。

最近は量子アニーリングマシンが使えるようになったので、一瞬で解を得られるかもしれないね。興味ある人はぜひチャレンジして結果を報告して欲しい!

コンピューターで問題を解くときに、シミュレーテッドアニーリングを使うと、このように徐々に解を絞り込んでいくことで、最終的には良い解が得られる可能性が高くなるんだよ。

処理の流れ

今回のプログラムは、OpenGLPygameを使用して3Dグラフィックスを作成し、SA法を利用して目標画像に近似する立方体の配置を探索するもので、処理手順は下記の通り。

  1. 「温度」変数の初期値を決定

  2. 解の候補として立方体をランダム配置し、画像を生成(画像が指定するビットマップに近づく場合は受理、そうでない場合も一定の確率で受理)

  3. 一定回数2.を試行したら温度を下げる

  4. 温度が下がりきるまで2-3を繰り返す

プログラム詳細

シミュレーティッドアニーリングを含むメインプログラムsimulated_annealing_3d_art.pyの主なコードを解説します。

立方体の定義: 立方体の頂点(vertices)と面(surfaces)を定義しています。今回は立方体だけど、任意のポリゴンでこのプログラムは機能する(はず。

# Cube vertices and surfaces
vertices = (
    (1, -1, -1),
    (1, 1, -1),
    (-1, 1, -1),
    (-1, -1, -1),
    (1, -1, 1),
    (1, 1, 1),
    (-1, -1, 1),
    (-1, 1, 1)
)

surfaces = (
    (0,1,2,3),
    (3,2,7,6),
    (6,7,5,4),
    (4,5,1,0),
    (1,5,7,2),
    (4,0,3,6)
)

setup_viewport: OpenGLのビューポートを設定する関数です。ウィンドウのサイズに基づき、視野を設定します。ビューポートを変更すると立方体の配置が同じでも見え方が変化するので、結果に大きく影響を与えるよ。

def setup_viewport(width, height):
    glViewport(0, 0, width, height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45, (width / height), 0.1, 50.0)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0)  # カメラの位置と向きを設定

create_initial_cubes: 初期の立方体の位置、角度、サイズをランダムに生成する関数です。各パラメータは一定の範囲内でランダムに変化します。

def create_initial_cubes(num_cubes, image_size, min_cube_size, max_cube_size, init_cubes=None):
    pygame.init()
    display = (image_size[0], image_size[1])
    pygame.display.set_mode(display, DOUBLEBUF | OPENGL)

    glClearColor(1.0, 1.0, 1.0, 1.0)  # 白色に設定
    glEnable(GL_DEPTH_TEST)

    # ここでビューポートと投影を設定
    setup_viewport(display[0], display[1])

    cubes = []

    if init_cubes == None:

        """ 初期の立方体の配置を生成 """
        for _ in range(num_cubes):
            x, y, z = [random.uniform(-5, 5) for _ in range(3)]
            angle = random.uniform(0, 45)
            size = random.uniform(min_cube_size, max_cube_size)
            cubes.append((x, y, z, angle, size))
    else:
        for x, y, z, angle, size in init_cubes:
            cubes.append((x, y, z, angle, size))

    return cubes

generate_image: 現在の立方体の配置から画像を生成する関数です。もっとスマートで高速な方法があれば教えてね。

def generate_image(current_cubes, img_size):

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    for x, y, z, angle, size in current_cubes:
        glPushMatrix()
        glTranslatef(x, y, z)
        glRotatef(angle, 0, 1, 0)
        draw_cube(size)  # 立方体を描画
        glPopMatrix()

    #glFinish()  # レンダリングが完了するまで待機
    pygame.display.flip()

    # OpenGLのフレームバッファからビットマップを取得
    bitmap = grab_opengl_bitmap(img_size)

    # NumPy配列をPillow画像に変換
    pillow_image = numpy_to_pillow_image(bitmap)

    return pillow_image.convert('L')

calculate_error: 目標画像と生成された画像の誤差(RMSE)を計算する関数です。今回はモノクロのビットマップだけど、カラーでも同様に最適化できます。

def calculate_error(target_img, generated_img):
    """ RMSEを計算 """
    target_arr = np.array(target_img, dtype=np.float64)
    generated_arr = np.array(generated_img, dtype=np.float64)
    mse = np.mean((target_arr - generated_arr) ** 2)
    rmse = np.sqrt(mse)
    return rmse

simulated_annealing: シミュレーテッドアニーリングを行い、最適な立方体の配置を見つける関数です。これがメインの関数です。3Dグラフィックスを使って特定の画像を再現するために、立方体の配置を最適化する目的の関数です。ランダムな探索と段階的な冷却を組み合わせた関数です。

def simulated_annealing(cubes, target_img, max_iter, start_temp, end_temp, img_size, min_cube_size, max_cube_size):
    """ シミュレーテッドアニーリングのメインループ """
    temp = start_temp
    current_cubes = cubes
    current_img = generate_image(current_cubes, img_size)
    current_error = calculate_error(target_img, current_img)

    for i in range(max_iter):
        new_cubes = current_cubes.copy()
        # ここでランダムに正方形を変更
        cube_index = random.randint(0, len(new_cubes) - 1)
        new_cubes[cube_index] = (
            random.uniform(-5, 5),
            random.uniform(-5, 5),
            random.uniform(-5, 5),
            random.uniform(0, 45),
            random.uniform(min_cube_size, max_cube_size)
        )

        new_img = generate_image(new_cubes, img_size)
        new_error = calculate_error(target_img, new_img)

        if i % 1000 == 0:
            print('new_error',i,new_error)
            #cv2.imshow('rendering',np.array(new_img, dtype=np.uint8))
            #cv2.waitKey(1)

        # エラーが減少するか、確率で更新を受理
        if new_error < current_error or random.random() < math.exp((current_error - new_error) / temp):
            current_cubes = new_cubes
            current_error = new_error

        # 温度を更新
        temp = start_temp * (end_temp / start_temp) ** (i / max_iter)

    return current_cubes

やってみよう!(難易度:★)

最初に走らせておいた探索がうまくいったなら、目的の画像をお好みの画像に差し替えてやってみよう。

お好みの128x128のモノクロビットマップを作成して、下記のコマンドラインを参考に、探索してみてください。一度に多くのパラメータを変更せず、ひとつずつ変更していくことが結果的に近道だよ。人生と同じだね。

探索プログラムパラメータ

python simulated_annealing_3d_art.py --target-img [your_favarit_mono_img.bmp] --num-cubes 200 --max-iter 40000 --start-temp 10.0 --end-temp 0.1 --min-cube-size 0.1 --max-cube-size 0.5
  • --target-img モノクロビットマップファイル
  • --num-cubes 立方体の数
  • --max-iter 最大イテレーション回数
  • --start-temp 開始温度
  • --end-temp 終了温度
  • --min-cube-size 立方体の最小サイズ(一辺の長さ)
  • --max-cube-size 立方体の最大サイズ(一辺の長さ)

処理が終了すると、xxxxx_cubes.pkl ファイルがカレントフォルダーに出力されます。

結果表示プログラムパラメータ

次のコマンドで上記プログラムの出力ファイル(xxxxx_cubes.pkl)を3次元表示できます。

python viewer_3d_art.py --cubes-file xxxxx_cubes.pkl --img-size 128 
  • --cubes-file 探索した立方体の座標ファイル
  • --img-size ビットマップの縦横ピクセル数(正方形)

お好みの画像がうまくいけば、ビットマップのサイズを変更してチャレンジしてみて、目的画像の白と黒の比率に応じて、立方体の数やサイズを変更すると良いよ。

やってみよう!(難易度:★★)

さらに、プログラムを改善して、モノクロだけではなく、グレースケールやカラーへの応用、任意のポリゴンへの応用などに挑戦してね。

また、量子アニーリングマシンで解を得られるようモデリングするのは難易度★★★だね。

難易度の高い課題に挑戦して、良い結果が得られた兵は、連絡ちょうだい。このマグカップをあげたい。(最大5個、無くなり次第終了。)

booth.pm

まとめ

アーティストになる道は、技術と芸術の融合によっても実現できる。私たちが普段目にするもの、感じることは、技術とアートの素晴らしいハーモニーによって生み出されている。私が今回挑戦したのは、シミュレーティッドアニーリングを用いて、技術の力でアートを創造すること。このプロジェクトは、小学4年生のときの私の夢を実現するための一歩だ。

シミュレーティッドアニーリングは、焼きなましのプロセスを模倣したアルゴリズムで、問題解決において最適な解を見つけるための効果的な方法。この技術を使って、3D空間に立方体を配置し、特定のビットマップ画像に近づけることができた。プログラムはシンプルでわずか200行程度だが、その背後にある理論は深い。

この実験は、技術とアートの融合がいかに美しい結果を生むかを示している。プログラムの各ステップ、OpenGLでの立方体の定義、ビューポートの設定、画像の生成、誤差計算、そしてシミュレーティッドアニーリングの適用という流れは、このプロジェクトの核をなす。

アートと技術は、一見異なる分野のように思えるかもしれないが、実際には互いに補完し合い、新しい可能性を生み出す。このプロジェクトは、その一例に過ぎない。技術を使ってアートを創造することに興味があるなら、ぜひ挑戦してみてほしい。そして、そのプロセスを楽しんでほしい。技術とアートの組み合わせによって、新しい扉が開かれるかもしれない。

最後に

最近、描いたタコ。この絵をみて「たこ焼きが食べたくなった」と言っていただければ、私の芸術家への挑戦は続くだろう。

The Nostr 2023 (with Bluesky) - 僕が四谷ラボとともに歩んだ一年間

今日のこのブログ記事は Nostr Advent Calender 第2会場 の25日目の記事になります。

昨日のアドベントカレンダーはkaijiさんの「Nostrではじめる、分散型アプリケーション開発 」と、雨鹿茶房/fei🫑さんの「2023年 Nostrの思い出」でした。

adventar.org

adventar.org

Shino3 こと、しのさんで、しのはらです。

The Nostr (with Bluesky)

2023年という歳をあらためて振り返ってみると、僕にとっても四谷ラボにとっても、Nostr (Blueskyも含む) を主軸として共に過ごしてきた一年だったと改めて思います。今年は僕も久しぶりに四谷ラボの名前をお借りして複数のイベントとともに歩いたとても濃い一年間でした。この記事にて活動を振り返るとともに、今年様々なイベントでご協力いただいた皆様、参加していただいた皆様、また同時に Nostr (with Bluesky) でご一緒させていただいた皆様への感謝とともに、まだ見ぬ Nostr ユーザー、四谷ラボメンバーにも思うことを伝えていければと考えております。

続きを読む

ぼくとBluesky 2023

はいどうも〜!kojiraです!

この記事はBluesky Advent Calendar 2023

adventar.org

の24日の記事です。 23日の記事はみりめいさんのSNS擬人化漫画の本編(3話)です。

それではさっそくいってみましょう!!

2023年は分散型SNSにどっぷり浸かった1年でした。コロナ禍の中、ほとんど誰とも会わない日々が続いていましたが、分散型SNSを始めてしばらくしてから非常に多くの人々と会うことになりました。

スクショや写真を見て思い出しながらひとつひとつを振り返ってみようと思います。

2月25日、Nostrで「Nostrの歌」を作詞して投稿する所からがBlueskyとの本格的(?)な関わりだったかもしれません。NostrではBlueskyへ憧れ、招待コードを手に入れて青空へ飛び立つのを待っている人がたくさんいました。そんなNostr民の気持ちを代弁するかのように作ったのがこの歌でした。(所要時間約10分)

Blueskyへの憧れをうまく表現できていますね(?) そして30分ほどで歌って録音して投稿したものがこちらです。(勢いで録音したのでピッチもブレブレ)

そして、2023年3月3日、ついに先行してBlueskyに参加したKaoriさんからNostrのDMで招待コードをいただき、めでたくBlueskyに参加することができました。

Blueskyに参加した日

当時はまだアカウント数が1500程度しかおらず投稿のほとんどが英語話者で、数少ない日本人も英語で投稿している人が多かったです。 この頃はBluesky開発チームのWhyさんはBluesky参加者全員をフォローしていました。懐かしいですね。

当時のWhyさん。招待コードをひたすらばらまいていた。招待コードが短い!

そして当時はiOSアプリのみでAndroidアプリが存在しておらず、ブラウザでも見ることもできなかったので、AndroidユーザーのためにNostrでこんなクエストを投稿しました。

するとなんと1時間も経たないうちにブラウザでアカウントが作成できるツールができあがってきました。

正常系はテストできていませんってテストしてへんやんと思いつつも、このツールで多くのAndroidユーザーがBlueskyのアカウントを作成することができました。 そしてさらにしばらくすると、タイムラインが取得できるようになります。

スピード速すぎ。当時のNostrは精神と時の部屋としか言いようのない異様な密度で、少しタイムラインから目を離すとすぐに新しい話が生まれてくるので、まったく持って目が離せませんでした。あやしうこそものぐるほしけれ。FOMOることこの上なし。

なんとその深夜にはBluesky勉強会のconnpassが立てられたのでした。

当時はBlueskyの方が人が少なかったので、Nostrでのみ告知されています。 そして3月17日に第一回目のBluesky/ATP勉強会を開催されました。勉強会の配信のアーカイブはこちらです。

そしてWhyさんが日本に3月末に桜を見に来たいという投稿(探すのが大変で見つかりませんでした)を受けて、Nostrでこんなこともしていました。 当時、すでに関東では3月末には桜がほとんど散ってしまっているはずなので、桜が見れないかなあと思っていたためです。

しかし、京都で無事に桜は見れたようです。よかったね! bsky.app

そんな中、3月28日にWhyさんがこんな投稿をしていました。 bsky.app

翻訳: 4月7日から9日の間に東京でブルースカイミートアップを開催したいと考えています、興味のある人はいますか?

私もリプしたのですが、この時はWhyさんからの反応はありませんでした。 そしてBlueskyチームのRoseさんよりWhyさんの投稿に以下の返信があり、メールで協力者を募集していました。 (メールのやり取りは大変そうだったので私からはメールは送りませんでした。)

bsky.app

色んな人からメールが来たようですが、各自バラバラで情報を投げているため、土地勘も何もないRoseさんが取りまとめるのは大変そうでした。複数人の日本人とやり取りするのはまず無理だったと思います。 そこで、すでにBlueskyの勉強会を開催していた私に白羽の矢が立ったようでした。

bsky.app

まずは協力者がバラバラでメールでやり取りするのは大変なのでdiscordのサーバーを立てました。

bsky.app

このサーバーで色々と準備と調整を進め、開催まで約1週間程度しかない状態で100人規模のイベントを開催することとなりました。 まずは日程を4月7日に確定させ、会場は未定でしたが、すぐに集客用のconnpassページを立てました。これで集客はなんとかなりました。 イベントの集客状況はこんな感じ。

集客状況

我ながら1週間でよくここまでオフラインで集客できたなあと思います。

翌日の3月31日に池袋の会場をレンタルスペースサービスで押さえることもできました。 と思ったら、なんとレンタルスペースのサービスから数日後にキャンセルメールが飛んできて、よくよく調べるとその会場はだいぶ前に潰れてしまっていたのでした…。それがわかったのがなんと4月4日の開催三日前!

急遽また会場探しをして、電話をかけまくってその日のうちに銀座の会場を押さえることができました。そしてその流れで、そのまま会場の下見に行き、会場の状態や飲み物、ケータリング、ゴミ出し方法など開催に必要な情報を聞いて準備を整えました。この時は流石に焦りましたね!

なんやかんやあって無事にイベントは開催できました。沢山の方々のご協力感謝します。

現地が夜中3時にも関わらず付き合ってくれたJayさん、Roseさん、Paulさんにも感謝!

イベントの様子はこちら。

イベントは大盛況に終わり、イベント内で招待コードも配られました。 後に定量解析したときに、この時期に参加した人はリテンションが高い事がわかっています。

自作した週毎のリテンションのコホート

Whyさんもかなり喜んでいたようで、私が直接聞いたわけではないのですが「私が以前にミートアップをやった時はこんなにたくさん人も来なかったし寂しかった。でも今回こんな沢山の人が来てくれて活気があってすごく嬉しかった。」というようなことをおっしゃっていたようです。

そして、帰国してからWhyさんがミートアップのことを開発チームに話すと、チーム全員の人が日本に来たい!といっていたというようなことも聞いています。 Whyさんが帰国してからしばらくすると、アメリカのあちこちで毎週のようにミートアップを開催していた投稿がありました。

開発チームの人たちいつ日本に来るのかなあ。当時とはだいぶ状況が変わりましたが、いつか来てくれたら嬉しいですね!

そして4月28日に2回目のBluesky/ATP勉強会の開催。

428lab.connpass.com 配信アーカイブはこちら。

6月2日に3回目のBluesky/ATP勉強会の開催。 この勉強会で登壇し、発表用に開催当日に急ピッチでBlueskyちゃんbotを作成したのでした。 428lab.connpass.com 配信アーカイブはこちら。

connpassでは募集していませんでしたが以下のように5月に企画したOsaka meetupを6月25日に開催しました。 bsky.app

約20名参加し、大盛況のうちに終わりました。ぜひまた開催したいですね!shigeponさんが企画してくれそうですよ!(圧)

そして、9月2日に4回目のBluesky/ATP勉強会の開催。

ここではBlueskyの定量解析で登壇しました。 428lab.connpass.com 配信アーカイブはこちら。

9月16日、100万人突破記念オンライン座談会

座談会という初の試み。 428lab.connpass.com 配信アーカイブはこちら。

9月29日、meetup開催を手伝った人たち向けにBlueskyチームからお礼のグッズが届きました!

現在はアプリのアイコンが🦋になったので、いまグッズが作られると🦋のロゴになるかもしれませんね。

10月22日、第二回オンライン座談会

技術話ではなく難しくならないように緩くやってみました。 428lab.connpass.com

12月8日、NostrとBlueskyの合同オフライン勉強会

初めての大規模オフラインとオンラインハイブリッド開催。 428lab.connpass.com 配信アーカイブはこちら。

12月16日、四谷ラボ忘年会

焼肉とたこ焼きと生ハム原木で大いに盛り上がりました!

428lab.connpass.com

来年もまたたくさん盛り上げていきたいですね! なにか面白そうなことを思いついたらぜひお知らせください!

協力できそうなことであればバックアップします!!

明日(25日)のアドベントカレンダーの最後の記事はHimaさんです!

メリークリスマス! 良いお年を!

技術書典 15 が終わったので収支をまとめてみる。

Shino3(しのさん)です。

この記事は Bluesky アドベントカレンダー 第2会場 一日目の記事になります

adventar.org

翌日は未定ですが、誰かが書いてくれるでしょう・・・。

タイトルにもありますが過去2回、技術書典に参加してきました。以前の記事で技術書典 15 に参戦してきました!という内容のイベントレポートを上げておりました。

今回は私が統括的なことも行っており、最終的にどの程度の金額がかかっていたのかを振り返ってみたいと思います。

結論から申しますと「趣味で出すのはアリ!」なので是非皆様も参加してみてはいかがでしょうか

続きを読む