使用k-means对3D网格模型进行分割
使用k-means对3D网格模型进行分割
由于一些原因,最近在做网格分割的相关工作。网格分割的方法有很多,如Easy mesh cutting、K-means、谱分割、基于SDF的分割等。根据对分割要求的不同,选取合适的分割方法。本文中使用了较为简单的k-means对网格进行分割。
K-means原理
K-means是一种简单的聚类方法,聚类属于无监督学习,聚类的样本中却没有给定y,只有特征x,比如假设宇宙中的星星可以表示成三维空间中的点集(x,y,z)。聚类的目的是找到每个样本x潜在的类别y,并将同类别y的样本x放在一起。对于上述的星星,聚类后结果是一个个星团,星团里面的点相互距离比较近,不同星团间的星星距离就比较远了。
算法描述
(1)从数据集中随机抽取k个质心作为初始聚类的中心;
(2)计算数据集中所有的点到这k个点的距离,将点归到离其最近的聚类里;
(3)调整聚类中心,即将聚类的中心移动到聚类的几何中心(即平均值)处;
(4)重复第2步和第3步,直到聚类的中心不再移动,此时算法收敛。
matlab代码如下
function cluster_labels = k_means(data, centers, num_clusters)
%K_MEANS Euclidean k-means clustering algorithm.
%
% Input : data : N-by-D data matrix, where N is the number of data,
% D is the number of dimensions
% centers : K-by-D matrix, where K is num_clusters, or
% 'random', random initialization, or
% [], empty matrix, orthogonal initialization
% num_clusters : Number of clusters
%
% Output : cluster_labels : N-by-1 vector of cluster assignment
% Parameter setting
%
iter = 0;
qold = inf;
threshold = 0.001;
%
% Check if with initial centers
%
if strcmp(centers, 'random')
disp('Random initialization...');
centers = random_init(data, num_clusters);
elseif isempty(centers)
disp('Orthogonal initialization...');
centers = orth_init(data, num_clusters);
end
%
% Double type is required for sparse matrix multiply
%
data = double(data);
centers = double(centers);
%
% Calculate the distance (square) between data and centers
%
n = size(data, 1);
x = sum(data.*data, 2)';
X = x(ones(num_clusters, 1), :);
y = sum(centers.*centers, 2);
Y = y(:, ones(n, 1));
P = X + Y - 2*centers*data';
%
% Main program
%
while 1
iter = iter + 1;
% Find the closest cluster for each data point
[val, ind] = min(P, [], 1);
% Sum up data points within each cluster
P = sparse(ind, 1:n, 1, num_clusters, n);
centers = P*data;
% Size of each cluster, for cluster whose size is 0 we keep it empty
cluster_size = P*ones(n, 1);
% For empty clusters, initialize again
zero_cluster = find(cluster_size==0);
if length(zero_cluster) > 0
disp('Zero centroid. Initialize again...');
centers(zero_cluster, :)= random_init(data, length(zero_cluster));
cluster_size(zero_cluster) = 1;
end
% Update centers
centers = spdiags(1./cluster_size, 0, num_clusters, num_clusters)*centers;
% Update distance (square) to new centers
y = sum(centers.*centers, 2);
Y = y(:, ones(n, 1));
P = X + Y - 2*centers*data';
% Calculate objective function value
qnew = sum(sum(sparse(ind, 1:n, 1, size(P, 1), size(P, 2)).*P));
mesg = sprintf('Iteration %d:\n\tQold=%g\t\tQnew=%g', iter, full(qold), full(qnew));
disp(mesg);
% Check if objective function value is less than/equal to threshold
if threshold >= abs((qnew-qold)/qold)
mesg = sprintf('\nkmeans converged!');
disp(mesg);
break;
end
qold = qnew;
end
cluster_labels = ind';
%-----------------------------------------------------------------------------
function init_centers = random_init(data, num_clusters)
%RANDOM_INIT Initialize centroids choosing num_clusters rows of data at random
%
% Input : data : N-by-D data matrix, where N is the number of data,
% D is the number of dimensions
% num_clusters : Number of clusters
%
% Output: init_centers : K-by-D matrix, where K is num_clusters
rand('twister', sum(100*clock));
init_centers = data(ceil(size(data, 1)*rand(1, num_clusters)), :);
function init_centers = orth_init(data, num_clusters)
%ORTH_INIT Initialize orthogonal centers for k-means clustering algorithm.
%
% Input : data : N-by-D data matrix, where N is the number of data,
% D is the number of dimensions
% num_clusters : Number of clusters
%
% Output: init_centers : K-by-D matrix, where K is num_clusters
%
% Find the num_clusters centers which are orthogonal to each other
%
Uniq = unique(data, 'rows'); % Avoid duplicate centers
num = size(Uniq, 1);
first = ceil(rand(1)*num); % Randomly select the first center
init_centers = zeros(num_clusters, size(data, 2)); % Storage for centers
init_centers(1, :) = Uniq(first, :);
Uniq(first, :) = [];
c = zeros(num-1, 1); % Accumalated orthogonal values to existing centers for non-centers
% Find the rest num_clusters-1 centers
for j = 2:num_clusters
c = c + abs(Uniq*init_centers(j-1, :)');
[minimum, i] = min(c); % Select the most orthogonal one as next center
init_centers(j, :) = Uniq(i, :);
Uniq(i, :) = [];
c(i) = [];
end
clear c Uniq;
网格分割
对网格使用K-means进行聚类,首先要构造用于聚类的特征,也就是要构造data、center和num_clusters
如果只使用网格顶点坐标作为聚类特征,并使用'random'初始化聚类中心,聚类结果如下:
模型顶点:53054,面:106104,聚类特征:顶点坐标,聚类数目:4

如果将顶点法向也加入聚类的特征中,得到的结果如下:

附获取顶点法向的代码如下:
/*获取所有顶点的法向*/
_mesh->request_face_normals();
_mesh->request_vertex_normals();
_mesh->update_normals();
int vnidx = 0;
for (auto vit = _mesh->vertices_begin(); vit != _mesh->vertices_end(); ++vit,vnidx++)
{
auto vertex = vit.handle();
OpenMesh::Vec3d v_normal;
v_normal = _mesh->normal(vertex);
Vnx[vnidx] = v_normal.data()[0];
Vny[vnidx] = v_normal.data()[1];
Vnz[vnidx] = v_normal.data()[2];
}
/*一部分参考YQ,一部分参考OpenMesh入门程序介绍*/
使用k-means对3D网格模型进行分割的更多相关文章
- pcl曲面网格模型的三种显示方式
pcl网格模型有三种可选的显示模式,分别是面片模式(surface)显示,线框图模式(wireframe)显示,点模式(point)显示.默认为面片模式进行显示.设置函数分别为: void pcl:: ...
- 基于HTML5 Canvas 点击添加 2D 3D 机柜模型
今天又返回好好地消化了一下我们的数据容器 DataModel,这里给新手做一个典型的数据模型事件处理的例子作为参考.这个例子看起来很简单,实际上结合了数据模型中非常重要的三个事件处理的部分:属性变化事 ...
- 3D max模型导入unity 3D中注意事项
一.单位,比例统一 在建模型前先设置好单位,在同一场景中会用到的模型的单位设置必须一样,模型与模型之间的比例要正确,和程序的导入单位一致,即便到程序需要缩放也可以统一调整缩放比例.统一单位为米. ...
- 用基于WebGL的BabylonJS来共享你的3D扫描模型
转自:http://www.geekfan.net/6578/ 用基于WebGL的BabylonJS来共享你的3D扫描模型 杰克祥子 2014 年 2 月 26 日 0 条评论 标签:3D扫描 , B ...
- WPF 3D 平移模型+动画(桥梁检测系统)
原文:WPF 3D 平移模型+动画(桥梁检测系统) 关于WPF 3D,网上有很多旋转的例子,但是关于平移的例子并不是太多.本文并非WPF 3D扫盲篇,因此需要对WPF 3D有一定了解,至少知道View ...
- WPF在3D Cad模型中利用TextureCoordinates实现颜色渐变显示偏差值的变化
原文:WPF在3D Cad模型中利用TextureCoordinates实现颜色渐变显示偏差值的变化 注:最近在做3D机械模型重建方面的软件,需要根据光栅传感器采集的数据绘制3D图形,并显示出色差以及 ...
- iNeuOS工业互联网操作系统,三维(3D)模型在线编辑应用和实时数据统计(和值、均值、众数、方差、中位数等)
目 录 1. 概述... 1 2. 三维(3D)模型在线编辑与应用... 2 3. 实时数据统计... 4 1. 概述 此次,iNeuOS工业互联网操作系 ...
- 新上线!3D单模型轻量化硬核升级,G级数据轻松拿捏!
"3D模型体量过大.面数过多.传输展示困难",用户面对这样的3D数据,一定不由得皱起眉头.更便捷.快速处理三维数据,是每个3D用户对高效工作的向往. 在老子云最新上线的单模型轻量化 ...
- 点云3d检测模型pointpillar
PointPillars 一个来自工业界的模型.https://arxiv.org/abs/1812.05784 3D目标检测通常做法 3d卷积 投影到前平面 在bird-view上操作 处理思路依然 ...
随机推荐
- 合并傻子//区间dp
P1062 合并傻子 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 从前有一堆傻子,钟某人要合并他们~但是,合并傻子是要掉RP的...... 描述 在一个园 ...
- 李洪强iOS开发之最全App上架流程
在上架App之前想要 真机测试的同学 请查看 iOS- 最全的真机测试教程 里面包含怎么让多台电脑同时 上架App和同时真机调试.P12文件的使用详解 准备 开发者账号 完工的项目 上架步骤 一.创建 ...
- lintcode :搜索旋转排序数组
题目 搜索旋转排序数组 假设有一个排序的按未知的旋转轴旋转的数组(比如,0 1 2 4 5 6 7 可能成为4 5 6 7 0 1 2).给定一个目标值进行搜索,如果在数组中找到目标值返回数组中的索引 ...
- 【原创】MySql 数据库导入导出(备份)
啥不说了,两周前刚刚做过mysql导入导出的结果现在又忘了.. 更可悲的是竟然同样的三篇blog,现在看起来还是如当初一样费劲,里面的内容..所以自己写个记录一下 环境:*nix 权限:有相关表的写读 ...
- Oracle数据库ORA-12154: TNS: 无法解析指定的连接标识符详解
ORA-12154: TNS: 无法解析指定的连接标识符(转自http://www.cnblogs.com/psforever/p/3929064.html) 相信使用过Oracle数据库的人一定碰到 ...
- WINCE 开机自动弹USB连接窗口问题(已解决)
平台:S3C6410+WinCE6.0 问题现像: 当启用UART0也就是COM1时,无论插没插USB线,一开机,它都会弹出个USB连接的窗口, 原因分析: 是因为在三星原版本BSP里的串口驱动上制定 ...
- 用git difff 生成补丁
http://stackoverflow.com/questions/1191282/how-to-see-the-changes-between-two-commits-without-commit ...
- voliecty indexOf的写法
Velocity allows you to use all Java methods available in your objects. So just write as if it was Ja ...
- AngularJS 拦截器和应用例子(转)
$httpAngularJS 的 $http 服务允许我们通过发送 HTTP 请求方式与后台进行通信.在某些情况下,我们希望可以俘获所有的请求,并且在将其发送到服务端之前进行操作.还有一些情况是,我们 ...
- 聚焦 SQL 数据库活动异地复制
Tobias Ternstrom US-DS-PM 首席部门项目经理 本文作为一系列业务连续性和灾难恢复文章的开篇,概述了业务连续性的各种场景,然后重点介绍 SQL 数据库高级服务级别提供的活动异地 ...