三维网格精简算法(Quadric Error Metrics)附源码
在计算机图形应用中,为了尽可能真实呈现虚拟物体,往往需要高精度的三维模型。然而,模型的复杂性直接关系到它的计算成本,因此高精度的模型在几何运算时并不是必须的,取而代之的是一个相对简化的三维模型,那么如何自动计算生成这些三维简化模型就是网格精简算法所关注的目标。
[Garland et al. 1997]提出了一种基于二次误差作为度量代价的边收缩算法,其计算速度快并且简化质量较高。该方法在选择一条合适的边进行迭代收缩时,定义了一个描述边收缩代价的变量Δ,具体如下:对于网格中的每个顶点v,我们预先定义一个4×4的对称误差矩阵Q,那么顶点v = [vx vy vz 1]T的误差为其二次项形式Δ(v) = vTQv。假设对于一条收缩边(v1, v2),其收缩后顶点变为vbar,我们定义顶点vbar的误差矩阵Qbar为Qbar = Q1 + Q2,对于如何计算顶点vbar的位置有两种策略:一种简单的策略就是在v1, v2和(v1+ v2)/2中选择一个使得收缩代价Δ(vbar)最小的位置。另一种策略就是数值计算顶点vbar位置使得Δ(vbar)最小,由于Δ的表达式是一个二次项形式,因此令一阶导数为0,即
,该式等价于求解:

其中qij为矩阵Qbar中对应的元素。如果系数矩阵可逆,那么通过求解上述方程就可以得到新顶点vbar的位置,如果系数矩阵不可逆,就通过第一种简单策略来得到新顶点vbar的位置。根据以上描述,算法流程如下:

那么剩下的问题就是如何计算每个顶点的初始误差矩阵Q,在原始网格模型中,每个顶点可以认为是其周围三角片所在平面的交集,也就是这些平面的交点就是顶点位置,我们定义顶点的误差为顶点到这些平面的距离平方和:

其中p = [a b c d]T代表平面方程ax + by + cz + d = 0(a2 + b2 + c2 = 1)的系数,Kp为二次基本误差矩阵:

