Pynote

Python、機械学習、画像処理について

OpenCV - 描画系の関数まとめ / 長方形、円、テキストを画像に描画する。

概要

OpenCV の描画系関数をサンプルコード付きでまとめた。

import cv2
import matplotlib.pyplot as plt
import numpy as np

def imshow(img):
    plt.imshow(img[...,::-1])
    plt.axis('off')
    plt.show()

描画系の関数の共通の仕様

  • 図形を描画する関数は thickness 引数を負の値にすると、塗りつぶしになる。
  • 描画は inplace で行われる。つまり、第1引数に渡した画像に直接描画される。
  • shift でオフセットを指定できる。例えば、line() 関数の場合、始点を pt1、終点を pt2 で指定するが、オフセットを加算して shift + pt1, shift + p2 として描画される。これは ROI の座標で指定して、元の画像に描画する際に使用できる。

矢印を描画する。

arrowedLine()

arrowedLine()

img = cv2.arrowedLine(
    img, pt1, pt2, color[, thickness[, line_type[, shift[, tipLength]]]])
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • pt1: 始点
    • pt2: 終点
    • color: 色
    • thickness: 太さ
    • line_type: 線の種類
    • shift: オフセット
    • tipLength: 矢印の長さに対する末端の長さ
  • 返り値
    • img: 描画結果

サンプルコード

img = np.zeros((300, 300, 3), dtype=np.uint8)
cv2.arrowedLine(img, (50, 50), (250, 250), color=(255, 0, 0), thickness=2)
imshow(img)


円を描画する。

circle()

circle()

img = cv2.circle(img, center, radius, color[, thickness[, lineType[, shift]]])
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • center: 中心
    • radius: 半径
    • color: 色
    • thickness: 太さ。負の値で塗りつぶし。
    • lineType: 線の種類
    • shift: オフセット
  • 返り値
    • img: 描画結果

サンプルコード

塗りつぶさないで円を描画する。
img = np.zeros((300, 300, 3), dtype=np.uint8)
cv2.circle(img, (150, 150), 100, color=(255, 0, 0), thickness=2)
imshow(img)


塗りつぶして円を描画する。
img = np.zeros((300, 300, 3), dtype=np.uint8)
cv2.circle(img, (150, 150), 100, color=(255, 0, 0), thickness=-1)
imshow(img)


輪郭を描画する。

drawContours()

drawContours()

