利用Python多處理庫處理3D數(shù)據(jù)詳解
今天我們將介紹處理大量數(shù)據(jù)時非常方便的工具。我不會只告訴您可能在手冊中找到的一般信息,而是分享一些我發(fā)現(xiàn)的小技巧,例如tqdm與 multiprocessing?imap??一起使用、并行處理檔案、繪制和處理 3D 數(shù)據(jù)以及如何搜索如果您有點云,則用于對象網(wǎng)格中的類似對象。?
那么我們?yōu)槭裁匆笾诓⑿杏嬎隳??如今,如果您處理任何類型的?shù)據(jù),您可能會面臨與“大數(shù)據(jù)”相關(guān)的問題。每次我們有不適合 RAM 的數(shù)據(jù)時,我們都需要一塊一塊地處理它。幸運的是,現(xiàn)代編程語言允許我們生成在多核處理器上完美運行的多個進程(甚至線程)。(注意:這并不意味著單核處理器不能處理多處理。? 這是關(guān)于該主題的堆棧溢出線程。)
今天,我們將嘗試處理經(jīng)常發(fā)生的計算網(wǎng)格和點云之間距離的 3D 計算機視覺任務(wù)。例如,當您需要在所有可用網(wǎng)格中找到定義與給定點云相同的 3D 對象的網(wǎng)格時,您可能會遇到此問題。
我們的數(shù)據(jù)由??.obj???存儲在??.7z??存檔中的文件組成,這在存儲效率方面非常出色。但是當我們需要訪問它的確切部分時,我們應(yīng)該努力。在這里,我定義了包裝 7-zip 存檔并提供底層數(shù)據(jù)接口的類。
類 Archive7z(基礎(chǔ)): def __init__ ( self , file , password = None ): # ... 自我。文件={} # ... 對于信息的文件。文件: #創(chuàng)建一個知道磁盤位置的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(基礎(chǔ)): 定義讀取(自我): # ... 對于水平,編碼器在枚舉(自我。_folder。編碼器): # ... #獲取解碼器并解碼底層數(shù)據(jù) data = getattr ( self , decoder ) ( coder , data , level , num_coders ) 返回數(shù)據(jù)
這個類幾乎不依賴??py7zlib???包,它允許我們在每次調(diào)用get方法時解壓縮數(shù)據(jù)并為我們提供存檔中的文件數(shù)。我們還定義了??__iter__??這將幫助我們map像在可迭代對象上一樣在該對象上啟動多處理。
您可能知道,可以創(chuàng)建一個 Python 類,從中可以實例化可迭代對象。該類應(yīng)滿足以下條件:覆蓋??__getitem__???返回??self???和??__next__???返回后續(xù)元素。我們絕對遵守這條規(guī)則。
上面的定義為我們提供了遍歷存檔的可能性,但 它是否允許我們 并行隨機訪問內(nèi)容,這是一個有趣的問題,我在網(wǎng)上沒有找到答案,但我們可以研究源代碼??py7zlib??并嘗試自己回答。
在這里,我提供了來自pylzma的代碼片段:
類 Archive7z(基礎(chǔ)): def __init__ ( self , file , password = None ): # ... 自我。文件={} # ... 對于信息的文件。文件: #創(chuàng)建一個知道磁盤位置的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(基礎(chǔ)): 定義讀取(自我): # ... 對于水平,編碼器在枚舉(自我。_folder。編碼器): # ... #獲取解碼器并解碼底層數(shù)據(jù) data = getattr ( self , decoder ) ( coder , data , level , num_coders ) 返回數(shù)據(jù)
在代碼中,您可以看到在從存檔中讀取下一個對象期間調(diào)用的方法。我相信從上面可以清楚地看出,只要同時多次讀取存檔,就沒有理由阻止存檔。
接下來,我們快速介紹一下什么是網(wǎng)格和點云。
首先,網(wǎng)格是頂點、邊和面的集合。頂點由空間中的(x,y,z) 坐標定義并分配有唯一編號。邊和面是相應(yīng)的點對和三元組的組,并用提到的唯一點 id 定義。通常,當我們談?wù)摗熬W(wǎng)格”時,我們指的是“三角形網(wǎng)格”,即由三角形組成的表面。使用??trimesh??庫在 Python 中使用網(wǎng)格要容易得多。例如,它提供了一個接口來加載??.obj??內(nèi)存中的文件。要在??jupyter notebook??一個3D 對象中顯示和交互,可以使用??k3d??庫。
所以,用下面的代碼片段我回答這個問題:“你怎么繪制??trimesh???的對象??jupyter???有??k3d???”
進口飾面 導入k3d 使用 open ( w. /data/meshes/stanford-bunny, obj")作為 f : bunny_mesh =網(wǎng)眼。力口載(f , 'obj') 情節(jié)=k3d。情節(jié)() 網(wǎng)格= k3d。網(wǎng)格 (bunny_mesh . vertices> bunny_mesh . faces) 繪圖上網(wǎng)格 情節(jié)。顯示。
其次,點云是表示空間中對象的 3D 點數(shù)組。許多 3D 掃描儀生成點云作為掃描對象的表示。出于演示目的,我們可以讀取相同的網(wǎng)格并將其頂點顯示為點云。
?進口飾面 導入k3d 使用 open ( w. /data/meshes/stanford-bunny, obj")作為 f : bunny_mesh =網(wǎng)眼。力口載(f , 'obj') 情節(jié)=k3d。情節(jié)() 云=k3d。點(bunny_mesh . vertices , point_size = 0. 0001 , shader = "flat") 情節(jié)+=云 情節(jié)。顯示。 ?
?
k3d繪制的點云
如上所述,3D 掃描儀為我們提供了一個點云。假設(shè)我們有一個網(wǎng)格數(shù)據(jù)庫,我們想在我們的數(shù)據(jù)庫中找到一個與掃描對象對齊的網(wǎng)格,也就是點云。為了解決這個問題,我們可以提出一種簡單的方法。我們將從我們的檔案中搜索給定點云的點與每個網(wǎng)格之間的最大距離。如果??1e-4??某些網(wǎng)格的距離更小,我們將認為該網(wǎng)格與點云對齊。
?最后,我們來到了多處理部分。請記住,我們的存檔中有大量文件可能無法放在一起放在內(nèi)存中,因為我們更喜歡并行處理它們。為了實現(xiàn)這一點,我們將使用 ??multiprocessing Pool???,它使用??map???或??imap/imap_unordered???方法處理用戶定義函數(shù)的多次調(diào)用。??map???和??imap???影響我們的區(qū)別在于,??map???在將其發(fā)送到工作進程之前將可迭代對象轉(zhuǎn)換為列表。如果存檔太大而無法寫入 ??RAM???,則不應(yīng)將其解壓縮到 ??Python ??列表中。換句話說,兩者的執(zhí)行速度是相似的。
[加載網(wǎng)格:pool.map w/o manager] 4 個進程的池經(jīng)過時間:37.213207403818764 秒 [加載網(wǎng)格:pool.imap_unordered w/o manager] 4 個進程的池經(jīng)過時間:37.219303369522095 秒
上面您可以看到從適合內(nèi)存的網(wǎng)格檔案中簡單讀取的結(jié)果。
更進一步??imap???:讓我們討論如何實現(xiàn)我們的目標,即找到靠近點云的網(wǎng)格。這是數(shù)據(jù)。我們有 5 種來自斯坦福模型的不同網(wǎng)格。我們將通過向斯坦福兔子網(wǎng)格的頂點添加噪聲來模擬 3D 掃描。
將numpy導入為np A numpy。隨機 導入 defaulting def normalize_pc (點): 點額=點額-點額。平均值(軸=0)[無,:] 分布=np。linalg<>范數(shù)(點,軸=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
當然,我們之前在下面將點云和網(wǎng)格頂點歸一化,以在 3D 立方體中縮放它們。
要計算點云和網(wǎng)格之間的距離,我們將使用??igl??。為了完成,我們需要編寫一個函數(shù)來調(diào)用每個進程及其依賴項。讓我們用下面的代碼片段來總結(jié)一下。
導入迭代工具 導入時間 將 numpy 導入為 np nwnpyo 隨機導入 default rng 面以1 口口如 進進從 A多處理導入池 de£ load_mesh ( obj_file ): 目二 trimesh。力口載(obj_file , ' obj') 返回網(wǎng)格 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 ] 網(wǎng)格二 load_mesh ( obj_file ) 網(wǎng)。頂點=RormaliNe_pc (網(wǎng)格。頂點) max_dist = get_max_dist (網(wǎng)格,點云) 返回 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辱檔))) 池。關(guān)閉0 池。加入o 結(jié)束=時間。時間0 elapsed time o追加(結(jié)束一開始) print ( F [Process meshes: pool, imap] {num_proc}個進程的池經(jīng)過的時間:{np. array (elapsed_time). mean()} sec ) 對于 name , di st in zip ( archive . namesjist , result ): 打印(r{name} {dist}") 返回結(jié)果 如果 _name_ == bunny_path = /data/meshes/stanford-bunny, obj" archive_path = /data/meshes. 7zff nwn_proc = 4 num_iterations = 3 point__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是一個中心函數(shù),其中完成以下操作:??
- MeshesArchive??并??multiprocessing.Pool??初始化
- ??tqdm?? 用于觀察池進度,并手動完成整個池的分析
- 執(zhí)行結(jié)果的輸出
請注意我們?nèi)绾蝹鬟f參數(shù)以??imap???從??archive???和??point_cloud???使用??zip(archive, itertools.repeat(point_cloud))???. 這允許我們將點云數(shù)組粘貼到存檔的每個條目上,避免轉(zhuǎn)換??archive??為列表。
執(zhí)行結(jié)果如下:
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]
[進程網(wǎng)格:pool.imap w/o manager] 4 個進程的池經(jīng)過時間:1.0080536206563313 秒
犰狳.obj 0.16176825266293382
野獸.obj 0.28608649819198073
牛.obj 0.41653845909820164
現(xiàn)貨.obj 0.22739556571296735
stanford-bunny.obj 2.3699851136074263e-05
我們可以注意到斯坦福兔子是最接近給定點云的網(wǎng)格。還可以看出,我們沒有使用大量數(shù)據(jù),但我們已經(jīng)證明,即使我們在存檔中有大量網(wǎng)格,該解決方案也能奏效。
多處理使數(shù)據(jù)科學家不僅在 3D 計算機視覺中而且在機器學習的其他領(lǐng)域中都取得了出色的表現(xiàn)。理解并行執(zhí)行比在循環(huán)內(nèi)執(zhí)行快得多是非常重要的。差異變得顯著,尤其是在正確編寫算法時。大量數(shù)據(jù)揭示了如果沒有關(guān)于如何使用有限資源的創(chuàng)造性方法就無法解決的問題。幸運的是,Python 語言及其廣泛的庫集幫助我們數(shù)據(jù)科學家解決了這些問題。
到此這篇關(guān)于利用Python多處理庫處理3D數(shù)據(jù)詳解的文章就介紹到這了,更多相關(guān)Python處理3D數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python3.6 tkinter實現(xiàn)屏保小程序
這篇文章主要為大家詳細介紹了python3.6 tkinter實現(xiàn)屏保小程序,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-07-07使用Python建立RNN實現(xiàn)二進制加法的示例代碼
這篇文章主要介紹了使用Python建立RNN實現(xiàn)二進制加法的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03使用PyTorch構(gòu)建神經(jīng)網(wǎng)絡(luò)的操作指南
PyTorch 是一個在研究領(lǐng)域廣泛使用的深度學習框架,提供了大量的靈活性和效率,本文將向你介紹如何使用 PyTorch 構(gòu)建你的第一個神經(jīng)網(wǎng)絡(luò),感興趣的小伙伴可以參考閱讀2023-07-07Django Admin后臺添加數(shù)據(jù)庫視圖過程解析
這篇文章主要介紹了Django Admin后臺添加數(shù)據(jù)庫視圖過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-04-04