The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# -*- mode: pod; coding: utf-8; tab-width: 4; -*-
=encoding utf8

=head1 名前

Cv - 何かコンピュータビジョンでやってみるとき、あなたの助けになるように
(只今、書き直し中)

=head1 概要

 use Cv;
 
 my $image = Cv->LoadImage("/path/to/image");
 $image->ShowImage("image");
 Cv->WaitKey;
 
 my $capture = Cv->CaptureFromCAM(0);
 while (my $frame = $capture->QueryFrame) {
   $frame->Flip(\0, 1)->ShowImage;
   my $c = Cv->WaitKey(100);
   last if $c >= 0;
 }

=head1 説明

C<Cv> は OpenCV コンピュータビジョンライブラリの Perl インタフェースで
す。OpenCV の C言語のリファレンスを元にしたので、リファレンスとして
http://opencv.willowgarage.com/ が使えます。とは言え、異なる部分もあり、
少しずつ文書にまとめています。

中途半端で申し訳ありません。

コンピュータビジョンは少し難しいので、Perl のスローガンに則り「簡単なこ
とは簡単に、難しいこともそれなりに」を心掛けています。

=head2 オブジェクト

=head3 オブジェクトの作成と解放

OpenCV の画像やマトリクスのオブジェクトは、C言語と同様に
C<Createなんとか()> で作ります。

 my $img = Cv->CreateImage([ 320, 240 ], IPL_DEPTH_8U, 3);
 my $mat = Cv->CreateMat(240, 320, CV_8UC4);

オブジェクトは C<new> で作ることもできます。画像を作る CreateImage() と
マトリクスを作る CreateMat() は、上の例のとおり呼び出し形式が違いますが。
C<new> なら同じように作ることができます。

 my $arr = Cv::Image->new($size, $type);
 my $arr = Cv::Mat->new($size, $type);
 my $arr = Cv::MatND->new($size, $type);
 my $arr = Cv::SparseMat->new($size, $type);

またオブジェクトを作るとき、元のオブジェクトがあれば引数を省略すること
もできます。

 my $sameone = $img->new;
 my $gray = $color->new(CV_8UC1);

オブジェクトが不要になったら、C言語では C<Createなんとか()> と対の
C<Releaseなんとか()> で利用者がオブジェクトを解放します。Perl は同じ場
面で C<DESTROY> を呼ぶので、C<Cv> はこの仕組みを使ってオブジェクトを解
放します。従って解放について利用者が注意を払う必要はありません。解放で
きないオブジェクトは C<Cv::なんとか::Ghost> というクラスで bless し、
C<Cv> の中で識別できるようにしています。

=head3 OpenCVのデータ型とCvのクラス名

OpenCV には画像やマトリクスのデータ型として C<CvImage>, C<CvMat>,
C<CvMatND>, C<CvSparseMat> など、いろいろな型があります。C<Cv> は、この
データ型とクラス名が対応しています。クラス名は、C<Cv> の後に :: を置い
た名前で、たとえば、C<CvImage> は C<Cv::Image> に、C<CvMat> は
C<Cv::Mat> に対応しています。そして、オブジェクトは、OpenCV のデータの
ポインタをそのデータ型に対応するクラス名で bless したものになります。

OpenCV の画像やマトリクスのデータ型 C<CvMat>、C<CvImage> は、C<CvArr>
から導出されたデータ型です。従って、画像やマトリクスは C<CvArr> を介し
て受け渡されます。C<Cv> でも同様に、スーパクラスとして C<Cv::Arr> を用
意し、メソッドはできるだけここに置くことにしました。

OpenCV には更にシーケンスと呼ばれる動的なデータ型もありますが、これにつ
いては、L<Cv::Seq|Cv::Seq-ja> を参照してください。

=head3 データ領域の共有

OpenCV の画像やマトリクスは、ヘッダ部とデータ部が分れており、データ部の
ないヘッダだけのオブジェクトが作れます。データのないことを伝えるために、
次のとおり undef を渡します。

 my $arr = Cv::Mat->new([$rows, $cols], $type, undef);

このようにして作成したヘッダだけのオブジェクトは、GetRows(), GetCols()
のようにデータ部を共有するメソッドで使っています。

