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

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

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

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

1回答

9082閲覧

pythonで物体検出&ピクセル座標の取得

sekaikan_ozaki

総合スコア65

OpenCV

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

1グッド

4クリップ

投稿2018/01/11 08:27

編集2018/01/11 09:26

python3.5,OpenCV3.3を使っているプログラミング初心者です。

いつもお世話になっております。

今回、画像から「赤色の物体」を検知し、検知した箇所のピクセルを取得するプログラムを作成しようと考えています。

現在、赤色検出のマスク画像を表示するところまではできています。

検知した箇所のピクセルを取得する方法として、
「赤色の部分」を上下左右から範囲を狭めて、物体を矩形で囲み、その中心座標を物体位置するやり方があると思うのですが、うまくコードが書けません。。。

ちなみに使用する画像は、4096×2048(pixel)で、(画像左上が(0,0)、右下が(4096,2048))となっており、
例えば、検出した「赤い物体」のピクセルの中心(例えば(200,400))を取得するといった形です。

よろしくお願いいたします。

~追記~

ちなみに,使用する画像はこちらで、海面150mからドローンで撮影した画像です.
この画像には、小さくて見にくいですが2隻の船以外に漁で使用する赤い(オレンジ色)の漁具が何個か漂流しています。
とても小さくほぼ点(5~6ピクセルほど)のような大きさで検出されるかと思います。

イメージ説明

python

1#-*- coding:utf-8 -*- 2import cv2 3import numpy as np 4 5 6def main(): 7 8 #画像を入力 9 img = input('画像をを入力してください: ') 10 #画像の読み込み 11 12 img=cv2.imread(img) 13 14 # HSV色空間に変換 15 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 16 17 18 cv2.namedWindow("hsv.jpg", cv2.WINDOW_KEEPRATIO | cv2.WINDOW_NORMAL) 19 20 21 # 赤色のHSVの値域 22 lower_red = np.array([170,100,190]) 23 upper_red = np.array([200,255,255]) 24 mask = cv2.inRange(hsv, lower_red, upper_red) 25 26 hsv = mask 27 28 #画像の表示 29 cv2.imshow("hsv.jpg", hsv) 30 cv2.waitKey(0) 31 cv2.destroyAllWindows() 32 33  #以下に赤色の物体を検知した部分のピクセル座標を取得するコードを書きたい 34 35 36 37if __name__ == "__main__": 38 main()
haru135👍を押しています

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

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

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

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

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

guest

回答1

0

マスク画像が既に手に入っているなら、重心を求めればいいかと。

Python

