3D指纹 - 需要提取山脊和山谷? Visual Studio 2010和C ++

时间:2011-06-20 03:27:17

标签: c++ visual-studio graphics fingerprint

我需要提取3D指纹的脊和谷。输出应该是一个层文件,它使用不同的颜色准确显示3d指纹上的脊和谷的位置。

输入文件 - 仅包含x,y,z位置的ply文件。我是从3d扫描仪得到的。 这是前几行文件的样子 -

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
...     ...      ...       

如果您需要数据 - 请发送电子邮件至 nisha.m234@gmail.com

算法: 我试图找到用于提取山脊和山谷的主曲率。

我遵循的步骤是:

      
  1. 取点x
  2.   
  3. 找到它的k个最近邻居。我使用了3到20的k。
  4.   
  5. 平均k个最近邻居=>给出(_x,_y,_z)
  6.   
  7. 计算协方差矩阵
  8.   
  9. 现在我取这个协方差矩阵的特征值和特征向量
  10.   
  11. 我从特征向量得到你,v和n。     u是对应于最大特征值的向量     v对应第二大     n是对应于最小特征值的第三最小向量
  12.   
  13. 然后,为了变换点(x,y,z),我计算矩阵T.
    T = 
      | ui |     |u |     |x - _x| 
      | vi |  =  |v |  x  |y - _y|
      | ni |     |n |     |z - _z|
  14.   
  15. 对于k个最近邻居的每个i:
      
      | n1 |   |u1*u1  u1*v1  v1*v1| | a |
    | n2 | = |u2*u2 u2*v2 v2*v2| | b |
    |... | | ... ... ... | | c |
    | nk | |uk*uk uk*vk vk*vk|
     用a,b和c解决这个问题,最小二乘
  16. 这个等式会给我a,b,c
  17. 现在我计算矩阵的特征值
    | a b |
    | b a |
  18. 这将给出2个特征值。一个是Kmin,另一个是Kmax。
  19. 我的问题: 输出没有接近找到正确的山脊和山谷。我完全被困和沮丧。我不知道到底哪里弄错了。我认为法线不能正确计算。但我不确定。我是图形编程的新手,因此这个数学,法线,着色器远远超出我的想象。任何帮助将不胜感激。 请帮助!!

    资源: 我正在使用Visual Studio 2010 + Eigen Library + ANN Library。

    使用的其他选项 我尝试过使用MeshLab。我使用了在MeshLab中重新网格化的球形旋转三角形,然后应用了polkadot3d着色器。如果正确识别山脊和山谷。但我无法对其进行编码。

    我的功能: //函数输出到ply文件

    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();
    }
    

    它是我论文项目的一部分。我需要使用3D点云数据来完成它。我没有扫描仪。它的第三方公司,他们只是给我提供3D点。我只能处理这个3D点。

    谢谢,
    NISHA

    @Tom - 谢谢。 MeshLab的polkadot3d着色器不准确,但它让我粗略地了解了山脊和山谷的位置。我认为ANN库没有给我正确的neigbours开始导致错误的法线。但我不知道如何解决这个问题。由于这是论文的一部分,我和我的教授提出了这种算法来提取山脊和山谷。根据我的研究和其他论文,我读到这种方法确实适用于提取rigeys和山谷。我只是没有正确地在代码中得到它:(我很确定你建议的方法也可以工作,但我可能必须坚持我当前的算法,如果它根本不工作应该能够说明为什么它是不行的!但是,目前我的代码问题似乎与我使用的方法有关,或者我在这里错过了一些步骤。

1 个答案:

答案 0 :(得分:2)

您是否考虑过将问题转化为图像分析问题?如果通过将手指按到平坦表面来扫描数据,则可以将扫描转换为图像,其中灰度级由每个点的z深度(表面和点之间的距离)确定。然后,您可以通过Gourad着色绘制三角形。你可以通过创建一个3D凸包然后测量它的z距离来做类似的事情。

拥有图像后,您可以轻松找到山脊和山谷。