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

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

詳細はこちら
OpenCV

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

Python

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

Q&A

解決済

2回答

2559閲覧

複数画像の円形検出の手法について相談したいです。

gomsis

総合スコア11

OpenCV

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

Python

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

0グッド

0クリップ

投稿2020/12/04 05:11

編集2020/12/17 08:16

python,Opencvを用いたプログラムで質問です。

まだプログラムを触り始めて1か月程度の初心者なのですが、円形の検出を行いたいです。
100枚以上の画像から円の検出を行うのですが、それぞれの画像にはランダムで円が配置されており、中には円がない画像もあります。
また、画像には検出したい円とは別のモノも写っています。
画像は照度が一致しておらず、フレーム差分、背景差分は影を誤認識してしまい、難しいのではないかと考えています。

検出したい円はランダムで表示され、検出したくないモノは、全画像で同じ位置に配置されています。 

このような条件下で、検出したい円だけを数えたいのですが、どのようなプログラムが考えられるでしょうか。

私なりに考えたプログラムでは、とりあえず、検出したい円形、検出したくない円形のどちらもを円形検出したあと、前後(またはどちらか)の画像と比較して動いていない円形は消去し、動いた(または同じ位置で検出されない)円形は採用するようなものを考えましたが、このような処理が行えるかどうかが、私自身の知識では手法が分かりません。

ご意見おまちしております。宜しくお願い致します。

参考画像1

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

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

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

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

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

fana

2020/12/04 05:14

画像例を示すことはできませんか?
gomsis

2020/12/04 05:45

画像追加しました。 宜しくお願い致します。
fana

2020/12/04 08:11

画像毎に照度が異なることに対しては,以下のようないくつかの方針が考えられると思います. ・画像の 明るさ/コントラスト を揃えるための補正処理を考える ・単一の画像内で,円とその周辺との相対的な 明るい/暗い 関係から円を検出することによって,照度のゆらぎに対抗する ・「円の有無による画素値の変化量というのは,画像間の照度のゆらぎ幅よりも大きい」という前提を置いて(実際に置けるのかわかりませんけど)画素値の平均や分散等を用いた「背景差分」のような処理を組む
guest

回答2

0

ベストアンサー

提示された5枚の画像のうち,4番目(明るい)と5枚目(暗い)に関して,
てきとーに画素の明るさの差分を見れる程度に補正処理をできるかどうか? をやってみました.

テストに際しては,

  • 画像サイズがでかかったので,縦横共に1/4に縮小して使った
  • とりあえず明るさだけを見たいので,グレースケールで読み込んだ

下図の

  • 上段は,{画像4そのもの,画像5そのもの,両者のabsdiff結果を(見やすいように)5倍したもの}
  • 下段は,{画像4補正結果,画像5補正結果,両者のabsdiff結果を(見やすいように)5倍したもの}

です.
この程度の急峻でない明暗変化具合であれば,まぁ,てきとーに前処理で明るさを補正してやる方向でも良いのではないか?と思います.

テスト処理結果

テストに用いた明るさ補正コードです.(C++ですが)

C++

1cv::Mat Correction( const cv::Mat &Src, int KernelSizeFactor=6 ) 2{ 3 cv::Mat Blurred; 4 { 5 int s = ( std::min( Src.rows, Src.cols ) / KernelSizeFactor ) | 0x01; 6 cv::GaussianBlur( Src, Blurred, cv::Size(s,s), 0 ); 7 } 8 9 cv::Mat Result = cv::Mat( Src.rows, Src.cols, CV_8UC1 ); 10 for( int y=0; y<Src.rows; ++y ) 11 { 12 const unsigned char *pS = Src.ptr<unsigned char>(y); 13 const unsigned char *pB = Blurred.ptr<unsigned char>(y); 14 unsigned char *pR = Result.ptr<unsigned char>(y); 15 for( int x=0; x<Src.cols; ++x, ++pS,++pB,++pR ) 16 { 17 double b = std::max<unsigned char>( 1, *pB ) / 255.0; 18 double g = log(0.5) / log(b); 19 *pR = cvRound( 255.0 * pow(*pS / 255.0, g) ); 20 } 21 } 22 return Result; 23}

[補足]
この処理のPython化の話をしている質問にて,上記テストコードの処理内容に関する指摘があったのでその点を補足しておく.

問題点
double b = std::max<unsigned char>( 1, *pB ) / 255.0;
の行が,*pBが0の場合についてはガードを入れているが,255の場合へのガードが抜けている.
そのため,*pBが255であるとき,double g = log(0.5) / log(b); の分母が0になってしまう.

対策について
0側と同様に,255側へのガードも入れれば良いであろうと思う.
すなわち,*pB の値を適当な有効範囲内に抑え込んでやればよかろう.

//2つの閾値 T_min, T_max の値はてきとーに決めるとして. const unsigned char T_min = 1; //1以上の値 const unsigned char T_max = 250; //254以下の値 ... double b = std::max( T_min, std::min(T_max,*pB) ) / 255.0;

投稿2020/12/04 09:21

編集2020/12/11 01:58
fana

総合スコア11985

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

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

gomsis

2020/12/07 09:18

回答ありがとうございます。 申し訳ないのですが、c++はほとんど触ったことがなく、分からないので簡単でいいので処理の内容を教えていただけますか?
fana

2020/12/07 09:58 編集

提示したサンプルコードの先頭らへん: まず,( GaussianBlur で )原画を強めにぼかした絵を作ってます.結果画像が Blurred です. 「強め」:サンプルコードでは,ガウシアンフィルタのサイズを 原画の幅/6 くらい(かなりでかい値)にしてます. 提示コードのfor: 全ての画素位置(x,y) について,以下を計算しています. b = {ぼかし画像Blurredの(x,y)の輝度か,1のうち大きい側の値} / 255.0 g = log(0.5) / log(b) 位置(x,y)の補正結果輝度値 = 255.0 * (元画像の(x,y)の輝度値/255.0)^g
fana

2020/12/07 10:02 編集

上記の謎の計算の意味: 255で割ったり255をかけたりしているのは,0~255の輝度値を 0~1.0 の範囲に正規化したり,後で 0~1.0 の値を輝度値の範囲に戻したりしているだけです. なので,下記は,値が 0~1.0 の範囲の世界について書きます. 入力値 v (0~1.0) をガンマ補正して v' にすることを考えます.式は, v' = v^g です.補正結果の v' も (0~1.0) です. 「ガンマ補正」については必要ならかるくググってください. 画像の明るさに対して,いい感じの g の値を与えれば,いい感じの補正結果 v' が得られるだろうと期待します. 画像の明るさが場所によって異なっている(例えば,画像5では右に行くほど暗い)ので,いい感じになる g の値も,画素位置毎に異なるでしょう. なので,やるべきことは,画素位置(x,y)毎に,何か適当に「いい感じになるg」の値をでっち上げてやることです. で,ここでは「ぼかした画像の輝度値 b に対して補正値が0.5になるような g」としてそれを算出しています. 0.5 = b^g をgについて解いた結果が, g = log(0.5) / log(b) です.
fana

2020/12/07 09:57 編集

暗い絵と明るい絵とでは,いい感じの補正結果になる g の値は異なる. →だったら,着目位置(x,y)周辺が明るいか暗いかに応じて g の値を決めよう →着目位置(x,y)周辺の明るさを示すものとして,ぼかし画像を用いた という話ですね. 「ぼかし画像の位置(x,y)の輝度値」は,ざっくりと言えば「着目位置(x,y)を中心とした一定範囲の輝度値の平均値」みたいなものです.
gomsis

2020/12/07 13:43

非常にわかりやすく説明していただきありがとうございます。 とても助かりました。 これを元にpytonでの実装をやってみます。
gomsis

2020/12/10 06:17 編集

度々申し訳ございません。 *pR = cvRound( 255.0 * pow(*pS / 255.0, g) );のところで、最後の部分、1/gではなくgになる理由は正規化しているためでしょうか?
fana

2020/12/10 08:51

> v' = v^g の部分ですから g乗 です.
gomsis

2020/12/11 04:27

ありがとうございます。勘違いをしていました。 ご丁寧に追記ありがとうございます。t_max=250となっていますが、255ではないでしょうか?
fana

2020/12/11 05:49

「*pBが255のときに 255 という値をそのまま使わないこと」を目的としているのですから 255 では意味ないです. T_min=1 と T_max=250 という値は,てきとーな値を例示しただけです. 何かしらの理屈で厳密な値を挙げているわけではないので,ご自身の処理においてどんな値が良いのかは御検討ください. (極端に真っ白/真っ黒 な画像を相手にするのでもなければ,実際上はT_minやT_maxの値が計算に使われることは稀であろうと思います)
gomsis

2020/12/11 05:54

なるほど、理解致しました。ありがとうございます。
guest

0

円形の検出、というのは置いておいて、まずは照度変化のある背景との差分を抽出するところから始める必要があるでしょう。
例えば createBackgroundSubtractorMOG という関数があります。試してみてはどうでしょうか。
参考:http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_video/py_bg_subtraction/py_bg_subtraction.html

投稿2020/12/04 09:01

yuki23

総合スコア1448

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問