(注意) コードを見ると、undef の代りに文字列でデータ部を与えることが可能
だと気付くかもしれません。別のシステムで作成した画像やマトリクスを扱う
とき、データ変換の手間を減らすことができると考える人もいると思います。
しかし、オブジェクトが開放されるとき Cv::Image ではエラーが起きます。
Cv::Mat はなんとなく動いているように見えますが、安定していません。文字
列でデータ部を渡さないようにしてください。(これは bugs へ)

=head3 OpenCVの構造体

Cv のオブジェクトは、OpenCV の構造体をその型名に対応するクラス名で
bless したものです。従って、Cv (Perl) から OpenCV の構造体は直接操作で
きません。しかし、OpenCV に同梱されているサンプルでは、構造体の大きさや
要素の型を直接使っています。たぶんそれが簡単なんでしょう。Cv でも同様の
使い方をするために、構造体のメンバの名前でメソッドを作りました。詳細は
L</Cvで追加されたメソッド> を参照してください。

=head2 メソッド

=head3 メソッドの名前とその統合

メソッドの名前は、OpenCV の関数名の頭の C<cv> を省いた名前と、名前のは
じめの大文字を小文字に直したものが使えます。次の 2つの例はどちらも
C<cvCreateMat()> を呼び出します。

 my $mat = Cv->CreateMat(240, 320, CV_8UC3);
 my $mat = Cv->createMat(240, 320, CV_8UC3);

それから C<cvAdd()> と C<cvAddS()> のような類似した関数はより簡潔な名前、
つまりこの例では C<Add()> にまとめました。おそらく C言語では異なる型の
引数を受けとることができないので、分けるしかなかったのでしょう。C<Cv>
ではこれらを統合し、引数で呼び出す関数を決めています。

 my $ar2 = Cv->CreateImage();      # ref Cv::Image
 my $sc2 = cvScalar();             # ref ARRAY
 my $d = $ar->Add($ar2);           # cvAdd($ar, $ar2)
 my $d = $ar->Add($sc2);           # cvAddS($ar, $sc2)

統合した関数は次のとおり。あまり多くありません。リファレンスを参照して、
C<cvなんとか()> と C<cvなんとかS()> の両方あるものがそうだと考えてください。

 AbsDiff(), Add(), And(), Cmp(), InRange(), Max(), Min(), Or(), Sub(), Xor()

=head3 引数の省略、インプレース、戻り値

出力先の画像やマトリクス (C<dst> として表わされることが多い) が省略され
たとき、それが補える場合は補うようにしています。補える例とそうでない例の
両方を示します。

 my $dst = $src->Add($src2);
 my $dst = $src->Add($src2, $mask);  # can't omit dst

後者は、マスクとして与えた C<$mask> と出力先を区別することができません。
このような場合には C<$dst> を呼び出し元で用意してください。C<$dst> が
C<$src> と同じなら次のとおり。

 my $dst = $src->Add($src2, $src->new, $mask); 

OpenCV は、インプレース処理が可能な関数では出力先の画像やマトリクス
C<dst> に C<NULL> を指定し、入力画像を出力先としても使います。C<Cv> で
はこの C<NULL> を表わすために C<\0> を使います。次の例は左右反転した画
像を返します。

 my $dst = $src->Flip(\0);

OpenCV の関数は、この Flip() に限らず、出力先は呼び出し元が用意します。
そうした使い方では特に戻り値を使う必要はありません。しかし、上述のとお
り C<Cv> では出力先を省略できるので、その場合にはメソッドの中で必要に応
じて作られた出力先を戻り値として受けとることになります。

この出力を戻り値として受けとる方法は、次の例のとおり、メソッドをつない
で書けるようにしてくれますが、メソッドが呼ばれる度にオブジェクトの確保
と開放があるので、その分だけオーバヘッドがあります。

 my $bin = $src->cvtColor(CV_RGB2GRAY)->threshold(...);


=head3 Cvで追加されたメソッド

(これはプログラムで生成したい。書くのは疲れる)


=head2 エラー処理

