dara日記 RSSフィード

2007-02-23

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

2007-03-14追記: インストールしやすいようにgemを作りました→ gem objectdetect を公開しました - 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->x*scale), INT2NUM(r->y*scale),
			    INT2NUM(r->width*scale),INT2NUM(r->height*scale)
			    )
		);
  }

  /* 後片付け */
  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);
}

舞波舞波 2007/03/01 05:02 楽しんでます。dara乙!

darashidarashi 2007/03/02 19:26 ありがとうございます!楽しんでいただけたようで!

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証