The scope discussed in this paper does not include geometry reconstruction, texture reconstruction, but only three-dimensional measurement algorithm based on the existing three-dimensional triangular mesh model (the human triangular grid). In fact, the circumference measurement is a three-dimensional model with a specific plane intersection, and the intersection further analysis of the intersection of the specific closed part (if there are multiple closed parts) of the contour perimeter and area data, that is, to calculate the slice of the grid. GB/t 16160-2008 "clothing with human body measurement of the parts and methods" given the human body size characteristics and height of the proportion of data (hereinafter referred to as the characteristics of the proportion), to find a specific proportion and height of the point of the French plane and three-dimensional mesh slice can further obtain specific characteristics of the specific values.
1.1 Coordinate system correction of human triangle grid
Assuming that the z-axis in the coordinate system of the human triangle mesh is the direction vector of the midpoint of the human Horn and the center of the head, the coordinate system of the triangle mesh obtained by the handheld scanner depends on the orientation of the first scan, so that the z-axis of the grid has an error with the correct coordinate system.
The core method used in this paper is PCA (Principal Component analysis). For the face element adhesion problem of the arm and body, it can be circumvented by the scanning target opening arm, while the high and low shoulder of the target person standing and opening arm will influence the effect of PCA coordinate correction. The main part of the PCA algorithm is the arm part three-dimensional point, the removal of the arm part three-dimensional point two PCA algorithm can be. It can be selected by a specific proportional relationship, or by the distance from the three-dimensional point to the z-axis.
1.2 Triangular mesh slicing algorithm 1.2.1 triangulation algorithm based on sorting
The slicing algorithm based on triangular meshes can be divided into two categories. One is the triangular mesh slicing algorithm based on the half-data structure, assuming that half half of the structure is:
struct HE_edge{ HE_vert* from; HE_vert* to; HE_edge* pair; // oppositely oriented adjacent half-edge HE_edge* next; // next half-edge around the face ... // other members};
And at this time obtains the plane plane and the specified one-sided intersection of the beginning half of s, the result of the algorithm is a half-point sequence from s , then the algorithm can be described as a simple he_slice (s->pair,*), The loop-through recursion can be further optimized:
void HE_Slice(HE_edge* curr, std::vector<glm::vec3>& res){ if(curr->next == s || curr->next->next == s) return ; for(auto e: {e->next, e->next->next}) { if(is_intersect(e,plane)) { ... // calculate and store the intersection HE_Slice(e->pair, res); } }}
1.2.2 Triangle mesh slicing algorithm based on sorting
The slicing algorithm based on the half-edge data structure is efficient, but the maintenance of half-side data structure requires more memory support and the construction time _o (N*log (n)) _, only provides the local topology information can not support by height ratio to obtain a specific half. Both of these drawbacks can be resolved by sorting the polygons described below. Considering that the intersection of the human triangle mesh and the plane plane can be multiple closed parts (hand and torso, two feet), half of the structure can and can only get to the closed part of the given initial half, unable to obtain the number of closed parts of the intersection between the specified plane and the triangular mesh (the closed number of the next name). The algorithm framework is as follows:
1. 对共享顶点结构的三角网格进行排序2. 通过二分查找确定需要与平面求交的有序面元的最小子序列3. 遍历子序列,生成平面与三角形面元的边的交的集合,集合元素为{A,B,k},其中A,B为边的顶点索引,k为相交系数。4. 通过选择排序对3.生成的集合完成有序化,并得到闭合部分的划分。
The smallest geometric element that participates in the slicing algorithm is an edge, so the sorting of the triangular mesh should be equivalent to the ordering of the triangular polygon elements. The sorting algorithm is briefly described as follows:
// 1. 对共享顶点结构的三角网格进行排序void sortByVector(TriMesh *mesh, glm::vec3 x) { std::sort(mesh->f.begin(), mesh->f.end(), [=](glm::ivec3& e1, glm::ivec3& e2){ return glm::dot(mesh->v[e1[0]] - mesh->v[e2[0]], x) > 0; });}
In fact, the surface element that participates in the slicing algorithm is a sub-sequence of the sorted surface element sequence, when given the slice plane (point French plane, normal vector is Z axis) and the maximum projection distance _gap_ on the z axis, the sub-sequence extraction algorithm is as follows:
// 2. 通过二分查找确定需要与平面求交的面元的最小有序子序列std::array<std::vector<glm::ivec3>::iterator,2> getSliceInterval(TriMesh* mesh,glm::vec3 n, float d, float gap) { std::array<std::vector<glm::ivec3>::iterator,2> result = { std::lower_bound(mesh->f.begin(),mesh->f.end(), d-gap, [=](glm::ivec3& e1,float v){ return v < glm::dot(mesh->v[e1[0]], n); }), std::lower_bound(mesh->f.begin(),mesh->f.end(), d+gap, [=](glm::ivec3& e1,float v){ return v < glm::dot(mesh->v[e1[0]], n); })}; if(result[0] > result[1]) std::swap(result[0],result[1]); return result;}
To determine the bounds of a subsequence, the slicing algorithm requires very few polygons to be cross with a particular plane. The geometric calculation of intersection and intersection of surface element and plane is as follows:
bool Isfaceinersected (trimesh* mesh,glm::ivec3 F, glm::vec3 N, float d) {int flags = (GLM::d ot (mesh->v[ F[0]], n) > D) + (GLM::d ot (mesh->v[f[1], n) > D) + (GLM::d ot (mesh->v[f[2], n) > D)); return flags = = 1 | | Flags = = 2;} Std::array<glm::vec3,2> getfaceintersection (trimesh* mesh,glm::ivec3 F, glm::vec3 N, float d) {STD::ARRAY<GLM ::vec3,2> result; int size = 0; Dot (n, P1) + dot (n, t* (P1-P2)) = d//0 < T < 1 for (int i:{0,1,2}) {Double numerator = D-GLM:: Dot (Mesh->v[f[i]], n); Double denominator = glm::d ot (mesh->v[f[i==2?0:i+1]]-mesh->v[f[i]], n); if (ABS (denominator) > 1e-8) {numerator/= denominator; if (numerator >= 0 && Numerator <= 1.0) {result[size++] = GLM::VEC3 (f[i],f[i==2?0:i+1],numera TOR); }}} return result;}
3. The resulting line segments are unordered and cannot satisfy subsequent operations, such as the number of closures, the smoothing of a particular closed part, or the calculation of geometric features such as the perimeter area of a particular part, so that the results of the 3 are ordered. Considering the actual grid size of the intersection line is often less than 10000, the algorithm design using the choice of sorting, the algorithm complexity of _o (N*log (n)) _, the simple description is as follows:
4. By selecting sort to 3. The resulting collection is ordered and the closed section is divided. std::vector<std::array< std::vector<std::array<glm::vec3,2>>::iterator,2>> sortContours ( std::vector<std::array<glm::vec3,2>>&& intersections) {std::vector<std::array< std:: vector<std::array<glm::vec3,2>>::iterator,2>> intervals = {{Intersections.begin (), Intersections.begin ()}}; for (Auto it = Intersections.begin (); It! = Intersections.end (); it++) {Auto Find_it = std::find_if (Std::next (IT), Intersections.end (), [=] (std::array<glm::vec3,2>& e) {return (e[0][0] = = (*it) [1][1] && e[0] [1] = = (*it) [1][0]) | | (E[0][0] = = (*it) [0][1] && e[0][1] = = (*it) [0][0]) | | (E[1][0] = = (*it) [0][1] && e[1][1] = = (*it) [0][0]) | | (E[1][0] = = (*it) [1][1] && e[1][1] = = (*it) [1][0]); }); if (find_it! = Intersections.end ()) {Std::swap (*std::next (IT), *find_it); }else{(*STD::p rev (inTervals.end ())) [1] = Std::next (IT); if (It! = std::p rev (Intersections.end ())) Intervals.push_back ({std::next (IT), Std::next (IT)}); }} return intervals;}
To this end, the basic principle and implementation of the sorting-based slicing algorithm has been introduced. Specific code implementation can be seen in my git repository yubamesh