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

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

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

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

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

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

Q&A

1回答

4068閲覧

Opencv・Pythonを用いて線分の長さを検出するプログラムの精度を改善したい

退会済みユーザー

退会済みユーザー

総合スコア0

OpenCV

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

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

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

0グッド

0クリップ

投稿2021/06/09 01:45

編集2021/06/19 10:26

前提・実現したいこと

以下の質問にいただいた回答
URL: https://teratail.com/questions/342736
から、実測値を出力することまではできました。

補足
・二値化、contourによる輪郭の検出
ここまでは可視化することによって正しい処理がなされていることが確認できました。
・boudingRect,及びnumpyによるベクトルの算出
ここからが理解できていません。どのような計算プロセスを経て結果が出力さているのかがわからず、
そのため、なぜ誤差が生じているのかもわかっていません。

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

長めの線や平行な線ならほとんど誤差なく検出できます。しかし、
・↑の画像のように線が斜めに交差している場合(実際はもう少し複雑に分岐)
・短い線が複数(上記画像内に10本程度のイメージ)
主にこれらのパターンで許容できないレベルの誤差(±10%程度)が生じてしまいます。
なお、線分の太さは統一しています。

ここから精度を上げる方法はあるのでしょうか。
ご教授いただければ幸いです。

該当のソースコード

Python

1import cv2 2import numpy as np 3import glob 4import os 5 6""" 7赤 青 それ以外で二値化 8輪郭の座標から線分の長さを計算 9""" 10 11# 赤色の範囲 12lower = (0, 20, 0) # 下限 13upper = (94, 255, 255) # 上限 14# 青色の範囲 15lower_blue = np.array([90, 64, 0]) # 下限 16upper_blue = np.array([150, 255, 255]) # 上限 17 18# ①画像読み込み 19file = find_files() 20img = cv2.imread(file, cv2.IMREAD_COLOR) 21img_2 = cv2.imread(file, cv2.IMREAD_COLOR) 22 23# ②HSV変換 24hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 25hsv_2 = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 26 27# ③二値化 28binary = cv2.inRange(hsv, lower, upper) 29binary_2 = cv2.inRange(hsv, lower_blue, upper_blue) 30 31# ④輪郭の座標を抽出 32contours, hierarchy = cv2.findContours( 33 binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) 34 35contours_2, hierarchy_2 = cv2.findContours( 36 binary_2, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) 37 38# 長さ計算用 39red_length = 0.0 40blue_length = 0.0 41 42# 赤色 43for i in range(len(contours)): 44 # ⑤輪郭情報から外接矩形の座標を抽出 45 x, y, w, h = cv2.boundingRect(contours[i]) 46 # ⑥線分の長さを計算(lengthに足す) 47 red_length += np.linalg.norm([w, h]) 48 print(red_length) 49 50# 青色 51for i in range(len(contours_2)): 52 x, y, w, h = cv2.boundingRect(contours_2[i]) 53 blue_length += np.linalg.norm([w, h]) 54 print(blue_length) 55 56# 出力 57Scale_set = int(input('縮尺を入力してください:')) 58red_length_True = Scale_set * red_length / blue_length 59 60print(f'{file} の赤線の実測値:{red_length_True}')

試したこと

contourの結果を可視化することで目標とする線分(赤/青ともに)が正しく認識できていることを確認しました。
線分がどんな状態であっても輪郭の検出までは上手く行っています。
しかし、実現したいことにあるような
・短めの線が多数
・線同士が重なり合っている
といった状況だと出力される値(boudingRect→numpyによる計算)に誤差が生じてしまいます。

contourAreaによる面積の算出、arcLengthによる周囲長さの算出も試しましたが、
面積:以下のような状況で、何故か出力が0になってしまう事がある
・輪郭を正しく認識できている
・引数として渡しているcontourの結果(contours)の中身には座標の値が入っている
周囲長さ:基準線は線分を1本のみ、赤い線分は複数検出ため、赤い線分の値が大きくなってしまう
といった問題が発生しており、上手く行っていません。

boudingRect,及びnumpyによるベクトルの算出については自分なりに調べてみましたが、最終的に何を求めているのか、理解ができていません。

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

python3.8
anaconda

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

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

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

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

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

fana

2021/06/09 02:03 編集

状況が他者には不明すぎるのではないでしょうか. 最終的な値だけを見るのではなくて,その値が得られた過程を解析してください. 例えば,以下のような処理の各段階の結果をしっかり可視化して,各段階で所望の処理結果を得られているのか?を確かめてください. ・2値化 ・contour検出の結果 ・各contour の boundingRect の結果 そのような作業を行って,せめて,「何がどうなって 10% の誤差を生じているのか」という要因くらいは突き止めてください. (その要因に対応できないときに「どうすれば対策できるか?」という話をスタートラインにするべきではないでしょうか) 「要因が何なのか?(何だと考えているのか?)」が明記されない状態で「試したこと」を書かれても,何故それを試すに至ったのか?が読み取れません.
fana

2021/06/09 02:08

「誤差」と言っているということは,処理結果値の比較対象たる「真値」が既知なのだと思いますが, 線を引かれた画像を出発点にして「手作業で」長さを計測した場合には真値と一致するのでしょうか?
yuki23

2021/06/09 04:51

プログラミングに関する質問とは思われません。指導教員から指摘されたことを丸投げされているだけではないでしょうか。何も思いつかないなら、まずは指導教員に相談してはいかがでしょうか。
退会済みユーザー

