2013-08-29 103 views
7

Tôi đã cố gắng để nhận ra một lưới có tất cả các khuôn mặt bình thường chỉ ra ngoài. Để nhận ra điều này, tôi tải một lưới từ tệp * .ctm, sau đó đi qua tất cả các hình tam giác để xác định bình thường bằng cách sử dụng sản phẩm chéo và nếu bình thường trỏ đến hướng z âm, I lật v1 và v2 (do đó định hướng bình thường). Sau khi thực hiện xong, tôi lưu kết quả vào tệp * .ctm và xem nó bằng Meshlab.Làm thế nào để thống nhất định hướng bình thường

Kết quả trong Meshlab vẫn cho thấy rằng các chỉ tiêu được trỏ theo cả hai hướng dương và hướng z âm (có thể được nhìn thấy từ các hình tam giác màu đen). Ngoài ra khi xem các tiêu chuẩn trong Meshlab chúng thực sự chỉ về phía sau.

Có ai có thể cho tôi một số lời khuyên về cách giải quyết vấn đề này không?

Các mã nguồn cho phần bình thường là:

pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud1 (new pcl::PointCloud<pcl::PointXYZRGBA>()); 
pcl::fromROSMsg (meshFixed.cloud,*cloud1);for(std::vector<pcl::Vertices>::iterator it = meshFixed.polygons.begin(); it != meshFixed.polygons.end(); ++it) 
{ 
    alglib::real_2d_array v0; 
    double _v0[] = {cloud1->points[it->vertices[0]].x,cloud1->points[it->vertices[0]].y,cloud1->points[it->vertices[0]].z}; 
    v0.setcontent(3,1,_v0); //3 rows, 1col 
    alglib::real_2d_array v1; 
    double _v1[] = {cloud1->points[it->vertices[1]].x,cloud1->points[it->vertices[1]].y,cloud1->points[it->vertices[1]].z}; 
    v1.setcontent(3,1,_v1); //3 rows, 1col 
    alglib::real_2d_array v2; 
    double _v2[] = {cloud1->points[it->vertices[2]].x,cloud1->points[it->vertices[2]].y,cloud1->points[it->vertices[2]].z}; 
    v2.setcontent(1,3,_v2); //3 rows, 1col 
    alglib::real_2d_array normal; 
    normal = cross(v1-v0,v2-v0); 
    //if z<0 change indices order v1->v2 and v2->v1 
    alglib::real_2d_array normalizedNormal; 
    if(normal[2][0]<0) 
    { 
      int index1,index2; 
      index1 = it->vertices[1]; 
      index2 = it->vertices[2]; 
      it->vertices[1] = index2; 
      it->vertices[2] = index1; 
      //make normal of length 1 
      double normalScaling = 1.0/sqrt(dot(normal,normal)); 
      normal[0][0] = -1*normal[0][0]; 
      normal[1][0] = -1*normal[1][0]; 
      normal[2][0] = -1*normal[2][0]; 
      normalizedNormal = normalScaling * normal; 
    } 
    else 
    { 
      //make normal of length 1 
      double normalScaling = 1.0/sqrt(dot(normal,normal)); 
      normalizedNormal = normalScaling * normal; 
    } 
    //add to normal cloud 
    pcl::Normal pclNormalizedNormal; 
    pclNormalizedNormal.normal_x = normalizedNormal[0][0]; 
    pclNormalizedNormal.normal_y = normalizedNormal[1][0]; 
    pclNormalizedNormal.normal_z = normalizedNormal[2][0]; 
    normalsFixed.push_back(pclNormalizedNormal); 
} 

Kết quả từ mã này là:
enter image description here

Tôi đã tìm thấy một số mã trong thư viện VCG để định hướng cho mặt và đỉnh normals. Sau khi sử dụng phần lớn lưới này có các chỉ tiêu khuôn mặt chính xác, nhưng không phải tất cả.

Mã mới:

