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

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

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

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

Python 3.x

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

Q&A

解決済

2回答

3822閲覧

openCV 色の判定について

ChaCha_MaRu

総合スコア15

OpenCV

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

Python 3.x

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

0グッド

1クリップ

投稿2019/08/15 08:25

pythonを用いたopenCVについて質問です。

行いたいこと

ハフ変換により検出した球体の色を調べ、何色の玉か判定する。
玉には目的とする色(赤や青)の外に不要な色(白と黒)が混ざっているので、HSV変換を用いて不要な色を除いたものだけで判定したい。
中心から周囲(円形)の画素を調べることで色を判定できるのかが分からないです。それとも、もっと簡単な判別方法がありますでしょうか。

行ったこと

エッジ処理→ハフ変換→円の中心の座標を求める

python3

1 2# -*- coding: utf-8 -*- 3 4import cv2 5import numpy as np 6 7#入力画像の読み込み 8img = cv2.imread(r'画像へのパス') 9 10#Gray Scaleへ変換 11gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 12 13#Sobelフィルタでx方向のエッジ検出 14gray_sobelx = cv2.Sobel(gray,cv2.CV_32F,1,0) 15 16#x方向のエッジ検出結果表示 17#cv2.imshow('gray_sobelx',gray_sobelx) 18 19#Sobelフィルタでy方向のエッジ検出 20gray_sobely = cv2.Sobel(gray,cv2.CV_32F,0,1) 21 22#8ビット符号なし整数変換 23gray_abs_sobelx = cv2.convertScaleAbs(gray_sobelx) 24gray_abs_sobely = cv2.convertScaleAbs(gray_sobely) 25 26#重み付き和 27gray_sobel_edge = cv2.addWeighted(gray_abs_sobelx,0.5,gray_abs_sobely,0.5,0) 28 29 30 31img=gray_sobel_edge.copy() 32img = cv2.medianBlur(img,5) 33cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR) 34 35circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,40, 36 param1=149,param2=15,minRadius=8,maxRadius=11) 37 38 39circles = np.uint16(np.around(circles)) 40 41#結果用の画像 42result = cv2.imread(r'画像へのパス') 43 44#中心の描写 45for i in circles[0,:]: 46 cv2.circle(result,(i[0],i[1]),1,(0,0,255),3) 47 48 49#結果の表示 50cv2.imshow('detected circles',result) 51 52 53cv2.waitKey(0) 54cv2.destroyAllWindows() 55 56 57 58 59

三つの玉の画像

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

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

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

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

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

fana

2019/08/15 09:58

> 玉には目的とする色(赤や青)の外に不要な色(白と黒)が混ざっている これは,例えば「赤い玉」の表面全てが赤いわけではなく,白や黒で何かしらの模様が描かれている的な話ですか?
guest

回答2

0

ベストアンサー

以下のようにしてみてはどうでしょうか。

  1. 2値化後に輪郭抽出して、各円を取り出す。
  2. 各円内の色に対して、k-mean クラスタリングを行い、代表色を計算する。

以下、OpenCV のチュートリアル

OpenCVのK-Meansクラスタリング — OpenCV-Python Tutorials 1 documentation

サンプルコード

python

1import cv2 2import numpy as np 3import matplotlib.pyplot as plt 4 5 6# 画像を読み込む。 7img = cv2.imread(r"sample.png") 8 9# HSV に変換する。 10hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 11 12# 水色かどうかで2値化する。(水色は0、それ以外は255) 13binary = cv2.inRange(hsv, lowerb=(95, 0, 0), upperb=(100, 255, 255)) 14binary = ~binary 15 16# メディアンフィルタで端をなめらかにする。 17binary = cv2.medianBlur(binary, 7) 18 19# 輪郭抽出を実行する。 20contours, hierarchy = cv2.findContours( 21 binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE 22) 23 24for cnt in contours: 25 # ROI 領域以外をマスクする。 26 mask = np.zeros_like(img) 27 cv2.drawContours(mask, [cnt], -1, color=(255, 255, 255), thickness=-1) 28 masked = img & mask 29 30 # 色一覧 31 colors = masked.reshape(-1, 3) 32 colors = colors[(colors != 0).all(axis=1)] # 黒は除く 33 34 # k平均法でクラスタリングする。 35 k = 3 36 criteria = cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0 37 ret, label, center = cv2.kmeans( 38 colors.astype(np.float32), k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS 39 ) 40 41 # 円の中に含まれる代表色 Top3 を可視化する。 42 fig, [ax1, ax2] = plt.subplots(1, 2, figsize=(10, 5)) 43 # 各クラスに属するサンプル数を計算する。 44 height = [np.count_nonzero(label == i) for i in range(k)] 45 # 各クラスたの色を取得する。matplotlib の引数の仕様上、[0, 1] にして、(R, G, B) の順番にする。 46 rep_color = (center / 255)[:, ::-1] 47 48 # 画像を表示する。 49 ax1.imshow(cv2.cvtColor(masked, cv2.COLOR_BGR2RGB)) 50 ax1.set_axis_off() 51 52 # ヒストグラムを表示する。 53 ax2.barh(np.arange(k), height, color=rep_color, tick_label=height) 54 plt.show()

イメージ説明

イメージ説明

イメージ説明

投稿2019/08/15 10:32

編集2019/08/15 13:28
tiitoi

総合スコア21956

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

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

fana

2019/08/19 08:02

主要な色を決めるのにざっくりとkmeansを使うのはなるほどなぁ,と思ったので高評価を入れました. 初期クラスタ中心(乱数?)次第で主要色が1クラスタにまとまらずに複数個のクラスタに分かれてしまう(→結果として他の色の頻度を下回ってしまう)可能性を考慮すると,複数回試行した結果から決める等すると良いのかもしれません. (KMEANS_RANDOM_CENTERSをKMEANS_PP_CENTERSに変えればそういった可能性がいくらか緩和するのかも?)
tiitoi

2019/08/19 08:54

確かに、初期値依存を減らすのに KMEANS_PP_CENTERS で kmeans++ を使うようにしたほうが安定しそうですね。 アドバイスありがとうございます。
fana

2019/08/19 08:59

玉の色の種類が既知な実施形態の場合には,それらの色(と,ノイズである白や黒)をクラスタ中心に使う感じになりますかね.
guest

0

HSV変換を用いて不要な色を除いたものだけで判定したい。

中心から周囲(円形)の画素を調べることで色を判定できるのかが分からないです。

円の内部の画素群を走査して色を調べる際に「彩度Sがある閾値に満たない画素は無視する」ような形にすれば良いのではないでしょうか.
(実際上は,明度の閾値も適当に与えた方がよいハズ)
残った(彩度をある程度持つ)画素群の色相(H)の平均なりから結果を決定すれば良いでしょう.

候補の色が既知である(例えば,赤青黄の3種類のどれかだと事前にわかっているような)場合には,画素値(色相だけでも良いかも)のSSDだとか相関係数的な物を評価して,どの候補色に最も近いかを判定すれば良いでしょう.


追記:
(前処理にハフ変換を用いる関係で)エッジ強度に関するデータが得られているなら,エッジ強度が強い画素も無視すると良いかもしれません.

投稿2019/08/19 08:13

編集2019/08/19 08:15
fana

総合スコア11658

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問