Hello,
I need to extract ridges and valleys of a 3D fingerprint. The output
should be a ply file which shows exactly where are the ridges and
valleys on 3d fingerprint using different colors.
**Input file** - ply file with just x,y,z locations. I got it from a
3d scanner.
Here is how first few lines of file looks like -
ply
format ascii 1.0
comment VCGLIB generated
element vertex 6183
property float x
property float y
property float z
end_header
-32.3271 -43.9859 11.5124
-32.0631 -43.983 11.4945
12.9266 -44.4913 28.2031
13.1701 -44.4918 28.2568
13.4138 -44.4892 28.2531
13.6581 -44.4834 28.1941
13.9012 -44.4851 28.2684
... ... ...
In case you need the data - please email me on
**
nisha.m234@gmail.com**.
**Algorithm:**
I am trying to find principal curvatures for extracting the ridges and
valleys.
The steps I am following is:
1. Take a point x
2. Find its k nearest neighbors. I used k from 3 to 20.
3. average the k nearest neighbors => gives (_x, _y, _z)
4. compute covariance matrix
5. Now I take eigen values and eigen vectors of this covariance matrix
6. I get u, v and n here from eigen vectors.
u is a vector corresponding to largest eigen value
v corresponding to 2nd largest
n is 3rd smallest vector corresponding to smallest eigen value
7. Then for transforming the point(x,y,z) I compute matrix T
T =
[ui ] [u ] [x - _x]
[vi ] = [v ] x [y - _y]
[ni ] [n ] [z - _z]
8. for each i of the k nearest neighbors:<br>
[ n1 ] [u1*u1 u1*v1 v1*v1] [ a ]<br>
[ n2 ] = [u2*u2 u2*v2 v2*v2] [ b ] <br>
[... ] [ ... ... ... ] [ c ] <br>
[ nk ] [uk*uk uk*vk vk*vk]<br>
Solve this for a, b and c with least squares
9. this equations will give me a,b,c
10. now I compute eigen values of matrix
[a b
b a ]
11. This will give me 2 eigen values. one is Kmin and another Kmax.
**My Problem:**
The output is no where close to finding the correct Ridges and
Valleys. I am totally Stuck and frustrated. I am not sure where
exactly I am getting it wrong. I think the normal's are not computed
correctly. But I am not sure. I am very new to graphics programming
and so this maths, normals, shaders go way above my head. Any help
will be appreciated.
**PLEASE PLEASE HELP!!**
**Resources:**
I am using Visual Studio 2010 + Eigen Library + ANN Library.
**Other Options used**
I tried using MeshLab. I used ball pivoting triangles remeshing in
MeshLab and then applied the polkadot3d shader. If correctly
identifies the ridges and valleys. But I am not able to code it.
**My Function:**
//the function outputs to ply file
void getEigen()
{
int nPts; // actual number of data points
ANNpointArray dataPts; // data points
ANNpoint queryPt; // query point
ANNidxArray nnIdx;// near neighbor indices
ANNdistArray dists; // near neighbor distances
ANNkd_tree* kdTree; // search structure
//for k = 25 and esp = 2, seems to got few ridges
queryPt = annAllocPt(dim); // allocate query point
dataPts = annAllocPts(maxPts, dim); // allocate data points
nnIdx = new ANNidx[k]; // allocate near neigh indices
dists = new ANNdist[k]; // allocate near neighbor dists
nPts = 0; // read data points
ifstream dataStream;
dataStream.open(inputFile, ios::in);// open data file
dataIn = &dataStream;
ifstream queryStream;
queryStream.open("input/query.
pts", ios::in);// open data file
queryIn = &queryStream;
while (nPts < maxPts && readPt(*dataIn, dataPts[nPts])) nPts++;
kdTree = new ANNkd_tree( // build search structure
dataPts, // the data points
nPts, // number of points
dim); // dimension of space
while (readPt(*queryIn, queryPt)) // read query points
{
kdTree->annkSearch( // search
queryPt, // query point
k, // number of near neighbors
nnIdx, // nearest neighbors (returned)
dists, // distance (returned)
eps); // error bound
double x = queryPt[0];
double y = queryPt[1];
double z = queryPt[2];
double _x = 0.0;
double _y = 0.0;
double _z = 0.0;
#pragma region Compute covariance matrix
for (int i = 0; i < k; i++)
{
_x += dataPts[nnIdx[i]][0];
_y += dataPts[nnIdx[i]][1];
_z += dataPts[nnIdx[i]][2];
}
_x = _x/k; _y = _y/k; _z = _z/k;
double A[3][3] = {0,0,0,0,0,0,0,0,0};
for (int i = 0; i < k; i++)
{
double X = dataPts[nnIdx[i]][0];
double Y = dataPts[nnIdx[i]][1];
double Z = dataPts[nnIdx[i]][2];
A[0][0] += (X-_x) * (X-_x);
A[0][1] += (X-_x) * (Y-_y);
A[0][2] += (X-_x) * (Z-_z);
A[1][0] += (Y-_y) * (X-_x);
A[1][1] += (Y-_y) * (Y-_y);
A[1][2] += (Y-_y) * (Z-_z);
A[2][0] += (Z-_z) * (X-_x);
A[2][1] += (Z-_z) * (Y-_y);
A[2][2] += (Z-_z) * (Z-_z);
}
MatrixXd C(3,3);
C A[0][0]/k, A[0][1]/k, A[0][2]/k,
A[1][0]/k, A[1][1]/k, A[1][2]/k,
A[2][0]/k, A[2][1]/k, A[2][2]/k;
#pragma endregion
EigenSolver<MatrixXd> es(C);
MatrixXd Eval = es.eigenvalues().real().asDiagonal();
MatrixXd Evec = es.eigenvectors().real();
MatrixXd u,v,n;
double a = Eval.row(0).col(0).value();
double b = Eval.row(1).col(1).value();
double c = Eval.row(2).col(2).value();
#pragma region SET U V N
if(a>b && a>c)
{
u = Evec.row(0);
if(b>c)
{ v = Eval.row(1); n = Eval.row(2);}
else
{ v = Eval.row(2); n = Eval.row(1);}
}
else
if(b>a && b>c)
{
u = Evec.row(1);
if(a>c)
{ v = Eval.row(0); n = Eval.row(2);}
else
{ v = Eval.row(2); n = Eval.row(0);}
}
else
{
u = Eval.row(2);
if(a>b)
{ v = Eval.row(0); n = Eval.row(1);}
else
{ v = Eval.row(1); n = Eval.row(0);}
}
#pragma endregion
MatrixXd O(3,3);
O u,
v,
n;
MatrixXd UV(k,3);
VectorXd N(k,1);
for( int i=0; i<k; i++)
{
double x = dataPts[nnIdx[i]][0];;
double y = dataPts[nnIdx[i]][1];;
double z = dataPts[nnIdx[i]][2];;
MatrixXd X(3,1);
X x-_x,
y-_y,
z-_z;
MatrixXd T = O * X;
double ui = T.row(0).col(0).value();
double vi = T.row(1).col(0).value();
double ni = T.row(2).col(0).value();
UV.row(i) ui * ui, ui * vi, vi * vi;
N.row(i) ni;
}
Vector3d S = UV.colPivHouseholderQr().solve(N);
MatrixXd II(2,2);
II S.row(0).value(), S.row(1).value(),
S.row(1).value(), S.row(2).value();
EigenSolver<MatrixXd> es2(II);
MatrixXd Eval2 = es2.eigenvalues().real().asDiagonal();
MatrixXd Evec2 = es2.eigenvectors().real();
double kmin, kmax;
if(Eval2.row(0).col(0).value() < Eval2.row(1).col(1).value())
{
kmin = Eval2.row(0).col(0).value();
kmax = Eval2.row(1).col(1).value();
}
else
{
kmax = Eval2.row(0).col(0).value();
kmin = Eval2.row(1).col(1).value();
}
double thresh = 0.0020078;
if (kmin < thresh && kmax > thresh )
cout x " " y " " z " "
255 " " 0 " " 0
endl;
else
cout x " " y " " z " "
255 " " 255 " " 255
endl;
}
delete [] nnIdx;
delete [] dists;
delete kdTree;
annClose();
}
Thanks,
NISHA