1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Python/OpenCV】輪郭の面積・周囲長・重心を求める方法

1
Last updated at Posted at 2026-03-22

概要

OpenCVで検出した輪郭から面積・周囲長・重心などの幾何学的特徴量を計算し、外接矩形や最小外接円を描画する方法を解説する。

1. ライブラリのインポートと画像の読み込み

import cv2
import numpy as np

img = cv2.imread("input.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  • cv2.cvtColor() でグレースケールに変換する

2. 二値化と輪郭検出

ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  • cv2.RETR_EXTERNAL : 最外部の輪郭のみ取得
  • cv2.CHAIN_APPROX_SIMPLE : 輪郭点を圧縮して格納

3. 輪郭の面積を求める

for cnt in contours:
    area = cv2.contourArea(cnt)
    print(f"面積: {area}")
  • cv2.contourArea(contour) : 輪郭で囲まれた領域の面積をピクセル単位で返す
  • 面積が0の場合、輪郭が直線状であることを意味する

4. 輪郭の周囲長を求める

for cnt in contours:
    perimeter = cv2.arcLength(cnt, closed=True)
    print(f"周囲長: {perimeter}")
  • cnt : 輪郭の点群
  • closed=True : 輪郭が閉じた曲線であることを指定(始点と終点を結ぶ)
  • closed=False : 開いた曲線として計算する

5. 重心を求める

for cnt in contours:
    M = cv2.moments(cnt)
    if M["m00"] != 0:
        cx = int(M["m10"] / M["m00"])
        cy = int(M["m01"] / M["m00"])
        cv2.circle(img, (cx, cy), 5, (0, 0, 255), -1)
        print(f"重心: ({cx}, {cy})")
  • cv2.moments() : 輪郭のモーメントを辞書形式で返す
  • m00 : 面積(ゼロ次モーメント)
  • m10 / m00 : 重心のx座標
  • m01 / m00 : 重心のy座標
  • m00 == 0 の場合はゼロ除算を避ける

6. 外接矩形を描画する

for cnt in contours:
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
  • cv2.boundingRect() : 輪郭を囲む最小の軸平行な矩形を返す
  • 戻り値は (x, y, w, h) の4要素タプル

7. 最小外接円を描画する

for cnt in contours:
    (cx, cy), radius = cv2.minEnclosingCircle(cnt)
    center = (int(cx), int(cy))
    radius = int(radius)
    cv2.circle(img, center, radius, (255, 0, 0), 2)
  • cv2.minEnclosingCircle() : 輪郭を囲む最小の円を返す
  • 戻り値は中心座標 (x, y) と半径 radius

8. 回転矩形を描画する

for cnt in contours:
    rect = cv2.minAreaRect(cnt)
    box = cv2.boxPoints(rect)
    box = np.int32(box)
    cv2.drawContours(img, [box], 0, (0, 255, 255), 2)
  • cv2.minAreaRect() : 輪郭を囲む最小面積の回転矩形を返す
  • 戻り値は ((cx, cy), (w, h), angle) のタプル
  • cv2.boxPoints() : 回転矩形の4頂点座標を取得する
  • np.int32() : 描画用に整数座標に変換する

9. 表示して確認

import cv2
import numpy as np

img = cv2.imread("input.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
    area = cv2.contourArea(cnt)
    perimeter = cv2.arcLength(cnt, closed=True)

    M = cv2.moments(cnt)
    if M["m00"] != 0:
        cx = int(M["m10"] / M["m00"])
        cy = int(M["m01"] / M["m00"])
        cv2.circle(img, (cx, cy), 5, (0, 0, 255), -1)
        print(f"面積: {area:.1f}, 周囲長: {perimeter:.1f}, 重心: ({cx}, {cy})")

    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

cv2.imshow("Contour Properties", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?