実例で学ぶPHP拡張モジュールの作り方

第3回 WEBカメラから画像をキャプチャ

この記事を読むのに必要な時間:およそ 9 分

今回は外部ライブラリとリンクする方法,定数を定義する方法,引数を取り値を返す関数の作り方を紹介します。題材はWEBカメラの画像をキャプチャする拡張モジュールです。

WEBカメラのようなハードウェアにアクセスするのはPHPの標準機能では不可能なことで,まさに拡張モジュールの出番です。しかし,ハードウェアにアクセスするとなると敷居が高いと思われるかもしれませんが,ご心配なく。Intelが開発しているOpenCVというオープンソースの画像処理ライブラリを使えば,簡単にWEBカメラから画像をキャプチャできます。

OpenCVのインストール

まずは公式WikiのLinux向けインストールガイド(英文)を参考にOpenCVをインストールしてください。Mac OS Xの場合はconfigureのオプションで--without-gtk2 --with-carbon --with-quicktimeを指定することによってGTK2の代わりにMac OS X標準のウインドウシステムを,Video4Linux(カメラからのキャプチャ)とlibavcodec(動画ファイルからのキャプチャ)の代わりにQuickTimeを使うことができます。

specファイルを記述する

今回制作するcvcaptureモジュールのspecファイルの構成はリスト1のようになっています。

リスト1 specファイル概要(cvcapture-0.1.0.xml)

<?xml version="1.0" encoding="UTF-8"?>
<extension name="cvcapture" version="0.1.0">
  <summary>Capture frames from webcams.</summary>
  <!-- モジュール情報(説明は省略) -->
  <!-- 依存関係(リスト2-1,2-2) -->
  <!-- 定数定義(リスト3) -->
  <!-- 関数定義(リスト4) -->
</extension>

依存関係を定義する

依存関係の定義はリスト2-1にあるように,<deps>タグに記述します。OpenCVのように依存関係が複雑なライブラリを使いたい場合はpkg-configというツールを使うと依存関係が簡潔に記述できます※1)。pkg-configを使わない場合はリスト2-2のように記述します。

リスト2-1 依存関係定義(cvcapture-0.1.0.xml)

<deps language="c" platform="all">
  <!-- pkg-configを使って“opencv”の設定を取得する -->
  <with name="opencv" mode="pkg-config">
    <!-- ヘッダ名(ヘッダのインクルードパスもpkg-configで設定される) -->
    <header name="cv.h"/>
    <header name="highgui.h"/>
  </with>
</deps>

リスト2-2 pkg-configを使わない依存関係定義

<deps language="c" platform="all">
  <!-- configureの引数--with-cvcaptureで指定されたパス(省略時は
       “/usr /usr/local”)から“include/opencv/cv.h”を探す -->
  <with testfile="include/opencv/cv.h">
    <!-- ヘッダ名(includeからの相対パス) -->
    <header name="opencv/cv.h"/>
    <header name="opencv/highgui.h"/>
    <!-- ライブラリ名(libなどの接頭辞や.soなどの拡張子は不要) -->
    <lib name="cv"/>
    <lib name="highgui"/>
  </with>
</deps>

定数を定義する

続いて,カメラの種類を指定するための定数を定義します。定数の情報は<constants>タグ内の<constant>タグに記述します。<constant>タグではtype属性で型,name属性で定数名,value属性で値を指定します。定数の説明は<description>タグや<summary>タグは使わず,<constant>タグの中に文字データとして記述します。説明はマニュアルに反映されるのですが,不要なら<constant ... />と書いてもかまいません。

リスト3 定数定義(cvcapture-0.1.0.xml)

<constants>
  <!-- CV_CAP_*はopencv/highgui.hで定義されているマクロ -->
  <constant type="int" name="CV_CAP_ANY" value="CV_CAP_ANY">autodetect</constant>
  <-- (省略) -->
  <constant type="int" name="CV_CAP_QT" value="CV_CAP_QT">QuickTime</constant>
</constants>

関数を定義する

最後に,カメラから画像をキャプチャする関数cv_camera_capture()と動画の最初のフレームをキャプチャする関数cv_file_capture()を定義します。cv_camera_capture()は第1引数でキャプチャした画像を保存するパス,第2引数でカメラを指定する数値(省略された場合は自動選択)を指定し,キャプチャに成功したかどうかを真偽値で返します。第3引数が指定された場合は,キャプチャした画像の幅と高さのペアを配列で代入します。cv_file_capture()も第2引数で読み込む動画ファイルのパスを指定する以外は同じです。

筆者はCodeGen_PECLを使うのは,ひな型の生成までにし,実際の処理はソースコードに直接記述するスタイルをお勧めするので,今回のspecファイルには関数の実装は書いていません。

値を返す関数のプロトタイプでは関数名の前にvoidではなく戻り値の型を書きます。また,引数の情報は型と名前のセットをカンマ区切りで指定します。このとき引数名の先頭に$をつけてはいけません。必須でない引数は角括弧で囲み,参照として受け取る引数は名前の前に&リスト4ではエスケープして&amp;)をつけます。引数の型を特定しない場合はmixedとします。

キャプチャする画像の大きさはカメラによって変わるので,両関数のテストケースでは<result mode="format">として期待する出力をフォーマット文字列にしています。また,cv_file_capture()のテストケースでは<skipif>タグでテスト用の動画ファイルが存在しない場合はテストを省略するようにしています。テストを省略する場合はskip(半角スペース)(理由)の書式で文字列を出力してテストケースを終了させます。

リスト4 関数定義

<function name="cv_camera_capture">
 <proto>bool cv_camera_capture(string filename[, int index[, mixed &amp;size]])</proto>
  <summary>Capture from camera.</summary>
  <description>(省略)</description>
   <test>
    <code><?data
if (cv_camera_capture("test_camera.jpg", CV_CAP_ANY, $size)) {
    print_r($size);
}
    ?></code>
    <result mode="format"><?data
Array
(
    [0] => %d
    [1] => %d
)
    ?></result>
  </test>
</function>

<function name="cv_file_capture">
  <proto>bool cv_file_capture(string dst_filename, string src_filename[, mixed &amp;size])</proto>
  <summary>Capture from video file.</summary>
  <description>(省略)</description>
  <test>
    <skipif><?data
if (!file_exists("sample.3g2")) {
    die("skip sample video file does not exist");
}
    ?></skipif>
    <code><?data
if (cv_file_capture("test_file.jpg", "sample.3g2", $size)) {
    print_r($size);
}
  ?></code>
  <result mode="format"><?data
Array
(
    [0] => %d
    [1] => %d
)
    ?></result>
  </test>
</function>
※1

ライブラリがpkg-configをサポートしている必要があります。インストール先によっては,環境変数PKG_CONFIG_PATHでパッケージ情報ファイル(*.pc)のあるディレクトリを指定する必要があります。詳しくはpkg-configのmanページをご参照ください。

著者プロフィール

関山隆介(せきやまりゅうすけ)

ジンガジャパン株式会社に所属。PHP拡張モジュールを作った数なら(たぶん)日本一。PHP 5.3に対応したものはPEARチャンネルGitHubで公開中。

URLhttp://d.hatena.ne.jp/rsky/

コメント

コメントの記入