読者です 読者をやめる 読者になる 読者になる

第1回 Ruby/OpenCV進捗報告

はじめに

ちょっと前にRuby/OpenCVをいじってます宣言をしてからだいぶいろいろやったので、ここらで一旦まとめておきます。

進捗

テスト

ユニットテストの進捗は以下の通りです。CvMatクラスがツワモノすぎてなかなか終わりません。
進捗は、現在Ruby/OpenCVがラップしている関数の数をもとにした値です。OpenCVに実装されている関数はもっといっぱいあります。
さらに、表に書いていないクラスについてはまったく手をつけていません。つまり、まだまだ作業がいっぱい残ってるということです。

クラス/モジュール 進捗
CvMat 半分くらい
CvBox2D だいたい完了
CvFont だいたい完了
CvMat だいたい完了
CvPoint だいたい完了
CvPoint2D32f だいたい完了
CvPoint3D32f だいたい完了
CvRect だいたい完了
CvScalar だいたい完了
CvSize だいたい完了
CvSize2D32f だいたい完了
IplImage だいたい完了
OpenCV cvCvtColor系の機能がけっこう残ってる

変更したもの

いろいろ変更しているので、抜けとかもあるかもです。
方針としては、なるべくOpenCVやRubyのお約束に従うようにと考えています。

  • to_aryを持ってるクラスにはto_aも実装

最近はto_aryよりto_aを使うことのほうが多いと思うので、エイリアスとしてto_aも実装しました。

  • CvVector削除

現在使われておらず、これからも使う予定がなさそうなので削除しました。必要になったら復活させるかも。

  • CvMatの各ピクセルへアクセスする際の座標の指定方法

CvMatの各ピクセルにアクセスする際、mat[(x座標), (y座標)]の順だったのを、OpenCVのお約束に従いmat[(y座標), (x座標)]に変更しました。互換性を考えるとアレなのですが、これまでのバージョンでも引数を4つ以上与えると順番が逆になっていたので、まぁいいかなと。

  • CvSeqで帰ってくるメソッドをArrayで返すように変更

CvMat#copyとかです。現在のところCvSeqを使うメリットが見当たらなかったので、素直にArrayで返すようにしました。もしかしたら直すかもしれません。

  • CvMatにcvMatMulを実装してCvMat#*をそっちに割り当て

以前はcvMulに割り当てられていたのですが、一般的に行列の乗算と言ったらcvMatMulのほうだと思うので。

  • CvMat#flipで引数を渡さないときの挙動を変更

引数が無い場合、以前はx方向、y方向の両方の軸について反転していましたが、OpenCVに合わせてy方向の反転をするようにしました。
それに伴い、両方の軸について反転するときはシンボル:xyを渡すように変更しています。

  • CvMatの==, >, >=, <, <=, !=は削除

これらはcvCmp, cvCmpSに割り当てられており、必ずnilではないCvMatのインスタンスが返ってきます。
そのため、

if mat1 > mat2
  # hogehoge...
end

とかやったときに条件式が必ず真になってしまい、紛らわしいので削除しました。行列の比較系メソッド(CvMat#gtとか)はまた見直すかもしれません。

要検討項目

  • CvMatで画素値を簡単に変更できない

現在、CvMatのあるピクセルの値を変更するには、

mat = CvMat.new(128, 128, :cv8u)
mat[0, 0] = CvScalar.new(0, 0, 255) # matの(0, 0)をR=255, G=0, B=0にしたい

のようにいちいちCvScalarクラスのインスタンスを作成しなければならず、「ちょっとRの値だけ変えたい」みたいなことが簡単にできません。これはCvMat#[]で値を返すときにCvScalarのインスタンスを新たに作ってしまっているのが原因なのですが、現状では良い解決策が思いつかないので、そのままになっています。

  • テストランナーで実行したときと単体でユニットテストを実行した時で結果がちょっと変わるメソッドがある

要はバグです。ぼちぼち直します。

  • エラーハンドリング

現在はOpenCVの投げる例外をキャッチしていないので、OpenCV側で例外が投げられると、その場でプログラムが落ちてしまいます。
なんとかしなければとは思うものの、各メソッドをtry-catchで囲むくらいしか対策が思いつかないので、保留になっています。
なんかいい方法ないかなー。

デモ

せっかくなので、現状でちゃんと動いてるっぽい機能のデモなどを。
Webカメラでキャプチャした映像からcvGoodFeaturesToTrackで特徴点を取得するサンプルです。
Ruby 1.9.2+OpenCV 2.2+Ubuntu 10.10でやっています。

require "opencv"
include OpenCV

# ウィンドウを作成
window = GUI::Window.new("Good features to track")

# キャプチャ開始
capture = CvCapture.open

# 何かキーが押されるまで
while GUI::wait_key(10).nil?
  # カメラからフレーム取ってきて
  img = capture.query
  # グレイスケールに変換した画像からcvGoodFeaturesToTrackで特徴点を取得
  corners = img.BGR2GRAY.good_features_to_track(0.2, 5, :use_harris => true)
  # 特徴点を赤丸で囲んで
  corners.each { |point|
    img.circle!(point, 5, :thickness => 2, :color => CvColor::Red, :line_type => :aa)
  }
  # 表示
  window.show img
end
# 最後にウィンドウを破棄
window.destroy

こんな感じで特徴点を取得し、描画します。
f:id:ser1zw:20110116223549p:image

まとめ

そんなわけで、Ruby/OpenCVの現状をまとめてみました。


ser1zw/ruby-opencv - GitHub
https://github.com/ser1zw/ruby-opencv