資料分析、科學運算、人工智慧……這些有的沒的名詞,近幾年一直幾乎是與Python同時出現的關鍵字,無論你想從事的是這些熱門名詞中哪一部分,多半會接觸到Matplotlib、NumPy、Scipy等工具構築起來的生態系,使得現在若談到這類工具時,幾乎都只會聯想到人工智慧、科學運算、資料分析等應用。

經常出現在眼前的技術名詞、關鍵字,總是會引發我的好奇,從而想要去瞭解,知道它們(或他們)是在玩什麼把戲,只不過這些畢竟非我擅長的領域,有段時間總是不得其門而入,後來我突發奇想,拋開資料分析、科學運算、人工智慧等,純粹從個人興趣,以繪圖、3D建模的角度切入,倒也玩出了一些心得(可參考〈笨學資料運算〉)。

也因為從繪圖、3D建模的角度切入,在認識這些工具的過程中,倒也發現不少可用於3D建模的工具,從而在採用CadQuery建模時,可以更方便地結合這些工具。或許是因為視覺化在這個生態系中極為重要,而圖像分析、地理位置、空間幾何等,其實也是資料科學處理的幾個對象。

資料科學中的運算幾何

例如,雖然相對其他語言少了一些,但Python在3D繪圖的方案並不是沒有,像是OpenGL(或者其擴充VTK等)的Python綁定版本、遊戲引擎方面的Panda3D,或者是想簡單建立3D場景、設定簡單模型間的互動關係來建立動畫的VPython等,然而,若試著以「Python 3D」作為關鍵字搜尋,找到的資料絕大多數卻與Matplotlib有關。

這當然跟Python主要應用的領域有關,但確實也使得繪圖、建模等運算幾何相關的方案,圍繞著資料科學而建立,有趣的是,因為Matplotlib可以進行3D視覺化,也就有人拿來做些3D建模的任務,先前的專欄〈Matplotlib玩3D建模〉也談過相關的做法。

雖然用Matplotlib從事3D建模,僅屬於娛樂性質居多的Hack玩法,畢竟每次移動模型都會引發重繪,在模型複雜時,顯示上的延遲會令人抓狂,然而,從這類Hack玩法可以找到不少靈感與工具,這陣子我就經常使用「Python 3D」之類關鍵字搜尋圖片,看看別人在Matplotlib中畫了什麼有趣的3D模型,然後從中發現更多包含了運算幾何的資料科學工具。

NumPy與Scipy的幾何方案

從事資料科學方面任務的Python開發者,想必都會接觸NumPy,就3D建模而言,NumPy提倡的陣列程式設計典範,與3D繪圖時的著色器設計有些類似。畢竟3D建模時也常面對大量的點、線、面資料,若以NumPy陣列程式設計典範來操作這些資料,無論在可讀性或者是效能上,都有很大助益。

另一方面,NumPy陣列易於從事向量與矩陣的操作,而且由於Python可以定義運算子,若想設計專用於3D轉換的矩陣庫,提供平移、旋轉、投影等操作或組合,結合NumPy陣列來實作非常方便,有興趣可以參考〈實作轉換矩陣〉,看看實現方式,以及在CadQuery中的應用。

基於NumPy而建構的Scipy,其中有個spatial模組,顧名思義,它提供了空間分析相關的演算法與資料結構,例如ConvexHull函式,可用來建立2D或3D版本的凸包,就影像或資料分析而言,凸包常用來取得輪廓,而就3D建模而言,會經常用來從多個2D/3D模型取得頂點,以建立凸包的方式建立新的2D/3D模型,是非常重要的工具。

spatial模組也包含了Voronoi與Delaunay函式,可以讓我們用來建立2D或3D版本的Voronoi與Delaunay空間分割,在〈2D/3D Voronoi〉,以及〈Delaunay 三角分割〉中,也談到如何整合至CadQuery使用(而非透過spatial中的delaunay_plot等繪圖函式)。

spatial模組甚至還包含了SphericalVoronoi函式,可以用來繪製球面版本的Voronoi;另外,雖然不直接用於繪圖,然而Scipy的spatial.distance模組,也提供了各種距離計算用的函數。

附帶一提的是,Matplotlib的plot_trisurf函式可以繪製三角曲面,其底層使用了tri.Triangulation,若自行建立Triangulation實例,就可以透過triplot方法來繪製三角分割,或者是透過get_masked_triangles方法取得分割後的各個三角形。

scikit-image

在尋找可用於3D建模的資料科學工具時,我發現了scikit-image,簡稱skimage,它是基於scipy.ndimage的擴充,由Scipy社群開發與維護,會尋找這類方案的原因在於:我想要從基於像素的圖像中提取資訊,像是取得圖像輪廓、灰階值等,以便在模型上貼圖,或是進行曲面建立之類的任務。

談到圖像處理,不少開發者必然想到OpenCV(的Python綁定)或類似的其他程式庫(像是PIL、Pillow等),OpenCV與skimage確實有不少功能是重疊的,如常見的濾鏡、圖像變換(縮放、旋轉)、凸包運算等,兩者幾乎都有各自對應的方案。

然而,相較於OpenCV主要專注在二維圖像處理本身,功能強大而龐多,skimage則是更著重於圖像分析,輕量且易於與既有的資料科學運算工具結合(畢竟是基於Scipy),而且圖像分析工具並不限於二維,也有著三維的方案,畢竟電腦斷層掃描之類就不會只是二維的資訊。

這也是我會發現skimage的原因,因為我想尋找可以從體素(Voxel)資料重建立體表面的方案,在先前專欄〈等值線、帶、立方演算〉中談過,這可以透過Marching cubes演算來達成任務。

如果搜尋「python marching cubes」,會發現skimage的measure模組,它包含marching_cubes函式,我用來解決一直想做的Gyroid曲面模型,有興趣可以參考〈gyroid.py〉中的程式實作。

相對地,在Marching squares演算方面,可以使用measure模組的find_contours函式來實現(OpenCV則是由cv2模組的findContours函式來實現);measure模組之所以稱為measure,在於它還提供了許多面積計算、質心座標、區域標記等功能。

skimage其他模組也提供一些三維方案,如draw模組提供ellipsoid,可以產生橢球體素;在morphology模組當中,提供了cube、octahedron、ball等函式,可以建立各種三維的體素資料,主要是作為三維的型態學,像是膨脹、腐蝕等處理時的運算子。

其他的幾何工具

其他還有一些可留意的幾何工具,如SymPy,這是可進行數學代數運算的程式庫,本身包含Matrix可進行矩陣運算,而其中的geometry模組,可以用來進行二維、三維空間中的點、線、面等計算;SymPy也可以進行3D繪圖,目前是基於matplotlib。

只不過看到這邊,確實也突顯一件事實,Python生態圈就是缺少了專注於幾何的程式庫。幸而在2020年初,scikit-geometry出現了,它基於C++生態圈中成熟的運算幾何程式庫CGAL,試著為Python生態圈提供2D/3D方面的運算幾何方案,有興趣可以參考〈Introducing scikit-geometry〉,作者在SciPy 2020也演講了〈Scikit Geometry and Generic Computing in Python〉。

總而言之,如果你跟我一樣,因為想在Python中從事3D建模之類的任務,必須尋找Python中的幾何方案,可以試著在資料科學相關領域中尋得,scikit-geometry是個新的程式庫,由於基於C++的CGAL,未來的發展值得期待!

作者簡介


熱門新聞

Advertisement