/*
call-seq:
  ObjectDetect::detect(model_path, target_path, rescale_size=nil) -> [[x,y,width,height]]

Detects objects in the image file +target_path+.
+model_path+ needs to point a model file (e.g. /usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml).
If +rescale_size+ is specified and the width or height of the image is larger than +rescale_size+,
the image is rescaled to fit into the size before processing.
 */
static VALUE rb_detect(int argc, VALUE *argv, VALUE self)
{
  VALUE model_path, target_path, rescale_size;
  rb_scan_args(argc, argv, "21", &model_path, &target_path, &rescale_size);

  Check_Type(model_path, T_STRING);
  Check_Type(target_path, T_STRING);

  /* load the model */
  CvHaarClassifierCascade* cascade = cvLoad(RSTRING(model_path)->ptr, 0, 0, 0);
  if( cascade == 0 ) {
    rb_raise(rb_eArgError, "Can't load the cascade file");
  }

  /* load the target picture */
  IplImage *img = cvLoadImage(RSTRING(target_path)->ptr, 1);
  if( !img ) {
    cvReleaseHaarClassifierCascade(&cascade);
    rb_raise(rb_eArgError, "Can't load the image file");
  }

  /* to gray scale */
  IplImage *gray = cvCreateImage( cvSize(img->width, img->height), 8, 1);
  cvCvtColor(img, gray, CV_BGR2GRAY);
  cvEqualizeHist(gray, gray);

  /* rescale */
  double scale = 1;
  if(argc == 3 || rescale_size != Qnil) {
    double limit = (double)NUM2INT(rescale_size);
    double scale_w, scale_h;
    scale_w = (double)img->width/limit;
    scale_h = (double)img->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 );

  /* detect regions */
  CvMemStorage* storage = cvCreateMemStorage(0);
  CvSeq *faces = cvHaarDetectObjects(small_img, cascade, storage,
                                     1.1, 2, CV_HAAR_DO_CANNY_PRUNING,
                                     cvSize(0,0) );

  /* output */
  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)
                            )
                );
  }

  /* cleanups */
  cvReleaseHaarClassifierCascade(&cascade);
  cvReleaseMemStorage(&storage);
  cvReleaseImage(&img);
  cvReleaseImage(&gray);
  cvReleaseImage(&small_img);

  return results;
}