🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
OpenCV

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

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

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

Q&A

解決済

2回答

3894閲覧

pythonでHSVを指定した色の認識をしたいのだが、設定したHSVの範囲以外も認識してしまう。

退会済みユーザー

退会済みユーザー

総合スコア0

OpenCV

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

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

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

0グッド

1クリップ

投稿2019/11/02 08:52

編集2019/11/03 14:58

何度も同じような質問をしてしまい、申し訳ありません。
以下のコードで画像から赤色を認識して枠で囲んでウィンドウに表示させるということを行っているのですが、目的の色と違うものが認識されてしまうことがあります。そしてその認識された部分のRGBをネットのツールで調べて計算してHSV変換したのですが、設定したHSV(Vは未設定)と違う値でした。ということは設定したHSVの範囲外のものを認識してしまっているということになるのですが、改善する方法はないでしょうか。

・追記
もしかしてHSVの指定方法が間違っているのでしょうか。
誤認識したHSVのSは設定の範囲内で、もしかしたら[(h > 240) & ((100 < s) & (s < 200))] はhが240以上または、sが100〜200までなら認識してしまうということなのでしょうか。でもそれだと壁一面を認識してもおかしくないとも思って結局よくわからないので教えていただきたいです。

また、他の人(このときは誤認識した赤色のHSVが設定したHSVの範囲から外れているとは言っていない)から「if文を使って指定した赤色を認識した場合、赤枠を表示するといいのでは」と言われましたが、これでは、どのみち誤認識は変わらないのではないかと思ってしまいました。実際この方法で誤認識は減らせるのでしょうか。

import cv2 import numpy as np def find_rect_of_target_color(image): hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV_FULL) h = hsv[:, :, 0] s = hsv[:, :, 1] v = hsv[:, :, 1] mask = np.zeros(h.shape, dtype=np.uint8) mask[(h > 240) & ((100 < s) & (s < 200))] = 255 mask, contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) rects = [] for contour in contours: approx = cv2.convexHull(contour) rect = cv2.boundingRect(approx) rects.append(np.array(rect)) return rects img = cv2.imread('/home/pi/picture/alarm7-2.png') rects = find_rect_of_target_color(img) if len(rects) > 0: rect = max(rects, key=(lambda x: x[2] * x[3])) cv2.rectangle(img, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), (0, 0, 255), thickness=2) cv2.imshow("red", img) cv2.waitKey(0) cv2.destroyAllWindows()

・誤認識の画像その1
誤認識した部分の
RGB:82,66,76
HSV:228,50,82
イメージ説明

・誤認識画像その2
誤認識した部分の
RGB:82,26,25
HSV:1,177,82
イメージ説明

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

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

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

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

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

tanishi_a

2019/11/03 02:20 編集

質問そのもののことはわからないですが、 > [(h > 240) & ((100 < s) & (s < 200))] はhが240以上または、sが100〜200までなら認識してしまうということなのでしょうか この部分は違って、「h が 240以上かつ、sが100〜200」ですね。 ```py def check(h, s): x = (h > 240) & ((100 < s) & (s < 200)) print(x) check(241, 99) # => False check(241, 101) # => True check(241, 199) # => True check(241, 201) # => False check(239, 99) # => False check(239, 101) # => False check(239, 199) # => False check(239, 201) # => False ```
tanishi_a

2019/11/03 02:21 編集

あと、質問文のコードは 実行できるものですか? 手元で実行しようとするとエラーになりますが。 → これは下記のように変更したら動作しました。 mask, contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) ↓↓↓ contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
tanishi_a

2019/11/03 01:36 編集

細かいことですみませんが「ご認識」→「誤認識」。 紛らわしいので質問文を修正してほしいです。
退会済みユーザー

退会済みユーザー

2019/11/03 14:57

そうしたらなぜ違う色が認識されてしまったのでしょうか。 あと、エラーについてはおそらく、openCV2か3の違いによるものだと思います。 ご認識→誤認識に変えておきました。
thkana

2019/11/10 07:42

Pythonは得意でないので後回しになってましたがやっと手を付け始めました。 > openCV2か3の違い じゃなくて3と4との違いらしいです。私も最初ハマりましたが、エラーメッセージそのままでググったらひっかかりました。
thkana

2019/11/10 07:50

テストデータ(画像)は、回答者が同じ実験が出来るように元データを載せていただけませんか。 「質問」というと学校などでそもそもの出題者だったり友人だったり、問題の背景がわかっている人から「答えやヒントを聞き出す」というのが中心だったせいか、そういう情報を欠落させてしまう人がしばしばです。 こういう場での質問はそういうものではなくて、何も知らない相手に相談するのですから、あなたは相手があなたと同じ道筋を辿ってみられるだけの情報や材料を提供しないと、他人には手出しが出来ないで話が終わってしまうこともあります。OpenCVのバージョン情報にしてもそう。テストデータについてもそう。
退会済みユーザー

退会済みユーザー

2019/11/18 04:13

すみません!返信遅れました! 画像なんですけど、データが大きくて乗せることが出来ませんでした。 あと、V値を指定したら何とか認識できました。
guest

回答2

0

ベストアンサー

・誤認識の画像その1

誤認識した部分の
RGB:82,66,76
HSV:228,50,82
・誤認識画像その2
誤認識した部分の
RGB:82,26,25
HSV:1,177,82

これはどうやって抽出しましたか?

Python

