0

videoInputを使用して Web カメラからライブ ストリームを取得していますが、videoInput のドキュメントでは常に BGR/RGB を取得する必要があることが示されているという問題に遭遇しましたが、「詳細な」出力では、ピクセル フォーマットが YUY2 であることがわかります。 .

***** VIDEOINPUT LIBRARY - 0.1995 - TFW07 *****
SETUP: Setting up device 0
SETUP: 1.3M WebCam
SETUP: Couldn't find preview pin using SmartTee
SETUP: Default Format is set to 640 by 480 
SETUP: trying format RGB24 @ 640 by 480
SETUP: trying format RGB32 @ 640 by 480
SETUP: trying format RGB555 @ 640 by 480
SETUP: trying format RGB565 @ 640 by 480
SETUP: trying format YUY2 @ 640 by 480
SETUP: Capture callback set
SETUP: Device is setup and ready to capture.

私が最初に考えたのは、RGB への変換を試みることでした (実際に YUY2 データを取得していると仮定した場合)。

YUY2 を BGR に変換するためのコードを次に示します (注:これは非常に大きなプログラムの一部であり、借用したコードです - 誰の要求でも URL を取得できます):

#define CLAMP_MIN( in, min ) ((in) < (min))?(min):(in)
#define CLAMP_MAX( in, max ) ((in) > (max))?(max):(in)

#define FIXNUM 16
#define FIX(a, b) ((int)((a)*(1<<(b))))
#define UNFIX(a, b) ((a+(1<<(b-1)))>>(b))

#define ICCIRUV(x) (((x)<<8)/224)
#define ICCIRY(x) ((((x)-16)<<8)/219)
#define CLIP(t) CLAMP_MIN( CLAMP_MAX( (t), 255 ), 0 )
#define GET_R_FROM_YUV(y, u, v) UNFIX((FIX(1.0, FIXNUM)*(y) + FIX(1.402, FIXNUM)*(v)), FIXNUM)
#define GET_G_FROM_YUV(y, u, v) UNFIX((FIX(1.0, FIXNUM)*(y) + FIX(-0.344, FIXNUM)*(u) + FIX(-0.714, FIXNUM)*(v)), FIXNUM)
#define GET_B_FROM_YUV(y, u, v) UNFIX((FIX(1.0, FIXNUM)*(y) + FIX(1.772, FIXNUM)*(u)), FIXNUM)
bool yuy2_to_rgb24(int streamid) {
    int i;
    unsigned char y1, u, y2, v;
    int Y1, Y2, U, V;
    unsigned char r, g, b;

    int size = stream[streamid]->config.g_h * (stream[streamid]->config.g_w / 2);
    unsigned long srcIndex = 0;
    unsigned long dstIndex = 0;

    try {

        for(i = 0 ; i < size ; i++) {

            y1 = stream[streamid]->vi_buffer[srcIndex];
            u = stream[streamid]->vi_buffer[srcIndex+ 1];
            y2 = stream[streamid]->vi_buffer[srcIndex+ 2];
            v = stream[streamid]->vi_buffer[srcIndex+ 3];

            Y1 = ICCIRY(y1);
            U = ICCIRUV(u - 128);
            Y2 = ICCIRY(y2);
            V = ICCIRUV(v - 128);

            r = CLIP(GET_R_FROM_YUV(Y1, U, V));
            //r = (unsigned char)CLIP( (1.164f * (float(Y1) - 16.0f)) + (1.596f * (float(V) - 128)) );
            g = CLIP(GET_G_FROM_YUV(Y1, U, V));
            //g = (unsigned char)CLIP( (1.164f * (float(Y1) - 16.0f)) - (0.813f * (float(V) - 128.0f)) - (0.391f * (float(U) - 128.0f)) );
            b = CLIP(GET_B_FROM_YUV(Y1, U, V));
            //b = (unsigned char)CLIP( (1.164f * (float(Y1) - 16.0f)) + (2.018f * (float(U) - 128.0f)) );


            stream[streamid]->rgb_buffer[dstIndex] = b;
            stream[streamid]->rgb_buffer[dstIndex + 1] = g;
            stream[streamid]->rgb_buffer[dstIndex + 2] = r;

            dstIndex += 3;

            r = CLIP(GET_R_FROM_YUV(Y2, U, V));
            //r = (unsigned char)CLIP( (1.164f * (float(Y2) - 16.0f)) + (1.596f * (float(V) - 128)) );
            g = CLIP(GET_G_FROM_YUV(Y2, U, V));
            //g = (unsigned char)CLIP( (1.164f * (float(Y2) - 16.0f)) - (0.813f * (float(V) - 128.0f)) - (0.391f * (float(U) - 128.0f)) );
            b = CLIP(GET_B_FROM_YUV(Y2, U, V));
            //b = (unsigned char)CLIP( (1.164f * (float(Y2) - 16.0f)) + (2.018f * (float(U) - 128.0f)) );

            stream[streamid]->rgb_buffer[dstIndex] = b;
            stream[streamid]->rgb_buffer[dstIndex + 1] = g;
            stream[streamid]->rgb_buffer[dstIndex + 2] = r;

            dstIndex += 3;

            srcIndex += 4;
        }

        return true;
    } catch(...) {
        return false;
    }
}

