Почему kinect цвет и глубина не выровнены правильно?

Я работаю над этой проблемой довольно давно и нахожусь в конце своего творчества, так что, надеюсь, кто-то еще может помочь мне указать верное направление. Я работал с Kinect и пытался записать данные в MATLAB. К счастью, есть довольно много способов сделать это (в настоящее время я использую http://www.mathworks.com/matlabcentral/fileexchange/30242-kinect-matlab). Когда я попытался спроецировать полученные данные в 3D, мои традиционные методы дали плохие результаты реконструкции.

Короче говоря, в итоге я написал оболочку Kinect SDK для Matlab, которая выполняет реконструкцию и выравнивание. Реконструкция работает как мечта, но...

У меня тонны проблем с выравниванием, как вы можете видеть здесь:

Пожалуйста, не смотрите внимательно на модель:(.

Как видите, выравнивание неверное. Я не уверен, почему это так. Я прочитал много форумов, где другие добились большего успеха, чем я, используя те же методы.

Мой текущий конвейер использует Kinect Matlab (используя Openni) для захвата данных, реконструкции с использованием Kinect SDK, а затем выравнивания с использованием Kinect SDK (NuiImageGetColorPixelCoordinateFrameFromDepthPixelFrameAtResolution). Я подозревал, что это возможно из-за Openni, но у меня был небольшой успех в создании вызовов функций mex для захвата с использованием Kinect SDK.

Если кто-то может указать мне направление, в которое я должен углубиться, это будет очень цениться.

Редактировать:

Рисунок, я должен опубликовать код Это код, который я использую для выравнивания:

    /* The matlab mex function */
    void mexFunction( int nlhs, mxArray *plhs[], int nrhs, 
            const mxArray *prhs[] ){

        if( nrhs < 2 )
        {
            printf( "No depth input or color image specified!\n" );
            mexErrMsgTxt( "Input Error" );
        }

        int width = 640, height = 480;

        // get input depth data

        unsigned short *pDepthRow = ( unsigned short* ) mxGetData( prhs[0] );
        unsigned char *pColorRow = ( unsigned char* ) mxGetData( prhs[1] );

        // compute the warping

        INuiSensor *sensor = CreateFirstConnected();
        long colorCoords[ 640*480*2 ];
        sensor->NuiImageGetColorPixelCoordinateFrameFromDepthPixelFrameAtResolution(
                NUI_IMAGE_RESOLUTION_640x480, NUI_IMAGE_RESOLUTION_640x480, 
                640*480, pDepthRow, 640*480*2, colorCoords );
        sensor->NuiShutdown();
        sensor->Release();

        // create matlab output; it's a column ordered matrix ;_;

        int Jdimsc[3];
        Jdimsc[0]=height;
        Jdimsc[1]=width;
        Jdimsc[2]=3;

        plhs[0] = mxCreateNumericArray( 3, Jdimsc, mxUINT8_CLASS, mxREAL );
        unsigned char *Iout = ( unsigned char* )mxGetData( plhs[0] );

        for( int x = 0; x < width; x++ )
            for( int y = 0; y < height; y++ ){

                int idx = ( y*width + x )*2;
                long c_x = colorCoords[ idx + 0 ];
                long c_y = colorCoords[ idx + 1 ];

                bool correct = ( c_x >= 0 && c_x < width 
                        && c_y >= 0 && c_y < height );
                c_x = correct ? c_x : x;
                c_y = correct ? c_y : y;

                Iout[ 0*height*width + x*height + y ] =
                        pColorRow[ 0*height*width + c_x*height + c_y ];
                Iout[ 1*height*width + x*height + y ] =
                        pColorRow[ 1*height*width + c_x*height + c_y ];
                Iout[ 2*height*width + x*height + y ] =
                        pColorRow[ 2*height*width + c_x*height + c_y ];

            }

    }

3 ответа

Решение

Это хорошо известная проблема для систем стереозрения. У меня была такая же проблема некоторое время назад. Оригинальный вопрос, который я разместил, можно найти здесь. То, что я пытался сделать, было похоже на это. Однако после многих исследований я пришел к выводу, что захваченный набор данных не может быть легко выровнен.

С другой стороны, во время записи набора данных вы можете легко использовать вызов функции для выравнивания как RGB, так и данных глубины. Этот метод доступен как в OpenNI, так и в Kinect SDK (функциональность одинакова, а имена вызовов функций различны для каждого)

Похоже, что вы используете Kinect SDK для захвата набора данных, для выравнивания данных с Kinect SDK вы можете использовать MapDepthFrameToColorFrame.

Поскольку вы также упомянули об использовании OpenNI, взгляните на AlternativeViewPointCapability.

У меня нет опыта работы с Kinect SDK, однако в OpenNI v1.5 вся эта проблема была решена путем выполнения следующего вызова функции перед регистрацией узла устройства записи:

depth.GetAlternativeViewPointCap().SetViewPoint(image);

где image является узлом генератора изображений и depth это узел генератора глубины. Это было со старым SDK, который был заменен OpenNI 2.0 SDK. Так что если вы используете последний SDK, то вызов функции может отличаться, однако общая процедура может быть похожей.

Я также добавляю несколько примеров изображений:

Без использования вышеуказанного вызова функции выравнивания края глубины на RGB не были выровненыБез выравнивания

При использовании вызова функции край глубины становится идеально выровненным (есть некоторые области инфракрасного тени, которые показывают некоторые края, но они являются просто недопустимыми областями глубины)С выравниванием

Вы можете легко выровнять Глубинные и Цветные рамки, считав параметры отображения текстуры U,V с помощью Kinect SDK. Для каждой пиксельной координаты (i,j) Глубинного фрейма D(i,j) соответствующая пиксельная координата Цветного фрейма задается как (U(i,j),V(i,j)), поэтому цвет задается C(U(i,j),V(i,j)).

Функции U,V содержатся в аппаратном обеспечении каждого Kinect, и они отличаются от Kinect к Kinect, поскольку камеры глубины по-разному выровнены по отношению к видеокамерам из-за крошечных различий при наклеивании на аппаратную плату на заводе. Но вам не нужно беспокоиться об этом, если вы читаете U,V из Kinect SDK.

Ниже я приведу пример изображения и пример исходного кода с использованием Kinect SDK в Java с библиотекой с открытым исходным кодом J4K:

public class Kinect extends J4KSDK{

    VideoFrame videoTexture; 

public Kinect() { 
    super(); 
    videoTexture=new VideoFrame(); 
}

@Override 
public void onDepthFrameEvent(short[] packed_depth, int[] U, int V[]) { 
    DepthMap map=new DepthMap(depthWidth(),depthHeight(),packed_depth); 
    if(U!=null && V!=null) map.setUV(U,V,videoWidth(),videoHeight()); 
} 

@Override 
public void onVideoFrameEvent(byte[] data) {     
    videoTexture.update(videoWidth(), videoHeight(), data); 
} }

Пример изображения, показывающий 3 разных ракурса одного и того же выровненного кадра глубины видео:

Я надеюсь, что это поможет вам!

depth.GetAlternativeViewPointCap() SetViewPoint(изображение).

работает хорошо, но проблема в том, что он уменьшает изображение глубины (по FOCAL_rgb/FOCAL_kinect) и сдвигает пиксель глубины на диспаратность d=focal*B/z; в зависимости от заводских настроек возможно небольшое вращение.

Таким образом, невозможно восстановить все 3 координаты реального мира без отмены этих преобразований. При этом методы, которые не зависят от точных x, y и учитывают только z (например, сегментация), могут хорошо работать даже в сдвинутой сдвинутой карте. Кроме того, они могут использовать цвет и глубину для лучшей сегментации.

Другие вопросы по тегам