ネコと和解せよ

JMFのバグ?

JMFをWindowsで複数のキャプチャデバイスが接続された環境で使うと、一番はじめに認識したキャプチャデバイスしか認識しないみたいです。実際にうちの環境でも発生しました。
(結構有名な話かもしれないけど。)

これが厄介なのは、カメラ以外のキャプチャデバイス、たとえばテレビキャプチャとか、そういうものとも干渉すること。

回避策はデバイスマネージャでキャプチャデバイスの利用を停止する方法しかないけど、明らかに間違った方法だと思う。

というわけで、なんとかならないものかと解析をしてみました。

解析

JMFRegistryがデバイス認識しない理由が解れば何か解るかな?ということで、ソースコードを探したらありました。Java SE Desktop Technologies - Java Media Framework API (JMF) ここの、JMFRegistry source for JMF 2.1.1. からダウンロード。


Eclipseでコンパイルできるようにして、JMF Registry のCapture DevicesタブでDetect Capture Devicesボタンを押すと呼ばれる関数を探すと、VFWAuto.javaファイルの中で、vfwデバイスを検出してることがわかった。

そのコードは以下の通り。

VFWAuto.java

public class VFWAuto {

    public VFWAuto() {
        Vector devices = (Vector) CaptureDeviceManager.getDeviceList(null).clone();
        Enumeration enum = devices.elements();

        while (enum.hasMoreElements()) {
            CaptureDeviceInfo cdi = (CaptureDeviceInfo) enum.nextElement();
            String name = cdi.getName();
            if (name.startsWith("vfw:"))
                CaptureDeviceManager.removeDevice(cdi);
        }
	
        int nDevices = 0;
        for (int i = 0; i < 10; i++) {
            String name = VFWCapture.capGetDriverDescriptionName(i);
            if (name != null && name.length() > 1) {
                System.err.println("Found device " + name);
                System.err.println("Querying device. Please wait...");
                com.sun.media.protocol.vfw.VFWSourceStream.autoDetect(i);
                nDevices++;
            }
        }
    }

    public static void main(String [] args) {
        VFWAuto a = new VFWAuto();
        System.exit(0);
    }
}

2個以上のデバイスが接続されていても、VFWCapture.capGetDriverDescriptionNameが0番目以降に有効なものを返してこない。うーん、バグかな?

結局、どうにもならなかったorz
DirectShowをJava経由でいじる方法があるので、(arc@dmzさんに教えてもらった)それ用のキャプチャでやろうかな。

NyARToolkit2.1の最適化について

忘れそうなのでそろそろ書こう。

NyARToolkit/2.1では、NyARToolkit/2.0で積み残しになっていた最適化が実装されてます。

coreの最適化

まずはオリジナルの計算結果と互換性を保てる最適化。これはNyARToolkit/2.1のcoreに実装済みです。

カメラ歪みの事前計算

カメラ歪みの事前計算は、事前に各画素に対応する座標を計算しておくことで、マーカ座標取得時に行う歪み補正計算を省略します。この処理はNyARSquareDetectorのgetSquareLine関数にあり、歪みマップの作成と保持は、NyARObserv2IdealMapクラスが行います。認識するマーカのサイズにも依存しますが、1〜2割程度の速度向上があります。

ちなみに、ARToolkitplusもこの方法を使ってました。

PCA(主成分分析)の専用関数化

NyARToolkit/2.1では、主成分分析関数(輪郭座標の集合から線分を取得するために使用)を、NyARMatからNyARPca2d_MatrixPCA_O2移しました。処理シーケンスの合理化などにより、計測できない程度の速度向上、使用メモリの削減効果があります。NyARPca2d_MatrixPCA_O2もNyARSquareDetectorクラスから使用しています。

core2の最適化

次に、オリジナルの計算結果とは誤差が出るけど、論理的には正しい最適化。これは、NyARToolkit/2.1のsandboxプロジェクトのcore2以下にある、モバイル向けのコード(NyARFixedFloatなんちゃらクラス)に実装済みです。

PCAに入力する輪郭点のサンプリング

ARToolKitでは、マーカの輪郭を抽出後、PCAを使って4本の線分を計算するわけですが、通常は輪郭線すべてをPCAに入力して線分を計算しています。でも実際には、大体20点位を入力すれば十分な値がとれるので、輪郭線から適当数の点をサンプリングしてPCAに入力することで、計算量を減らせます。この方法は、NyARSquareDetector_X2クラスと、そこから使用するNyARFixedFloatObserv2IdealMapに実装があります。

これにより、撮影しているマーカーのサイズによらず、処理量が一定になります。(通常はマーカーサイズが大きくなると処理量が増える。)

そのほか

モバイル機で実行する時は、紹介した最適化のほかに、固定小数点化、認識画像の縮小、座標最適化処理の省略等が必要になります。
特に固定小数点化は、浮動小数点ユニットのないCPUで大きな効果(大体1/5)があります。