// VCG library implementation 
    MyMesh m; 
    // Convert pcl::PolygonMesh to VCG MyMesh 
    m.Clear(); 
    // Create temporary cloud in to have handy struct object 
    pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud1 (new pcl::PointCloud<pcl::PointXYZRGBA>()); 
    pcl::fromROSMsg (meshFixed.cloud,*cloud1); 
    // Now convert the vertices to VCG MyMesh 
    int vertCount = cloud1->width*cloud1->height; 
    vcg::tri::Allocator<MyMesh>::AddVertices(m, vertCount); 
    for(unsigned int i=0;i<vertCount;++i) 
     m.vert[i].P()=vcg::Point3f(cloud1->points[i].x,cloud1->points[i].y,cloud1->points[i].z); 
    // Now convert the polygon indices to VCG MyMesh => make VCG faces.. 
    int triCount = meshFixed.polygons.size(); 
    if(triCount==1) 
    { 
     if(meshFixed.polygons[0].vertices[0]==0 && meshFixed.polygons[0].vertices[1]==0 && meshFixed.polygons[0].vertices[2]==0) 
      triCount=0; 
    } 
    Allocator<MyMesh>::AddFaces(m, triCount); 
    for(unsigned int i=0;i<triCount;++i) 
    { 
     m.face[i].V(0)=&m.vert[meshFixed.polygons[i].vertices[0]]; 
     m.face[i].V(1)=&m.vert[meshFixed.polygons[i].vertices[1]]; 
     m.face[i].V(2)=&m.vert[meshFixed.polygons[i].vertices[2]]; 
    } 

    vcg::tri::UpdateBounding<MyMesh>::Box(m); 
    vcg::tri::UpdateNormal<MyMesh>::PerFace(m); 
    vcg::tri::UpdateNormal<MyMesh>::PerVertexNormalizedPerFace(m); 
    printf("Input mesh vn:%i fn:%i\n",m.VN(),m.FN()); 

    // Start to flip all normals to outside 
    vcg::face::FFAdj<MyMesh>::FFAdj(); 
    vcg::tri::UpdateTopology<MyMesh>::FaceFace(m); 
    bool oriented, orientable; 
    if (vcg::tri::Clean<MyMesh>::CountNonManifoldEdgeFF(m)>0) { 
     std::cout << "Mesh has some not 2-manifold faces, Orientability requires manifoldness" << std::endl; // text 
     return; // can't continue, mesh can't be processed 
    } 
    vcg::tri::Clean<MyMesh>::OrientCoherentlyMesh(m, oriented,orientable); 
    vcg::tri::Clean<MyMesh>::FlipNormalOutside(m); 
    vcg::tri::Clean<MyMesh>::FlipMesh(m); 
    //vcg::tri::UpdateTopology<MyMesh>::FaceFace(m); 
    //vcg::tri::UpdateTopology<MyMesh>::TestFaceFace(m); 
    vcg::tri::UpdateNormal<MyMesh>::PerVertexNormalizedPerFace(m); 
    vcg::tri::UpdateNormal<MyMesh>::PerVertexFromCurrentFaceNormal(m); 

    // now convert VCG back to pcl::PolygonMesh 
    pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGBA>); 
    cloud->is_dense = false; 
    cloud->width = vertCount; 
    cloud->height = 1; 
    cloud->points.resize (vertCount); 
    // Now fill the pointcloud of the mesh 
    for(int i=0; i<vertCount; i++) 
    { 
     cloud->points[i].x = m.vert[i].P()[0]; 
     cloud->points[i].y = m.vert[i].P()[1]; 
     cloud->points[i].z = m.vert[i].P()[2]; 
    } 
    pcl::toROSMsg(*cloud,meshFixed.cloud); 
    std::vector<pcl::Vertices> polygons; 
    // Now fill the indices of the triangles/faces of the mesh 
    for(int i=0; i<triCount; i++) 
    { 
     pcl::Vertices vertices; 
     vertices.vertices.push_back(m.face[i].V(0)-&*m.vert.begin()); 
     vertices.vertices.push_back(m.face[i].V(1)-&*m.vert.begin()); 
     vertices.vertices.push_back(m.face[i].V(2)-&*m.vert.begin()); 
     polygons.push_back(vertices); 
    } 
    meshFixed.polygons = polygons; 

nào dẫn đến: (Meshlab vẫn cho thấy normals đang phải đối mặt cả hai bên)
enter image description here

Trả lời

6

