クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

三角形の塗りつぶし

このレッスンのあとで: ピクセルが三角形の内側にあるかを、辺のテストで判定できる。

75分のレッスンコマンド2件コンピュータビジョンラボ:JupyterLab でピクセル、しきい値、物の数え方

三角形の中のピクセルを見つける

三角形の塗りつぶしとは、三角形の中にあるピクセルを見つけて、色をつけることです。ゲームや3D の絵は、小さな三角形をたくさん塗って作られています。

このレッスンでは、辺のテストで、ピクセルが三角形の中にあるかを調べます。さらに、重心座標という重みで、点の位置を表します。

このレッスンのゴール

メモ

ピクセルが三角形の内側にあるかを、辺のテストで判定できる。

キーワード

ことばいみ
頂点三角形の角の点
辺のテスト点が辺のどちら側かを、符号で調べる計算
内側3つの辺の、同じ側にある場所
バウンディングボックス三角形をぴったり囲む四角
重心座標点を3つの頂点の重みで表したもの

学生が入力するセルは、このプレビューでは空白です。

辺のテストは、点が辺のどちら側かを教える

三角形の1つの辺を、a から b への矢印と考えます。点 p が矢印のどちら側にあるかは、ある計算の符号で決まります。

計算は、(bx − ax) × (py − ay) − (by − ay) × (px − ax) です。この値が正なら一方の側、負ならもう一方の側、0 なら辺の上です。

辺 (0, 0) から (6, 0) のテストの例

点 p計算値位置
(2, 3)6 × 3 − 0 × 218正の側
(2, -1)6 × (-1) − 0 × 2-6負の側
(8, 0)6 × 0 − 0 × 80辺の上

学生が入力するセルは、このプレビューでは空白です。

内側は、3つの辺のテストが同じ向きの点

点が三角形の内側にあるのは、3つの辺のテストの値が、すべて同じ向きのときです。つまり、すべて 0 以上か、すべて 0 以下です。

1つでも向きが違えば、外側です。辺の上の点、つまり値が 0 の点は、この課題では内側に数えます。

三角形 (0, 0)、(6, 0)、(0, 6) の判定

点3つのテストの値判定
(1, 1)6、24、6内側。すべて正
(5, 5)30、-24、30外側。向きが混ざる
(3, 3)18、0、18内側。1つは辺の上

学生が入力するセルは、このプレビューでは空白です。

3つの辺のテストの値を出す

コード: python
def side(start, end, point):
    return (end[0] - start[0]) * (point[1] - start[1]) - (end[1] - start[1]) * (point[0] - start[0])

a = [0, 0]
b = [6, 0]
c = [0, 6]
p = [1, 1]
print(side(a, b, p), side(b, c, p), side(c, a, p))
# p を [5, 5] に変えて、もう一度実行します。
# 3つの値の符号は、そろっていますか。

よくある間違い

注意

内側の判定は、1つの辺を調べればよいと考えがちです。1つの辺のテストは、辺の片側すべてを内側にしてしまいます。3つの辺がすべて同じ向きのときだけ、内側です。

調べるのは、バウンディングボックスの中だけ

塗るときは、画面のすべてのピクセルを調べる必要はありません。三角形をぴったり囲む四角、バウンディングボックスの中だけを調べれば十分です。

四角の中の各ピクセルが、内側かどうかを判定し、内側なら色をつけます。内側の数を数えれば、塗ったピクセルの数が分かります。

Pillow で三角形を塗って数える

Pillow の polygon は、多角形を塗りつぶします。次のコマンドは、16 × 16 の黒い画像に、(0, 0)、(15, 0)、(0, 15) の三角形を白で塗り、triangle.png に保存します。

triangle.png を開くと、左上が白い直角三角形が見えます。白いピクセルの数は 136 です。これは、x と y が 0 以上で、x + y が 15 以下の点の数と同じです。

三角形を塗って triangle.png に保存

コマンド
docker exec jupyter python3 -c "from PIL import Image, ImageDraw; im = Image.new('L', (16, 16), 0); ImageDraw.Draw(im).polygon([(0, 0), (15, 0), (0, 15)], fill=255); im.resize((160, 160), Image.NEAREST).save('triangle.png'); print(sum(1 for p in im.getdata() if p)); print(im.getpixel((2, 2)), im.getpixel((14, 14)))"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

重心座標は、点を3つの頂点の重みで表す

三角形の中の点は、3つの頂点の重みつき平均で表せます。この3つの重みを重心座標と呼びます。重みは、足すと 1 になります。

重みは、点の向かい側にできる小さな三角形の面積を、全体の面積で割った値です。重みがすべて 0 以上なら、点は内側にあります。色を頂点の間でなめらかに変えるときにも使います。

点 (1, 1) の3つの重みを求める

次のコマンドは、三角形 (0, 0)、(4, 0)、(0, 4) の中の点 (1, 1) について、3つの重みを求めます。全体の面積は 8 で、3つの小さな三角形の面積は 4、2、2 です。

出力は 0.5 0.25 0.25 で、足すと 1 です。最初の頂点 (0, 0) に近い点なので、その重みがいちばん大きくなります。

面積の比で3つの重みを求める

コマンド
docker exec jupyter python3 -c "a = (0, 0); b = (4, 0); c = (0, 4); p = (1, 1); area = lambda u, v, w: abs((v[0] - u[0]) * (w[1] - u[1]) - (w[0] - u[0]) * (v[1] - u[1])) / 2; t = area(a, b, c); print(area(p, b, c) / t, area(a, p, c) / t, area(a, b, p) / t)"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

このラボとソースについて: コンピュータビジョンラボ:JupyterLab でピクセル、しきい値、物の数え方

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。