image = cv2.drawContours(image, contours, contourIdx,
                        color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
  • 引数
    • image: 描画対象の画像 (inplace で描画される)
    • contours: 輪郭一覧
    • contourIdx: 輪郭一覧のうち、描画する輪郭のインデックス。すべての輪郭を描画する場合は負の値を指定する。
    • color: 色
    • thickness: 線の太さ。負の値で塗りつぶし。
    • lineType: 線の種類
    • hierarchy: 輪郭の階層構造。maxLevel を指定する場合に渡す。
    • maxLevel: 階層の深さいくつまで描画するか。
      • 0の場合は contourIdx で指定した輪郭のみ描画する。
      • 1以上の場合は、指定した深さの輪郭まで描画する。
      • offset: オフセット
  • 返り値
    • image: 描画した画像

サンプルコード

画像から輪郭を抽出する。

サンプル画像

# 画像を読み込む。
img = cv2.imread('sample.png')

# 輪郭抽出する。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
塗りつぶさないですべての輪郭を描画する。

contourIdx=-1 とすると、すべての輪郭を描画する。

# すべての輪郭を描画
ret_img = cv2.drawContours(img.copy(), contours, -1, color=(0, 255, 0), thickness=3)
imshow(ret_img)


塗りつぶしてすべての輪郭を描画する。
# 塗りつぶし
ret_img = cv2.drawContours(img.copy(), contours, -1, color=(0, 255, 0), thickness=-1)
imshow(ret_img)


指定した輪郭を描画する。

輪郭のリストの contourIdx で指定したインデックスの輪郭のみ描画する。

# 指定したインデックスの輪郭を描画
ret_img = cv2.drawContours(img.copy(), contours, 2, color=(0, 255, 0), thickness=3)
imshow(ret_img)


単一の輪郭を描画する。

単一の輪郭を描画するには、リストにする。

# 1つの輪郭を描画する場合、リストにする。
cnt = contours[0]
ret_img = cv2.drawContours(img.copy(), [cnt], -1, color=(0, 255, 0), thickness=3)
imshow(ret_img)


マーカーを描画する。

drawMarker()

drawMarker()

img = cv2.drawMarker(
    img, position, color[, markerType[, markerSize[, thickness[, line_type]]]])
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • position: 位置
    • color: 色
    • markerType: マーカーの種類
    • thickness: 線の太さ。負の値で塗りつぶし。
    • lineType: 線の種類
  • 返り値
    • img: 描画した画像
  • markerType で指定できる種類
    • cv2.MARKER_CROSS
    • cv2.MARKER_TILTED_CROSS
    • cv2.MARKER_STAR
    • cv2.MARKER_DIAMOND
    • cv2.MARKER_SQUARE
    • cv2.MARKER_TRIANGLE_UP
    • cv2.MARKER_TRIANGLE_DOWN

サンプルコード

markers = {'cv2.MARKER_CROSS': cv2.MARKER_CROSS, 
           'cv2.MARKER_TILTED_CROSS': cv2.MARKER_TILTED_CROSS, 
           'cv2.MARKER_STAR': cv2.MARKER_STAR, 
           'cv2.MARKER_DIAMOND': cv2.MARKER_DIAMOND, 
           'cv2.MARKER_SQUARE': cv2.MARKER_SQUARE, 
           'cv2.MARKER_TRIANGLE_UP': cv2.MARKER_TRIANGLE_UP, 
           'cv2.MARKER_TRIANGLE_DOWN': cv2.MARKER_TRIANGLE_DOWN}

fig, axes = plt.subplots(figsize=(10, 10))
for i, (title, marker) in enumerate(markers.items(), 1):
    img = np.zeros((100, 100, 3), dtype=np.uint8)
    cv2.drawMarker(img, (50, 50), color=(255, 0, 0),
                   markerType=marker, thickness=2)

    plt.subplot(3, 3, i)
    plt.title(title)
    plt.imshow(img[..., ::-1])
    plt.axis('off')

plt.show()


楕円を描画する。

ellipse()

ellipse()

img = cv2.ellipse(img, center, axes, angle, startAngle, endAngle,
                  color[, thickness[, lineType[, shift]])
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • center: 中心
    • axes: 長径、短径
    • angle: 回転角度
    • startAngle: 円弧開始角度
    • endAngle: 円弧終了角度
    • color: 色
    • thickness: 太さ。負の値で塗りつぶし。
    • line_type: 線の種類
    • shift: オフセット
  • 返り値
    • img: 描画結果


サンプルコード

塗りつぶさないで楕円を描画する。
# 回転角度 45°、円弧の範囲 0° ~ 360°
img = np.zeros((300, 300, 3), dtype=np.uint8)
cv2.ellipse(img, (150, 150), (50, 70), angle=45, startAngle=0, endAngle=360,
            color=(255, 0, 0), thickness=2)
imshow(img)


塗りつぶして楕円を描画する。
# 回転角度 45°、円弧の範囲 0° ~ 360°
img = np.zeros((300, 300, 3), dtype=np.uint8)
cv2.ellipse(img, (150, 150), (50, 70), angle=45, startAngle=0, endAngle=360,
            color=(255, 0, 0), thickness=-1)
imshow(img)


塗りつぶさないで円弧を描画する。
img = np.zeros((300, 300, 3), dtype=np.uint8)
cv2.ellipse(img, (150, 150), (50, 70), angle=45, startAngle=0, endAngle=100,
            color=(255, 0, 0), thickness=2)
imshow(img)


塗りつぶして円弧を描画する。
img = np.zeros((300, 300, 3), dtype=np.uint8)
cv2.ellipse(img, (150, 150), (50, 70), angle=45, startAngle=0, endAngle=100,
            color=(255, 0, 0), thickness=-1)
imshow(img)


凸なポリゴンを描画する。

fillConvexPoly()

fillConvexPoly()

img = cv2.fillConvexPoly(img, points, color[, lineType[, shift]])
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • points: 点の一覧。(N, 2) の numpy 配列。
    • color: 色
    • line_type: 線の種類
    • shift: オフセット
  • 返り値
    • img: 描画結果

サンプルコード

img = np.zeros((300, 300, 3), dtype=np.uint8)
points = np.array([[100, 100],
                   [120, 180],
                   [190, 250],
                   [270, 120],
                   [220, 50]])
ret_img = cv2.fillConvexPoly(img.copy(), points, color=(0, 255, 0))
imshow(ret_img)


ポリゴンを描画する。

fillPoly()

fillPoly()

img = cv2.fillPoly(img, points, color[, lineType[, shift]])
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • points: 点の一覧。(1, N, 2) の numpy 配列。
    • color: 色
    • line_type: 線の種類
    • shift: オフセット
  • 返り値
    • img: 描画結果

サンプルコード

img = np.zeros((300, 300, 3), dtype=np.uint8)
points = np.array([[100, 50],
                   [120, 180],
                   [50, 250],
                   [270, 120],
                   [220, 50]]).reshape(1, -1, 2)
ret_img = cv2.fillPoly(img.copy(), points, color=(0, 255, 0))
imshow(ret_img)


線を描画する。

line()

line()

img = cv2.line(img, pt1, pt2, color[, thickness[, lineType[, shift]]])
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • pt1: 線の始点
    • pt2: 線の終点
    • color: 色
    • thickness: 太さ。負の値で塗りつぶし。
    • line_type: 線の種類
    • shift: オフセット
  • 返り値
    • img: 描画結果

サンプルコード

img = np.zeros((300, 300, 3), dtype=np.uint8)
cv2.line(img, (50, 50), (250, 250), color=(255, 0, 0), thickness=2)
imshow(img)


ポリゴンの輪郭線を描画する。

polylines()

polylines()

img = cv2.polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]])
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • pts: 点の一覧
    • isClosed: ポリゴンが閉じているかどうか
    • color: 色
    • thickness: 太さ。負の値で塗りつぶし。
    • line_type: 線の種類
    • shift: オフセット
  • 返り値
    • img: 描画結果

