Home > Tags > opencv

opencv

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 0x02D6BA30>,
h_next=<opencv.cxcore.LP_CvSeq object at 0x02E05620>,
v_prev=<opencv.cxcore.LP_CvSeq object at 0x02E05800>,
v_next=<opencv.cxcore.LP_CvSeq object at 0x02E056C0>,
total=2502, elem_size=8, block_max=”, ptr=”, delta_elems=1024,
storage=<opencv.cxcore.LP_CvMemStorage object at 0x02E058F0>,
free_blocks=<opencv.cxcore.LP_CvSeqBlock object at 0x02E058F0>,
first=<opencv.cxcore.LP_CvSeqBlock object at 0x02E058F0>))

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

contour_error

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

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

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

OpenCV+Python特集の目次へ戻る

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

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

■はじめに
私はハードウェアグループ所属で、プログラミング業務に携わることが少なかったのですが、
画像処理プログラミングについて先輩から教わる機会を設けることができました。
ここでは、プログラミング入門者である私が、日々学んだ技術を紹介していきたいと思います。

■今回のテーマ
まずはIntel社の画像処理ライブラリOpenCVを使った画像処理プログラムについて紹介します。
OpenCVは、500以上もの関数が用意され、座標変換、特徴点抽出といった画像処理が容易に行えます。
OpenCVはC言語用のライブラリですが、今回はコンパイル不要でデバッグがスムーズに行える
スクリプト言語python、OpenCVをpythonで使用するためのctypes OpenCVモジュールを使った
画像処理について、紹介したいと思います。

■  ギヤの歯数の検出
メカトロニクスでは、ギヤは必ずと言っていいほど使われます。その一環でギヤの歯数を数えるという場面は、
しばしば遭遇します。20歯程度なら、容易に数えられるのですが、30歯、40歯…100歯と歯数が増える程、
人間の目で数えるのはとても困難になります。それを自動で数えるものがあったら、便利ではないでしょうか。
ここでは画像処理学習の題材として、ギヤの画像から歯数を自動で数える画像処理プログラムを作成してみました。

■  画像処理アルゴリズム概要
今回は以下のようなアルゴリズムで、プログラムを作成しました。第1回目は、グレースケール変換まで紹介したいと思います。

gear-chart-090721a

■  ギヤ画像の取得
まずは画像処理対象となるギヤの画像を用意します。
今回は歯数が28歯のモールドギヤをCanon IXY DIGITAL600デジタルカメラで撮影しました。

gear

画像が用意出来たら、ctypes OpenCVモジュールをインポートし、OpenCVのcvLoadImage関数で画像をロードし、
cvCreateImage関数で画像データを格納するメモリ領域を確保します。また、cvResize関数を用いて画像サイズを変換します。

from opencv import *
#画像ファイル読込 (ファイル名:sampleImage.JPG)
readImage = cvLoadImage(‘C:\\python26\\Image\\sampleImage.JPG’,
CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR )

#画像サイズ変換(1152×864に変換)
sourceImage = cvCreateImage(cvSize(1152, 864), IPL_DEPTH_8U, 3)
cvResize(readImage, sourceImage, CV_INTER_CUBIC)

次に、画像変換後の画像メモリ領域を同様にcvCreateImage関数で確保します。
あらかじめsizeOfImage関数で元画像のサイズを読み込み、同サイズのものを作成します。

#変換画像メモリ領域確保
sizeOfImage = cvGetSize(sourceImage)
grayImage = cvCreateImage(sizeOfImage, IPL_DEPTH_8U, 1)   #グレースケール変換画像用
smoothImage = cvCreateImage(sizeOfImage, IPL_DEPTH_8U, 1)  #ぼかし画像用
binImage = cvCreateImage(sizeOfImage, IPL_DEPTH_8U, 1)  #2値化画像用
contImage = cvCreateImage(sizeOfImage, IPL_DEPTH_8U, 1)  #輪郭検出画像用

次にcvCvtColor関数で、元画像をグレースケールに変換します。

#グレースケール変換
cvCvtColor(sourceImage, grayImage, CV_BGR2GRAY)

画像がグレースケールに変換されたか確認するため、cvShowImage関数で変換画像を表示してみます。
cvNamedWindow関数で、あらかじめ表示用のウィンドウを作成します。

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

記述できたら、いざプログラムを実行してみます。

gear-gray

グレースケール画像に変換出来ました。次回は画像の2値化、ギヤ歯輪郭検出などについて紹介します。

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

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

Home > Tags > opencv

Search
Feeds
Authorized
奨学金支援制度
Meta

Return to page top