cuối cùng tôi giải quyết được vấn đề. Vì vậy, tôi vẫn đang sử dụng thư viện VCG. Từ mã mới trên tôi một chút được cập nhật phần sau:

vcg::tri::Clean<MyMesh>::OrientCoherentlyMesh(m, oriented,orientable); 
//vcg::tri::Clean<MyMesh>::FlipNormalOutside(m); 
//vcg::tri::Clean<MyMesh>::FlipMesh(m); 
//vcg::tri::UpdateTopology<MyMesh>::FaceFace(m); 
//vcg::tri::UpdateTopology<MyMesh>::TestFaceFace(m); 
vcg::tri::UpdateNormal<MyMesh>::PerVertexNormalizedPerFace(m); 
vcg::tri::UpdateNormal<MyMesh>::PerVertexFromCurrentFaceNormal(m); 

Bây giờ tôi đã cập nhật các chức năng trong vcg::tri::Clean<MyMesh>::OrientCoherentlyMesh()clean.h. Ở đây bản cập nhật là định hướng đa giác đầu tiên của một nhóm chính xác. Ngoài ra sau khi trao đổi các cạnh bình thường của khuôn mặt được tính toán và cập nhật.

static void OrientCoherentlyMesh(MeshType &m, bool &Oriented, bool &Orientable) 
{ 
    RequireFFAdjacency(m); 
    assert(&Oriented != &Orientable); 
    assert(m.face.back().FFp(0)); // This algorithms require FF topology initialized 

    Orientable = true; 
    Oriented = true; 

    tri::UpdateSelection<MeshType>::FaceClear(m); 
    std::stack<FacePointer> faces; 

    for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) 
    { 
     if (!fi->IsD() && !fi->IsS()) 
     { 
      // each face put in the stack is selected (and oriented) 
      fi->SetS(); 
      // New section of code to orient the initial face correctly 
      if(fi->N()[2]>0.0) 
      { 
       face::SwapEdge<FaceType,true>(*fi, 0); 
       face::ComputeNormal(*fi); 
      } 
      // End of new code section. 
      faces.push(&(*fi)); 

      // empty the stack 
      while (!faces.empty()) 
      { 
       FacePointer fp = faces.top(); 
       faces.pop(); 

       // make consistently oriented the adjacent faces 
       for (int j = 0; j < 3; j++) 
       { 
        //get one of the adjacent face 
        FacePointer fpaux = fp->FFp(j); 
        int iaux = fp->FFi(j); 

        if (!fpaux->IsD() && fpaux != fp && face::IsManifold<FaceType>(*fp, j)) 
        {    
         if (!CheckOrientation(*fpaux, iaux)) 
         { 
          Oriented = false; 

          if (!fpaux->IsS()) 
          { 
           face::SwapEdge<FaceType,true>(*fpaux, iaux); 
           // New line to update face normal 
           face::ComputeNormal(*fpaux); 
           // end of new section. 
           assert(CheckOrientation(*fpaux, iaux)); 
          } 
          else 
          { 
           Orientable = false; 
           break; 
          } 
         } 

         // put the oriented face into the stack 

         if (!fpaux->IsS()) 
         { 
          fpaux->SetS(); 
          faces.push(fpaux); 
         } 
        } 
       } 
      } 
     } 
     if (!Orientable) break; 
    } 
} 

Ngoài ra tôi cũng đã cập nhật hàm bool CheckOrientation(FaceType &f, int z) để thực hiện phép tính dựa trên hướng z bình thường.

template <class FaceType> 
bool CheckOrientation(FaceType &f, int z) 
{ 
    // Added next section to calculate the difference between normal z-directions 
    FaceType *original = f.FFp(z); 
    double nf2,ng2; 
    nf2=f.N()[2]; 
    ng2=original->N()[2]; 
    // End of additional section 
    if (IsBorder(f, z)) 
     return true; 
    else 
    { 
     FaceType *g = f.FFp(z); 
     int gi = f.FFi(z); 
     // changed if statement from: if (f.V0(z) == g->V1(gi)) 
     if (nf2/abs(nf2)==ng2/abs(ng2)) 
      return true; 
     else 
      return false; 
    } 
} 

Kết quả là như tôi mong đợi và mong muốn từ các thuật toán:

enter image description here