サンプルコード

img = np.zeros((300, 300, 3), dtype=np.uint8)
points = np.array([[100, 50],
                   [120, 180],
                   [50, 250],
                   [270, 120],
                   [220, 50]]).reshape(1, -1, 2)
ret_img = cv2.polylines(img.copy(), points, isClosed=True, color=(0, 255, 0), thickness=2)
imshow(ret_img)


テキストを描画する。

putText()

putText()

img = cv2.putText(img, text, org, fontFace, fontScale,
                 color[, thickness[, lineType[, bottomLeftOrigin]]])
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • text: テキスト (Ascii 文字のみ対応)
    • org: テキストの描画を開始する左下の点
    • fontFace: フォントの見た目
    • fontScale: フォントの大きさの倍率。1.0 で等倍。
    • color: 色
    • thickness: 線の太さ。
    • line_type: 線の種類
    • bottomLeftOrigin: True の場合、右下が原点。False の場合、左下が原点になる。
  • 返り値
    • img: 描画結果

サンプルコード

font_faces = {'cv2.FONT_HERSHEY_SIMPLEX': cv2.FONT_HERSHEY_SIMPLEX,
              'cv2.FONT_HERSHEY_PLAIN': cv2.FONT_HERSHEY_PLAIN,
              'cv2.FONT_HERSHEY_DUPLEX': cv2.FONT_HERSHEY_DUPLEX,
              'cv2.FONT_HERSHEY_COMPLEX': cv2.FONT_HERSHEY_COMPLEX,
              'cv2.FONT_HERSHEY_TRIPLEX': cv2.FONT_HERSHEY_TRIPLEX,
              'cv2.FONT_HERSHEY_COMPLEX_SMALL': cv2.FONT_HERSHEY_COMPLEX_SMALL,
              'cv2.FONT_HERSHEY_SCRIPT_SIMPLEX': cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
              'cv2.FONT_HERSHEY_SCRIPT_COMPLEX': cv2.FONT_HERSHEY_SCRIPT_COMPLEX,
              'cv2.FONT_ITALIC': cv2.FONT_ITALIC}

