基本図形の描画3 – 多角形・折れ線【OpenCV】

多角形の描画

多角形を1つ描画する

polylines関数を用いて、画像・頂点のリスト・閉じた図形かどうか・色を指定することで多角形を描画します。頂点の組み合わせは(頂点数 x 2)のndarrayで表し、pts引数にリストとして渡します。

import numpy as np
import cv2
 
img = np.zeros((300, 300, 3), np.uint8)
points = np.array([(50, 50), (100, 50), (250, 200), (180, 250)])
cv2.polylines(img, [points], True, (255, 255, 0))
 
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

ここで指定した頂点の順番に線をつないでいきます。上の例の③と④を入れ替えると次のようになります。

import numpy as np
import cv2
 
img = np.zeros((300, 300, 3), np.uint8)
points = np.array([(50, 50), (100, 50), (180, 250), (250, 200)])
cv2.polylines(img, [points], True, (255, 255, 0))
 
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

多角形を複数描画する

複数の多角形を一度に描画する場合は、頂点の一覧を表すndarrayを多角形の数だけ作成し、リストとしてpolylines関数のpts引数に指定します。

import numpy as np
import cv2
 
img = np.zeros((300, 300, 3), np.uint8)
pts1 = np.array([(50, 50), (100, 50), (250, 200), (180, 250)])
pts2 = np.array([(50, 100), (100, 200), (50, 250)])
cv2.polylines(img, [pts1, pts2], True, (255, 255, 0))
 
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

内部が塗りつぶされた多角形を描画する

多角形を1つ描画する

描画する多角形が1つのみの場合はfillPoly関数よりもfillConvexPoly関数の方が高速なので、fillConvexPoly関数を用います。fillConvexPoly関数では、points引数に頂点の一覧を表すndarrayをそのまま渡すだけで描画可能です。

import numpy as np
import cv2
 
img = np.zeros((300, 300, 3), np.uint8)
points = np.array([(50, 50), (100, 50), (250, 200), (180, 250)])
cv2.fillConvexPoly(img, points, (255, 255, 0))
 
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

多角形を複数描画する

複数の多角形をまとめて描画する場合はfillPoly関数を用います。pts引数に頂点の一覧を表すndarrayを多角形の数だけリストとして渡します。

import numpy as np
import cv2
 
img = np.zeros((300, 300, 3), np.uint8)
pts1 = np.array([(50, 50), (100, 50), (250, 200), (180, 250)])
pts2 = np.array([(50, 100), (100, 200), (50, 250)])
cv2.fillPoly(img, [pts1, pts2], (255, 255, 0))
 
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

RotatedRectを描画する

OpenCVではRotatedRectオブジェクトを描画する関数が、なぜか用意されていません。RotatedRectに内接する楕円はellipse関数で描画できるのですが…

そこで、RotatedRectを描画するには、それぞれの頂点の座標を求めてpolylines関数を用います。

import numpy as np
import math
import cv2
 
def rotatedRectangle(img, rotatedRect, color, thickness=1, lineType=cv2.LINE_8, shift=0):
    (x,y), (width, height), angle = rotatedRect
    angle = math.radians(angle)

    # 回転する前の矩形の頂点
    pt1_1 = (int(x + width / 2), int(y + height / 2))
    pt2_1 = (int(x + width / 2), int(y - height / 2))
    pt3_1 = (int(x - width / 2), int(y - height / 2))
    pt4_1 = (int(x - width / 2), int(y + height / 2))

    # 変換行列
    t = np.array([[np.cos(angle),   -np.sin(angle), x-x*np.cos(angle)+y*np.sin(angle)],
                    [np.sin(angle), np.cos(angle),  y-x*np.sin(angle)-y*np.cos(angle)],
                    [0,             0,              1]])

    tmp_pt1_1 = np.array([[pt1_1[0]], [pt1_1[1]], [1]])
    tmp_pt1_2 = np.dot(t, tmp_pt1_1)
    pt1_2 = (int(tmp_pt1_2[0][0]), int(tmp_pt1_2[1][0]))

    tmp_pt2_1 = np.array([[pt2_1[0]], [pt2_1[1]], [1]])
    tmp_pt2_2 = np.dot(t, tmp_pt2_1)
    pt2_2 = (int(tmp_pt2_2[0][0]), int(tmp_pt2_2[1][0]))

    tmp_pt3_1 = np.array([[pt3_1[0]], [pt3_1[1]], [1]])
    tmp_pt3_2 = np.dot(t, tmp_pt3_1)
    pt3_2 = (int(tmp_pt3_2[0][0]), int(tmp_pt3_2[1][0]))

    tmp_pt4_1 = np.array([[pt4_1[0]], [pt4_1[1]], [1]])
    tmp_pt4_2 = np.dot(t, tmp_pt4_1)
    pt4_2 = (int(tmp_pt4_2[0][0]), int(tmp_pt4_2[1][0]))

    points = np.array([pt1_2, pt2_2, pt3_2, pt4_2])
    cv2.polylines(img, [points], True, color, thickness, lineType, shift)
    return img

