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

2024年8月16日(金)
大西 武 (オオニシ タケシ)
第4回の今回は「Krita」で数学を用いたプログラミングをして、アーティスティックな絵を描く解説をします。

はじめに

今回は前回の応用例として、もっと意味のある図形を描くために「三角関数」の「sin(正弦)」と「cos(余弦)」を使います。三角関数は要するに円周上の(X,Y)座標に関する計算を三角形を用いて計算するようなものです。

今回のサンプルはほとんど前回のテンプレートに書き足すだけです。まずラインを1本とSIN波とCOS波を描きます。次に円1個と色相12色の円を描いて、新規レイヤーを作成していきます。

SIN波とCOS波を描く

SIN波とCOS波は短い直線をたくさん繋げて曲線のように見せています。人間の人差し指を曲げてみてください。3本の直線の骨が曲がっていますが、少し曲線にも見えますね。

1本のラインを描く

前回のテンプレート「template.py」を参考に、サンプルスクリプト「line.py」のようにスクリプティングして「▷(実行)」ボタンを押すと、黒い1本のラインが描画されます(図1)。

今回は図形の境界が滑らかに見えるように「アンチエイリアス」をかけます。Windows標準の文字はズームしてみると塗りの境界がギザギザで、PDFファイルの文字の方が塗りの境界が滑らかに見えますよね。あれはアンチエイリアスがかかっているからです。

図1:1本のラインを描画

・サンプルスクリプト「line.py」
01# モジュール
02from PyQt5.Qt import *
03import math
04# ドキュメントの作成
05def create_doc(width,height):
06  doc = Krita.instance().createDocument(width,height, "Document name", "RGBA", "U8", "", 300.0)
07  Krita.instance().activeWindow().addView(doc)
08  return doc
09# 直線の描画
10def draw_line(doc):
11  pixmap = QPixmap(doc.bounds().size())
12  pixmap.fill(QColor(255,255,255,255))
13  painter = QPainter()
14  painter.begin(pixmap)
15  painter.setRenderHint(QPainter.Antialiasing,True)
16  pen = QPen(QColor(0,0,0,255))
17  pen.setWidth(50)
18  painter.setPen(pen)
19  painter.drawLine(0,0,800,800)
20  painter.end()
21  return pixmap.toImage()
22# レイヤーのセット
23def set_layer(doc,img):
24  # 修正箇所
25  root = doc.rootNode()
26  # 修正箇所
27  layer = root.childNodes()[0]
28  if img.sizeInBytes() == 4 * layer.channels()[0].channelSize() * doc.width() * doc.height():
29    ptr = img.bits()
30    ptr.setsize(img.byteCount())
31    layer.setPixelData(QByteArray(ptr.asstring()), 0, 0, doc.width() , doc.height())
32  else:
33    print('Error')
34# メイン関数
35def begin_draw():
36  doc = create_doc(800,800)
37  img = draw_line(doc)
38  set_layer(doc,img)
39  doc.refreshProjection()
40# メイン関数の呼び出し
41begin_draw()

【サンプルスクリプトの解説】
「draw_line」関数で直線を描画します。
イメージのデータを「pixmap」変数に代入し、真っ白に塗り潰し(fill)ます。
「QPainter」クラスのインスタンスを「painter」変数に代入し、pixmap変数への図形の描画を開始(「begin」メソッド)します。
「setRenderHint」メソッドで図形にアンチエイリアスをかける設定をします。
「QPen」クラスで線(輪郭)の色を黒色に指定し、太さを50に指定して(X,Y)座標の(0,0)と(800,800)を繋いで直線を描画します。
「end」メソッドで「pixmap」変数への描画を終了し、「QImage」クラスに変換したデータを戻り値として返します。
「begin_draw」関数の「create_doc」関数で800x800pxのドキュメントを作成し、draw_line関数を呼び出します。

SIN波を描く

サンプルスクリプト「line.py」に追記し、サンプルスクリプト「sin.py」のようにスクリプティングして「▷(実行)」ボタンを押せば、SIN波の曲線が描かれます(図2)。

正弦を取得する「sin」関数には引数に角度ではなく円周率の「ラジアン」を渡します。ラジアンとは円1周の360度を「2π(パイ)」とした場合の度を表します。

図2:SIN波の描画

