「Krita」と「Python」でアニメーションを描いてみよう

2024年9月24日(火)
大西 武 (オオニシ タケシ)
第6回の今回は「Krita」で「Python」をプログラミングして、正方形が回転するアニメーションを作成する解説をします。

はじめに

静止画も良いですが、アニメーションも作れると楽しいですよね。今回は簡単なアニメーションの作り方を解説します。アニメーションと言っても、これまでの連載で解説してきたことを応用すれば同様に作れます。

アニメーションは静止画をたくさん描いて、順番に1秒間に30コマなど一度に1枚ずつ切り替えて表示するだけです。まさに子どもの頃ノートにパラパラ漫画を描いたのと全く同じ原理です。1秒間に30コマで再生することを「30FPS(Frames per second)」とも言います。最近のゲームでは60FPS以上のもありますね。FPSが大きいほど滑らかにアニメーションできます。

アニメーションを作る

まず、画像をランダムな1色ずつで塗りつぶしたアニメーションを作ります(図1)。次に正方形が1個ずつ現れて回転するアニメーションを作ります。できればキャラクターが喋ったりといったアニメーションの方がそれらしいのですが、本連載はプログラミングしてKritaを扱う内容なので、幾何学的な図形にしました。

図1:1色ずつだけのアニメーション

最も単純なアニメーションを作る

まず「ウィンドウ」→「ワークスペース」→「Animation」メニューを選択して、メインウィンドウをアニメーションワークスペースにしてください。スクリプトを「▷(実行)」すると、しばらくの間1コマずつ150枚の絵が描かれるのを待ってください。150枚の絵が完成したら、メインウィンドウの方の「▶(再生)」ボタンを押してアニメーションを再生してください。ランダムに色が変化するだけのアニメーションが表示されましたか?

ここでは、これまでと違って描いた画像をpngファイルに保存します。その方が複数の画像を扱いやすいからです。pngファイルは「tempfile.mkdtemp」関数で一時フォルダを作ってその中に保存し、アニメーションができたら「shutil.rmtree」関数で一時フォルダを削除します。

・サンプルスクリプト「animation.py」
# モジュール
import tempfile
import shutil
import os.path
import random
from krita import *
from PyQt5.Qt import *
# 正方形のリスト
rects = []
# 正方形とフレームの数
RECTS_NUM = 150
# ドキュメントの作成
def create_doc(width,height):
  doc = Krita.instance().createDocument(width, height, "Animation", "RGBA", "U8", "", 300.0)
  Krita.instance().activeWindow().addView(doc)
  return doc 
# フレームごとに描画して一時ファイルに保存して動画に
def insertFrames(doc, maxFrames):
  tmpPath = tempfile.mkdtemp()
  files = []
  for index in range(maxFrames):
    fileName = os.path.join(tmpPath, f"tmp{index:04}.png")
    files.append(fileName)
    img = draw_rect(doc,index)
    img.save(fileName)
  doc.importAnimation(files,0,1)
  doc.setFullClipRangeEndTime(maxFrames-1)
  shutil.rmtree(tmpPath)
# 1色ずつの塗りつぶし描画
def draw_rect(doc,num):
  pixmap = QPixmap(doc.bounds().size())
  pixmap.fill(QColor(random.randint(0,255),random.randint(0,255),random.randint(0,255),255))
  return pixmap.toImage()
# メイン関数
def begin_draw():
  doc = create_doc(800,800)
  doc.setFramesPerSecond(30)
  insertFrames(doc,RECTS_NUM)
# メイン関数の呼び出し
begin_draw()

【サンプルスクリプトの解説】
フレームの数は「RECTS_NUM」変数の150コマです。
「create_doc」関数は今までの連載と同じです。
「insertFrames」関数で一時フォルダに「draw_rect」関数で描いた画像をpngファイルに保存します。
そのpngファイル名を「files」リストに追加して、アニメーションワークスペースに読み込みます。
「draw_rect」関数でランダムな1色で画像を塗り潰し(fill)してQImageを返します。
「begin_draw」関数で30FPSにセット(setFramesPerSecond)し、insertFrames関数を呼び出します。

正方形が回転するアニメーションを作る

今度は、色が変化するだけのサンプルスクリプト「animation.py」を改造して150個の正方形のデータをランダムに用意し、1コマずつ1枚ずつの正方形を追加しながらその場で回転させます。

スクリプトを「▷(実行)」してしばらくすると、1コマずつ150枚の絵が描かれます。150枚の絵が完成したら、メインウィンドウの方の「▶(再生)」ボタンを押してアニメーションを再生してください。徐々に正方形が現れてきてそれぞれ回転するアニメーションをしましたか(図2)?

