Posts Tagged ‘Kinect’

Kinect and OpenCV

After struggling several days with all stuff related to OpenKinect (libfreenect) and Microsoft Visual Studio 2008, finally I could execute the experiment on getting the Kinect RGB-Depth image wrapped with the OpenCV2.1 library functions.


Special thanks to Tisham Dhar who wrote a very nice article on his blog   :
http://whatnicklife.blogspot.com
You can access the source code from his google code page : freenectopencv.cpp

Or, the below code is taken from Tisham’s page which then combined with Canny Filter operation :
(comment out all the glview.c code and replace with the below source code)

/* freenectopencv.cpp
Copyright (C) 2010 Arne Bernin
This code is licensed to you under the terms of the GNU GPL, version 2 or version 3;
see:
http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
http://www.gnu.org/licenses/gpl-3.0.txt
*/

/*
 * Makefile for ubuntu, assumes that libfreenect.a is in /usr/lib, and libfreenect.h is in /usr/include
 *
 * make sure you have the latest version of freenect from git!

***************************************************************************************************************************
* Makefile
***************************************************************************************************************************
CXXFLAGS = -O2 -g -Wall -fmessage-length=0 `pkg-config opencv --cflags ` -I /usr/include/libusb-1.0

OBJS = freenectopencv.o

LIBS = `pkg-config opencv --libs` -lfreenect

TARGET = kinectopencv

$(TARGET): $(OBJS)
$(CXX) -o $(TARGET) $(OBJS) $(LIBS)

all: $(TARGET)

clean:
rm -f $(OBJS) $(TARGET)

*************************************************************************************************** * End of Makefile
***************************************************************************************************
*/

#include <stdio.h>
#include <string.h>
#include <math.h>

#include <libfreenect.h>
#include <pthread.h>

#define CV_NO_BACKWARD_COMPATIBILITY

#include <cv.h>
#include <highgui.h>

#define FREENECTOPENCV_WINDOW_D "Depthimage"
#define FREENECTOPENCV_WINDOW_N "Normalimage"
#define FREENECTOPENCV_RGB_DEPTH 3
#define FREENECTOPENCV_DEPTH_DEPTH 1
#define FREENECTOPENCV_RGB_WIDTH 640
#define FREENECTOPENCV_RGB_HEIGHT 480
#define FREENECTOPENCV_DEPTH_WIDTH 640
#define FREENECTOPENCV_DEPTH_HEIGHT 480

IplImage* depthimg = 0;
IplImage* rgbimg = 0;
IplImage* tempimg = 0;
IplImage* canny_img = 0;
IplImage* canny_temp = 0;
pthread_mutex_t mutex_depth = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_rgb = PTHREAD_MUTEX_INITIALIZER;
pthread_t cv_thread;

// callback for depthimage, called by libfreenect
void depth_cb(freenect_device *dev, void *depth, uint32_t timestamp)

{
        cv::Mat depth8;
        cv::Mat mydepth = cv::Mat( FREENECTOPENCV_DEPTH_WIDTH,FREENECTOPENCV_DEPTH_HEIGHT, CV_16UC1, depth);

        mydepth.convertTo(depth8, CV_8UC1, 1.0/4.0);
        pthread_mutex_lock( &mutex_depth );
        memcpy(depthimg->imageData, depth8.data, 640*480);
        // unlock mutex
        pthread_mutex_unlock( &mutex_depth );

}

// callback for rgbimage, called by libfreenect

void rgb_cb(freenect_device *dev, void *rgb, uint32_t timestamp)
{

        // lock mutex for opencv rgb image
        pthread_mutex_lock( &mutex_rgb );
        memcpy(rgbimg->imageData, rgb, FREENECT_VIDEO_RGB_SIZE);
        // unlock mutex
        pthread_mutex_unlock( &mutex_rgb );
}

/*
 * thread for displaying the opencv content
 */
void *cv_threadfunc (void *ptr) {
        cvNamedWindow( FREENECTOPENCV_WINDOW_D, CV_WINDOW_AUTOSIZE );
        cvNamedWindow( FREENECTOPENCV_WINDOW_N, CV_WINDOW_AUTOSIZE );
		cvNamedWindow( "Canny Image", CV_WINDOW_AUTOSIZE );
		cvNamedWindow( "Depth Canny", CV_WINDOW_AUTOSIZE );
        depthimg = cvCreateImage(cvSize(FREENECTOPENCV_DEPTH_WIDTH, FREENECTOPENCV_DEPTH_HEIGHT), IPL_DEPTH_8U, FREENECTOPENCV_DEPTH_DEPTH);
        rgbimg = cvCreateImage(cvSize(FREENECTOPENCV_RGB_WIDTH, FREENECTOPENCV_RGB_HEIGHT), IPL_DEPTH_8U, FREENECTOPENCV_RGB_DEPTH);
        tempimg = cvCreateImage(cvSize(FREENECTOPENCV_RGB_WIDTH, FREENECTOPENCV_RGB_HEIGHT), IPL_DEPTH_8U, FREENECTOPENCV_RGB_DEPTH);
		canny_img = cvCreateImage(cvSize(FREENECTOPENCV_RGB_WIDTH, FREENECTOPENCV_RGB_HEIGHT), IPL_DEPTH_8U, 1);
		canny_temp = cvCreateImage(cvSize(FREENECTOPENCV_DEPTH_WIDTH, FREENECTOPENCV_DEPTH_HEIGHT), IPL_DEPTH_8U, FREENECTOPENCV_DEPTH_DEPTH);

        // use image polling
        while (1) {
                //lock mutex for depth image
                pthread_mutex_lock( &mutex_depth );
                // show image to window
                cvCanny(depthimg, canny_temp, 50.0, 200.0, 3);
				cvCvtColor(depthimg,tempimg,CV_GRAY2BGR);
                cvCvtColor(tempimg,tempimg,CV_HSV2BGR);

                cvShowImage(FREENECTOPENCV_WINDOW_D,tempimg);
				cvShowImage("Depth Canny", canny_temp);
                //unlock mutex for depth image
                pthread_mutex_unlock( &mutex_depth );

                //lock mutex for rgb image
                pthread_mutex_lock( &mutex_rgb );
                // show image to window
                cvCvtColor(rgbimg,tempimg,CV_BGR2RGB);
				cvCvtColor(tempimg, canny_img, CV_BGR2GRAY);
                cvShowImage(FREENECTOPENCV_WINDOW_N, tempimg);

				// Canny filter
				cvCanny(canny_img, canny_img, 50.0, 200.0, 3);
				cvShowImage("Canny Image", canny_img);
                //unlock mutex
                pthread_mutex_unlock( &mutex_rgb );

                // wait for quit key
                if( cvWaitKey( 15 )==27 )
                                break;

        }
        pthread_exit(NULL);

		return NULL;

}