・サンプルスクリプト「sin.py」
01(前略)
02# 曲線の描画
03def draw_line(doc):
04  pixmap = QPixmap(doc.bounds().size())
05  pixmap.fill(QColor(255,255,255,255))
06  painter = QPainter()
07  painter.begin(pixmap)
08  painter.setRenderHint(QPainter.Antialiasing,True)
09#  pen = QPen(QColor(0,0,0,255))
10#  pen.setWidth(50)
11#  painter.setPen(pen)
12#  painter.drawLine(0,0,800,800)
13  draw_sin(doc,painter)
14  painter.end()
15  return pixmap.toImage()
16# SIN波の描画
17def draw_sin(doc,painter):
18  for i in range(0,doc.width()):
19    color = QColor.fromHsl(i%360, 255, 128, 255)
20    pen = QPen(color)
21    pen.setWidth(5)
22    painter.setPen(pen)
23    x1 = i
24    radian = math.radians(x1)
25    y1 = doc.height()/2-90*math.sin(radian)
26    x2 = i+1
27    radian = math.radians(x2)
28    y2 = doc.height()/2-90*math.sin(radian)
29    painter.drawLine(x1,int(y1),x2,int(y2))
30(後略)

【サンプルスクリプトの解説】
「draw_line」関数で「draw_sin」関数を呼び出します。
スクリプトを「#(コメントアウト)」すると、その行のスクリプトは実行されません。#を書く代わりにその1行を削除しても構いません。
「draw_sin」関数でSIN波を描画します。
曲線の色は色相を変えて描くので「fromHsl」クラスメソッドで0~360未満の整数で表します。
(X,Y)座標=(i,中心-90*sin(iのラジアン))です。ただし直線をひくので、そこから(i+1,中心-90*sin(i+1のラジアン))へのライン(drawLine)を描きます。

COS波を描く

サンプルスクリプト「sin.py」に追記し、サンプルスクリプト「cos.py」のようにスクリプティングして「▷(実行)」ボタンを押せば、SIN波に重なってCOS波も描かれます(図3)。

余弦を取得する「cos」関数も「sin」関数同様、引数にラジアンを渡します。角度からラジアンに変換する中身は「ラジアン=角度*2*π/360」で計算します。πは約3.141592です。

図3:SIN波とCOS波の描画

・サンプルスクリプト「cos.py」
01(前略)
02# 曲線の描画
03def draw_line(doc):
04  pixmap = QPixmap(doc.bounds().size())
05  pixmap.fill(QColor(255,255,255,255))
06  painter = QPainter()
07  painter.begin(pixmap)
08  painter.setRenderHint(QPainter.Antialiasing,True)
09  draw_sin(doc,painter)
10  draw_cos(doc,painter)
11  painter.end()
12  return pixmap.toImage()
13# COS波の描画
14def draw_cos(doc,painter):
15  for i in range(0,doc.width()):
16    color = QColor.fromHsl(i%360, 255, 128, 255)
17    pen = QPen(color)
18    pen.setWidth(5)
19    painter.setPen(pen)
20    x1 = i
21    radian = math.radians(x1)
22    y1 = doc.height()/2-90*math.cos(radian)
23    x2 = i+1
24    radian = math.radians(x2)
25    y2 = doc.height()/2-90*math.cos(radian)
26    painter.drawLine(x1,int(y1),x2,int(y2))
27(後略)

【サンプルスクリプトの解説】
「draw_line」関数で「draw_cos」関数も呼び出します。
「draw_cos」関数でCOS波を描画します。
曲線の色は色相を変えて描くので「fromHsl」クラスメソッドで0~360未満の整数で表します。
(X,Y)座標=(i,中心-90*cos(iのラジアン))です。ただし直線をひくので、そこから(i+1,中心-90*cos(i+1のラジアン))へのラインを描きます。

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

連載バックナンバー

開発言語技術解説
第15回

「Krita」と「Python」でUIパーツを使って「ドッキングパネル」を構築する

2025/4/11
第15回の今回は「Krita」のメインUIの右側にあるエリアにドッキングするパネルにUIパーツを配置して構築する解説をします。
開発言語技術解説
第14回

「Krita」と「Python」でプラグインを作ろう

2025/3/21
第14回の今回は「Krita」で「Python」スクリプトを「プラグイン」にしたり、「ショートカットキー」をセットする解説をします。
開発言語技術解説
第13回

「Krita」と「Python」でオリジナルの幾何学模様を作ろう

2025/2/27
第13回の今回は「Krita」の「Python」でダイアログUIにUIパーツを貼り付けて操作できるようにして、オリジナルの幾何学模様を作成できるプログラムを解説します。さらにアニメーションも作ります。

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

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

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

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