<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3230570763723541579</id><updated>2012-02-23T20:32:03.961-08:00</updated><category term='Microsoft Kinect Android'/><title type='text'>Raymond's Blog</title><subtitle type='html'>Android, iPhone, J2ME, CUDA, GPGPU, HDR Imaging.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://raymondlo84.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3230570763723541579/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://raymondlo84.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>raymondlo84</name><uri>http://www.blogger.com/profile/03006577844333563556</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_iai8t1xHPZA/TI5PwsALvtI/AAAAAAAAAIM/zIai5sXJ620/S220/DSC_9655.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3230570763723541579.post-5986538314058287361</id><published>2012-01-23T21:07:00.000-08:00</published><updated>2012-02-14T13:34:12.633-08:00</updated><title type='text'>HDR on Canon 50D! (hacking a hack!)</title><content type='html'>Finally! The Magic Lantern Firmware had solved my ultimate problem! HDR video on a DSLR! My Lovely 50D is like super powered now :) !&lt;br /&gt;&lt;br /&gt;I had been working with the PointGrey Flea3 camera for the HDR video, but the resolution and the noise performance are just too disappointing! 640x480, 10bits A/D... The only great thing about that camera would be the frame rate! 120fps. &lt;br /&gt;&lt;br /&gt;Here I will show you how to compile the Magic Lantern Firmware on Mac OS X (10.6.8) with Macport!&lt;br /&gt;&lt;br /&gt;Basically you only need to install through Macport using the following command.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;sudo port install arm-elf-gcc &lt;br /&gt;&lt;br /&gt;arm-elf-gcc @4.6.1 (cross, devel)&lt;br /&gt;    gcc cross-compilers for arm-elf, with newlib runtime library.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then, you will need to grab the source code from the official website or directly from my hacked version that runs on mac&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;http://magiclantern.wikia.com/wiki/Unified#Downloads&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;or&lt;br /&gt;&lt;pre class="prettyprint"&gt;http://www.eyetap.org/~raymondlo84/magic_shutter.tgz&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Well, good luck if you can get any support from that team? I tried to email them but I believe they are all busy working on something? and ignored me totally.&lt;br /&gt;&lt;br /&gt;Anyways, today I will show you how to hack the camera firmware hack so it will use alternating shutter speed instead of ISO to create the HDR video sequence. The key advantage is we can get better noise performance by utilizing a much lower ISO settings. (i.e., using ISO 100 constantly instead of alternating ISO 100 and ISO 1600). &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;#ifdef CONFIG_500D&lt;br /&gt;#define MOVREC_STATE (*(struct state_object **)0x7AF4)&lt;br /&gt;#define LV_STRUCT_PTR 0x1d78&lt;br /&gt;#define FRAME_ISO *(uint16_t*)(MEM(LV_STRUCT_PTR) + 0x56)&lt;br /&gt;#endif&lt;br /&gt;......&lt;br /&gt;&lt;br /&gt;void hdr_step()&lt;br /&gt;{&lt;br /&gt;    if (!hdrv_enabled) return;&lt;br /&gt;    if (!lv) return;&lt;br /&gt;    if (!is_movie_mode()) return;&lt;br /&gt;    &lt;br /&gt;    static int odd_frame = 0;&lt;br /&gt;    static int frame;&lt;br /&gt;    frame++;&lt;br /&gt;        &lt;br /&gt;    if (recording)&lt;br /&gt;    {&lt;br /&gt;        #ifdef MOVREC_STATE // sync by Canon frame number&lt;br /&gt;        frame = MVR_FRAME_NUMBER;&lt;br /&gt;        #endif&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        if (!HALFSHUTTER_PRESSED) odd_frame = (frame / video_mode_fps) % 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    int iso_low, iso_high;&lt;br /&gt;    hdr_get_iso_range(&amp;amp;iso_low, &amp;amp;iso_high);&lt;br /&gt;&lt;br /&gt;    //hack!!&lt;br /&gt;    //if we enable the HDR mode with the same ISO settings, we will use&lt;br /&gt;    //alternating shutter to accomplish the same thing&lt;br /&gt;    //now we use 3 exposures- that will cover a very very wide dynamic range!!&lt;br /&gt;    if(iso_high == iso_low){&lt;br /&gt;     odd_frame = frame % 3;&lt;br /&gt;  if(odd_frame==0){&lt;br /&gt;   int shutter_speed = 8000/16;&lt;br /&gt;   FRAME_SHUTTER_TIMER=49440/(shutter_speed);&lt;br /&gt;  }else if(odd_frame==1){&lt;br /&gt;   int shutter_speed = 8000;&lt;br /&gt;   FRAME_SHUTTER_TIMER=49440/(shutter_speed);&lt;br /&gt;  }else{&lt;br /&gt;   int shutter_speed = 8000/16/16;&lt;br /&gt;   FRAME_SHUTTER_TIMER=49440/(shutter_speed);&lt;br /&gt;  }&lt;br /&gt;    }else{&lt;br /&gt;        odd_frame = frame % 2;&lt;br /&gt;        //int iso = iso_high;&lt;br /&gt;        int iso = odd_frame ? iso_low : iso_high; // ISO 100-1600&lt;br /&gt;        FRAME_ISO = iso | (iso &amp;lt;&amp;lt; 8);&lt;br /&gt;    }&lt;br /&gt;    //FRAME_SHUTTER_TIMER = 8000/16*10; //lower the max by 4 stops&lt;br /&gt;    //~ *(uint8_t*)(lv_struct + 0x54) = iso;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I have packaged everything for this hack and you can try compiling this using &lt;br /&gt;&lt;br /&gt;make 50D &lt;br /&gt;&lt;br /&gt;make install&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I haven't confirmed if it will compile and run on the 60D or other DSLRs. If you give me your camera, maybe I will give that a try? :)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Demo Video:&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Coming up soon. I have a new real-time HDR rendering engine to present next. Follow me to get the latest update.&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3230570763723541579-5986538314058287361?l=raymondlo84.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raymondlo84.blogspot.com/feeds/5986538314058287361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://raymondlo84.blogspot.com/2012/01/hdr-on-canon-50d-hacking-hack.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3230570763723541579/posts/default/5986538314058287361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3230570763723541579/posts/default/5986538314058287361'/><link rel='alternate' type='text/html' href='http://raymondlo84.blogspot.com/2012/01/hdr-on-canon-50d-hacking-hack.html' title='HDR on Canon 50D! (hacking a hack!)'/><author><name>raymondlo84</name><uri>http://www.blogger.com/profile/03006577844333563556</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_iai8t1xHPZA/TI5PwsALvtI/AAAAAAAAAIM/zIai5sXJ620/S220/DSC_9655.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3230570763723541579.post-1546480433581332696</id><published>2012-01-15T22:14:00.000-08:00</published><updated>2012-01-15T22:44:43.521-08:00</updated><title type='text'>Real-time PointCloud Data Visualization on Tegra 2</title><content type='html'>In this tutorial, I will explain the last piece of the&amp;nbsp;puzzle in creating high performance 3D visualization of the Kinect 3D range data on the Tegra 2 platform. Even with the 3D rendering, we can still achieve approximately 8fps! Pretty impressive. It is definitely a very usable frame rate for real-time interactions.&lt;br /&gt;&lt;br /&gt;OpenGL ES2 provides a simple 3D interface to render 3D points efficiently. PointCloud Data are basically 3D vertices with color information -&amp;nbsp; e.g., (x,y,z, r,g,b). With the Kinect camera streams these data as of a (r,g,b,d). To recover the (x,y,z) information, we can simply project the depth information back using the&amp;nbsp;intrinsic&amp;nbsp;information of the camera. We can offload such work on the GPU easily by writing another shader program. See comments below.&lt;br /&gt;&lt;br /&gt;To push the data onto the screen, we first load the rgbd data to an array buffer, and then we have to construct an perspective matrix manually (see &lt;a href="http://www.songho.ca/opengl/gl_projectionmatrix.html"&gt;OpenGL perspective projection tutorial&lt;/a&gt;). We have also added a bounding box to show the projection of the data and the bounded area as shown in the demo video.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;void Renderer::displayOverlay2(){&lt;br /&gt; glViewport(0, 0, screen_width, screen_height);&lt;br /&gt;&lt;br /&gt; double max_range = 5.0; //5 meters = max range?&lt;br /&gt;&lt;br /&gt; //load the depth map&lt;br /&gt; GLfloat *point_vertices = myVertices;&lt;br /&gt; float *depth_float_ptr = depth_float_info;&lt;br /&gt; //overwrite the depth buffer&lt;br /&gt;    for (float j = 0; j &amp;lt; IMAGE_HEIGHT; j++) {&lt;br /&gt;  for (float i = 0; i &amp;lt; IMAGE_WIDTH; i++) {&lt;br /&gt;   //unsigned short raw_depth = *point_depth;&lt;br /&gt;   float real_depth=*depth_float_ptr; //this range from...?&lt;br /&gt;   if(real_depth&amp;lt;=0)&lt;br /&gt;    real_depth=9999;&lt;br /&gt;   *(point_vertices + 0) = i;&lt;br /&gt;   *(point_vertices + 1) = j;&lt;br /&gt;   *(point_vertices + 2) = real_depth;&lt;br /&gt;   point_vertices += 3;&lt;br /&gt;   depth_float_ptr++;&lt;br /&gt;  }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt; glEnable(GL_DEPTH_TEST);&lt;br /&gt; glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);&lt;br /&gt;&lt;br /&gt; glUseProgram(overlayProgram);&lt;br /&gt;&lt;br /&gt; //Comment the lines below to disable rotation&lt;br /&gt; iXangle = 5.0+user_input_x/5.0;&lt;br /&gt; //iYangle += 5;&lt;br /&gt; iZangle = -180;&lt;br /&gt; iYangle += 1;&lt;br /&gt; //reset it&lt;br /&gt; if(iYangle&amp;gt;270){&lt;br /&gt;  iYangle=90;&lt;br /&gt; }&lt;br /&gt; //rotate - begin&lt;br /&gt; rotate_matrix(iXangle, 1.0, 0.0, 0.0, aModelView);&lt;br /&gt; rotate_matrix(iYangle, 0.0, 1.0, 0.0, aRotate);&lt;br /&gt; multiply_matrix(aRotate, aModelView, aModelView);&lt;br /&gt; rotate_matrix(iZangle, 0.0, 0.0, 1.0, aRotate);&lt;br /&gt; multiply_matrix(aRotate, aModelView, aModelView);&lt;br /&gt;&lt;br /&gt; //translate_matrix(user_input_x,user_input_y,-5,aModelView);&lt;br /&gt; //Pull the camera back from the geometry&lt;br /&gt;&lt;br /&gt; aModelView[12] = 0;&lt;br /&gt; aModelView[13] = -0.5;&lt;br /&gt; aModelView[14] -= 50;&lt;br /&gt;&lt;br /&gt; //use very little FOV ~ 5 degree... we should use orthogonal instead...&lt;br /&gt; perspective_matrix(_PI/36.0, (double)screen_width/(double)screen_height, 1, 300.0, aPerspective);&lt;br /&gt; multiply_matrix(aPerspective, aModelView, aMVP);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; glUniformMatrix4fv(glGetUniformLocation(overlayProgram, "MVPMat"), (GLsizei)1, GL_FALSE, aMVP);&lt;br /&gt; // Load the vertex data&lt;br /&gt; glVertexAttribPointer(glGetAttribLocation(overlayProgram, "vPosition"), 3, GL_FLOAT, GL_FALSE, 0, myVertices);&lt;br /&gt; glVertexAttribPointer(glGetAttribLocation(overlayProgram, "a_color"), 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, processed_data);&lt;br /&gt;&lt;br /&gt; glEnableVertexAttribArray(glGetAttribLocation(overlayProgram, "vPosition"));&lt;br /&gt; glEnableVertexAttribArray(glGetAttribLocation(overlayProgram, "a_color"));&lt;br /&gt; glDrawArrays(GL_POINTS, 0, NUM_VERTICES);&lt;br /&gt;&lt;br /&gt; //this will get transformed by the vertex program&lt;br /&gt; float cube_depth = 7;&lt;br /&gt; float cube_width = 640;&lt;br /&gt; float cube_height = 480;&lt;br /&gt; float min_front = 0.6;&lt;br /&gt; GLfloat cubeVertex[]={&lt;br /&gt;   //front&lt;br /&gt;   cube_width, cube_height, 0.0,&lt;br /&gt;   0, cube_height, 0.0,&lt;br /&gt;   0, 0, 0.0,&lt;br /&gt;   cube_width, 0, 0.0,&lt;br /&gt;   cube_width, cube_height, 0.0,&lt;br /&gt;   //right&lt;br /&gt;   cube_width, cube_height, 0.0,&lt;br /&gt;   cube_width, cube_height, cube_depth,&lt;br /&gt;   cube_width, 0, cube_depth,&lt;br /&gt;   cube_width, 0, 0.0,&lt;br /&gt;   cube_width, cube_height, 0.0,&lt;br /&gt;   //left&lt;br /&gt;   0, cube_height, 0.0,&lt;br /&gt;   0, cube_height, cube_depth,&lt;br /&gt;   0, 0, cube_depth,&lt;br /&gt;   0, 0, 0.0,&lt;br /&gt;   0, cube_height, 0.0,&lt;br /&gt;   //up&lt;br /&gt;   cube_width, cube_height, 0.0,&lt;br /&gt;   0, cube_height, 0.0,&lt;br /&gt;   0, 0, 0.0,&lt;br /&gt;   cube_width, 0, 0.0,&lt;br /&gt;   cube_width, cube_height, 0.0,&lt;br /&gt;   //down&lt;br /&gt;   cube_width, cube_height, 0.0,&lt;br /&gt;   0, cube_height, 0.0,&lt;br /&gt;   0, 0, 0.0,&lt;br /&gt;   cube_width, 0, 0.0,&lt;br /&gt;   cube_width, cube_height, 0.0,&lt;br /&gt;   //back&lt;br /&gt;   cube_width, cube_height, cube_depth,&lt;br /&gt;   0, cube_height, cube_depth,&lt;br /&gt;   0, 0, cube_depth,&lt;br /&gt;   cube_width, 0, cube_depth,&lt;br /&gt;   cube_width, cube_height, cube_depth,&lt;br /&gt; };&lt;br /&gt; GLfloat cubeColor[]={&lt;br /&gt;   1.0, 0.0, 0.0, 1.0,&lt;br /&gt;   0.0, 1.0, 0.0, 1.0,&lt;br /&gt;   0.0, 0.0, 1.0, 1.0,&lt;br /&gt;   1.0, 1.0, 0.0, 1.0,&lt;br /&gt;   1.0, 0.0, 1.0, 1.0,&lt;br /&gt;&lt;br /&gt;   1.0, 0.0, 0.0, 1.0,&lt;br /&gt;   0.0, 1.0, 0.0, 1.0,&lt;br /&gt;   0.0, 0.0, 1.0, 1.0,&lt;br /&gt;   1.0, 1.0, 0.0, 1.0,&lt;br /&gt;   1.0, 0.0, 1.0, 1.0,&lt;br /&gt;&lt;br /&gt;   1.0, 0.0, 0.0, 1.0,&lt;br /&gt;   0.0, 1.0, 0.0, 1.0,&lt;br /&gt;   0.0, 0.0, 1.0, 1.0,&lt;br /&gt;   1.0, 1.0, 0.0, 1.0,&lt;br /&gt;   1.0, 0.0, 1.0, 1.0,&lt;br /&gt;&lt;br /&gt;   1.0, 0.0, 0.0, 1.0,&lt;br /&gt;   0.0, 1.0, 0.0, 1.0,&lt;br /&gt;   0.0, 0.0, 1.0, 1.0,&lt;br /&gt;   1.0, 1.0, 0.0, 1.0,&lt;br /&gt;   1.0, 0.0, 1.0, 1.0,&lt;br /&gt;&lt;br /&gt;   1.0, 0.0, 0.0, 1.0,&lt;br /&gt;   0.0, 1.0, 0.0, 1.0,&lt;br /&gt;   0.0, 0.0, 1.0, 1.0,&lt;br /&gt;   1.0, 1.0, 0.0, 1.0,&lt;br /&gt;   1.0, 0.0, 1.0, 1.0,&lt;br /&gt;&lt;br /&gt;   1.0, 0.0, 0.0, 1.0,&lt;br /&gt;   0.0, 1.0, 0.0, 1.0,&lt;br /&gt;   0.0, 0.0, 1.0, 1.0,&lt;br /&gt;   1.0, 1.0, 0.0, 1.0,&lt;br /&gt;   1.0, 0.0, 1.0, 1.0&lt;br /&gt; };&lt;br /&gt; glVertexAttribPointer(glGetAttribLocation(overlayProgram, "a_color"), 4, GL_FLOAT, GL_FALSE, 0, cubeColor);&lt;br /&gt; glVertexAttribPointer(glGetAttribLocation(overlayProgram, "vPosition"), 3, GL_FLOAT, GL_FALSE, 0, cubeVertex);&lt;br /&gt; glEnableVertexAttribArray(glGetAttribLocation(overlayProgram, "vPosition"));&lt;br /&gt; glEnableVertexAttribArray(glGetAttribLocation(overlayProgram, "a_color"));&lt;br /&gt;//draw the bounding box to visualize the boundary.&lt;br /&gt; glDrawArrays(GL_LINE_STRIP, 0, 5*6); //6 faces&lt;br /&gt;&lt;br /&gt; glDisable(GL_DEPTH_TEST);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Then, on the shader program side, we basically construct the (x,y,z) coordinates on GPU using the depth data and the camera calibration data (see Tutorial # 1) we have found previously.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;uniform mat4 MVPMat;    // Model-View-Projection matrix&lt;br /&gt;attribute vec4 vPosition; &lt;br /&gt;attribute vec4 a_color;&lt;br /&gt;varying vec4 v_color;&lt;br /&gt;&lt;br /&gt;const float fx_d = 5.5879981950414015e+02;&lt;br /&gt;const float fy_d = 5.5874227168094478e+02;&lt;br /&gt;const float cx_d = 3.1844162327317980e+02;&lt;br /&gt;const float cy_d = 2.4574257294583529e+02;&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt;    //perform the transformation on GPU&lt;br /&gt;    //transform the position so it will remap back to the real-world coordinate...&lt;br /&gt;    float z = vPosition.z; //depth &lt;br /&gt;    float x = z * (vPosition.x-cx_d) / fx_d; &lt;br /&gt;    float y = z * (vPosition.y-cy_d) / fy_d;&lt;br /&gt;    float w = 1.0;&lt;br /&gt;    gl_Position = MVPMat*vec4(x,y,z,w); //perspective transformation&lt;br /&gt;    gl_PointSize = 1.0; //we can make the points bigger or small with this&lt;br /&gt;    v_color = a_color;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then, the fragment program will just handle the rest by setting the color.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;precision mediump float;&lt;br /&gt;varying vec4 v_color;&lt;br /&gt;void main()&lt;br /&gt;{   &lt;br /&gt;    gl_FragColor = v_color;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I highly recommend you to download the source code and read it through. It is just too difficult to explain everything in one tutorial. However, I can put down these keywords just to allow others to search through these topics easily. Keywords: vertex and fragment shaders, perspective transformation, OpenGL ES2, 3D PointCloud data, etc...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Thoughts:&lt;/b&gt;&lt;br /&gt;The configuration and fine-grain data handling is rather tricky with the GPU! Basically, the main problem I had was the lack of APIs for handling the projective matrices (everything is manual!). &amp;nbsp;That indefinitely forced one to go back to OpenGL 101 and start the reading exercise again. I will leave the explanation of how OpenGL handles 3D data, and how to construct the projective matrices as your homework (see related work and references). In this tutorial, I will basically show you setup the projective matrices, how to write a proper function that will push the 3D vertices to the graphics card efficiently and assign proper color to each of them!&amp;nbsp; With these you have opened up infinite options on how you want to render 3D data on screen! Most importantly, I found the finer control to this does give me a lot more advantages over the older version of the OpenGL. That is just a trade off after all.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Performance:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The performance is rather mediocre mainly because of the 'memory-copy-back' function (i.e., copying the data from graphics card back to a memory buffer that is usable by the process). We have spent almost 30% of the runtime trying to convert such buffer! What a drag! Today, I have found no way to work around this problem and I will leave that as an open problem for NVIDIA to solve. I beleive we can hack the GraphicsBuffer but that option will destroy the future development of this project due to lack of compatibility in future releases.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;OpenCV on Tegra 2&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I've also cross-compiled OpenCV 2.3.1 to run on the Tegra 2. The performance was definitely not&amp;nbsp;significantly better than what I have written so far. Maybe OpenCV is just a lazy way to do computer vision on Tegra 2? ;) Check out the source code and you will see sample usage of the library in the source code. We have done the Canny edge detection and some other simple image processing.&lt;br /&gt;&lt;br /&gt;Sample Videos:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/xLN2kfbx6io/0.jpg" height="266" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/xLN2kfbx6io?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="480" height="320"  src="http://www.youtube.com/v/xLN2kfbx6io?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;Note: The application runs at 8fps now at 640x480 with all the processing.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Donation:&lt;/b&gt;&lt;br /&gt;To continue my development on this project, I believe the best way is to get better hardware or donation.&lt;br /&gt;&lt;br /&gt;&lt;form action="https://www.paypal.com/cgi-bin/webscr" method="post"&gt;&lt;input name="cmd" type="hidden" value="_s-xclick" /&gt;&lt;br /&gt;&lt;input name="encrypted" type="hidden" value="-----BEGIN PKCS7-----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-----END PKCS7-----" /&gt;&lt;br /&gt;&lt;input alt="PayPal - The safer, easier way to pay online!" border="0" name="submit" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" type="image" /&gt;&lt;br /&gt;&lt;img alt="" border="0" height="1" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" /&gt;&lt;/form&gt;&lt;br /&gt;Hope this tutorial will help others on getting efficient 3D rendering on Tegra 2 platform! especially people who are also interested in utilizing the Kinect camera for input!&lt;br /&gt;&lt;br /&gt;Source Code:&lt;br /&gt;&lt;pre class="prettyprint"&gt;svn co https://openvidia.svn.sourceforge.net/svnroot/openvidia/tegra_kinect multitouch&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3230570763723541579-1546480433581332696?l=raymondlo84.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raymondlo84.blogspot.com/feeds/1546480433581332696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://raymondlo84.blogspot.com/2012/01/real-time-pointcloud-data-visualization.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3230570763723541579/posts/default/1546480433581332696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3230570763723541579/posts/default/1546480433581332696'/><link rel='alternate' type='text/html' href='http://raymondlo84.blogspot.com/2012/01/real-time-pointcloud-data-visualization.html' title='Real-time PointCloud Data Visualization on Tegra 2'/><author><name>raymondlo84</name><uri>http://www.blogger.com/profile/03006577844333563556</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_iai8t1xHPZA/TI5PwsALvtI/AAAAAAAAAIM/zIai5sXJ620/S220/DSC_9655.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3230570763723541579.post-3541991424153529071</id><published>2011-08-12T13:45:00.000-07:00</published><updated>2011-12-14T17:29:23.209-08:00</updated><title type='text'>GPU-based Image Processing on Tegra 2 and Microsoft Kinect</title><content type='html'>&lt;b&gt;Introduction:&amp;nbsp; &lt;/b&gt;&lt;br /&gt;In this tutorial, we will focus on the real-time image processing of the depth data and RGB data we collect from the Microsoft Kinect (see &lt;a href="http://raymondlo84.blogspot.com/2011/07/howto-using-microsoft-kinect-on-tegra.html"&gt;last tutorial&lt;/a&gt; if you want to configure your Tegra 2 to interface with the Kinect). In particular, we will show you how we can write custom fragment shader programs that will perform the image transformation (i.e., mapping the color map back to the depth map data) using the GPUs on the Tegra 2.&lt;br /&gt;&lt;br /&gt;When we mention GPGPU (General-Purpose computation on Graphics Processing Units) nowadays, one may immediately think of CUDA C/C++, ATI Streams, or OpenCL. &amp;nbsp;In fact, prior to these tools (about 7 years ago), people have already invented ways to utilize GPUs for computing demanding tasks. &lt;br /&gt;&lt;br /&gt;To harness the GPU processing power on the Tegra 2, we will first introduce vertex&amp;nbsp;shader&amp;nbsp;and fragment shader programs in OpenGL ES2.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;b&gt; OpenGL ES2 and Shader Programs:&amp;nbsp;&lt;/b&gt;&lt;br /&gt;The Nvidia Development Kit (NDK) provides a easy-to-use shader wrapper (nv_shader.cpp) to interface with the graphics cards. The idea behind GPGPU is simple, we basically create a texture (a piece of memory on the GPU, either shared with the CPU or not). Then, we write a custom vertex shader and a fragment shader to perform image&amp;nbsp;transformation&amp;nbsp;on that texture. Similar to the CUDA's kernel calls, the fragment programs will execute in parallel and provide us a reasonable speedup if we can utilize it properly. Of course, all these come with limitations that we will explore next.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;RGB+D? (Simple calibration on GPU)&lt;/b&gt;&lt;br /&gt;The Kinect RGB camera and depth camera are physically located at two different places.&amp;nbsp; In addition, the depth camera and rgb camera has different focal length, principle point, etc... Explaining the underlying camera calibration methods, camera models, and is beyond the scope of this tutorial. Feel free to check out the work from others below.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Important: You may need to run this and extract the&amp;nbsp;intrinsic&amp;nbsp;and&amp;nbsp;extrinsic&amp;nbsp;parameters of your Kinect. Just update the parameters in our fragment program accordingly.&lt;br /&gt;&lt;a href="http://nicolas.burrus.name/index.php/Research/KinectCalibration"&gt;http://nicolas.burrus.name/index.php/Research/KinectCalibration&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Fragment Shader for Mapping RGB values to depth map&lt;/b&gt;&lt;br /&gt;Fragment program is basically a small program that runs on the graphics card on a per-pixel basis. Here is the fragment program that we have created to map the RGB (640x480) color image back to the depth map (640x480). Notice that we have stored the depth value in the alpha channel of the RGBA texture. The detail of the calibration is shown below. The source code shall be straightforward to others who have done GPU programming.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;precision mediump float;&lt;br /&gt;varying vec2 v_texCoord;  &lt;br /&gt;uniform sampler2D s_texture;&lt;br /&gt;&lt;br /&gt;//my own calibrated data.. replace the following with your own.&lt;br /&gt;//xxx_rgb - parameters for the color camera&lt;br /&gt;//xxx_d - parameters for the depth camera&lt;br /&gt;const float fx_rgb = 5.0995627581871054e+02;&lt;br /&gt;const float fy_rgb = 5.1009672745532589e+02;&lt;br /&gt;const float cx_rgb = 3.2034728823678967e+02;&lt;br /&gt;const float cy_rgb = 2.5959956434787728e+02;&lt;br /&gt;&lt;br /&gt;//DEPTH CAMERA&lt;br /&gt;const float fx_d = 5.5879981950414015e+02;&lt;br /&gt;const float fy_d = 5.5874227168094478e+02;&lt;br /&gt;const float cx_d = 3.1844162327317980e+02;&lt;br /&gt;const float cy_d = 2.4574257294583529e+02;&lt;br /&gt;&lt;br /&gt;//Size of the image, use to transform from texture coord to image coord..&lt;br /&gt;vec2 img_coord = vec2(640.0,480.0);&lt;br /&gt;&lt;br /&gt;//Rotation and translation matrix&lt;br /&gt;vec3 T = vec3(2.7127130138943419e-02, -1.0041314603411674e-03,-5.6746227781378283e-03);&lt;br /&gt;vec3 R1 = vec3(9.9996078957902945e-01, -8.5633968850082568e-03,-2.2555571980713987e-03);&lt;br /&gt;vec3 R2 = vec3(8.5885385454046812e-03, 9.9989832404109968e-01, 1.1383258999693677e-02);&lt;br /&gt;vec3 R3 = vec3(2.1578484974712269e-03, -1.1402184597253283e-02, 9.9993266467111286e-01);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{  &lt;br /&gt;        //get the depth data from the texture.&lt;br /&gt; float depth = texture2D(s_texture, v_texCoord).w; &lt;br /&gt; if(depth == 0.0 || depth == 1.0){&lt;br /&gt;  gl_FragColor = vec4(0, 0, 0, 1);&lt;br /&gt;  return;&lt;br /&gt; }&lt;br /&gt;        //transform to image coordinate first, texture coord is from 0 to 1&lt;br /&gt; float x_d = (v_texCoord.x)*img_coord.x;&lt;br /&gt; float y_d = (v_texCoord.y)*img_coord.y;&lt;br /&gt;    &lt;br /&gt;        vec3 P3D;&lt;br /&gt; vec3 P3D_1;&lt;br /&gt; vec2 P2D_rgb;&lt;br /&gt; float real_depth = (2.0 * depth)+0.35;&lt;br /&gt;  &lt;br /&gt;        //this should be in metric 3D space (world coordinate)&lt;br /&gt;        P3D.x = real_depth * (x_d - cx_d) / fx_d;&lt;br /&gt; P3D.y = -real_depth * (y_d - cy_d) / fy_d; //negative because +y is up.&lt;br /&gt; P3D.z = real_depth;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt; //transform this then project to the camera using the extrinsic parameters.&lt;br /&gt; P3D_1 = vec3(dot(R1, P3D)-T.x, dot(R2, P3D)-T.y, dot(R3, P3D)-T.z); &lt;br /&gt;    &lt;br /&gt; //now we map this back to the image using the intrinsic parameters of the color camera&lt;br /&gt; float P3D_1_1 = 1.0 / P3D_1.z;&lt;br /&gt; P2D_rgb.x = (P3D_1.x * fx_rgb * P3D_1_1) + cx_rgb;&lt;br /&gt; P2D_rgb.y = -(P3D_1.y * fy_rgb * P3D_1_1) + cy_rgb; //negative for the +y is down &lt;br /&gt; &lt;br /&gt; //transform back to texture coordinate &lt;br /&gt; P2D_rgb = P2D_rgb/img_coord;&lt;br /&gt; &lt;br /&gt; //extract the RGB value, linearly interpolated, &lt;br /&gt;        //and store the final result (1.0-depth inverted the result such that objects are brighter if they are closer to the camera)&lt;br /&gt;&lt;br /&gt; gl_FragColor=vec4(1.0, 1.0, 1.0, 0)*texture2D(s_texture, P2D_rgb)+vec4(0,0,0,1.0-depth);&lt;br /&gt;}&lt;/pre&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Performance:&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;I/Render Loop:(  842): Display loop 0.029735 (s)&lt;br /&gt;I/Render Loop:(  842): Display loop 0.031630 (s)&lt;br /&gt;I/Render Loop:(  842): Display loop 0.032471 (s)&lt;br /&gt;~ about 0.03 ms per frame!&lt;br /&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;i&gt;&lt;/i&gt;&lt;/blockquote&gt;&lt;div&gt;It takes about 0.03ms to perform such computation on the GPU. This includes the time requires to update the texture, to perform rgb to depth mapping which includes pixel interpolation, and to display the result on screen. Pretty impressive! What's next? We will now ready to render these in 3D, and perhaps allow user to change the perspective using the touchscreen.&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Source Code:&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;svn co https://openvidia.svn.sourceforge.net/svnroot/openvidia/tegra_kinect multitouch&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Demo Video:&lt;/b&gt;&lt;br /&gt;Non-calibrated&amp;nbsp;RGBD (using fragment program to adjust the brightness of the pixel). Notice the misalignment.&lt;br /&gt;&lt;br /&gt;&lt;object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/-H3A28ZallU/0.jpg" height="266" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/-H3A28ZallU?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266"  src="http://www.youtube.com/v/-H3A28ZallU?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;With the proper calibration, now the RGB (color) image will map to the depth image.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/c14kdcuWbAg/0.jpg" height="266" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/c14kdcuWbAg?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266"  src="http://www.youtube.com/v/c14kdcuWbAg?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Special Thanks:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://eyetap.org/%7Efungja/"&gt;James Fung, Nvidia Technology Development&lt;/a&gt; for supplying the Ventana Development Kit.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Related Articles:&lt;/b&gt;&lt;br /&gt;OpenGL ES2 Tutorial&lt;br /&gt;&lt;a href="http://www.khronos.org/img/books/openglr_es_20_programming_guide_sample.pdf"&gt;http://www.khronos.org/img/books/openglr_es_20_programming_guide_sample.pdf&lt;/a&gt;&lt;br /&gt;Camera Matrix Tutorial&lt;br /&gt;&lt;a href="http://db-in.com/blog/2011/04/cameras-on-opengl-es-2-x/"&gt;http://db-in.com/blog/2011/04/cameras-on-opengl-es-2-x/&lt;/a&gt;&lt;br /&gt;To be continued....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3230570763723541579-3541991424153529071?l=raymondlo84.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raymondlo84.blogspot.com/feeds/3541991424153529071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://raymondlo84.blogspot.com/2011/08/gpu-based-image-processing-on-tegra-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3230570763723541579/posts/default/3541991424153529071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3230570763723541579/posts/default/3541991424153529071'/><link rel='alternate' type='text/html' href='http://raymondlo84.blogspot.com/2011/08/gpu-based-image-processing-on-tegra-2.html' title='GPU-based Image Processing on Tegra 2 and Microsoft Kinect'/><author><name>raymondlo84</name><uri>http://www.blogger.com/profile/03006577844333563556</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_iai8t1xHPZA/TI5PwsALvtI/AAAAAAAAAIM/zIai5sXJ620/S220/DSC_9655.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3230570763723541579.post-2282609441076261940</id><published>2011-07-27T11:51:00.000-07:00</published><updated>2011-09-01T16:23:12.599-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft Kinect Android'/><title type='text'>HOWTO: Using Microsoft Kinect on Tegra Ventana (Android 3.0)</title><content type='html'>&amp;nbsp; In this tutorial, we will show you how to write a native Android application (NDK) that uses Microsoft Kinect on the Tegra Ventana (Android 3.0) development kit. Although we have not verified that our setup will run on other platforms, the process we describe below shall be easily ported to other Linux based devices. To achieve real-time performance, we have used OpenGL ES2 to render the depth data as a 2D texture (see demo video), thus reduced the overheads in transferring and re-rendering the frames over the Java layer. Since the data capturing and rendering engine are fully multi-threaded, our approach can utilize the multi-core on the Tegra 2 platform.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Environment Setup (Ubuntu/Debian):&lt;/b&gt;&lt;br /&gt;To get started, first you need to install Nvidia &lt;a href="http://developer.nvidia.com/tegra-android-development-pack"&gt;Tegra Android Development Kit&lt;/a&gt; on your machine. In our setup, we have used the Ubuntu-Linux (64-bit) version.&lt;br /&gt;&lt;br /&gt;The setup shall be straight forward. &lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;chmod +x TADP-1.0-gbhc-linux-x64-2011-06-23.run&lt;/i&gt;&lt;br /&gt;&lt;i&gt;./TADP-1.0-gbhc-linux-x64-2011-06-23.run&lt;/i&gt;&lt;/blockquote&gt;My default installation path is &lt;i&gt;~/NVPACK&lt;/i&gt;.&amp;nbsp;Please make sure you flash the Ventana board with Android 3.0 (if you haven't done so before) at the end of the installation process. Also, please do backup the data before doing so.&lt;br /&gt;&lt;br /&gt;Now once the setup is completed, you shall have the android ndk, eclipse, and TDK sample code, etc... installed.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;raymondlo84@ealab_corei7:~/NVPACK$ ls -C&lt;br /&gt;android-ndk-r5c &amp;nbsp; &amp;nbsp;android-sdk-linux_x86 &amp;nbsp;eclipse &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; oprofile &amp;nbsp; &amp;nbsp;TDK_Samples&lt;br /&gt;Android_OS_Images &amp;nbsp;apache-ant-1.8.2 &amp;nbsp; &amp;nbsp; &amp;nbsp; nvsample_workspace &amp;nbsp;readme.txt &amp;nbsp;uninstall&lt;/i&gt;&lt;/blockquote&gt;&lt;br /&gt;Now to verify if we have setup everything correctly, we will run eclipse (the one in NVPACK directory), compile the source code (use Build Projects or Ctrl+B), and run the multitouch source code on the device (right click on the project name, Run, and Run As Application). Now you can touch the screen and see your fingers (up to 10) being tracked in real-time. Pretty amazing.&lt;br /&gt;&lt;br /&gt;Important: Please make sure you uninstall the multitouch application after testing. Else, it will conflict with our current application.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Hardware setup:&lt;/b&gt;&lt;br /&gt;At this step, we shall be able to run the sample code on the Ventana and confirm that the development environment is setup properly. If not, please check if the Ventana is connected to the PC properly.&lt;br /&gt;&lt;br /&gt;The easiest way to know is to run&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;$adb shell&lt;/i&gt;&lt;/blockquote&gt;This shall bring you to the shell on the Ventana.&lt;br /&gt;&lt;br /&gt;Next, we plug the Microsoft Kinect to the Ventana's USB port. To check if the camera is detected properly, we can check the dmesg with the following commands. ($ - bash shell, # the shell on the Ventana).&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;$adb shell &lt;/i&gt;&lt;br /&gt;&lt;i&gt;#dmesg &lt;/i&gt;&lt;/blockquote&gt;Then, we shall see the device is detected and mounted. Notice that Kinect is actually recognized as multiple devices:&amp;nbsp;&lt;i&gt;Xbox NUI Camera &lt;/i&gt;and&lt;i&gt;&amp;nbsp;&lt;/i&gt;&lt;i&gt;Xbox NUI Audio. &lt;/i&gt;Looks like the Microsoft Kinect has a usb hub internally.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;&amp;lt;6&amp;gt;[70990.661082] usb 2-1.1: new high speed USB device using tegra-ehci and address 9&lt;br /&gt;&amp;lt;6&amp;gt;[70990.696832] usb 2-1.1: New USB device found, idVendor=045e, idProduct=02ad&lt;br /&gt;&amp;lt;6&amp;gt;[70990.703809] usb 2-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=4&lt;br /&gt;&amp;lt;6&amp;gt;[70990.711490] usb 2-1.1: Product: Xbox NUI Audio&lt;br /&gt;&amp;lt;6&amp;gt;[70990.716013] usb 2-1.1: Manufacturer: Microsoft&lt;br /&gt;&amp;lt;6&amp;gt;[70990.720483] usb 2-1.1: SerialNumber: A44887C10800045A&lt;br /&gt;&amp;lt;6&amp;gt;[70992.181268] usb 2-1.3: new high speed USB device using tegra-ehci and address 10&lt;br /&gt;&amp;lt;6&amp;gt;[70992.224649] usb 2-1.3: New USB device found, idVendor=045e, idProduct=02ae&lt;br /&gt;&amp;lt;6&amp;gt;[70992.240886] usb 2-1.3: New USB device strings: Mfr=2, Product=1, SerialNumber=3&lt;br /&gt;&amp;lt;6&amp;gt;[70992.256521] usb 2-1.3: Product: Xbox NUI Camera&lt;br /&gt;&amp;lt;6&amp;gt;[70992.274979] usb 2-1.3: Manufacturer: Microsoft&lt;br /&gt;&amp;lt;6&amp;gt;[70992.280051] usb 2-1.3: SerialNumber: A00367A07065045A&lt;/i&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;i&gt;#ls /dev/bus/usb/002/*&lt;br /&gt;001&lt;br /&gt;002&lt;br /&gt;004&lt;br /&gt;009&lt;br /&gt;010&lt;/i&gt;&lt;/blockquote&gt;To override the permission problem temporarily, we can run the following commands. (IMPORTANT: We have to run this command every time we restart the machine, unplug the Kinect, or if the device goes to sleep! oh well!)&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;$adb shell&lt;/i&gt;&lt;br /&gt;&lt;i&gt;#chmod -R 777 /dev/bus/usb/002/&lt;/i&gt;&lt;/blockquote&gt;Once we have confirmed that the Kinect is detected successfully, we shall then replace the &lt;i&gt;multitouch&lt;/i&gt; source code in the &lt;i&gt;~/NVPACK/TDK_Samples/Android_NVIDIA_samples_2_20110315/apps&lt;/i&gt; directory with the one we have provided below.&lt;br /&gt;&lt;br /&gt;Now, we will go back to eclipse, and then refresh the project. (click on the project folder in eclipse and then press F5). Again. &lt;i&gt;#chmod -R 777 /dev/bus/usb/002/ &lt;/i&gt;if you haven't done so, or you will see a blank screen). Rebuild and run! &lt;br /&gt;&lt;br /&gt;If everything goes well, we shall have the application running like the following video. To change the tilt angle on the Kinect, we can simply use the touchscreen as shown below.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/DbWW-qRvblI/0.jpg" height="266" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/DbWW-qRvblI?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266"  src="http://www.youtube.com/v/DbWW-qRvblI?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/lRPtPUzLLnQ/0.jpg" height="266" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/lRPtPUzLLnQ?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266"  src="http://www.youtube.com/v/lRPtPUzLLnQ?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Code Structure and Optimization:&lt;/b&gt;&lt;br /&gt;In this section, we will explain the structure of the source code, the optimization steps and customization that we have made to make the code runs as efficient as possible.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ETcKR32xn9s/TjGtofox7pI/AAAAAAAAALE/N6OX3s2_Vro/s1600/cropped.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-ETcKR32xn9s/TjGtofox7pI/AAAAAAAAALE/N6OX3s2_Vro/s1600/cropped.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;b&gt;Figure 1.&lt;/b&gt; The source code structure of our demo application.&amp;nbsp;&lt;/div&gt;&lt;br /&gt;Instead of recompiling the libfreenect and the libusb libraries from external sources (of course we can do that with static linked library approach or so), in this tutorial we provide a complete source tree, which includes the libfreenect and libusb libraries. (Note: Free feel to contact us if we shall not include this in our package.).&lt;br /&gt;&lt;br /&gt;As we can see from Figure 1, the structure of the source code is fairly simple.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;multi.cpp - the main code which handles OpenGL rendering, key/touchscreen events, and other logics (adopted from the TDK sample code).&lt;/li&gt;&lt;li&gt;kinect.cpp - &amp;nbsp;a wrapper for the kinect driver, convert depth map to RGB and handles other callback functions from libfreenect (adopted from the libfreenect sample code)&lt;/li&gt;&lt;li&gt;libusb/* - the libusb source code for the USB interface.&lt;/li&gt;&lt;li&gt;libfreenect/* - the libfreenect source code which interfaces with the Microsoft Kinect.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Performance:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The runtime of the rendering loop is ~16ms, which translates to ~60fps. The key bottleneck of the algorithm is the texture loading step which costs about ~14ms to perform.&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;&amp;nbsp; &amp;nbsp; struct timeval start, end;&lt;br /&gt;&amp;nbsp; &amp;nbsp; double t1,t2;&lt;br /&gt;&amp;nbsp; &amp;nbsp; static double elapsed_sec=0;&lt;br /&gt;&amp;nbsp; &amp;nbsp; static int count=0;&lt;br /&gt;&amp;nbsp; &amp;nbsp; gettimeofday(&amp;amp;start, NULL);&lt;br /&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; getDepthData(depth_info);&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; loadTexture_depth(depth_info);&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; displayTexture();&lt;/b&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; gettimeofday(&amp;amp;end, NULL);&lt;br /&gt;&amp;nbsp; &amp;nbsp; t1=start.tv_sec+(start.tv_usec/1000000.0);&lt;br /&gt;&amp;nbsp; &amp;nbsp; t2=end.tv_sec+(end.tv_usec/1000000.0);&lt;br /&gt;&amp;nbsp; &amp;nbsp; elapsed_sec += (t2-t1);&lt;br /&gt;&amp;nbsp; &amp;nbsp; count++;&lt;br /&gt;&amp;nbsp; &amp;nbsp; if(count&amp;gt;=100){&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;char buf[512];&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;sprintf(buf, "Display loop %f (s)\n", (elapsed_sec)/100.0);&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;elapsed_sec=0;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;count=0;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;__android_log_write(ANDROID_LOG_INFO, "Render Loop:", buf);&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;/i&gt;&lt;/blockquote&gt;&amp;nbsp;Total run time (averaged 100 trials) :&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;I/Render Loop:( 4026): Display loop 0.016168 (s)&lt;/i&gt;&lt;/blockquote&gt;&lt;div&gt;...&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Requirements:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://developer.nvidia.com/tegra-android-development-pack"&gt;Tegra Android Development Pack&lt;/a&gt;&lt;br /&gt;&lt;a href="http://openkinect.org/wiki/Main_Page"&gt;libfreenect&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.libusb.org/"&gt;libusb&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tested Platform:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://developer.nvidia.com/tegra-ventana-development-kit"&gt;Tegra Ventana Development Kit&lt;/a&gt; (from Nvidia)&lt;br /&gt;Ubuntu 10.04.2 (64 bits) &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Source Code:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://sourceforge.net/projects/openvidia/files/tegra_kinect/"&gt;https://sourceforge.net/projects/openvidia/files/tegra_kinect/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;svn co https://openvidia.svn.sourceforge.net/svnroot/openvidia/tegra_kinect multitouch&lt;br /&gt;&lt;br /&gt;for the latest source.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Other Demo video:&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&lt;object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://0.gvt0.com/vi/PJFQ-PPHEbw/0.jpg" height="266" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/PJFQ-PPHEbw&amp;fs=1&amp;source=uds" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266"  src="http://www.youtube.com/v/PJFQ-PPHEbw&amp;fs=1&amp;source=uds" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Blind navigation with a wearable range camera and vibrotactile helment:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This work is accepted and will be published in the proceeding of ACM Multimedia 2011 (ACMM2011).  &lt;br /&gt;&lt;embed allowfullscreen="true" allowscriptaccess="always" flashvars="file=http%3A%2F%2Fwww.glogger.mobi%2Fusers%2Fkinect%2Fimage_thumb_2%2F2011_05_06_16_27_04_85537900_hd.mp4&amp;amp;volume=29&amp;amp;image=http%3A%2F%2Fwww.glogger.mobi%2Fusers%2Fkinect%2Fimage_thumb%2F2011_05_06_16_27_04_85537900-1.jpg&amp;amp;bufferlength=10&amp;amp;plugins=viral-1d" height="360" src="http://www.glogger.mobi/video/player.swf" width="480"&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;See: &lt;a href="http://wearcam.org/blindvision/"&gt;http://wearcam.org/blindvision/&lt;/a&gt; and &lt;a href="http://www.eyetap.org/publications/index.html"&gt;http://www.eyetap.org/publications/index.html&lt;/a&gt; for a list of our publications.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Known Issues:&lt;/b&gt;&lt;br /&gt;1. The application will crash when we change the orientation of the device.&lt;br /&gt;2. The application does not wake up properly if it were sent to the background.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Special Thanks:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://eyetap.org/~fungja/"&gt;James Fung, Nvidia Technology Development&lt;/a&gt; for supplying the Ventana Development Kit.&lt;br /&gt;&lt;br /&gt;... to be continued.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3230570763723541579-2282609441076261940?l=raymondlo84.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raymondlo84.blogspot.com/feeds/2282609441076261940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://raymondlo84.blogspot.com/2011/07/howto-using-microsoft-kinect-on-tegra.html#comment-form' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3230570763723541579/posts/default/2282609441076261940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3230570763723541579/posts/default/2282609441076261940'/><link rel='alternate' type='text/html' href='http://raymondlo84.blogspot.com/2011/07/howto-using-microsoft-kinect-on-tegra.html' title='HOWTO: Using Microsoft Kinect on Tegra Ventana (Android 3.0)'/><author><name>raymondlo84</name><uri>http://www.blogger.com/profile/03006577844333563556</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_iai8t1xHPZA/TI5PwsALvtI/AAAAAAAAAIM/zIai5sXJ620/S220/DSC_9655.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-ETcKR32xn9s/TjGtofox7pI/AAAAAAAAALE/N6OX3s2_Vro/s72-c/cropped.png' height='72' width='72'/><thr:total>14</thr:total></entry></feed>