1import cv2 2 3color = { 4 'gray': (128, 128, 128), 5} 6 7img = cv2.imread('object.jpg', cv2.IMREAD_GRAYSCALE) 8assert img is not None 9 10m = cv2.moments(img) 11cx = int(m['m10'] // m['m00']) 12cy = int(m['m01'] // m['m00']) 13 14cv2.drawMarker(img, (cx, cy), color['gray']) 15cv2.imshow('img', img) 16cv2.waitKey() 17cv2.destroyAllWindows()

テスト画像での実行結果はこんな感じです。
ペイントで1分で作った


『良い感じに赤色の物体が写っている画像』を用意するのはなかなか大変です。
どれくらいの大きさ、どれくらいの数を想定しているのかわからないですから。

適当にテスト画像を用意してくださると回答しやすいので、次回以降は気にかけてみてください。

そもそもブイを正しく抽出できてなさそう

次のコードで実験しました、が...

Python

1import cv2 2import numpy as np 3 4 5def main(): 6 img = cv2.imread('sea.jpg') 7 8 hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 9 lower_red = np.array([170,100,190]) 10 upper_red = np.array([200,255,255]) 11 mask = cv2.inRange(hsv_img, lower_red, upper_red) 12 13 # 14 # Write points 15 points = np.vstack( 16 np.where(mask==255) 17 ).T 18 19 RED = (0, 0, 255) 20 for pt in map(tuple, points): 21 cv2.circle(img, pt, radius=20, color=RED, thickness=-1) 22 23 cv2.imwrite('result.jpg', img) 24 # 25 # 26 27if __name__ == "__main__": 28 main()

期待
期待


実際
実際

『ブイ候補』を正しく認識できたなら...

前述の理由により正しく動作しませんが... (make_buoy_mask関数に相当)
その部分さえ修正できれば、充分実用できるかと。

find_buoy.py

Python

1import sys 2 3import numpy as np 4import cv2 5 6from partition import partition 7 8 9# 質問のブイマスク抽出の流用 10def make_buoy_mask(img): 11 return cv2.inRange( 12 cv2.cvtColor(img, cv2.COLOR_BGR2HSV), 13 lowerb=np.array([170,100,190]), 14 upperb=np.array([200,255,255]) 15 ) 16 17# マスク画像を生成してから、ブイの座標のnp.arrayを返す 18def find_buoy(img): 19 return np.vstack( 20 np.where(make_buoy_mask(img)==255) 21 ).T 22 23def main(img_file): 24 img = cv2.imread(img_file) 25 26 # Find buoy pixels 27 buoy_pts = find_buoy(img) 28 buoy_ids = partition( 29 buoy_pts, 30 lambda x, y: np.linalg.norm(x-y) <= 10 31 ) 32 33 # Get center of buoys 34 num_of_buoy = max(buoy_ids) + 1 35 typical_buoy_pts = [ 36 buoy_pts[buoy_ids.index(i)] 37 for i in range(num_of_buoy) 38 ] 39 40 # Check buoy position 41 RED = (0, 0, 255) 42 for buoy in typical_buoy_pts: 43 cv2.circle(img, tuple(buoy), radius=10, color=RED, thickness=5) 44 45 # Show result 46 cv2.imshow('result', img) 47 cv2.waitKey() 48 cv2.destroyAllWindows() 49 50if __name__ == '__main__': 51 if len(sys.argv) != 2: 52 print('Usage: find_buoy.py img_file') 53 exit() 54 55 main(img_file=sys.argv[1])

partition.py OpenCV内部実装の焼き直し

Python

1from itertools import product 2from UnionFind import UnionFind 3 4# 番号を振りなおす e.g. [0, 0, 3, 5, 3, 2] -> [0, 0, 2, 3, 2, 1] 5def renumber(id_list): 6 id_set = set(id_list) 7 replace_dict = dict(zip( 8 sorted(list(id_set)), 9 [i for i, _ in enumerate(id_set)] 10 )) 11 return [replace_dict[elem] for elem in id_list] 12 13# UnionFind法を用いて、データを分類していく 14# 同一のクラスタであるとの判断基準はpredicate_funcで与える 15def partition(src_list, predicate_func): 16 src_len = len(src_list) 17 uf = UnionFind(src_len) 18 19 loop_obj = product(src_list, src_list) 20 for ij, (ei, ej) in enumerate(loop_obj): 21 i, j = divmod(ij, src_len) 22 23 if ei is ej: 24 continue 25 if not predicate_func(ei, ej): 26 continue 27 28 uf.union(i, j) 29 30 return renumber(uf._id)

test_partition.py

Python

1import unittest 2from partition import partition 3 4class TestPartition(unittest.TestCase): 5 def test_partition(self): 6 self.assertEqual( 7 partition([1, 2, 3, 7, 8, 9, 2], lambda x, y: abs(x-y) <= 1), 8 [0, 0, 0, 1, 1, 1, 0] 9 ) 10 self.assertEqual( 11 partition([1, 1, 1, 3, 4, 4, 5, 6], lambda x, y: x % 2 == y % 2), 12 [0, 0, 0, 0, 1, 1, 0, 1] 13 ) 14 15if __name__ == '__main__': 16 unittest.main()

UnionFind.pyは、既にあるものを利用。

投稿2018/01/11 08:49

編集2018/01/11 15:51
LouiS0616

総合スコア35660

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

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

sekaikan_ozaki

2018/01/11 09:00

ご回答ありがとうございます。 質問を編集し、使用画像を載せました!
LouiS0616

2018/01/11 09:15 編集

対応感謝します。 mask画像を表示してみましたが、ほとんどディスプレイの汚れと見分けがつかないくらいです。 もうちょっと距離の近い画像は使えないのでしょうか?
sekaikan_ozaki

2018/01/11 09:24

申し訳ありません。 このドローンの高度しか画像データがないので難しいです。 赤色の漁具の場所を丸で囲った画像に編集しなおしました。
LouiS0616

2018/01/11 09:44

このサイズだったら、左上のピクセルを代表点にしてもいいかもしれませんね。
sekaikan_ozaki

2018/01/11 10:28

ありがとうございます! 左上のピクセルを取得するのが一番楽ということですね。 ちなみに、 どういったコードを組めばよいでしょうか?
LouiS0616

2018/01/11 10:33

一番ごり押しな方法は左上から探査することです。 見つけたポイントを記録すると同時に、周囲を適度に塗りつぶしてやれば多重検出もないかと。 あるいは、活性化(?)しているピクセルをすべて集めて、クラスタリングするのもありです。
sekaikan_ozaki

2018/01/11 10:57

具体的には、画素(0,0)からスタートし、画素の色が白の部分を漁具1個としてカウントし、その時の画素を保存、周り10ピクセルほどを黒に変更、(4096,2160)になるまで繰り返すといった感じでしょうか? 二重for文でi=0からi=4096,j=0からj=2160でやれるかと思いつきました
LouiS0616

2018/01/11 11:08

そんな感じになるでしょうね。 ただ、ものすごく重い処理になりそうな予感はします。 もうちょっといい方法があると思います、もし思いついたら追記します。
sekaikan_ozaki

2018/01/11 11:17

手伝っていただき申し訳ないです。。。 本当にありがとうございます。
LouiS0616

2018/01/11 15:34

質問のブイの検出アルゴリズム自体にちょっと粗があったようです。 そこから見直す必要がありますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問