img = np.zeros((300, 300, 3), np.uint8)
rotatedRect = ((150, 150), (200, 120), 20)
rotatedRectangle(img, rotatedRect, (255, 255, 0))

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

折れ線の描画

polylines関数のisClosed引数をFalseに設定することで、始点と終点が閉じずに折れ線になります。

import numpy as np
import cv2
 
img = np.zeros((300, 300, 3), np.uint8)
points = np.array([(50, 50), (100, 50), (250, 200), (180, 250)])
cv2.polylines(img, [points], False, (255, 255, 0))
 
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

リファレンス

fillConvexPoly(img, points, color, lineType = cv2.LINE_8, shift = 0)

@ [APIドキュメント]

  • 引数
    • img : 内部を塗りつぶした多角形を描画する画像 <ndarray>
      • 引数として指定したimgにも折れ線(多角形)が上書きされてしまうので注意!
    • points : 多角形の頂点の一覧を表すshapeが(頂点数, 2)のndarray <ndarray>
    • color : 多角形の色 <Scala>
    • lineType : 多角形を描く線の種類(LineTypes列挙型で指定します) <int>
    • shift : 座標の小数点以下の桁を表すビット数 <int>
  • 戻り値
    • img : 多角形が描画された画像 <ndarray>

内部が塗りつぶされた多角形を1つ描画します。fillPolyよりも高速に描画することができます。

fillPoly(img, pts, color, lineType = cv2.LINE_8, shift = 0)

@ [APIドキュメント]

  • 引数
    • img : 内部を塗りつぶした多角形を描画する画像 <ndarray>
      • 引数として指定したimgにも折れ線(多角形)が上書きされてしまうので注意!
    • pts : 多角形の頂点の一覧を表すshapeが(頂点数, 2)のndarrayのリスト <list(ndarray)>
      • 描画する図形が1つのみの場合はリストの中に頂点の組み合わせを表すndarrayが一つだけ含まれます。
      • 描画する図形が複数ある場合は、描画する図形の数だけ頂点の組み合わせを表すndarrayを含むリストとなります。
    • color : 多角形の色 <Scala>
    • lineType : 多角形を描く線の種類(LineTypes列挙型で指定します) <int>
    • shift : 座標の小数点以下の桁を表すビット数 <int>
  • 戻り値
    • img : 多角形が描画された画像 <ndarray>

内部が塗りつぶされた多角形を描画します。複数の多角形を同時に描画することが可能ですが、fillConvexPoly関数よりも描画速度に劣ります。

polylines(img, pts, isClosed, color, thickness = 1, lineType = cv2.LINE_8, shift = 0)

@ [APIドキュメント]

  • 引数
    • img : 折れ線(多角形)を描画する画像 <ndarray>
      • 引数として指定したimgにも折れ線(多角形)が上書きされてしまうので注意!
    • pts : 折れ線(多角形)の頂点の一覧を表すshapeが(頂点数, 2)のndarrayのリスト <list(ndarray)>
      • 描画する図形が1つのみの場合はリストの中に頂点の組み合わせを表すndarrayが一つだけ含まれます。
      • 描画する図形が複数ある場合は、描画する図形の数だけ頂点の組み合わせを表すndarrayを含むリストとなります。
    • isClosed : 折れ線が閉じているかどうかを指定する <bool>
      • True -> 閉じた折れ線(=多角形)が描画される
      • False -> 多角形ではなく折れ線が描画される
    • color : 折れ線(多角形)の色 <Scalar>
    • thickness : 折れ線(多角形)を描く線の太さ <int>
    • lineType : 折れ線(多角形)を描く線の種類(LineTypes列挙型で指定します) <int>
    • shift : 座標の小数点以下の桁を表すビット数 <int>
  • 戻り値
    • img : 折れ線(多角形)が描画された画像 <ndarray>

折れ線、もしくは多角形を描画します。pts引数にリストとして頂点の一覧を渡すことで、複数の図形をまとめて描画することが可能です。
なお、thicknessを負の値にしても内部を塗りつぶすことはできません。内部を塗りつぶした多角形を描画する場合は、fillConvexPoly関数やfillPoly関数を用います。

関連記事・スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です