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

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

ただいまの
回答率

91.23%

  • Python 3.x

    2785questions

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

  • OpenCV

    674questions

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

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

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 139

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

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

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

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

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

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

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

~追記~

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

イメージ説明

#-*- coding:utf-8 -*-
import cv2
import numpy as np


def main():

    #画像を入力
    img = input('画像をを入力してください: ')
    #画像の読み込み

    img=cv2.imread(img)

    # HSV色空間に変換
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)


    cv2.namedWindow("hsv.jpg", cv2.WINDOW_KEEPRATIO | cv2.WINDOW_NORMAL)


    # 赤色のHSVの値域
    lower_red = np.array([170,100,190])
    upper_red = np.array([200,255,255])
    mask = cv2.inRange(hsv, lower_red, upper_red)

    hsv = mask

    #画像の表示
    cv2.imshow("hsv.jpg", hsv)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

  #以下に赤色の物体を検知した部分のピクセル座標を取得するコードを書きたい



if __name__ == "__main__":
    main()
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

+1

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

import cv2

color = {
    'gray': (128, 128, 128),
}

img = cv2.imread('object.jpg', cv2.IMREAD_GRAYSCALE)
assert img is not None

m = cv2.moments(img)
cx = int(m['m10'] // m['m00'])
cy = int(m['m01'] // m['m00'])

cv2.drawMarker(img, (cx, cy), color['gray'])
cv2.imshow('img', img)
cv2.waitKey()
cv2.destroyAllWindows()

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


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

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

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

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

import cv2
import numpy as np


def main():
    img = cv2.imread('sea.jpg')

    hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    lower_red = np.array([170,100,190])
    upper_red = np.array([200,255,255])
    mask = cv2.inRange(hsv_img, lower_red, upper_red)

    #
    # Write points
    points = np.vstack(
        np.where(mask==255)
    ).T

    RED = (0, 0, 255)
    for pt in map(tuple, points):
        cv2.circle(img, pt, radius=20, color=RED, thickness=-1)

    cv2.imwrite('result.jpg', img)
    #
    #

if __name__ == "__main__":
    main()

期待
期待


実際
実際

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

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

find_buoy.py

import sys

import numpy as np
import cv2

from partition import partition


# 質問のブイマスク抽出の流用
def make_buoy_mask(img):
    return cv2.inRange(
        cv2.cvtColor(img, cv2.COLOR_BGR2HSV),
        lowerb=np.array([170,100,190]),
        upperb=np.array([200,255,255])
    )

# マスク画像を生成してから、ブイの座標のnp.arrayを返す
def find_buoy(img): 
    return np.vstack(
        np.where(make_buoy_mask(img)==255)
    ).T

def main(img_file):
    img = cv2.imread(img_file)

    # Find buoy pixels
    buoy_pts = find_buoy(img)
    buoy_ids = partition(
        buoy_pts,
        lambda x, y: np.linalg.norm(x-y) <= 10
    )

    # Get center of buoys
    num_of_buoy = max(buoy_ids) + 1
    typical_buoy_pts = [
        buoy_pts[buoy_ids.index(i)]
        for i in range(num_of_buoy)
    ]

    # Check buoy position
    RED = (0, 0, 255)
    for buoy in typical_buoy_pts:
        cv2.circle(img, tuple(buoy), radius=10, color=RED, thickness=5)

    # Show result
    cv2.imshow('result', img)
    cv2.waitKey()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print('Usage: find_buoy.py img_file')
        exit()

    main(img_file=sys.argv[1])

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

from itertools import product
from UnionFind import UnionFind

# 番号を振りなおす  e.g. [0, 0, 3, 5, 3, 2] -> [0, 0, 2, 3, 2, 1]
def renumber(id_list):
    id_set = set(id_list)
    replace_dict = dict(zip(
        sorted(list(id_set)),
        [i for i, _ in enumerate(id_set)]
    ))
    return [replace_dict[elem] for elem in id_list]

# UnionFind法を用いて、データを分類していく
# 同一のクラスタであるとの判断基準はpredicate_funcで与える
def partition(src_list, predicate_func):
    src_len = len(src_list)
    uf = UnionFind(src_len)

    loop_obj = product(src_list, src_list)
    for ij, (ei, ej) in enumerate(loop_obj):
        i, j = divmod(ij, src_len)

        if ei is ej:
            continue
        if not predicate_func(ei, ej):
            continue

        uf.union(i, j)

    return renumber(uf._id)

test_partition.py

import unittest
from partition import partition

class TestPartition(unittest.TestCase):
    def test_partition(self):
        self.assertEqual(
            partition([1, 2, 3, 7, 8, 9, 2], lambda x, y: abs(x-y) <= 1),
            [0, 0, 0, 1, 1, 1, 0]
        )
        self.assertEqual(
            partition([1, 1, 1, 3, 4, 4, 5, 6], lambda x, y: x % 2 == y % 2),
            [0, 0, 0, 0, 1, 1, 0, 1]
        )

if __name__ == '__main__':
    unittest.main()

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/11 18:00

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

    キャンセル

  • 2018/01/11 18:15 編集

    対応感謝します。

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

    キャンセル

  • 2018/01/11 18:24

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

    キャンセル

  • 2018/01/11 18:44

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

    キャンセル

  • 2018/01/11 19:28

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

    キャンセル

  • 2018/01/11 19:33

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

    キャンセル

  • 2018/01/11 19:38

    了解です。やってみます。

    キャンセル

  • 2018/01/11 19:57

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

    キャンセル

  • 2018/01/11 20:08

    そんな感じになるでしょうね。
    ただ、ものすごく重い処理になりそうな予感はします。

    もうちょっといい方法があると思います、もし思いついたら追記します。

    キャンセル

  • 2018/01/11 20:17

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

    キャンセル

  • 2018/01/12 00:34

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

    キャンセル

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

ただいまの回答率

91.23%

関連した質問

  • 解決済

    python,opencvで円弧型の部分にのみ処理をしたい

    Python,OpenCVともに使うのが初めてです。 現在、類似画像検索のようなものを作っています。 そこで、画像の一部(円弧型)にある処理(ただ白いpixelを数えるだけ)を

  • 受付中

    C++のCAD上で作成した図形の輪郭切り取り

    C++ ```###前提・実現したいこと CADで図のような立体画像を作成し、この画像の赤い部分のような、輪郭画像を抽出するプログラムを作成しました。このプログラムを使用し現在

  • 解決済

    python3+OpenCVで、特定色の箇所を白い線で囲いたい

    お世話になっております。 今回は、python3 + opencvにて以下のようなことをやりたいと考えているのですが、どのようにすれば実現できるのか分からない為、ご質問させて

  • 解決済

    PIL Image 日本語が文字化けする

    from PIL import ImageFont, ImageDraw, Image img = Image.new("RGB", (500,750),(255, 255, 2

  • 解決済

    pythonの画像の読み込みについて

    pythonの勉強をしています。ある画像を読み込み、それを配列化してテキストデータとしてファイルに保存したいです。 下記のようなコードを描いたのですが、これが正しく出力がされ

  • 解決済

    背景色を素早く除去したい

    OpenCVを使い、画像処理を行なっているものです。 処理したい画像は白色の背景をしています。 そして、この白色が画像処理の邪魔になってしまっています。 def del

  • 解決済

    opencv python 画像処理

    # -*- coding: utf-8 -*- import cv2 import numpy as np # フレーム差分の計算 def frame_sub(src1, src

  • 解決済

    python,OpenCV,numpyによる色抽出・変換

    前提・実現したいこと pythonで画像の色変換を行いたいのですが, opencvのimreadで画像を読み込み, 例えば[R,G,B]=[255,0,0]の画素を[R,G,B]=

同じタグがついた質問を見る

  • Python 3.x

    2785questions

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

  • OpenCV

    674questions

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