Mario.Tapilouw

Monday, May 09, 2011

Plane Fitting using OpenCV


As what I've promised, I'm going to write about plane fitting using OpenCV. It's quite straight away and quite similar to my previous post, the difference is only about the physical representation of the variables in the equations. This time it's only a plane fitting, so it's a linear least square fitting. Later I would like to explore non-linear fitting as well and share it here when I have made it.

Let's say that we have a set of data that represents a plane in 3D coordinate X-Y-Z and modeled as Axi + Byi + C = zi. where i is the enumerator of the data (0~n).

Using the same approach, we can use matrix to represent the simultaneous equation and solve it.I will directly show you how.
1. prepare the matrices for the data.
CvMat *res  = cvCreateMat(3, 1, CV_32FC1);
CvMat *matX = cvCreateMat(10000, 3, CV_32FC1);
CvMat *matZ = cvCreateMat(10000, 1, CV_32FC1);
2. input the data into the matrices.
for(int row=0;row<100;row++)
{
for(int col=0;col<100;col++)
{
int idx = row * col;
double val = cvmGet(filteredMat, row, col);

cvmSet(matX, idx, 0, col*pixScale);
cvmSet(matX, idx, 1, row*pixScale);
cvmSet(matX, idx, 2, 1);
cvmSet(matZ, idx, 0, val);
}
}
3. solve the equation
cvSolve(matX, matZ, res, CV_SVD);
A = cvmGet(res, 0, 0);
B = cvmGet(res, 1, 0);
C = cvmGet(res, 2, 0);

4. calculate the distance between the plane and the real data.


double sqrtc = sqrt(pow(A, 2) + pow(B, 2) + pow(C, 2));

float min = 100;
float max = -100;

// plane generation, Z = Ax + By + C
// distance calculation d = Ax + By - z + C / sqrt(A^2 + B^2 + C^2)
// pointlist generation
for(int row=0;row<filteredMat->rows;row++)
{
for(int col=0;col<filteredMat->cols;col++)
{
double Zval = cvmGet(filteredMat, row, col);
double val = col*pixScale*A + row*pixScale*B - Zval + C;
double distance = val / sqrtc;

if(min > distance)
min = distance;

if(max < distance)
max = distance;

cvmSet(planeMat, row, col, distance);
}
}
Here is an example of this plane fitting, this is the surface before fitting, this is measurement result of a flat surface using white light interferometry:
and after fitting the result is:
The color represents the height, so we can see that after fitting the color of the surface is almost the same only a small variation of the surface. The sample should be flat and smooth, however it's not smooth anymore due to wear. However, the real scale is nanometer, the variation that we see in the result is around 100 nm.

Labels: , , , ,

6 Comments:

  • This comment has been removed by the author.

    By Blogger Unknown, at August 9, 2013 at 5:10 PM  

  • What is filteredMat?

    Can you Please send me the complete code for plane fitting?

    My Email:
    gharaeem@gmail.com

    By Blogger Unknown, at August 9, 2013 at 5:11 PM  

  • @gharaee
    Thanks for your comment, filteredMat is the matrix which stores the value of the plane that is going to be fit, inside is an array of height of each point on the plane.
    That's a good one, I'll try to find this source code first, it's been quite a while since I wrote this.

    By Blogger mario, at September 28, 2013 at 3:31 PM  

  • I think

    sqrtc = sqrt(pow(A, 2) + pow(B, 2) + pow(C, 2));

    should be changed to

    sqrtc = sqrt(pow(A, 2) + pow(B, 2) + 1);

    according to http://mathworld.wolfram.com/Point-PlaneDistance.html

    By Blogger kyu, at July 2, 2015 at 1:12 PM  

  • instead of

    for(int row=0;row<100;row++)
    {
    for(int col=0;col<100;col++)
    {
    int idx = row * col;
    _________

    it is better to write

    int width = 100;
    int height = 100;
    for(int row=0;row * width + <\b>col;

    By Blogger Vic, at July 10, 2015 at 6:23 AM  

  • @Vic: yes, thank you for the corrections..

    By Blogger mario, at July 11, 2015 at 5:55 AM  

Post a Comment

<< Home