作者:憨豆酒(YinDou),聯繫我[email protected],熟悉圖形學,圖像處理領域,本章的源代碼可在此倉庫中找到: https://github.com/douysu/person-summary 如果大家發現錯誤以及不合理之處,還希望多多指出。
查了一下中文文章,幾乎沒有一篇介紹曲率原理並且計算曲率的文章。首先總結了一下曲率的原理,參考的內容有:圖形學書籍、維基,和GitHub的項目。
參考內容:
[1] https://libigl.github.io/
[2] https://zh.wikipedia.org/wiki/曲率
[3] https://zh.wikipedia.org/wiki/PLY
[4] https://github.com/alecjacobson/geometry-processing-curvature
[5] http://meshlabstuff.blogspot.com/2010/03/mean-curvature-cavity-map-zbrush-and.html
[6] https://web.archive.org/web/20081203195143/http://www.cs.princeton.edu/~diego/professional/rply/
[7]章毓晉.圖像處理.北京:清華大學出版社,2018
1 曲率原理
什麼是曲率?
曲率是描述幾何體彎曲程度的量,例如三維曲面偏離平面的程度,或者二維曲線偏離直線的程度,也可確定曲面類型。常應用於幾何分析,地理測繪等領域。
例如在材料學中,材料的催化活性主要與表面活性位點有關,而曲率影響活性位點的數量。
曲線P點切線:
曲線任意一點Q,PQ兩點無限接近,所連直線爲切線。
曲線P點曲率:曲線任意一點?_1, ?_2 ,三點確定一圓, ?_1, ?_2 無限接近P點,密切圓半徑r的倒數爲曲率。
平面結論:圓上彎曲程度相同,任意一點曲率相等,越彎曲曲率越大,直線曲率爲0。
曲面曲率:
在曲面上取一點P,曲面在P點的法線爲n,過n可以有無限多個剖切平面,每個剖切平面與曲面相交,交線爲一條平面曲線。
不同的剖切平面上的平面曲線在P點的曲率半徑一般是不相等的。
三維空間中的曲率:
主曲率:曲面上有無數個不同方向的曲線,曲面上的點不同方向具有不同曲率,其中最大值和最小值爲稱爲主曲率 k1 和k2,極值方向稱爲主方向。數學上可證名k1和k2互相垂直。
高斯曲率:兩主曲率乘積,反映曲面在不同方向彎曲程度是否相同。高斯曲率爲正,爲球面。高斯曲率爲負雙曲面。
平均曲率:兩主曲率算數平均數(k1+k2)/2,反映曲面凹凸程度。平均曲率爲正,局部凹。平均曲率爲負,局部凸。
第一個圖形的高斯曲率爲負值,第二個爲0,第三個爲正數。
2 高斯曲率(G)和均值曲率(H)所確定表面類型:
通過高斯曲率和均值曲率的正負判斷曲面類型。
H<0 | H=0 | H>0 |
---|---|---|
G<0 | 鞍脊 | 最小/迷向 |
G=0 | 山脊 | 平面 |
G>0 | 山峯 |
3 曲率的計算
通過一段時間的調研,我發現使用此兩種方式計算曲率比較多。具體鏈接就不給出了,google一下就可以看到教程了案例了。
(1)C++圖形學幾何處理庫libigl
(2)三維幾何處理系統MeshLab
4 本人使用的方式
我採用的第二種方式,使用MeshLab進行處理,得到曲率數據,保存到.ply文件中,在從.ply文件中提取曲率的值即可。這裏我使用了Rply的框架進行ply的文件讀取。
這裏給出main.cpp的代碼
#include <stdio.h>
#include "rply.h"
#include <fstream>
#include <iostream>
using namespace std;
ofstream outfile;
static int vertex_cb(p_ply_argument argument) {
long eol;
ply_get_argument_user_data(argument, NULL, &eol);
float temp = ply_get_argument_value(argument);
outfile << temp << endl;
printf("%g", ply_get_argument_value(argument));
if (eol) printf("\n");
else printf(" ");
return 1;
}
static int face_cb(p_ply_argument argument) {
long length, value_index;
ply_get_argument_property(argument, NULL, &length, &value_index);
switch (value_index) {
case 0:
case 1:
printf("%g ", ply_get_argument_value(argument));
break;
case 2:
printf("%g\n", ply_get_argument_value(argument));
break;
default:
break;
}
return 1;
}
int main(void) {
outfile.open("mean_curvature_vertex.txt");
long nvertices;
p_ply ply = ply_open("Mean_01.ply", NULL);
if (!ply) return 1;
if (!ply_read_header(ply)) return 1; //運行檢查
nvertices = ply_set_read_cb(ply, "vertex", "x", vertex_cb, NULL, 0);
ply_set_read_cb(ply, "vertex", "y", vertex_cb, NULL, 0);
ply_set_read_cb(ply, "vertex", "z", vertex_cb, NULL, 0);
ply_set_read_cb(ply, "vertex", "quality", vertex_cb, NULL, 1);
//printf("%ld\n", nvertices);
if (!ply_read(ply)) return 1;
ply_close(ply);
outfile.close();//關閉文件流
getchar();
return 0;
}