因此原始网格中顶点v的初始误差为Δ(v) = 0,当边收缩后,新顶点误差为Δ(vbar) = vbarTQbarvbar,我们依次选取收缩后新顶点误差最小的边进行迭代收缩直到满足要求为止。
%% surface simplification using quadratic error metrics
clc
clear all
close all load('bunny.mat'); V = surfdata.point;
F = surfdata.face; nv = size(V,); % total vertex number
np = 0.1*nv; % remained vertex number % fundamental error quadric
N = normals(V,F);
N = normalizeVector3d(N);
p = [N, -sum(N .* V(F(:,),:), )];
Q0 = bsxfun(@times, permute(p, [,,]), permute(p, [,,])); % compute the Q matrices for all the initial vertices.
nf = size(F,);
Q = zeros(,,nv);
valence = zeros(nv,);
for i = :nf
for j = :
valence(F(i,j)) = valence(F(i,j)) + ;
Q(:,:,F(i,j)) = Q(:,:,F(i,j)) + Q0(:,:,i);
end
end % all valid pairs
E = edges(F); % compute Q1+Q2 for each pair
Qbar = Q(:,:,E(:,)) + Q(:,:,E(:,)); % a simple scheme: select either v1, v2 or (v1+v2)/
ne = size(E,);
v1 = permute([V(E(:,),:),ones(ne,)], [,,]);
v2 = permute([V(E(:,),:),ones(ne,)], [,,]);
vm = 0.5 .* (v1 + v2);
v = [v1, v2, vm]; cost = zeros(ne,);
cost(:,) = sum(squeeze(sum(bsxfun(@times,v1,Qbar),)).*squeeze(v1),)';
cost(:,) = sum(squeeze(sum(bsxfun(@times,v2,Qbar),)).*squeeze(v2),)';
cost(:,) = sum(squeeze(sum(bsxfun(@times,vm,Qbar),)).*squeeze(vm),)'; figure;
draw_t = ;
num = nv;
tic
for i = :nv-np
if (nv - i) < 0.9*num
num = nv - i; clf
drawMesh(V, F, 'facecolor','y', 'edgecolor','k', 'linewidth', 1.2);
view([ ])
axis equal
axis off
camlight
lighting gouraud
cameramenu
drawnow
end [min_cost, vidx] = min(cost,[],);
[useless, k] = min(min_cost);
e = E(k,:); % update position for v1
V(e(),:) = v(:, vidx(k), k)';
V(e(),:) = nan; % update Q for v1
Q(:,:,e()) = Q(:,:,e()) + Q(:,:,e());
Q(:,:,e()) = nan; % updata face
F(F == e()) = e();
f_remove = sum(diff(sort(F,),[],) == , ) > ;
F(f_remove,:) = []; % collapse and delete edge and related edge information
E(E == e()) = e();
E(k,:) = [];
cost(k,:) = [];
Qbar(:,:,k) = [];
v(:,:,k) = []; % delete duplicate edge and related edge information
[E,ia,ic] = unique(sort(E,), 'rows');
cost = cost(ia,:);
Qbar = Qbar(:,:,ia);
v = v(:,:,ia); % pairs involving v1
pair = sum(E == e(), ) > ;
npair = sum(pair); % updata edge information
Qbar(:,:,pair) = Q(:,:,E(pair,)) + Q(:,:,E(pair,)); pair_v1 = permute([V(E(pair,),:),ones(npair,)], [,,]);
pair_v2 = permute([V(E(pair,),:),ones(npair,)], [,,]);
pair_vm = 0.5 .* (pair_v1 + pair_v2);
v(:,:,pair) = [pair_v1, pair_v2, pair_vm]; cost(pair,) = sum(squeeze(sum(bsxfun(@times,pair_v1,Qbar(:,:,pair)),)).*squeeze(pair_v1),)';
cost(pair,) = sum(squeeze(sum(bsxfun(@times,pair_v2,Qbar(:,:,pair)),)).*squeeze(pair_v2),)';
cost(pair,) = sum(squeeze(sum(bsxfun(@times,pair_vm,Qbar(:,:,pair)),)).*squeeze(pair_vm),)'; fprintf('%d\n', i);
end clf
drawMesh(V, F, 'facecolor','y', 'edgecolor','k', 'linewidth', 1.2);
view([ ])
axis equal
axis off
camlight
lighting gouraud
cameramenu

