PLAYSTATION Eye を.NET Frameworkから使う

PLAYSTATION Eye について

PlayStation3用のカメラとして、「PLAYSTATION Eye」というものがあります。

PLAYSTATION Eye(CEJH-15001)

PLAYSTATION Eye(CEJH-15001)

私はPlayStation3は持っていませんが、PCでもドライバを入れれば使えて、しかもなかなか値段の割に高性能、という話を聞いたので、買ってみました。ブックオフで偶然、Amazonよりさらに500円ほど安い4000円弱ほどの値段で見かけたので即買いでした。

ドライバの入手

以下のページから入手できます。Donateのすぐ上のあたりです。現在での最新版はv3.0.0.0901だと思います。

http://alexpopovich.wordpress.com/2008/10/02/sony-ps3eye-camera-directshow-capture-source-filter/

ダウンロードしたら、インストールします。インストール後Windowsを再起動し、デスクトップにある「PS3Eye Test App」を実行して、正常に動作するか確かめましょう。

気持ち悪いほどスイスイ動きます。320x240なら125FPS、640x480なら75FPSまで可能です。この価格帯にしては非常に高性能だと思います。

PS3EyeLib

PLAYSTATION Eyeはドライバを入れた直後の状態でOpenCVからCvCaptureを使って扱うことは一応可能ですが、320x240・低フレームレート固定で、変更できません。

先ほどダウンロードしたドライバには、直接PLAYSTATION Eyeを制御することが出来るSDKが付属しています。SDKにより、PLAYSTATION Eyeの性能を余すところ無く発揮することが出来ます。C++を使って、以下のようにしてキャプチャが可能です。(SDKのIPS3EyeLib.hのサンプルコードから抜粋・コメントは適当に翻訳)

// カメラが接続されていなければ0、接続されていれば1を返す
int cnum = IPS3EyeLib::GetNumCameras();
if(cnum==0)
{
    // カメラが無いので処理を抜ける
    return;
}
// PS3EyeLib camera objectを生成する
IPS3EyeLib *pCam=IPS3EyeLib::Create();

// 使用するキャプチャのフォーマットを決定する (例: 320x240 * 30fps)
pCam->SetFormat(IPS3EyeLib::GetFormatIndex(320,240,30));
// キャプチャした画像データを保存するバッファを確保する(ここでは32bit RGB画像)
PBYTE pBuffer=new BYTE[(320*240*32)/8];

// キャプチャ開始
pCam->StartCapture();
// done がtrueになるまで処理を続ける
bool done=false;
while(!done)
{
    // 新しいフレームがキャプチャ可能になるまでこの関数の呼び出しはブロックされる。
    // バッファに今回のフレームのデータが格納される。
    if(pCam->GetFrame(pBuffer, 32, false))
    {
        // ここで処理したり、表示したり・・・・
    }
}
// リソースの解放
delete [] pBuffer;
pCam->StopCapture();
delete pCam;

バイト配列 pBuffer にキャプチャした画像が格納されます。OpenCVで使うなら、これをIplImageのピクセルデータにコピーすれば良いと言う訳です。

.NET Framework向けラッパー

このSDKをOpenCvSharp、というよりもそれに限らずC#.NET Framework)から使ってみたいと思ったので、ラッパーを書きました。Windows限定で問題ないので、C++/CLIで実装しました。SDKのヘッダはごくコンパクトかつわかりやすく出来ているので、特に苦労も無く作業は終わりました。


以下、ラッパーによるコードの例を示していきます。対応している解像度・FPS等の情報の一覧を取り出す方法です。

foreach (PS3EyeFormat f in IPS3EyeLib.GetFormats())
{
    Console.WriteLine("resolution:{0} width:{1} height:{2} rate:{3} txt:'{4}'",
        f.Res, f.Width, f.Height, f.Rate, f.FormatTxt);
}

IPS3EyeLibSDKの核となるクラスです。接頭辞Iからわかるように、インタフェース(正確には、実装上の都合からabstractなクラス)です。このあたりはSDKの仕様にあわせました。



そして以下のコードは、実際のキャプチャを行うものです。

const int Width = 640;
const int Height = 480;
const int Fps = 60;
const int ColorDepth = 24;

if (IPS3EyeLib.GetNumCameras() == 0)
{
    return;
}
 
using (IPS3EyeLib lib = IPS3EyeLib.Create())            
{
    lib.SetFormat(IPS3EyeLib.GetFormatIndex(Width, Height, Fps));
    byte[] buffer = new byte[Width * Height * ColorDepth / 8];
                
    lib.StartCapture();
    while (true)
    {
        if (lib.GetFrame(buffer, ColorDepth, false))
        {
            // フレーム取得時の処理をここに書く             
        }                    
    }
    lib.StopCapture();
}

非常にシンプルです。このコードに少し手を加えるだけで、OpenCvSharpとの併用もすぐに出来ます。

const int Width = 640;
const int Height = 480;
const int Fps = 60;
const int ColorDepth = 24;

if (IPS3EyeLib.GetNumCameras() == 0)
{
    return;
}

using (IPS3EyeLib lib = IPS3EyeLib.Create())            
using (IplImage capture = new IplImage(Width, Height, BitDepth.U8, 3))
using (IplImage canny = new IplImage(Width, Height, BitDepth.U8, 1))
using (CvWindow windowCapture = new CvWindow("capture"))
using (CvWindow windowCanny = new CvWindow("canny"))
{
    lib.SetFormat(IPS3EyeLib.GetFormatIndex(Width, Height, Fps));
    byte[] buffer = new byte[Width * Height * ColorDepth / 8];
                
    lib.StartCapture();
    while (true)
    {
        if (lib.GetFrame(buffer, ColorDepth, false))
        {
            capture.CopyPixelData(buffer);
            Cv.CvtColor(capture, canny, ColorConversion.BgrToGray);
            Cv.Threshold(canny, canny, 128, 255, ThresholdType.Binary);
            Cv.Canny(canny, canny, 50, 180);

            windowCapture.ShowImage(capture);
            windowCanny.ShowImage(canny);                   
        }                    
        if (Cv.WaitKey(1) > 0)
        {
            break;
        }
    }
    lib.StopCapture();
}

このラッパー、公開してもいいのですが、SDKの方のライセンスが特に記載が見当たらずよくわからないので、なんともいえない状況です。


PlayStationEye

PlayStationEye