これが機能しなかった後、a) 色空間変換関数が間違っているか、b) videoInput が嘘をついていると思います。

さて、私は videoInput が実際に私に真実を伝えていることを再確認したかったのですが、ビデオ入力:: getPixels() 関数から取得しているピクセル形式を詳細以外で確認する方法はまったくないことがわかりました。テキスト(私が非常に頭がおかしくて見えない場合を除きます)。これにより、videoInput が舞台裏で何らかの色空間変換を行っている可能性があるため、Web カメラに関係なく、常に一貫した画像が得られると思われます。これを念頭に置いて、videoInput.h:96 のいくつかのドキュメントに従うと、RGB または BGR 画像を提供しているように見えます。

画像を表示するために使用しているユーティリティは RGB 画像 (Java BufferedImage) を使用するため、videoInput から生データを直接フィードするだけで問題ないと考えました。

Javaで画像をセットアップする方法は次のとおりです。

BufferedImage buffer = new BufferedImage(directShow.device_stream_width(stream),directShow.device_stream_height(stream), BufferedImage.TYPE_INT_RGB );

int rgbdata[] = directShow.grab_frame_stream(stream);
if( rgbdata.length > 0 ) {
  buffer.setRGB(
    0, 0,
    directShow.device_stream_width(stream),
    directShow.device_stream_height(stream),
    rgbdata,
    0, directShow.device_stream_width(stream)
  );
}

そして、これを Java (C++/JNI) に送信する方法を次に示します。

JNIEXPORT jintArray JNICALL Java_directshowcamera_dsInterface_grab_1frame_1stream(JNIEnv *env, jobject obj, jint streamid)
{
    //jclass bbclass = env->FindClass( "java/nio/IntBuffer" );
    //jmethodID putMethod = env->GetMethodID(bbclass, "put", "(B)Ljava/nio/IntBuffer;");
    int buffer_size;
    jintArray ia;
    jint *intbuffer = NULL;
    unsigned char *buffer = NULL;

    append_stream( streamid );

    buffer_size = stream_device_rgb24_size(streamid);
    ia = env->NewIntArray( buffer_size );
    intbuffer = (jint *)calloc( buffer_size, sizeof(jint) );

    buffer = stream_device_buffer_rgb( streamid );
    if( buffer == NULL ) {
        env->DeleteLocalRef( ia );
        return env->NewIntArray( 0 );
    }

    for(int i=0; i < buffer_size; i++ ) {
        intbuffer[i] = (jint)buffer[i];
    }
    env->SetIntArrayRegion( ia, 0, buffer_size, intbuffer );

    free( intbuffer );

    return ia;
}

これは、過去 2 週間、私を完全に狂気に駆り立てており、私に提案されたもののバリエーションも試してみましたが、まともな成功はまったくありませんでした.

4

0 に答える 0