Smooth[er] point cloud with ofxKinect?

Hi all

I’m working with ofxKinect and the points seem to be bunched (see image). This effect seems to deepen for objects that are further away. It looks as though the depth data is coming through as ints and then translated to millimetres. I tried using getWorldCoordinate() and getRawDepthPixels() and found the same result. Is it possible to get a smoother point cloud?

Cheers

James

with a kinect you have hardware limitations: your resolution is 640x480 and your sensing the world shooting a cone of ir dots, so the bigger the distance, the poorer the quality.

That said I used a kinect at difference distances (i made an installation where I tracked objects at nearly 10m) and in very bad light conditions (IR pollutions from stage lighting) and never had a surface fragmented as yours: can you give us a little more informations about your setup and how you’re crunching the data?

Thanks for your reply. I should have mentioned that the above image is of a section of floor about 4 metres from the Kinect. The ofEasyCam has been moved forward and rotated 90 degrees on the y axis to show the bunching effect.

In terms of the code, I thought I’d go back to the ofxKinect example to see if the problem exists there also. It does. The image below (a bookshelf) was generated using the point cloud in the ofxKinect example. Again, the object is around 4 metres away, the ofEasyCam is zoomed and rotated 90 degrees on the y axis. The only change I made was to move the camera using the mouse in drawPointCloud()

  
void testApp::drawPointCloud() {  
	int w = 640;  
	int h = 480;  
	ofMesh mesh;  
	mesh.setMode(OF_PRIMITIVE_POINTS);  
	int step = 2;  
	for(int y = 0; y < h; y += step) {  
		for(int x = 0; x < w; x += step) {  
			if(kinect.getDistanceAt(x, y) > 0) {  
				mesh.addColor(kinect.getColorAt(x,y));  
				mesh.addVertex(kinect.getWorldCoordinateAt(x, y));  
			}  
		}  
	}  
	glPointSize(3);  
	ofPushMatrix();  
	// the projected points are 'upside down' and 'backwards'   
	ofScale(1, -1, -1);  
        ofRotateY(mouseX);  
	ofTranslate(0, 0, -mouseY * 10); // center the points a bit  
	glEnable(GL_DEPTH_TEST);  
	mesh.drawVertices();  
	glDisable(GL_DEPTH_TEST);  
	ofPopMatrix();  
}  

I decided to try ofxOpenNI but I keep getting the dreaded Apple Mach-O Linker (Id) Error with both OF 007 and 0071. It seems some files are missing. Here’s the error (and check image):

ld: library not found for -lXnVHandGenerator_1_5_0
Command /Developer/usr/bin/clang++ failed with exit code 1

I can’t find these files anywhere.

![](http://forum.openframeworks.cc/uploads/default/2467/Screen shot 2012-06-24 at 20.36.59.png)

hey James,

for your openNi woes, i’ve always used gameover’s experimental branch of openNI:
https://github.com/gameoverhack/ofxOpenNI/tree/experimental

you have to shuffle some libraries around but he makes it pretty easy
https://github.com/gameoverhack/ofxOpenNI/tree/experimental/mac/copy-to-data-openni-path/lib

the surface you have looks like it’s being viewed at a pretty steep angle and from far away.

one big cause of fragmenting is that there are discreet steps since the data is unsigned short – but once you’ve projected it into world space, you have floating coordinates. You can try going in and adding a bit of noise to each point, or local averaging (like a blur) to make it more regularly distributed.

Hi James. Thanks for the suggestions. I fixed this in the end by implementing a custom smoothing algorithm to the points. Thankfully the piece is not realtime so performance was not an issue.

Here’s the code if anyone is interested:

  
  
    // apply a blur like averaging to the z. Horizontal first...  
    vector<ofVec3f> hozontalBlurredVecs = vertices;  
    for (int y = 0; y < h; y++)  
    {  
        for (int x = 0; x < w; x++)  
        {  
            int index = (y * w) + x;  
            ofVec3f* vec = &vertices[index];  
              
              
            // don't average if outside clipping area  
            if (vec->z < app->nearThreshold && vec->z > app->farThreshold)  
            {  
                float average = vec->z;  
                int averageCount = 1;  
                  
              
                for (int i = 1; i < app->meshBlurRadius; i++)  
                {  
                    if (index - i > 0)  
                    {  
                        if (abs(vec->z - vertices[index - i].z) < app->zDifferencingAveragingMin)  
                        {  
                            ++averageCount;  
                            average += vertices[index - i].z;  
                        }  
                    }  
                    if (index + i < vertices.size())  
                    {  
                        if (abs(vec->z - vertices[index + i].z) < app->zDifferencingAveragingMin)  
                        {  
                            ++averageCount;  
                            average += vertices[index + i].z;  
                        }  
                    }  
                }  
                average /= averageCount;  
                hozontalBlurredVecs[index].z = average;  
            }  
        }  
    }  
      
      
    vector<ofVec3f> blurredVecs = hozontalBlurredVecs;  
      
    // ... then vertical  
    for (int y = 0; y < h; y++)  
    {  
        for (int x = 0; x < w; x++)  
        {  
            int index = (y * w) + x;  
            ofVec3f* vec = &hozontalBlurredVecs[index];  
              
              
            // don't average if outside clipping area  
            if (vec->z < app->nearThreshold && vec->z > app->farThreshold)  
            {  
                float average = vec->z;  
                int averageCount = 1;  
                  
                for (int i = 1; i < app->meshBlurRadius; i++)  
                {  
                    if (index - (w * i) > 0)  
                    {  
                        if (abs(vec->z - horizontalBlurredVecs[index - (w * i)].z) < app->zDifferencingAveragingMin)  
                        {  
                            ++averageCount;  
                            average += horizontalBlurredVecs[index - (w * i)].z;  
                        }  
                    }  
                    if (index + (w * i) < vertices.size())  
                    {  
                        if (abs(vec->z - horizontalBlurredVecs[index + (w * i)].z) < app->zDifferencingAveragingMin)  
                        {  
                            ++averageCount;  
                            average += horizontalBlurredVecs[index + (w * i)].z;  
                        }  
                    }  
                }  
                average /= averageCount;  
                blurredVecs[index].z = average;  
            }  
        }  
    }  

EDIT: There was an error in this code that would result in the horizontal averaging not taking place. Fixed now.