「Krita」と「Python」のクラスでアニメーション動画を作ろう
はじめに
今回は、クラスを使ってアニメーション動画を作成します。まず、表示する画像ファイルをファイルダイアログで開きます。それから「アルキメデスの螺旋」に沿って、その画像が1個ずつ追加されていくだけのアニメーションをします。アルキメデスの螺旋とは、要するに渦巻き状の螺旋のことです。
クラスを使って動画の作成
「クラスを使う」と言っても、今までにやってきたことを応用すれば簡単にアニメーション動画を作れます。ゲームプログラミングよりさらに一歩手前の、絵を扱うだけのプログラミングをすることでPython3を簡単に学習するのが本連載の狙いですが、簡単過ぎて物足りないかも知れません。
背景色だけの静止動画
まずは、アニメーションする前にクラスを使って動画を作るテンプレートを作ってみます。単純に第6回の解説をクラス化しただけです。まだ画像ファイルは扱いません。
サンプルをスクリプティングしたら「ウィンドウ」→「ワークスペース」→「Animation」を選択し、画像が90個準備できたら「アニメーションタイムライン」の「▶」でアニメーションを再生できます。まだ静止画像です。
・サンプルスクリプト「class_green.py」# モジュール import tempfile import shutil import os.path from krita import * from PyQt5.Qt import * # クラス class Animation(): # ドキュメント作成 def create_doc(self,width,height): self.doc = Krita.instance().createDocument(width, height, "Testing animation", "RGBA", "U8", "", 300.0) Krita.instance().activeWindow().addView(self.doc) # アニメーションフレーム def insertFrames(self, nbFrames): tmpPath = tempfile.mkdtemp() files = [] for imgNumber in range(nbFrames): fileName = os.path.join(tmpPath, f"tmp{imgNumber:04}.png") files.append(fileName) image = self.draw_img(imgNumber) image.save(fileName) self.doc.importAnimation(files, 0, 1) self.doc.setFullClipRangeEndTime(nbFrames - 1) shutil.rmtree(tmpPath) # 画像の描画 def draw_img(self,number): pixmap = QPixmap(self.doc.bounds().size()) pixmap.fill(QColor(0,128,0)) return pixmap.toImage() # メイン処理 def create(self): self.create_doc(800,800) self.doc.setFramesPerSecond(8) self.insertFrames(90) # インスタンスの生成 ins = Animation() ins.create()
【サンプルスクリプトの解説】
「create_doc」メソッドと「insertFrames」メソッドは第6回をクラス化しただけです。
「draw_img」メソッドで背景を緑色に塗り潰します。
「create」メソッドでドキュメントを作成し1秒間に8コマ(8FPS)にセットし、90コマの動画を作成します。
「Animation」クラスのインスタンスを作成し、「create」メソッドを実行します。
読み込んだ画像をアルキメデスの螺旋状に描画する動画
それでは、図2を右クリックメニューで画像を名前を付けて保存してください。この画像使って、この画像が1個ずつ増えていくだけのアニメーションを作ります。
ちょっと工夫したのは、アルキメデスの螺旋状に広がっていくところです。アルキメデスの螺旋は、次の計算式のように円周の角度が回っていくうちに徐々に円の半径が大きくなっていくだけの単純な計算です。
「アルキメデスの螺旋」の計算
求める座標(X,Y)
X = cosθ*円の半径
Y = sinθ*円の半径
円の半径 += 増分
(ただし実際の計算はサンプルスクリプト「class_animation.py」では「translate」メソッドと「rotate」メソッドに内包されている。一般にプログラミング言語の数学ライブラリのsin関数とcos関数は円の半径1とした場合の値が取得できる。長さ1にすることを正規化するという)
(前略) # 画像ファイルを開く def open_img(self): self.pix = QPixmap(self.doc.bounds().size()) filter = str('Supported Files (*.jpg *.png);;All files (*)') fileName = QFileDialog.getOpenFileName(None,str(''),str(''),filter) self.pix.load(fileName[0]) (中略) # 画像の描画 def draw_img(self,number): pixmap = QPixmap(self.doc.bounds().size()) pixmap.fill(QColor(Qt.transparent)) painter = QPainter() painter.begin(pixmap) cx = int(self.doc.width()/2) cy = int(self.doc.height()/2) for i in range(0,number): painter.save() painter.translate(cx,cy) painter.rotate(i*64) painter.drawPixmap(i*6,0,self.pix) painter.restore() painter.end() return pixmap.toImage() # メイン処理 def create(self): self.create_doc(800,800) self.open_img() self.doc.setFramesPerSecond(8) self.insertFrames(90) # インスタンスの生成 ins = Animation() ins.create()
【サンプルスクリプトの解説】
「open_img」メソッドでファイルダイアログで画像ファイルを開きます。
「draw_img」メソッドでアルキメデスの螺旋状に画像を1個ずつ描画(「drawPixmap」メソッド)していきます。
「create」メソッドでドキュメントを作成し、ファイルダイアログで画像を開き、8FPSにセットし、90コマのアニメーションを動画にします。
筆者は「プログラミング」「3DCG」「2DCG」「デザイン」「文筆」「音楽」「動画」など、クリエイティブは全て網羅してきたつもりでした。でも「Think IT」の記事を読んでいると「まだまだ手を付けていない分野が山ほどあるなぁ」と思い知らされます。
これらについては、今後Think ITで解説していきたいと思います。
おわりに
今回は、第6回で解説したアニメーションをクラスを使ってプログラミングする方法を解説しました。さらに、ファイルダイアログで開いた画像でアニメーション動画を作ってみました。