1def find_rect_of_target_color(image): 2 hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV_FULL) 3 h = hsv[:, :, 0] 4 s = hsv[:, :, 1] 5 v = hsv[:, :, 1] 6 mask = np.zeros(h.shape, dtype=np.uint8) 7 mask[(h > 240) & ((100 < s) & (s < 200))] = 255 8 mask, contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 9 #mask位置をみてみる 10 cv2.imshow("Mask",mask) 11 rects = [] 12 for contour in contours: 13 approx = cv2.convexHull(contour) 14 rect = cv2.boundingRect(approx) 15 rects.append(np.array(rect)) 16 #適当にあたりを付けて値をみてみる 17 for xx in range(0,len(mask[:,800])): 18 if mask[800,xx] != 0: 19 print(xx) 20 print(image[800,xx]) 21 print(hsv[800,xx]) 22 return rects 23 24img = cv2.imread(r'd:\testdata\red.png') 25rects = find_rect_of_target_color(img) 26#if len(rects) > 0: 27# rect = max(rects, key=(lambda x: x[2] * x[3])) 28# cv2.rectangle(img, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), (0, 0, 255), thickness=2) 29#全部の検出位置を枠で囲んで表示 30for rect in rects: 31 cv2.rectangle(img, tuple(rect[0:2]-[10,10]), tuple(rect[0:2] + rect[2:4]+[10,10]), (0, 255, 0), thickness=2) 32 33cv2.imshow("red", img) 34cv2.waitKey(0) 35cv2.destroyAllWindows()

として、マスク画像と全部の検出位置に枠を付けて表示して、さらに一部の画素の数値を見てみましたが、特に誤検出(指定された範囲外の検出)の気配はないです。
マスク画像
全検出

赤枠を表示するといい

これは誤検出とは関係なく、検出した位置の確認の手段の話ではないでしょうか。


おまけ。
私の慣れの関係で、Processingでカラーマップを描いてみました。
Vは0x3f,0x7f,0xbf,0xffについて、横軸H0~255,縦軸S0~255です。
ColorMap
で、線を入れたのがH=50,240とS=100,200ですから、黒線で区切られた領域は

h<50,s<100h<240,s<100240<h,s<100
h<50,100<s<200h<240,100<s<200240<h,100<s<200
h<50,200<sh<240,200<s240<h,200<s

h<50は以前の質問で使っていた判別要素です。
あなたが選んだ240<h,100<s<200(中段右)のエリアはあなたが欲しい色を必要十分に含んでいますか?(ちょっと違うんじゃないかと思って言ってますが)

Processing

1//参考 特に難しいことはしていないので読めばやっていることはわかるかと思います 2int limitY1=100; 3int limitY2=200; 4int limitX1=50; 5int limitX2=240; 6 7size(520, 520); 8background(0); 9textAlign(LEFT, TOP); 10for (int vv=0; vv<4; vv++) { 11 colorMode(HSB, 255); 12 int v=(vv+1)*0x40-1; 13 int xref=(vv&1)*width/2; 14 int yref=(vv&2)*height/4; 15 for (int x=0; x<256; x++) { 16 for (int y=0; y<256; y++) { 17 stroke(x, y, v);//色指定 18 point(x+xref, y+yref);//点を打つ 19 } 20 } 21 stroke(0); 22 line(xref, limitY1+yref, 255+xref, limitY1+yref); 23 line(xref, limitY2+yref, 255+xref, limitY2+yref); 24 line(limitX1+xref, yref, limitX1+xref, 255+yref); 25 line(limitX2+xref, yref, limitX2+xref, 255+yref); 26 colorMode(RGB); 27 fill(255, 0, 0); 28 text("v="+v, xref, yref); 29}

投稿2019/11/10 12:34

thkana

総合スコア7703

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

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

0

# 勘違いぽい回答をしてしまったので当初の回答は、いったん削除・・・すみません

理屈がわかってなくて対症療法的なので、回答としては非常にダメな感じですが、、
このようにしてみたら、左上のランプのところが検出されるようにはなりますね・・・。
(下の方の赤いバーが検出はされてるが、面積が減った)

py

1mask[(h > 240) & ((100 < s) & (s < 200))] = 255 2↓↓↓ 3mask[(h > 240) & ((128 < s) & (s < 200))] = 255

128 にしたのは、下記リンクの下記の記載を信じてみたもの。
参考になるでしょうか。

ここでは、赤色の判定なので、Sの値が (S > 128) である事を条件として付け加えましょう。

https://qiita.com/odaman68000/items/ae28cf7bdaf4fa13a65b

投稿2019/11/03 01:40

編集2019/11/03 15:58
tanishi_a

総合スコア484

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

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

退会済みユーザー

退会済みユーザー

2019/11/03 14:54

測った色の部分か、僕の使ったツールに問題があって値が違うのですかね。 ですが、Sが38なら設定した範囲と違うから認識しないのではありませんか?
tanishi_a

2019/11/03 15:32 編集

> Sが38なら設定した範囲と違うから認識しないのではありませんか? あ。ほんとですね。すみません。 あと、1 箇所でなく、全部の点で確認しないとあまり意味ないですね。 # 内容が誤りすぎるので、いったん編集して削除しました。。
退会済みユーザー

退会済みユーザー

2019/11/03 15:39

いえいえ、回答していただいただけでありがたいです! 全部の色を確認したとしても、HSVが範囲内にあるようには感じられません... 無理やり赤いところをさがして認識しているのですかね...
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問