fig, axes = plt.subplots(figsize=(10, 10))
for i, (title, font_face) in enumerate(font_faces.items(), 1):
    img = np.full((100, 100, 3), 255, dtype=np.uint8)
    cv2.putText(img, 'TEXT', (5, 50), fontFace=font_face, fontScale=1.,
                color=(0, 0, 0), thickness=2, lineType=cv2.LINE_AA)

    plt.subplot(3, 3, i)
    plt.title(title)
    plt.imshow(img[..., ::-1])
    plt.axis('off')

plt.show()


長方形を描画する。

rectangle()

rectangle()

img = cv2.rectangle(img, center, radius, color[, thickness[, lineType[, shift]]])
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • pt1: 長方形の左上の点
    • pt2: 長方形の右下の点
    • color: 色
    • thickness: 太さ。負の値で塗りつぶし。
    • line_type: 線の種類
    • shift: オフセット
  • 返り値
    • img: 描画結果

サンプルコード

塗りつぶさないで長方形を描画する。
img = np.zeros((300, 300, 3), dtype=np.uint8)
cv2.rectangle(img, (50, 50), (250, 250), color=(255, 0, 0), thickness=2)
imshow(img)


塗りつぶして長方形を描画する。
img = np.zeros((300, 300, 3), dtype=np.uint8)
cv2.rectangle(img, (50, 50), (250, 250), color=(255, 0, 0), thickness=-1)
imshow(img)

線を長方形の範囲に収まるようにクリップする。

clipLine()

この関数は次の目的で使える。

線が一部でも長方形に含まれるかどうかを調べる。

線のうち、長方形に含まれる範囲を調べる。

clipLine()

retval, pt1, pt2 = cv2.clipLine(imgRect, pt1, pt2)
  • 引数
    • imgRect: 長方形 (TopLeft.x, TopLeft.y, ImageWidth, ImageHeight)
    • pt1: 線の始点
    • pt2: 線の終点
  • 返り値
    • retval: 線が一部でも長方形に含まれるかどうか
    • pt1: 線の始点
    • pt2: 線の終点

サンプルコード

img = np.zeros((300, 300, 3), dtype=np.uint8)
h, w = img.shape[:2]

retval, pt1, pt2 = cv2.clipLine((0, 0, w, h), (-100, 100), (100, 100))

print('線が長方形に含まれるかどうか', retval)
# 線が長方形に含まれるかどうか True
print('クリップ後の始点: {}, 終点: {}'.format(pt1, pt2))
# クリップ後の始点: (0, 100), 終点: (100, 100)

楕円の円弧上の点を作成する。

ellipse2Poly()

ellipse2Poly()

pts = cv2.ellipse2Poly(center, axes, angle, arcStart, arcEnd, delta)
  • 引数
    • img: 描画対象の画像 (inplace で描画される)
    • center: 中心
    • axes: 長径、短径
    • angle: 回転角度
    • arcStart: 円弧開始角度
    • arcEnd: 円弧終了角度
    • delta: 点同士の角度の間隔
  • 返り値
    • img: 描画結果

サンプルコード

pts	= cv2.ellipse2Poly((150, 150), (50, 70), 45, 0, 200, 5)
print(pts)
[[185 185]
 [181 190]
 [176 193]
 [171 197]
 [166 200]
 [161 203]
 [156 205]
 [151 207]
 [145 209]
 [140 210]
 [135 211]
 [130 211]
 [125 211]
 [120 210]
 [116 209]
 [111 207]
 [107 205]
 [104 202]
 [101 199]
 [ 98 196]
 [ 95 193]
 [ 93 189]
 [ 91 184]
 [ 90 180]
 [ 89 175]
 [ 89 170]
 [ 89 165]
 [ 90 160]
 [ 91 155]
 [ 93 149]
 [ 95 144]
 [ 97 139]
 [100 134]
 [103 129]
 [107 124]
 [110 119]
 [115 115]
 [119 110]
 [124 107]
 [129 103]
 [134 100]]