図2:正方形が回転するアニメーション

・サンプルスクリプト「rotate_animation.py」
(前略)
# 回転しながら正方形の描画
def draw_rect(doc,num):
  pixmap = QPixmap(doc.bounds().size())
  pixmap.fill(QColor(Qt.transparent))
  painter = QPainter()
  painter.begin(pixmap)
  for index,rect in enumerate(rects):
    pen = QPen(QColor(255,255,255))
    painter.setPen(pen)
    brush = QBrush(rect[0])
    painter.setBrush(brush)
    painter.save()
    painter.translate(rect[1],rect[2])
    painter.rotate(num*8)
    size = rect[3]
    painter.drawRect(int(-size/2),int(-size/2),size,size)
    painter.restore()
    if index > num: break
  painter.end()
  return pixmap.toImage()
# 正方形の初期化
def init_rect(doc,num):
  for i in range(0,num):
    rnd = random.randint(0,359)
    color = QColor.fromHsl(rnd, 255, 128, 192)
    cx = doc.width()
    cy = doc.height()
    x = random.randint(0,cx)
    y = random.randint(0,cy)
    size = random.randint(int(cx/10),int(cy/5))
    rects.append([color,x,y,size])
# メイン関数
def begin_draw():
  doc = create_doc(800,800)
  doc.setFramesPerSecond(30)
  init_rect(doc,RECTS_NUM)
  insertFrames(doc,RECTS_NUM)
# メイン関数の呼び出し
begin_draw()

【サンプルスクリプトの解説】
「draw_rect」関数で半透明な正方形を描きます。正方形の「rects」リストには150個の正方形の情報が入っていますが、forループで「index」インデックスの数がフレーム番号「num」引数より大きくなるとループを抜け出して正方形の描画をストップします。正方形を変形行列で回転(rotate)する中心位置を平行移動(translate)しています。その前に変形行列の値を保存(save)してその後に復元(restore)します。
「init_rect」関数で正方形を150個ランダムな色でランダムな位置にランダムなサイズで作成したリストをrectsリストに追加します。
「begin_draw」関数でinit_rect関数も呼び出します。

アニメーションをファイルに保存する

完成したアニメーションはmp4などの動画ファイルに保存できます。メインウィンドウの「ファイル」→「アニメーションを出力」メニューを実行します(図3)。下表のように入力したら「OK」します。他にもアニメーションGIFなどにも出力できます。

図3:「アニメーションを出力」ダイアログ

最初のフレーム 開始フレーム
最後のフレーム 終了フレーム
Export as video チェックを入れる
出力 MPEG-4動画
動画の場所 mp4ファイル名
FFmpeg location 恐らく最新版のKritaでは「FFmpeg(動画エンコーダー)」がプリインストールされるが、なければ検索・ダウンロードして指定
【コラム】Kritaの最新版「5.2.3」がリリース

今さら気づいたのですが、2024年6月25日にKritaの最新バージョン「5.2.3」がリリースされていました。日本語版ではまだ英語表示だったところの一部が日本語表示になっているなどの変更点があるようです。

リリースノートで紹介されているアニメを見て思ったのですが、タイトル画面やエンディング画面を今回の動画に足せばちょっと作品っぽくなるかもしれません。

おわりに

今回はシンプルなアニメーションを作成しました。アニメーションと言っても静止画を複数描いて順番にパラパラ漫画のように表示するだけです。また、今回は描いた画像をpngファイルに保存して使用しました。

著者
大西 武 (オオニシ タケシ)
1975年香川県生まれ。大阪大学経済学部経営学科中退。プログラミング入門書など30冊以上を商業出版する作家。Microsoftで大賞やNTTドコモでグランプリなど20回以上全国区のコンテストに入賞するアーティスト。オリジナルの間違い探し「3Dクイズ」が全国放送のTVで約10回出題。
https://profile.vixar.jp

連載バックナンバー

開発言語技術解説
第6回

「Krita」と「Python」でアニメーションを描いてみよう

2024/9/24
第6回の今回は「Krita」で「Python」をプログラミングして、正方形が回転するアニメーションを作成する解説をします。
開発言語技術解説
第5回

「Krita」と「Python」で「ベジェ曲線」を描いてみよう

2024/9/5
第5回の今回は「Krita」でベジェ曲線のフキダシを描いたり、指定したフォントで文字を書いたりする解説をします。
開発言語技術解説
第4回

「Krita」と「Python」でアーティスティックな絵を描こう

2024/8/16
第4回の今回は「Krita」で数学を用いたプログラミングをして、アーティスティックな絵を描く解説をします。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています