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

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

詳細はこちら
OpenCV

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

Python

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

Q&A

解決済

2回答

2635閲覧

OpenCV・Pythonで画像から5本の直線をまとめて検出したいです

cherryblossom

総合スコア17

OpenCV

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

Python

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

0グッド

1クリップ

投稿2018/11/12 15:19

OpenCVを用いたPythonで五線譜画像の認識を行いたいです.
そのため,同じ間隔で,同一の方向を向いている直線の検出を試みています.
直線検出はHough変換を用いればよいかと思いますが,等間隔の5本の線を検出するのにどうすればよいか悩んでいます.
皆様の知恵をお借りできれば幸いです.

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

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

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

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

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

guest

回答2

0

内容は,2018/11/13 10:48のコメントの内容と同一です.
(この内容に関してのやりとりが発生したため,回答として分けました)

見つけたい線群が画像内で「水平な線」であることを仮定して良いならば,
直線の方向は既知ですから,直線の位置(y座標)だけを見つければよいわけです.
(ハフ変換として見れば,投票空間は1次元でよい.)
輝度勾配方向が画像上で上下方向になるエッジ点群だけのy座標のヒストグラムを作れば,5つずつの山ができるでしょうから,そこから線群のy座標を推定することができそうです.

(画像の具合次第ですが,「水平」を仮定できない場合でも,見つけたい線群の画像上での方向を,輝度勾配の主たる方向等から推定できるかもしれません.→方向が推定できれば以降の処理は同様.)


ヒストグラムの作成方法がわかりません.

度数分布を求めるだけですから,難しい話ではありません。
画像のy方向サイズ分の配列でも用意して(要素は全0に初期化しておき),画像の全画素を走査して,エッジ点のy座標に対応する配列要素をインクリメントすることを繰り返せばよいでしょう.


とりあえず,ものすごーく雑に実装してみました.
(当方,pythonがダメなので,C++ですが)

int main(void) { //画像読込 cv::Mat Src = cv::imread( "SrcImg.png", CV_LOAD_IMAGE_GRAYSCALE ); if( Src.empty() )return 0; cv::imshow( "Src", Src ); //ヒストグラム作成 std::vector< unsigned int > Hist( Src.rows, 0 ); //y方向サイズ分の配列.全要素0で初期化. for( int y=1; y+1<Src.rows; ++y ) { const unsigned char *pU = Src.ptr<unsigned char>( y-1 ); const unsigned char *pC = Src.ptr<unsigned char>( y ); const unsigned char *pD = Src.ptr<unsigned char>( y+1 ); for( int x=1; x+1<Src.cols; ++x ) { int Dx = std::max( abs( pC[x]-pC[x-1] ), abs( pC[x]-pC[x+1] ) ); int Dy = std::max( abs( pC[x]-pU[x] ), abs( pC[x]-pD[x] ) ); if( Dy>32 && Dy > Dx*4 ) //※エッジ点判定.雑すぎるが. { ++Hist[y]; } } } unsigned int MaxVal = *std::max_element( Hist.begin(), Hist.end() ); //ヒストグラムの最大値 {//表示:ヒストグラム画像 cv::Mat HistImg = cv::Mat::zeros( Src.rows, 100, CV_8U ); for( int y=0; y<Src.rows; ++y ){ cv::line( HistImg, cv::Point(0,y), cv::Point(100,y), cv::Scalar( 255.0 * Hist[y] / MaxVal ) ); } cv::imshow( "Hist", HistImg ); } //てきとー処理でヒストグラムの山(=線のy座標)を見つける std::vector< int > LineY; //ここに見つけた山のy座標群を格納 { unsigned int Thresh = MaxVal * 0.75; //閾値 int RiseY = -1; //閾値を越えた箇所記憶用.越えてないときは-1 for( int y=0; y<Hist.size(); ++y ) { if( RiseY < 0 ) { if( Hist[y]>=Thresh ) { RiseY = y; } } else { if( Hist[y]<Thresh ) { LineY.push_back( (RiseY + y)/2 ); RiseY = -1; } } } } {//表示:線検出結果 cv::Mat Result; cv::cvtColor( Src, Result, CV_GRAY2BGR ); for( int y : LineY ){ cv::line( Result, cv::Point(0,y), cv::Point(Result.cols,y), cv::Scalar( 0,0,255 ) ); } cv::imshow( "Lines", Result ); } // cv::waitKey(); return 0; }

結果の絵.
左から,原画,ヒストグラムを可視化したもの,線の位置を赤色で書いたもの.
(原画はてきとーにペイントで手書きしました.
線だけだと微秒なので,雑音として,小学校のときにこんな記号習ったような…?というのを何となく散りばめました.)
イメージ説明

投稿2018/11/13 08:46

編集2018/11/13 10:43
fana

総合スコア11987

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

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

cherryblossom

2018/11/13 09:52

丁寧な回答本当にありがとうございます. 頂いたアドバイスをもとにプログラムを組んでみます. 若輩者の私にアドバイスをいただけたこと感謝します.本当にありがとうございました.
fana

2018/11/13 10:47

話を雑にやってみた結果を追記しました.「5本ごとにまとめる」部分まではありませんが.
cherryblossom

2018/11/14 06:44

!!! アドバイスのみならず実際にプログラムまで書いてくださり,本当にありがたいです.... fana様,本当にありがとうございます. 今から実装してみます.
guest

0

ベストアンサー

五線譜というものを知らないのですが、調べてでてきたこのような画像という認識でよろしいでしょうか?

イメージ説明

Hough 変換で直線検出したあと、水平方向以外の線を検出対象外の直線として除去します。

直線は(始点、終点)という形で得られるので、楽譜の直線は水平方向に平行に並んでいるという仮定のもの、例えば、各直線の y 座標に注目し、以下のリストが得られたとします。
[直線1のy座標、直線2のy座標、...、直線nのy座標]

あとは楽譜も横棒がすべて5本ずつとか決まっているのであれば、
リストの最初の5本は1行目の楽譜の直線、6 ~ 10本目は2行目の楽譜の直線というようにすればよいのではないでしょうか?

投稿2018/11/12 15:32

tiitoi

総合スコア21956

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

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

cherryblossom

2018/11/12 15:35

それであっています! 迅速な回答ありがとうございます.なるほど,直線の数で制限をかけていけばよいのですね! 試してみます.本当にありがとうございます.
fana

2018/11/13 01:48

本当に水平方向を仮定していいならば,直線の「方向」に関して投票行動を行う意味は無いですよね. (ハフ変換として見れば,投票空間は1次元でよい.) 輝度勾配方向が画像上で上下方向になるエッジ点群だけのy座標のヒストグラムを作れば,きれいに5つずつの山ができるような気がします.
cherryblossom

2018/11/13 08:14

分かりづらい質問をしてしまい申し訳ないです....そして,回答ありがとうございます ヒストグラムを作れば,きれいに直線が取れるということですかね? また,若輩者ゆえ,ヒストグラムの作成方法がわかりません.自身でも調べていくのですが,なにか良い参考サイトなどがあれば教えていただきたいです.厚かましいお願いであることは承知しております.どうか,お願いいたします.ないようであれば,回答しなくて構いません.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問