質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.95%

描画した外接矩形の辺の長さを求める

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 4,317

score 14

 実現したいこと

輪郭抽出ののち描画した、外接矩形の各辺の長さを求めたいです。

下のコードで描画したそれぞれの外接矩形の各頂点座標がrectsに格納されていることはわかるのですが、
そこから座標情報を取り出して各外接矩形の辺の長さを求める繰り返し処理を行うコードがわかりません、、
どなたか教えていただけると幸いです。

 該当のソースコード

import cv2
import numpy as np

# 画像の読み込み
img = cv2.imread('C:/Users/ito/Anaconda3/envs/Sample/pic/testimg/IMG_0070.jpg')

# リサイズ
#img = cv2.resize(img, dsize=None, fx=0.2, fy=0.2)

# グレースケールに変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二値化
_, binary = cv2.threshold(gray, 89, 255, cv2.THRESH_BINARY_INV)

#輪郭抽出
_, contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 面積が小さい輪郭削除
area = img.shape[0] * img.shape[1]
contours = list(filter(lambda cnt:10< cv2.contourArea(cnt), contours))

# 外接矩形に変換
# drawContours() に渡す輪郭は int 型である必要があるため、astype(int) でキャストすること。
rects = [cv2.boxPoints(cv2.minAreaRect(cnt)).astype(int) for cnt in contours]

# 外接矩形を描画
cv2.drawContours(img, rects, -1, (0, 255, 0), 1)

#外接矩形の長さを算出


# 画像を保存
cv2.imwrite('C:/Users/ito/Anaconda3/envs/Sample/pic/result/minAR0070_89.jpg', img)
#cv2.imshow('sample', binary)
#cv2.waitKey(0)
#cv2.destroyAllWindows

print(rects)

 開発環境

windows7 professional
python3.6.5
opencv3.3.1

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

以下の関数に rects の各要素を渡せば、輪郭の長さが返ってきます。

retval = cv2.arcLength(curve, closed)

引数

  • curve: 輪郭
  • closed: 輪郭が閉じているかどうか。長方形は閉じているので True

返り値

  • retval: 輪郭の長さ

参考リンク

 追記

 回転した長方形の4点から中心、回転角度、大きさを計算するコード

def get_rect_info(rect):
    # 長方形の中心
    center = (rect[0] + rect[2]) / 2

    # 長さが異なる2つの辺の長さをそれぞれ計算する。
    vec1 = rect[0] - rect[1]
    vec2 = rect[1] - rect[2]
    vec1_len = np.linalg.norm(vec1)
    vec2_len = np.linalg.norm(vec2)

    # 長辺が幅、短辺が高さとする。
    if vec1_len < vec2_len:
        widht, height = vec2_len, vec1_len
        vecw = vec2
    else:
        widht, height = vec1_len, vec2_len
        vecw = vec1

    # x 軸と長辺のなす角を計算する。
    if np.isclose(vecw[0], 0):
        angle = 0
    else:
        angle = -np.arctan(vecw[1] / vecw[0])
        angle = np.rad2deg(angle)

    return {'center': center, 'angle': angle, 'size': (width, height)}

 テスト

import cv2
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Polygon

x, y = 100, 150
width, height = 300, 100
rect = np.array([
    [x, y],
    [x + width, y],
    [x + width, y + height],
    [x, y + height],
    [x, y]], dtype=float)

# 長方形を描画する。
fig, axes = plt.subplots(figsize=(6, 6))
axes.set_xlim(0, 500)
axes.set_ylim(0, 500)

for angle in range(0, 360, 40):
    # 長方形の中心周りに -angle 回転させる回転行列を作成する。
    center = tuple(((rect[0] + rect[2]) / 2).astype(int))
    R = cv2.getRotationMatrix2D(center, -angle, 1.)

    # 回転行列を適用し、回転した長方形の点を計算する。
    rotated_rect = cv2.transform(rect.reshape(1, -1, 2), R)[0]

    # 確認用に描画する。
    axes.add_patch(Polygon(rotated_rect, fill=None, lw=2., color='b'))

    # 4点の座標から中心、回転角度、大きさを計算する。
    info = get_rect_info(rotated_rect)

    print('center: {}, angle: {:.2f}, size: {}'.format(info['center'], info['angle'], info['size']))

plt.show()
center: [250. 200.], angle: 0.00, size: (300, 100.0)
center: [250. 200.], angle: -40.00, size: (300, 100.00000000000001)
center: [250. 200.], angle: -80.00, size: (300, 100.00000000000004)
center: [250. 200.], angle: 60.00, size: (300, 100.00000000000004)
center: [250. 200.], angle: 20.00, size: (300, 99.99999999999999)
center: [250. 200.], angle: -20.00, size: (300, 100.00000000000004)
center: [250. 200.], angle: -60.00, size: (300, 100.00000000000001)
center: [250. 200.], angle: 80.00, size: (300, 100.00000000000006)
center: [250. 200.], angle: 40.00, size: (300, 100.00000000000001)

イメージ説明

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/22 00:12

    ご回答いただきありがとうございます!
    大変ありがたいのですが、現在求めたいのが周囲長ではなく矩形の短辺と長辺をそれぞれでして、それについての解決方法を教えて頂けますと幸いなんですが、、
    よろしくお願いいたします。

    キャンセル

  • 2018/10/22 02:30

    追記しました。
    2つの異なる辺のベクトルを作り、ノルムを計算すればよいです。

    キャンセル

  • 2018/10/22 09:49

    ありがとうございます!
    自分の方でも試してみます。

    キャンセル

  • この投稿は削除されました

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.95%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る