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

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

詳細はこちら
OpenCV

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

Raspberry Pi

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

Python

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

Q&A

解決済

1回答

1400閲覧

pythonで映像から特定色を認識するコードでわからないところがある。

退会済みユーザー

退会済みユーザー

総合スコア0

OpenCV

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

Raspberry Pi

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

Python

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

0グッド

0クリップ

投稿2019/10/31 11:00

下記のコードはraspbery pi cameraで撮影した映像から特定色の部分を認識するコードです。
これについていくつかわからない部分があるので教えていただきたいです。

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] mask = np.zeros(h.shape, dtype=np.uint8) mask[(h > 240) & ((150 > s) & (s < 100))] = 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 capture = cv2.VideoCapture(0) while cv2.waitKey(30) < 0: _, frame = capture.read() rects = find_rect_of_target_color(frame) if len(rects) > 0: rect = max(rects, key=(lambda x: x[2] * x[3])) cv2.rectangle(frame, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), (0, 0, 255), thickness=2) cv2.imshow('red', frame) capture.release() cv2.destroyAllWindows()

・その1
この部分のnp.zerosがわかりません。
調べたらh.shapeとdtype=np.unit8を指定して0で埋められた配列を返すとでました。しかし、0の配列を作るとどうなるのか、なぜ0にするのかがわかりません。そしてh.shapeは配列の型と調べたら出ましたが、具体的にどのような配列なのかがわかりません。
また,dtype=np.unit8についてもわからず、調べるとdtypeは出力配列の型でnp.unit=8は符号なしの8ビット整数型と出ましたが、00000000~11111111の範囲で表わすと言うことでしょうか。

mask = np.zeros(h.shape, dtype=np.uint8) mask[(h > 240) & ((150 > s) & (s < 100))] = 255 mask, contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

・その2
この部分は確認に近いのですが、これはまずrectsの要素は0であり、cv2.findContoursでmask(入力画像)の赤い部分の輪郭を検出したものをcontourに入れて、cv2.convexHullとcv2.boundingRectで凹凸の凸部分を包み、その包状が入る最小の外接矩形を求めて、その要素をrectsに入れてそれを返すことで、要素がゼロであったrects=[]に要素を入れるということですか?

rects = [] for contour in contours: approx = cv2.convexHull(contour) rect = cv2.boundingRect(approx) rects.append(np.array(rect)) return rects

・その3
まず、rects = find_rect_of_target_color(frame)の分は映像(静止画像)であるframeをHSVに変換して、設定した値のところの輪郭を検出してその画像を囲む外接矩形を表示する処理を行う処理をしてrectsに入れているということでしょうか。
そして、このif len(rects) > 0:がよくわかりません。配列が0より大きいときにいかのそれ以降のコードが実行されるのかと考えましたが、それがあっていたとしてもどういうことなのかがよくわかりません。
また、 rect = max(rects, key=(lambda x: x[2] * x[3]))はrectsでいくつもの矩形のなかで一番大きいところだけを表示するようにしているのですか?
あと最後に cv2.rectangleのところで質問があり、長方形を描画と調べて出てきたのですが、この部分で初めて画像ないに長方形が表示されるのですか?輪郭を検出したり、矩形を表示したりいろいろ処理をしているのでわからなくなってしまいました。そしてこのコードでは入力画像はframeですがrects = find_rect_of_target_color(frame)の部分でrectsに静止画像であるframeを処理したものを入れているので、入力画像はrectsなのではないかと思ったのですが、違うのでしょうか。

_, frame = capture.read() rects = find_rect_of_target_color(frame) if len(rects) > 0: rect = max(rects, key=(lambda x: x[2] * x[3])) cv2.rectangle(frame, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), (0, 0, 255), thickness=2) cv2.imshow('red', frame)

いろいろ要領を得ない質問が多いと思いますが、答えることができる範囲で回答していただければ幸いです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

その1

OpenCV で画像は uint8 型の numpy 配列で表されます。
numpy.zeros で画像と同じ大きさですべての値が0のマスク画像を作成して、色が指定した範囲の画素だけ255にすることで2値画像を作成しています。
この2値画像はそのあとの輪郭抽出で使います。

その2

その理解であってます。

その3

質問内のコードにコメントを入れました。

python

1import cv2 2import numpy as np 3 4 5def find_rect_of_target_color(image): 6 # 画像の色空間を BGR から HSV に変換する。 7 hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV_FULL) 8 # H チャンネルを取得する。 9 h = hsv[:, :, 0] 10 # S チャンネルを取得する。 11 s = hsv[:, :, 1] 12 # 画像と同じ形状及び型を持つすべての値が0の配列を作成する。 13 mask = np.zeros(h.shape, dtype=np.uint8) 14 # 「h が 240 より大きい」かつ「s が100より小さい」位置は値を255にする。 15 mask[(h > 240) & ((150 > s) & (s < 100))] = 255 16 # 輪郭抽出する。 17 mask, contours, hierarchy = cv2.findContours( 18 mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE 19 ) 20 21 rects = [] 22 for contour in contours: 23 # 輪郭の凸包をとる。 24 approx = cv2.convexHull(contour) 25 # 凸包に外接する長方形をとる。 26 rect = cv2.boundingRect(approx) 27 # 長方形を rects に追加する。 28 rects.append(np.array(rect)) 29 return rects 30 31 32capture = cv2.VideoCapture(0) 33 34while cv2.waitKey(30) < 0: # なにかキーが押されるまでは while をループする。 35 # カメラから1フレーム取得する。 36 _, frame = capture.read() 37 # フレームから指定した色を持つ領域を探す。 38 rects = find_rect_of_target_color(frame) 39 40 # そのような領域が1つ以上見つかった場合 41 if len(rects) > 0: 42 # 面積が最大の長方形を取得する。 43 rect = max(rects, key=(lambda x: x[2] * x[3])) 44 # 面積が最大の長方形を赤色で描画する。 45 cv2.rectangle( 46 frame, 47 tuple(rect[0:2]), 48 tuple(rect[0:2] + rect[2:4]), 49 (0, 0, 255), 50 thickness=2, 51 ) 52 # フレームをウィンドウに表示する。 53 cv2.imshow("red", frame) 54 55# Video Capture をクローズする。 56capture.release() 57 58# すべてのウィンドウを閉じる。 59cv2.destroyAllWindows()

投稿2019/10/31 17:12

tiitoi

総合スコア21956

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

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

退会済みユーザー

退会済みユーザー

2019/11/01 05:19

とても丁寧に教えていただき、ありがとうございます!だいぶわかりました。 そこでもう少し質問があるのですが、key=(lambda x: x[2] * x[3])のところと tuple(rect[0:2]),tuple(rect[0:2] + rect[2:4])のところがよくわからないので教えていただけませんか。 前者のはおそらく面積関係で、後者は描出する長方形の座標ということはわかるのですが、x:x{2}だったり、rect{0:2}のような書き方がいまいち理解できません。
tiitoi

2019/11/01 06:05

rects の各要素は cv2.boundingRect の返り値なわけですが、この返り値 rect は (x, y, w, h) のタプルなので、面積は rect[2] * rect[3] で計算できます。 rect[0:2] + rect[2:4] は [x, y] + [w, h] なので、[x + w, y + h] つまり、長方形の右下の点の座標を計算しています。
退会済みユーザー

退会済みユーザー

2019/11/01 09:48

ありがとうございます! おそらくですがわかりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問