int main(int argc, char **argv)
{

        freenect_context *f_ctx;
        freenect_device *f_dev;

        int res = 0;
        int die = 0;
        printf("Kinect camera test\n");

        if (freenect_init(&f_ctx, NULL) < 0) {
                        printf("freenect_init() failed\n");
                        return 1;
                }

                if (freenect_open_device(f_ctx, &f_dev, 0) < 0) {
                        printf("Could not open device\n");
                        return 1;
                }

        freenect_set_depth_callback(f_dev, depth_cb);
        freenect_set_video_callback(f_dev, rgb_cb);
        freenect_set_video_format(f_dev, FREENECT_VIDEO_RGB);

        // create opencv display thread
        res = pthread_create(&cv_thread, NULL, cv_threadfunc, (void*) depthimg);
        if (res) {
                printf("pthread_create failed\n");
                return 1;
        }

        printf("init done\n");

        freenect_start_depth(f_dev);
        freenect_start_video(f_dev);

        while(!die && freenect_process_events(f_ctx) >= 0 );

}

Please notice that I am using : libfreenect for Windows + Microsoft Visual Studio 9 (2008) + OpenCV 2.1

Microsoft Kinect RGB Color and 3D Depth Sensor

The below videos are simulation of RGB and Depth data taken by Microsoft Kinect Sensor.

Kinect sensor equipped with RGB Camera, 3D Depth Sensors, Motorized Tilt and Multi-Array mic. (picture taken from Wikipedia)
Microsoft Kinect Sensor

In this experiment, left screen is a display of color image and right screen is a display of 3D depth image taken by the IR (infrared) sensor.

Beberapa bulan lalu (kalo nggak salah November 2010), Microsoft mengeluarkan produk baru yg bisa dipakai sebagai sensor utk bermain video game X-Box tanpa memakai joystick. Nama sensor barunya adalah Microsoft Kinect Sensor. Dengan memakai Kinect, kita nggak perlu lagi bermain video game dengan joystick. Nah, sebagai gantinya, joystick-nya itu adalah semua anggota badan kita yg setiap ayunan tangan, gerakan kaki atau anggukan kepala akan ditangkap oleh si Kinect dan diubah menjadi data yg selanjutnya diproses oleh komputer menjadi sinyal-sinyal input joystick. Kalau kita lompat, maka karakter video game di layar pun akan ikutan melompat.

Alat ini dilengkapi dengan beberapa sensor, yaitu : Kamera RGB (Red-Green-Blue), ‘Depth sensor’ yg dilengkapi dengan pemancar&penangkap Infra Merah, Multi-Array Microphone.

Baru-baru ini saya iseng nyobain kinerja si Kinect di laboratorium kampus. Lumayan, nyobain “mainan” baru yg dibeliin sama sensei Lab. (mahal jg kalo mesti beli sendiri dari kantong pribadi). Ternyata seru juga loh!!

Coba deh lihat dua video di atas. Hehehe.. ada orang aneh gerak-gerak nggak jelas :D…

Layar terbagi menjadi dua bagian : layar sebelah kiri dan layar sebelah kanan. Nah, layar sebelah kiri memberikan output berupa gambar asli yg ditangkap oleh kamera (gambar merah-hijau-biru), sedangkan layar sebelah kanan memberikan informasi berupa jarak antara si “benda” terhadap kamera.

Kinect bisa memberikan prediksi jarak antara “benda” dengan kamera berkat adanya sinar infra merah yg ditembakkan ke arah benda, lalu terpantul kembali ke bagian penerima infra merah. Dari situ bisa dihitung waktu pantulan, dan komputer bisa memberikan perkiraan jarak. Setelah itu, “data jarak” diubah menjadi gradasi warna yg menunjukkan perbedaan jarak antara benda dengan kamera. Kalau diperhatikan dengan jeli, di layar sebelah kanan akan terlihat gradai warna oranye, kuning, hijau, biru dan hitam. Semakin dekat suatu benda dengan kamera, maka tampilan gradasi akan manjadi hitam.

Setelah percobaan ini selesai dan koding-nya udah mantap, saya punya rencana utk memasang si Kinect di robot MG10. Kayanya bakal seru nih,,, robot MG10 akan punya “mata” baru yg bisa melihat kondisi sekitar sekaligus memberikan prediksi jarak dengan objek di sekitarnya.

%d bloggers like this: