OpenCVで物体認識を行うRuby拡張ライブラリのソース


2007-03-14追記: インストールしやすいようにgemを作りました→dara日記

概要

顔画像認識サービス Face Detector (http://face.orzorz.org/) でも利用している Ruby拡張ライブラリを公開します。OpenCVがインストールされている環境であれば、以下にありますソースファイルを用意して

% ruby extconf.rb
% make

で拡張ライブラリを作成できるはずです。

使用する際は

require 'detector'
Detector::detect("haarcascade_frontalface_alt2.xml", "image.jpg")

のようにします。検出された領域の (左上角の)x座標, y座標, 幅, 高さ の4要素からなる配列を検出された個数だけ含む配列が返ります。

"haarcascade_frontalface_alt2.xml"というファイルが顔画像のモデルファイルで、OpenCVのアーカイブ内(data/haarcascades/)に入っています。

extconf.rb

require 'mkmf'
pkg_config("opencv")
create_makefile 'detector'

detector.c

/*
  A Ruby Module for Object Detection
  by Yohji SHIDARA <dara@shidara.net>
*/

#include <stdio.h> #include “cv.h” #include “highgui.h” #include “ruby.h”

/ Usage: Detector::detect(“haar.xml”, “image.jpg”) => [[x,y,width,height], [x,y,width,height], … ] / VALUE rb_detect(VALUE self, VALUE model_path, VALUE target_path) { Check_Type(model_path, T_STRING); Check_Type(target_path, T_STRING);

/* モデルと画像を読み込む / CvHaarClassifierCascade cascade = cvLoad(RSTRING(model_path)->ptr, 0, 0, 0); if( cascade == 0 ) { rb_raise(rb_eArgError, “Can’t load the cascade file”); } IplImage *img = cvLoadImage(RSTRING(target_path)->ptr, 1); if( img == 0 ) { rb_raise(rb_eArgError, “Can’t load the image file”); }

/* グレースケールに変換 */ IplImage *gray = cvCreateImage( cvSize(img->width, img->height), 8, 1); cvCvtColor(img, gray, CV_BGR2GRAY); cvEqualizeHist(gray, gray);

/* 画像の大きさを調整 / int width_limit = 320, height_limit = 320; double scale_w, scale_h, scale; scale_w = (double)img->width/width_limit; scale_h = (double)img->height/height_limit; scale = (scale_w>scale_h) ? scale_w : scale_h; if(scale < 1) scale = 1; IplImage small_img = cvCreateImage( cvSize( cvRound (img->width/scale), cvRound (img->height/scale)), 8, 1 ); cvResize( gray, small_img, CV_INTER_LINEAR );

/* 領域を抽出する / CvMemStorage storage = cvCreateMemStorage(0); CvSeq *faces = cvHaarDetectObjects(small_img, cascade, storage, 1.1, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(0,0) );

/* 結果を出力する / VALUE results = rb_ary_new(); int i=0; for(i=0; i<(faces?faces->total:0); i++) { CvRect r = (CvRect*)cvGetSeqElem(faces, i); rb_ary_push(results, rb_ary_new3(4, INT2NUM(r->xscale), INT2NUM(r->yscale), INT2NUM(r->widthscale),INT2NUM(r->heightscale) ) ); }

/* 後片付け */ cvReleaseMemStorage(&storage); cvReleaseImage(&img); cvReleaseImage(&gray);

return results; }

void Init_detector() { VALUE module; module = rb_define_module(“Detector”); rb_define_module_function(module, “detect”, rb_detect, 2); }