Home > Tags > ギアの歯数を画像処理で数える

ギアの歯数を画像処理で数える

PythonとOpenCVによる画像処理プログラミングセミナー byタマちゃん

■はじめに
私はハードウェアグループ所属で、プログラミング業務に携わることが少なかったのですが、
画像処理プログラミングについて先輩から教わる機会を設けることができました。
ここでは、プログラミング入門者である私が、日々学んだ技術を紹介していきたいと思います。
PythonとOpenCVによる画像処理プログラミングセミナー 第1回
PythonとOpenCVによる画像処理プログラミングセミナー 第2回
ちょっと息抜きでC++でOpenCV編 cvFindContoursの結果から座標を得る

  • Comments (Close): 0
  • Trackbacks (Close): 0

pythonとOpenCVによる画像処理プログラミングセミナー 第2回目

■セミナー概要
このセミナーでは、pythonとOpenCVを使った画像処理の応用として、
ギヤの歯数を画像から自動で数えるアプリケーションを作成します。
第1回目では、画像の取得、グレースケール変換まで紹介しました。
今回は画像の2値化、ギヤ歯輪郭検出について紹介したいと思います。

■  画像の2値化
2値化を行う前に、cvSmooth関数を用いて、画像を平滑化(ぼかし処理
みたいなもの)します。入力画像にはグレースケール画像を指定します。

#画像の平滑化
cvSmooth(grayImage, smoothImage, CV_BLUR , 3, 0, 0)

次に、平滑化した画像をcvThreshold関数を用いて2値化します。
スレショルドレベルは、とりあえず50にセットしてみました。

#画像の2値化
cvThreshold(smoothImage, binImage, 50, 255, CV_THRESH_BINARY )

ここまでの段階で、2値化した結果を画面に表示して確認してみましょう。

cvNamedWindow(”Image”, CV_WINDOW_AUTOSIZE)  #ウィンドウ作成
cvShowImage( “Image”, binImage)  #2値化画像表示
cvWaitKey(0)  #何かキーを押されたら終了

2値化ギヤ-失敗編

画像を2値化出来ました。しかし、まだノイズが乗っています。スレショルドレベル
をいろいろ変更して2値化結果を確認しながら、最適な値を設定しましょう。
このパラメータ最適化が、画像処理では大変な作業です。
pythonではプログラム実行にコンパイルが不要な為、この検討作業が非常に
スムーズに行えます。ここではカットアンドトライで、スレショルドレベルは126に
設定したところ、綺麗な2値化画像が得られました。

2値化ギヤ-成功編

■  輪郭の検出
次に、2値化した画像からcvFindContours関数を用いて輪郭を検出します。
あらかじめcvCreateMemStorage関数を用いて、輪郭データ(シーケンスと
呼ばれるデータ構造に格納される)を格納するメモリストレージを確保します。
cvFindContours関数のmode引数にCV_RETR_EXTERNALを指定すると、
検出された輪郭のうち最も外側の輪郭のみstorageに格納されるため、ギヤの
歯の部分の輪郭のみが検出出来ます(内側の軸穴部分の輪郭データは格納されない)。

storage = cvCreateMemStorage(0)  #シーケンスデータ用のメモリストレージ確保
#輪郭検出.CV_RETR_EXTERNALは、検出された輪郭のうち最も外側の輪郭のみstorageに格納する
contours = cvFindContours( binImage, storage, None, sizeof(CvContour),
CV_RETR_EXTERNAL  , CV_CHAIN_APPROX_NONE ,cvPoint(0,0))

検出された結果を、cvDrawContours関数を用いて画面に表示してみます。
引数CvArr* imgには、輪郭線を表示する画像を指定します。ここでは、原画像を
指定します。輪郭線は赤色、太さ2に設定しました。

red = CV_RGB(255,0,0)
cvDrawContours( sourceImage, contours[1], red, red, 1, 2, 8, cvPoint(0,0))
cvNamedWindow(”Image”, CV_WINDOW_AUTOSIZE)  #ウィンドウ作成
cvShowImage( “Image”, sourceImage)  #輪郭線を含む原画像表示
cvWaitKey(0)  #何かキーを押されたら終了

contour

ギヤの歯の輪郭が検出出来ました。ここで、変数contoursには、輪郭線の総数と
シーケンス構造体CvSeqの2つを要素とするタプルが渡されます。contoursの中身
を参照してみましょう。

print  contours  #contousの中身を参照

以下のような結果が表示されます。0番目の要素は輪郭線の総数であり、
ここでは1になっています。輪郭線が1つということは、ギヤの場合、検出された
輪郭線は連続(途中で輪郭の欠損がない)で閉じていることになります。
もし輪郭線の総数が複数になった場合、ギヤの歯以外の輪郭が検出されている
場合があります。

出力結果:(1, CvSeq(flags=1117327884,header_size=88,
h_prev=<opencv.cxcore.LP_CvSeq object at 0×02D6BA30>,
h_next=<opencv.cxcore.LP_CvSeq object at 0×02E05620>,
v_prev=<opencv.cxcore.LP_CvSeq object at 0×02E05800>,
v_next=<opencv.cxcore.LP_CvSeq object at 0×02E056C0>,
total=2502, elem_size=8, block_max=”, ptr=”, delta_elems=1024,
storage=<opencv.cxcore.LP_CvMemStorage object at 0×02E058F0>,
free_blocks=<opencv.cxcore.LP_CvSeqBlock object at 0×02E058F0>,
first=<opencv.cxcore.LP_CvSeqBlock object at 0×02E058F0>))

例えば、2値化の説明で使用した、ノイズの多い2値化画像を用いて輪郭検出
を行うと、下図のようにノイズ部分も輪郭として検出されるため、歯の輪郭検出が
正しく行えなくなります。

contour_error

このとき、輪郭線の総数を参照すると、輪郭線は不連続であるため総数は多くなります。

print  contours[0]  #輪郭線の総数を参照
出力結果:2520

今回適用するアルゴリズムでは、輪郭線は連続で閉じていることが前提であるため、
輪郭線の総数が1となるよう、調整します。ピンぼけ画像や、歯のエッジが薄い画像
などは、輪郭がうまく検出出来ない場合もあります。
次回は、この輪郭データを用いてギヤの歯数を数えるアルゴズムについて紹介したい
と思います。

OpenCV+Python特集の目次へ戻る

  • Comments (Close): 0
  • Trackbacks (Close): 0

Home > Tags > ギアの歯数を画像処理で数える

Search
Feeds
Meta

Return to page top