退会済みユーザー

2021/06/09 13:38

>例えば,以下のような処理の各段階の結果をしっかり可視化して,各段階で所望の処理結果を得られて>いるのか?を確かめてください. ・2値化 二値化した画像を出力することで確認しました。 ・contour検出の結果 rawContoursを用いて認識した部分の輪郭を描画することで、指定した色の輪郭を認識していることを確認しました。 ・各contour の boundingRect の結果 ここからがわかりません。 boundingRect → np.linalg.norm でベクトルを求めている、とのことですがどうにも理解できませんでした。そのため、何がどうなって10%の誤差が出ているのかわかりません。 >「誤差」と言っているということは,処理結果値の比較対象たる「真値」が既知なのだと思います 恥ずかしながら、手作業で計測した値を真値としています。 >指導教員から指摘されたことを丸投げされているだけではないでしょうか。 指導教員はいません。現在業務で質問内容のような業務を行っており、モニタに直接定規を当てて真値を算出する、という非常に原始的なことをしています。 その状況をなんとかしようという思いが先走ってしまい、十分な検討をしないまま質問してしまいました。説明、思慮、検討不足でした。回答される方の時間を奪っているという考えのない他人任せで無責任な質問だったと思います。 申し訳ありませんでした。
fana

2021/06/10 01:09

領域の画素を■,背景の画素を□としたとき… 例えば, □□□□ □■■□ □□□□ みたいな領域のとき, Contourのデータに含まれている輪郭座標群とは,■の座標でしょうか? それとも□の座標でしょうか? また,boundingRectで得られた矩形というのは上図の■の部分でしょうか?それとも□でしょうか? … もしもそういったことがはっきりしていないのであれば, 私ならまずはそういったことから調査します. 短い線ほど誤差のパーセンテージがでかい,というのは,「1画素」の差が比率として大きく現れるからだろう,とか考えると,そのあたりは見ておくべきです. そして,調査の結果としてその推測が正しいとわかったとしたら, 容易に1画素の変動を起こし得るような手法(前回の質問についた回答の中にはいくつかの話があったが,それぞれこの変動具合が異なり得る)は今回の目的には使えない,というところもわかるでしょう.
fana

2021/06/10 01:52 編集

> モニタに直接定規を当てて の場合,その計測分解能は1画素よりも細かいものになり得ますね. それに相当するような結果を得ようとするならば,当然ながら「画素単位」の処理はいまいちな結果を生じ得るでしょう. ■■ の長さは2でしょうか?それとも1でしょうか? という話もある. 算出方法(処理内容)次第ではどちらにもなり得るでしょう. (ここは,定規で計る際と同じ基準になるようにすべきですね) 最初に2値化一発で領域範囲を決めてしまうような処理をしている時点で,既に精度を失っている可能性も考えられなくもない. たとえば,アンチエイリアスがかかった形で描画された線の先端の「赤かどうか微妙な画素」を2値化処理が残すか残さないかで結果は[pixel]単位で変動するでしょう.短い線であれば致命的な誤差になるかもしれません. あと,定規で計測する際にも, 同じデータに対しての{同一人物が複数回計測した際の結果の変動,計測者の違いで生じる結果が変動,…}というのがあるんじゃないかな?と思うので, 定規作業との比較で精度を語るならば,そういうのも把握しておくべきかも. (手作業での結果の変動範囲にプログラムの結果が入っているならば,現状の結果でも実用できる可能性?)
fana

2021/06/10 01:25

……とかいったような事柄は,特段の専門知識等がなくとも,話を聞いただけで思い浮かぶ話かと思います. そういうところを,とにかく本当に「ちまちまと」把握していく必要があるのではないかな,と. 「可視化」の目的とはそういうところです.起きていることを確認するための手段なのですから,「わからんこと」を確認するために行ってください. boundingRectの結果がわからんならば,その結果を徹底的に調べる必要があるでしょう. (そして,その結果を踏まえて,それを使うのがOKなのかNGなのか? という判断を行っていく)
fana

2021/06/10 01:30 編集

> boundingRect → np.linalg.norm でベクトルを求めている AABB(Axis-Aligned Bounding Box)の対角線の長さを求めている ですね. (この処理方法自体に関して疑問があるならば,この方法の出所に対して問うてみてもよいかもしれません.応答があるかどうかまではわかりませんが…)
fana

2021/06/10 01:43

これは質問内容と関係ない感じになりますけども, > その状況をなんとかしよう というとき,いきなり「全自動」でなくとも良いのではありませんか? 例えば「画面上で,マウスか何かで人手で2点をクリックしたら距離が得られる」ものがあったとして, その程度のものがあるだけでも助かるのであれば,まずはそういうところからやってみるのもアリなのではないでしょうか? また,その程度のものを試しにちょいと作ってご自身で使ってみるだけでも,いろいろと(全自動処理でも問題となるような)課題点が見えてくるのではないかな,と思うので, まぁすぐに実作業の助けにならないとしてもそういうステップを経てみるのも意味があるんじゃないかな.
退会済みユーザー

退会済みユーザー

2021/06/11 00:38

アドバイスいただきありがとうございます。 何の問題を解決したいのか明確にして、自分で一から考え直してみたいと思います。
guest

回答1

0

算出手法にこだわらず、線が多い=誤差が大きいことから線の本数に応じてマイナスの補正をかけるようにし、誤差を抑えました。

投稿2021/06/19 10:33

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問