本文为原创,转载请注明出处:http://www.cnblogs.com/shushen
参考文献:
[1] Michael Garland and Paul S. Heckbert. 1997. Surface simplification using quadric error metrics. In Proceedings of the 24th annual conference on Computer graphics and interactive techniques (SIGGRAPH '97). ACM Press/Addison-Wesley Publishing Co., New York, NY, USA, 209-216.
三维网格精简算法(Quadric Error Metrics)附源码的更多相关文章
- swfupload多文件上传[附源码]
swfupload多文件上传[附源码] 文件上传这东西说到底有时候很痛,原来的asp.net服务器控件提供了很简单的上传,但是有回传,还没有进度条提示.这次我们演示利用swfupload多文件上传,项 ...
- 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生
[转].NET(C#):浅谈程序集清单资源和RESX资源 目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...
- 8个前沿的 HTML5 & CSS3 效果【附源码下载】
作为一个前沿的 Web 开发者,对于 HTML5 和 CSS3 技术或多或少都有掌握.前几年这些新技术刚萌芽的时候,开发者们已经使用它们来小试牛刀了,如今这些先进技术已经遍地开发,特别是在移动端大显身 ...
- C#编程总结(七)数据加密——附源码
C#编程总结(七)数据加密——附源码 概述 数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为“密文”,使其只能在输入相应的密钥之后才能显示出本来内容 ...
- Remote验证及其改进(附源码)
Remote验证及其改进(附源码) 表单中的输入项,有些是固定的,不变的验证规则,比如字符长度,必填等.但有些是动态的,比如注册用户名是否存在这样的检查,这个需要访问服务器后台才能解决.这篇文章将会介 ...
- javaweb异常提示信息统一处理(使用springmvc,附源码)
一.前言 后台出现异常如何友好而又高效地回显到前端呢?直接将一堆的错误信息抛给用户界面,显然不合适. 先不考虑代码实现,我们希望是这样的: (1)如果是页面跳转的请求,出现异常了,我们希望跳转到一个异 ...
- 13行代码实现:Python实时视频采集(附源码)
一.前言 本文是<人脸识别完整项目实战>系列博文第3部分:程序设计篇(Python版),第1节<Python实时视频采集程序设计>,本章内容系统介绍:基于Python+open ...
- 日志组件Log2Net的介绍和使用(附源码开源地址)
Log2Net是一个用于收集日志到数据库或文件的组件,支持.NET和.NetCore平台. 此组件自动收集系统的运行日志(服务器运行情况.在线人数等).异常日志.程序员还可以添加自定义日志. 该组件支 ...
- openlayers5-webpack 入门开发系列结合 echarts4 实现散点图(附源码下载)
前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...
随机推荐
- .NET Core下的日志(2):日志模型详解
NET Core的日志模型主要由三个核心对象构成,它们分别是Logger.LoggerProvider和LoggerFactory.总的来说,LoggerProvider提供一个具体的Logger对象 ...
- 【CSS进阶】CSS 颜色体系详解
说到 CSS 颜色,相比大家都不会陌生,本文是我个人对 CSS 颜色体系的一个系统总结与学习,分享给大家. 先用一张图直观的感受一下与 CSS 颜色相关大概覆盖了哪些内容. 接下来的行文内容大概会按照 ...
- 从接口、抽象类到工厂模式再到JVM来总结一些问题
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习! 涉及到的知识点总结如下: 为什么使用接口? 接口和抽象类的区别 简单工厂模式总结 Java中new和newInstance的区别 J ...
- 使用MATLAB对图像处理的几种方法(下)
试验报告 一.试验原理: 图像点处理是图像处理系列的基础,主要用于让我们熟悉Matlab图像处理的编程环境.灰度线性变换和灰度拉伸是对像素灰度值的变换操作,直方图是对像素灰度值的统计,直方图均衡是对 ...
- 基于android studio的快捷开发(将持续更新)
对于Android studio作为谷歌公司的亲儿子,自然有它的好用的地方,特别是gradle方式和快捷提示方式真的很棒.下面是我在实际开发中一些比较喜欢用的快速开发快捷键,对于基本的那些就不多说了. ...
- 使用webfont为easyui扩充图标
目前回到pc端开发,开始用了easyui这个框架.重拾easyui后感觉这个框架用的很多技术太古老,页面风格也太控件化.单从图标一项来说吧,这种花花绿绿的图标用户一看都傻了眼,同时整个框架就提供了那么 ...
- User Growth Using Deeplink. (part1)
转载请注明来源 http://www.cnblogs.com/hucn/p/5917924.html 活跃人数是衡量app一项关键指标, dau, mau, 有了流量才能给业务发展提供养分和空间. a ...
- Objective-C集合总结
Objective-C里面的集合主要包括:NSString,NSMutableString,NSArray,NSMutableArray,NSDictionary,NSMutableDictionar ...
- scikit-learn一般实例之四:管道的使用:链接一个主成分分析和Logistic回归
主成分分析(PCA)进行无监督的降维,而逻辑回归进行预测. 我们使用GridSearchCV来设置PCA的维度 # coding:utf-8 from pylab import * import nu ...
- angularjs和ajax的结合使用 (一)
好久没写文了.这是一篇关于easyui配合ajax使用 的文章, 顺带介绍angularjs的使用 以及让你感受到angularjs的威力.网上对于ajax 的文也是多如牛毛 .我就不直接 从那种原生 ...