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

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

新規登録して質問してみよう
ただいま回答率
85.48%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1846閲覧

Python 点集合最外周矩形描写について

tomo754

総合スコア11

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/03/04 06:56

編集2022/03/04 10:30

前提・実現したいこと

複数ある丸い点の最外周を認識し、矩形を描写したい。
矩形は点の最外周をとりたく、イメージとしては①、②、③、④の点がそれぞれXYの最大、最小値となる。
その時、XY最小、最大座標を利用し矩形を描写。
また、点の配列は回転方向にズレる場合も考慮し、cv2.minAreaRectによる外接矩形を利用したいと考えております。

すでに回答いただいている方もいらっしゃいますが、ありがとうございます。
大変勉強になります。

質問内容が分かりにくかったため、上記内容に修正します。

イメージ説明
イメージ説明

発生している問題・エラーメッセージ

下記コードで動かすと特定の1つの丸に対して矩形を描写してしまう。 複数ある場合の最外周を取る方法が不明 すみませんが、ご教授ください。

該当のソースコード

Python

1import cv2 2import tkinter as tk 3from tkinter import filedialog 4import numpy as np 5 6# 画像を読み込む 7idir = r'C:\\descktop' 8filetype = [("すべて", "*")] 9filepath = tk.filedialog.askopenfilename(filetypes=filetype, initialdir=idir) 10frame = cv2.imread(filepath) 11 12# 画像をグレースケール化 13gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 14 15# 画像を二値化 16ret, bin = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) 17 18# モーメント関数で3次までのモーメントを取得 19mu = cv2.moments(bin) 20 21# 図心を出す 22x, y = int(mu["m10"]/mu["m00"]), int(mu["m01"]/mu["m00"]) 23 24# 図心を画像に記載する 25cv2.circle(frame, (x, y), 5, (0, 0, 255), 3) 26 27# 輪郭抽出 28contours, hierarchy = cv2.findContours(bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 29 30# s最外周に外接矩形を作成し、画像に重ね書き 31rect = cv2.minAreaRect(contours[0]) 32box = cv2.boxPoints(rect) 33box = np.int0(box) 34cv2.drawContours(frame, [box], 0, (0, 255, 0), 2) 35 36# 画像の情報を取得 37h, w, channels = frame.shape[:3] 38print("width: " + str(w)) 39print("height: " + str(h)) 40img = cv2.resize(frame, (int(w / 2), int(h / 2))) # 1/2に縮小 41 42 43 44# 画像を表示する 45cv2.imshow('frame', img) 46#cv2.imwrite('frame_moment.jpg',frame) 47 48# キー入力を待つ 49cv2.waitKey(0) 50 51# 全ての開いたウインドウ閉じる 52cv2.destroyAllWindows()

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

wWindows10
Python3.6

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2022/03/04 08:10

何がわからないのか が わからない. > cv2.minAreaRect(contours[0]) で,ある特定の丸に関する結果が得られるっていう話ならば, 例えば cv2.minAreaRect(contours[1]) とかすれば別の丸の結果が得られるんじゃない? そしたら,その2つの結果を用いれば,この2つの丸を囲む矩形を求められるよね. ↓ だったら,全部の丸についての結果を用いれば,全部の丸を囲む矩形を求められるよね.
fana

2022/03/04 10:12 編集

何も分かってないのは 私の方だった. 伏してお詫び申し上げる. 上記の「minAreaRect の結果」を統合するなんて話では全然ダメですね(最小サイズではない粗悪な近似にしかならない). 全 contour を統合したものに minAreaRect を1回やるべき.
fana

2022/03/07 05:15

> 点の配列は回転方向にズレる場合も考慮し、cv2.minAreaRectによる外接矩形を利用したいと考えております そういう場合は,誤解を生じないように「斜めな矩形が結果となることが明瞭な例」を示せばいいのに.
guest

回答2

0

ベストアンサー

findContours

の結果として複数の contour の情報が得られていると思われる.
各 contour の情報とは輪郭の座標群である.
そのうちの1つだけを用いて

cv2.minAreaRect(contours[0])

とすれば当然ながらある1つの領域の輪郭座標群に対しての最小外接矩形が得られる.

よって,単純には,全 contour が持つ座標群を1つにまとめたデータに対して minAreaRect を用いるならば,所望の最小外接矩形が得られるであろう.

投稿2022/03/07 04:31

fana

総合スコア11658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2022/03/07 04:35

仮に,この処理結果の精度が非常に重要なのであれば, CHAIN_APPROX_SIMPLE を使うべきではないだろうが, 前段処理がてきとーな二値化であることを見るに,そこらへんに拘る話ではなさそうに思う.
fana

2022/03/07 05:23

(ところで,minAreaRect のアルゴリズムってどうやってるんだろう? 凸包の2頂点を結ぶ方向を軸に取るみたいなのを全パターン調べるとか?)
tomo754

2022/03/07 09:20

追加の回答ありがとうございました。 ご教授頂いて色々調べたりしてみたところ下記内容で目的を果たせました。 ありがとうございました。 # 画像を二値化 ret, bin = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) # 二値化の輝度変化の位置情報を探す yl, xl = np.where(bin == 255) # 座標データ形式に変換 ←ここがキモっぽい! yl = yl.reshape((-1, 1)) xl = xl.reshape((-1, 1)) vec = np.hstack((xl, yl)) # 矩形描写 rect = cv2.minAreaRect(vec) box = cv2.boxPoints(rect) box = np.int0(box) result = cv2.drawContours(frame, [box], 0, (0, 0, 255), 2)
guest

0

複雑に考える必要はありません。
画像を二値化したなのであれば、その結果について、x座標の最小値と最大値、x座標の最小値と最大値を求めればそれでできます。

投稿2022/03/04 08:18

ppaul

総合スコア24666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2022/03/04 09:52 編集

質問に貼られている絵から判断するとAABBが欲しいという話であるようにも見える. しかしながら,質問者のコードを見ると boundingRect ではなくて minAreaRect が使われているので,そういう意図があるかのようにも見える. 何が正しいのかは謎ですが,AABBであれば2値画像をboundingRectに突っ込めば終わりでしょうね. # "AABB" って語の使い方合ってるかな…?
tomo754

2022/03/07 03:25

すみません。教えて頂きたいのですが、 idx = np.dstack(np.where(bin == 255)) にて二値化した画像の輝度変化の座標を取得させることはできました。 >> [[[ 36 528] [ 36 529] [ 36 530] ... [543 425] [543 427] [543 429]]] ここから最小値、最大値を抽出すればよいのでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問