OpenCVをJavaから使う

投稿者: 加藤 淳
投稿日:
カテゴリ: programming

2014 年 1 月 26 日追記; JavaCV のバージョンがあがって、使い方がもっとシンプルになりました。詳しくは新しい記事をご覧ください。

これまで、自前のライブラリで Web カメラから画像をとってきて、ARToolKitに渡してマーカー検出したりしていたのですが、画像処理関連の研究を始めたりして、そろそろ限界を感じるようになってきたので、Java からOpenCVの各機能が呼べるラッパーJavaCVを使ってみることにしました。

インストールおよび実行までの道のりが果てしなく遠い…かと思いきや、意外とすんなりできました。

64-bit Windows で JavaCV

  1. OpenCV のバイナリ版(OpenCV-*.exe, 自己展開 ZIP)をダウンロードして適当なディレクトリ(C:¥opencv など)に解凍
  2. Visual C++ 2010 のランタイムをインストール
  3. 環境変数 PATH を編集してパスを.¥build¥common¥tbb¥intel64¥vc10 と.¥build.¥x64¥vc10¥bin に通す
  4. JavaCV(javacv-*-bin.zip)をダウンロードして適当なディレクトリ(C:¥opencv¥javacv など)に解凍
  5. コンパイル、実行するときの Java のクラスパスに javacpp.jar, javacv.jar, javacv-windows-x86_64.jar を追加

64-bit Mac OS X で JavaCV

  1. MacPortsをインストール
  2. コマンドラインで sudo port install opencv +python27 を実行
  3. JavaCV(javacv-*-bin.zip)をダウンロードして適当なディレクトリ(/Users/*/lib/javacv など)に解凍
  4. コンパイル、実行するときの Java のクラスパスに javacpp.jar, javacv.jar, javacv-macosx-x86_64.jar を追加

以上です。

どちらの場合でも注意すべき内容としては、Java VM、OpenCV のビット数が合っていなくてはなりません。僕の環境では、古い研究プロジェクトを動かすため、Java VM が 32 ビットで起動するよう-d32 オプションをつけていました。ところが、OpenCV が 64 ビット版だったため、プログラムを走らせようとすると "java.lang.UnsatisfiedLinkError: Library jniopencv_core not found" というエラーが出てしばらく困りました。

JavaCV が正しくインストールできると、Web カメラから画像を読みとってウィンドウに表示するプログラムが、次のように簡単に書けます。

CaptureImage.java
import javax.swing.JFrame;

import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.cpp.opencv_core.IplImage;

public class CaptureImage {
  public static void main(String[] args) {
    new CaptureImage().loop();
  }

  private void loop() {
    CanvasFrame canvas = new CanvasFrame("Webcam");
    canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    // デフォルト(0)のWebカメラを使う
    OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
    try {
      grabber.start();

      // フレームレートを取得
      double frameRate = grabber.getFrameRate();
      long wait = (long) (1000 / (frameRate == 0 ? 10 : frameRate));

      // 画像を取りつづける
      while (true) {
        Thread.sleep(wait);
        IplImage image = grabber.grab();

        // 取ってきた画像を画面に表示
        if (image != null) { canvas.showImage(image); }
      }

    // 何かあったらエラーを吐いて終わる
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}