eval { ... } で保護したブロックの中のエラーを検出できるようになりました。
(Cv-0.13)

 my $img = eval { Cv->createImage([-1, -1], 8, 3) };
 if ($@) {
    print STDERR "*** got error ***";
 }

ただし、C<Cv> をインストールするとき、c++ でコンパイルしておく必要があります。
エラーを掴まえるだけでなく、自前で用意したエラー処理に向けることもできます。

 Cv->redirectError(
   sub { my ($status, $funcName, $errMsg, $fileName, $line, $data) = @_;
       ...
   },
   my $data = ...;
 );


=head2 エクスポート

Cv によってインポートされる名前は、use Cv の後に指定できます。(Cv-0.14)

次の 2行は、C<CV> や C<IPL> ではじまる定数やマクロと cvScalarAll()
のようないくつかの関数をインポートします。

 use Cv qw(:std);
 use Cv;			# 何も指定しないとき :std が補われる

次の 2行は、Cv のすべての名前をインポートします。

 use Cv qw(:all);
 use Cv qw(/^(CV|IPL|cv)/);

何もインポートしないときは、空のリストを続けます。

 use Cv qw( );

=head1 ヒント

Cv を使っている方から、ちょっといい使い方を教えて戴きました。

=over 4

=item *

Cv で作成した画像を CGI で直接出力するとき、
EncodeImage() と Ptr() を使うことができます。
画像をファイルに保存する必要がありません。

 use Cv;
 my $img = Cv::Image->new([240, 320], CV_8UC3);
 $img->zero->circle([ 100, 100 ], 100, CV_RGB(255, 100, 100));
 print "Content-type: image/jpg\n\n";
 print $img->encodeImage(".jpg")->ptr;

これは Imager 向けの変換にも使えます。

 use Imager;
 my $imager = Imager->new(data => $img->encodeImage(".ppm")->ptr);

=item *

C<Inline C> を使うためのコンフィギュレーションを用意しました。
これは、いろいろな実験や拡張を容易にしてくれます。
使い方は次のとおり簡単です。

 use Cv::Config;
 use Inline C => Config => %Cv::Config::C;

=back

=head1 サンプル

OpenCV に付属しているサンプルを、いくつか C<Cv> で書き直しました。
C<sample/> にあります。

=over 4

=item

 bgfg_codebook.pl calibration.pl camshiftdemo.pl capture.pl chamfer.pl
 contours.pl convexhull.pl delaunay.pl demhist.pl dft.pl distrans.pl
 drawing.pl edge.pl facedetect.pl fback_c.pl ffilldemo.pl find_obj.pl
 fitellipse.pl houghlines.pl image.pl imager.pl inpaint.pl kalman.pl
 kmeans.pl laplace.pl lkdemo.pl minarea.pl morphology.pl motempl.pl
 mser_sample.pl polar_transforms.pl pyramid_segmentation.pl squares.pl
 stereo_calib.pl stereo_match.pl tiehash.pl video-thread.pl
 watershed.pl

=back

=head1 バグ

=over 4

=item *

バージョン 0.07 で名前付きの引数を諦めました。
名前付きの引数を処理するためのオーバヘッドが大きかったからです。
この版では C<Cv::TieHash> と C<Cv::TieArr> も削除しました。
C<Cv::TieHash> は C<sample/tiehash.pl> を参照してください。

=item *

バージョン 0.14 で別名を整理しました。
CV_MAKETYPE() のようなマクロのいくつかには Cv::MAKETYPE()
のような別名もありましたが、もとの名前の方が短いので、
別名を止めることにしました。

=item *

バージョン 0.16 で C<Cv> を分け、拡張したコードを分離して
L<Cv::More|Cv::More-ja> に置くことにしました。

=item *

バージョン 0.17 で typemap の見直しを。一旦、xlib も止める。

=back

=head1 参考

http://sourceforge.net/projects/opencvlibrary/

=head1 著作権

Yuta MASUDA E<lt>yuta.masuda@newdaysys.co.jpE<gt>

Copyright (c) 2010, 2011, 2012 by Yuta MASUDA.

All rights reserved. This program is free software; you can
redistribute it and/or modify it under the same terms as Perl itself.

=cut