使用 Python 多处理库处理 3D 数据
今天我們將介紹處理大量數據時非常方便的工具。我不會只告訴您可能在手冊中找到的一般信息,而是分享一些我發現的小技巧,例如tqdm與 multiprocessing?imap??一起使用、并行處理檔案、繪制和處理 3D 數據以及如何搜索如果您有點云,則用于對象網格中的類似對象。?
那么我們為什么要求助于并行計算呢?如今,如果您處理任何類型的數據,您可能會面臨與“大數據”相關的問題。每次我們有不適合 RAM 的數據時,我們都需要一塊一塊地處理它。幸運的是,現代編程語言允許我們生成在多核處理器上完美運行的多個進程(甚至線程)。(注意:這并不意味著單核處理器不能處理多處理。 ?這是關于該主題的堆棧溢出線程。)
今天,我們將嘗試處理經常發生的計算網格和點云之間距離的 3D 計算機視覺任務。例如,當您需要在所有可用網格中找到定義與給定點云相同的 3D 對象的網格時,您可能會遇到此問題。
我們的數據由??.obj???存儲在??.7z??存檔中的文件組成,這在存儲效率方面非常出色。但是當我們需要訪問它的確切部分時,我們應該努力。在這里,我定義了包裝 7-zip 存檔并提供底層數據接口的類。
類 Archive7z(基礎): def __init__ ( self , file , password = None ): # ... 自我。文件={} # ... 對于信息的文件。文件: #創建一個知道磁盤位置的ArchiveFile實例 file = ArchiveFile ( info , pos , src_pos , folder , self , maxsize = maxsize ) # ... 自我。文件。追加(文件) # ... 自我。文件映射。更新([(X。文件名,X)為X的自我。文件]) #從files_map字典返回ArchiveFile的方法 def getmember ( self , name ): if isinstance ( name , ( int , long )): 嘗試: 回歸自我。文件[名稱] 除 了 IndexError: 返回無 回歸自我。文件映射。獲取(名稱,無) 類 Archive7(基礎): 定義讀取(自我): # ... 對于水平,編碼器在枚舉(自我。_folder。編碼器): # ... #獲取解碼器并解碼底層數據 data = getattr ( self , decoder ) ( coder , data , level , num_coders ) 返回數據
這個類幾乎不依賴??py7zlib???包,它允許我們在每次調用get方法時解壓縮數據并為我們提供存檔中的文件數。我們還定義了??__iter__??這將幫助我們map像在可迭代對象上一樣在該對象上啟動多處理。
您可能知道,可以創建一個 Python 類,從中可以實例化可迭代對象。該類應滿足以下條件:覆蓋??__getitem__???返回??self???和??__next__???返回后續元素。我們絕對遵守這條規則。
上面的定義為我們提供了遍歷存檔的可能性,但?它是否允許我們?并行隨機訪問內容,這是一個有趣的問題,我在網上沒有找到答案,但我們可以研究源代碼??py7zlib??并嘗試自己回答。
在這里,我提供了來自pylzma的代碼片段:
類 Archive7z(基礎): def __init__ ( self , file , password = None ): # ... 自我。文件={} # ... 對于信息的文件。文件: #創建一個知道磁盤位置的ArchiveFile實例 file = ArchiveFile ( info , pos , src_pos , folder , self , maxsize = maxsize ) # ... 自我。文件。追加(文件) # ... 自我。文件映射。更新([(X。文件名,X)為X的自我。文件]) #從files_map字典返回ArchiveFile的方法 def getmember ( self , name ): if isinstance ( name , ( int , long )): 嘗試: 回歸自我。文件[名稱] 除 了 IndexError: 返回無 回歸自我。文件映射。獲取(名稱,無) 類 Archive7z(基礎): 定義讀取(自我): # ... 對于水平,編碼器在枚舉(自我。_folder。編碼器): # ... #獲取解碼器并解碼底層數據 data = getattr ( self , decoder ) ( coder , data , level , num_coders ) 返回數據
在代碼中,您可以看到在從存檔中讀取下一個對象期間調用的方法。我相信從上面可以清楚地看出,只要同時多次讀取存檔,就沒有理由阻止存檔。
接下來,我們快速介紹一下什么是網格和點云。
首先,網格是頂點、邊和面的集合。頂點由空間中的(x,y,z)?坐標定義并分配有唯一編號。邊和面是相應的點對和三元組的組,并用提到的唯一點 id 定義。通常,當我們談論“網格”時,我們指的是“三角形網格”,即由三角形組成的表面。使用??trimesh??庫在 Python 中使用網格要容易得多。例如,它提供了一個接口來加載??.obj??內存中的文件。要在??jupyter notebook??一個3D 對象中顯示和交互,可以使用??k3d??庫。
所以,用下面的代碼片段我回答這個問題:“你怎么繪制??trimesh???的對象??jupyter???有??k3d???”
進口飾面 導入k3d 使用 open ( w. /data/meshes/stanford-bunny, obj")作為 f : bunny_mesh =網眼。力口載(f , 'obj') 情節=k3d。情節() 網格= k3d。網格 (bunny_mesh . vertices> bunny_mesh . faces) 繪圖上網格 情節。顯示。?
其次,點云是表示空間中對象的 3D 點數組。許多 3D 掃描儀生成點云作為掃描對象的表示。出于演示目的,我們可以讀取相同的網格并將其頂點顯示為點云。
?
?
k3d繪制的點云
如上所述,3D 掃描儀為我們提供了一個點云。假設我們有一個網格數據庫,我們想在我們的數據庫中找到一個與掃描對象對齊的網格,也就是點云。為了解決這個問題,我們可以提出一種簡單的方法。我們將從我們的檔案中搜索給定點云的點與每個網格之間的最大距離。如果??1e-4??某些網格的距離更小,我們將認為該網格與點云對齊。
?最后,我們來到了多處理部分。請記住,我們的存檔中有大量文件可能無法放在一起放在內存中,因為我們更喜歡并行處理它們。為了實現這一點,我們將使用 ??multiprocessing?Pool???,它使用??map???或??imap/imap_unordered???方法處理用戶定義函數的多次調用。??map???和??imap???影響我們的區別在于,??map???在將其發送到工作進程之前將可迭代對象轉換為列表。如果存檔太大而無法寫入 ??RAM???,則不應將其解壓縮到 ??Python ??列表中。換句話說,兩者的執行速度是相似的。
[加載網格:pool.map w/o manager] 4 個進程的池經過時間:37.213207403818764 秒 [加載網格:pool.imap_unordered w/o manager] 4 個進程的池經過時間:37.219303369522095 秒
上面您可以看到從適合內存的網格檔案中簡單讀取的結果。
更進一步??imap???:讓我們討論如何實現我們的目標,即找到靠近點云的網格。這是數據。我們有 5 種來自斯坦福模型的不同網格。我們將通過向斯坦福兔子網格的頂點添加噪聲來模擬 3D 掃描。
將numpy導入為np A numpy。隨機 導入 defaulting def normalize_pc (點):點額=點額-點額。平均值(軸=0)[無,:]分布=np。linalg<>范數(點,軸=1) scaled_points =點 / dists中。最大值。 返回 scaled_points def load_bunny_pc ( bunny_path ):標準差=l?-3使用 open ( bunny_path )作為 f : bunny_mesh = load_mesh ( f )#標準化后云scaled_bunny = normalize_pc ( bunny_mesh . vertices )#向點云添加一些噪聲 rng = defaulting ()噪音=rng。正常(0. 0 , STD , scaled_bunny . shape ) 畸變兔子=縮放兔子+噪聲返回 di st ort ed_bunny
當然,我們之前在下面將點云和網格頂點歸一化,以在 3D 立方體中縮放它們。
要計算點云和網格之間的距離,我們將使用??igl??。為了完成,我們需要編寫一個函數來調用每個進程及其依賴項。讓我們用下面的代碼片段來總結一下。
導入迭代工具 導入時間 將 numpy 導入為 npnwnpyo 隨機導入 default rng 面以1 口口如 進進從 A多處理導入池 de£ load_mesh ( obj_file ):目二 trimesh。力口載(obj_file , ' obj')返回網格 def get_max__dist ( basjmesh , point_cloud ):distance_sq , mesh_face__indexes , _ = igl。point_mesh_squared_distance (點云,basjmesho 頂點,basjmesho 面孔)返回distancjsq。最大值0 def 1 oad_mesh__get_di stance ( args ):obj_file , point__cloud = args [ 0 ]/ args [ 1 ]網格二 load_mesh ( obj_file )網。頂點=RormaliNe_pc (網格。頂點)max_dist = get_max_dist (網格,點云)返回 max__dist de£ read_meshes__get__di stances_pool__imap ( archive_path , point_cloud , nwn_proc , nwn_i terations ):#在疝中進行向格“理elapsed__time =[]為一在 范圍(nujn-i terati ons ):歸檔二 MeshesArchive (ARCHIVE-PATH)池二池(nwn_proc )開始=時間。時間0導致=名單(tqdm(池。IMAP (1 o ad_m e sh__ge t_di s t anc e ,zip (存檔,itertoolso 重復(point_cloud)),),總計=len辱檔)))池。關閉0池。加入o結束=時間。時間0elapsed time o追加(結束一開始)print ( F [Process meshes: pool, imap] {num_proc}個進程的池經過的時間:{np. array (elapsed_time). mean()} sec )對于 name , di st in zip ( archive . namesjist , result ): 打印(r{name} {dist}")返回結果 如果 _name_ ==bunny_path = /data/meshes/stanford-bunny, obj"archive_path = /data/meshes. 7zffnwn_proc = 4num_iterations = 3point__cloud - load__bunny_pc ( bunny_path )read_meshes__get__di stances_pool_no_manager__imap ( archive_path ,point_cloud , nwn_proc , num. iterations )
??? ?
這??read_meshes_get_distances_pool_imap是一個中心函數,其中完成以下操作:??
- ??MeshesArchive??并??multiprocessing.Pool??初始化
- ??tqdm???用于觀察池進度,并手動完成整個池的分析
- 執行結果的輸出
請注意我們如何傳遞參數以??imap???從??archive???和??point_cloud???使用??zip(archive, itertools.repeat(point_cloud))???.?這允許我們將點云數組粘貼到存檔的每個條目上,避免轉換??archive??為列表。
執行結果如下:
100%|########################################### #####################| 5/5 [00:00<00:00, 5.14it/s] 100%|########################################### #####################| 5/5 [00:00<00:00, 5.08it/s] 100%|########################################### #####################| 5/5 [00:00<00:00, 5.18it/s] [進程網格:pool.imap w/o manager] 4 個進程的池經過時間:1.0080536206563313 秒 犰狳.obj 0.16176825266293382 野獸.obj 0.28608649819198073 牛.obj 0.41653845909820164 現貨.obj 0.22739556571296735 stanford-bunny.obj 2.3699851136074263e-05
我們可以注意到斯坦福兔子是最接近給定點云的網格。還可以看出,我們沒有使用大量數據,但我們已經證明,即使我們在存檔中有大量網格,該解決方案也能奏效。
多處理使數據科學家不僅在 3D 計算機視覺中而且在機器學習的其他領域中都取得了出色的表現。理解并行執行比在循環內執行快得多是非常重要的。差異變得顯著,尤其是在正確編寫算法時。大量數據揭示了如果沒有關于如何使用有限資源的創造性方法就無法解決的問題。幸運的是,Python 語言及其廣泛的庫集幫助我們數據科學家解決了這些問題。
-----------------------------------
?著作權歸作者所有:來自51CTO博客作者一大口奶酪的原創作品,請聯系作者獲取轉載授權,否則將追究法律責任
使用 Python 多處理庫處理 3D 數據
https://blog.51cto.com/nailaoer/4832794
總結
以上是生活随笔為你收集整理的使用 Python 多处理库处理 3D 数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Silverlight学习笔记(一)——
- 下一篇: P3174 [HAOI2009]毛毛虫(