原文链接:http://blog.sciencenet.cn/blog-465130-1135112.html
三维曲面离散化为三维网格后,为了进行纹理贴图,有时还要展开到二维的uv坐标平面上。虽然大部分空间曲面都不是可展的,但是在曲面的局部区域观察是可以表示成f(u,v)的形式的,这个过程在数字图形处理中的术语叫参数化(Parameterization)。从三角网格的角度,每个三角形和它的uv平面上的对应都是仿射变换的关系,根据不同的应用,通常要给这种局部映射加约束,比如要求角度或者面积的变形最小等,在曲面不撕裂的情况下,这种假设只能近似满足。
常用的纹理映射方法是把和平面圆盘拓扑等价的曲面,映射到平面上。曲面的边界分别有固定边界和不固定边界两种。对于后者多数求解方法都是非线性的。而固定边界方法则用线性方程就能求解,即给定凸边界,不在边界上的点看成是边界点的某种线性加权(参见上一篇)。其中Tutte mapping堪称是最简单的uv映射方法,每个点是邻近点的重心位置。
下面针对Basel人脸模型做参数化。预先对于原网站上提供的10个模型作平均,得到一个平均模型,保存在Basel_color_meanface.mat中,三角形序号表示的‘面表’保存在face_tri.txt中。
clear all close all path = 'data\'; % load mesh data, Vertex, Color and Facets load([path,'Basel_color_meanface.mat']); facetri = 1 + load([path,'face_tri.txt']); % load IBUG 68 lmk for basel model idlmk = 1 + load([path,'lmk_id68_in53490.txt']);
meanshape = meanface.shape;
meantex = meanface.tex;
numv = size(meanshape,1);
% Calculate laplacian matrix
L = cal_mesh_laplacian(double(meanshape),facetri,‘conformal’);
% Find contour: edges has only one half edge in edgelist
[idcon,idseg] = find_mesh_contour( meanshape, facetri );
因为模型只有一条边界,idseg=1,即没有孔洞,拓扑结构和圆盘等价。68个蓝色点表示的是IBUG二维人脸特征点(ASM/AAM等face alignment方法常用的landmark配置)的对应位置:
把曲面x/z坐标归一化到一个半径r的圆柱面上(早年3DMM人脸模型经常做这样的操作):
sum2 = meanshape(:, 3).2 + meanshape(:, 1).2;
sum2 = sqrt(sum2);
r = mean(sum2);
meanshape(:, 3) = rmeanshape(:, 3)./sum2;
meanshape(:, 1) = rmeanshape(:, 1)./sum2;
trimesh( facetri, meanshape(:, 1), meanshape(:, 2), meanshape(:, 3), …
‘EdgeColor’, ‘none’, …
‘FaceVertexCData’, meantex/255, ‘FaceColor’, ‘interp’, …
‘FaceLighting’, ‘phong’ );
zlabel(‘Z’);hold onview(-35,60);
plot3( meanshape(idcon,1),meanshape(idcon,2),meanshape(idcon,3),‘r.’ );
axis equal
然后展开到Z=0平面上:
ang = atan2(meanshape(:, 1), meanshape(:, 3));
shx = angr;
shy = meanshape(:, 2);
shz = zeros(numv,1);
图中鼻孔和嘴部的瑕疵是鼻腔口腔内部三角网格映射形成的,也就是说网格点映射时产生了一对多的问题。这当然可以通过检查网格投影先后顺序来解决。但是参数化的要求是一对一的bijection,网格不能有折叠。
固定边界(红色的点)求内部点V的位置,保证每个三角网格的法线一致:都朝纸外。
%hard constaint
idx = ones(numv,1);
idx(idcon)=0;
id_unkown = find(idx);
% remove known vertex lines from L
L(idcon,:)=[];
% move column of boundary vertex in LV=0 to right
V = [shx,shy];
vh = sparse(double(V(idcon,:)));
Rhs = -L(:,idcon) (vh);
% Unknow vertex on left
Lhs = L(:,id_unkown);
Vp = Lhs\Rhs;
% copy back to vertex
V(id_unkown,:) = full(Vp);
figure
trimesh( facetri, V(:,1), V(:,2), shz, ‘EdgeColor’, ‘none’, …
‘FaceVertexCData’, meantex/255, ‘FaceColor’, ‘interp’, …
‘FaceLighting’, ‘phong’ );
zlabel(‘Z’);view(2);axis equal;hold on,
shx = V(:,1); shy = V(:,2);
plot3( shx(idcon),shy(idcon), zeros(length(idcon),1),‘r.’ );
plot3( shx(idlmk),shy(idlmk), zeros(length(idlmk),1),‘b.’ );
仍然用trimesh函数画出网格和颜色,以及边界和68个landmark的位置:
固定边界也可以按照edge的长度比例固定在圆形(长度按比例对应2PI角)或者正方形上,比如映射到正方形上是这样(“好吓人!”):
如果只固定少量边界点会怎样?比如只用8个点:
idcon = idcon(1:round(end/8):end);
如果在边界约束中加入部分face landmark会怎样?
idcon = [idcon;idlmk(9);idlmk(18:end-20)];
内部约束点会导致附近的三角形方向发生翻折,法线朝向纸内:
用 triplot()函数叠加网格,在下巴点处放大观察:
参考:
[1].计算稀疏矩阵L和W的函数cal_mesh_laplacian()参考自:
http://www.numerical-tours.com/matlab
http://blog.sciencenet.cn/blog-465130-1135112.html
上一篇: 三角剖分网格的邻接矩阵和Laplacian矩阵实验
下一篇: 三维网格在参数化uv图上进行网格重采样做Remesh