3D物體分類---ModelNet .OFF格式生成多視角圖像(Blender方法之第二步)
強烈建議使用Blender方法!!!
說明
2 python調用Blender生成多視角圖像
2.1 Blender準備工作
2.2 python代碼實作.off檔案讀取和投影成像
2.3 python和blender聯合使用生成多視角圖像
2.3.1 單個.off檔案生成多視角圖像
2.3.2 資料集txt生成多視角圖像
2.4 最想要的開箱即用代碼
問題彙總:
1.blender版本問題
2. Import blender-off-addon failed
以上是郵件或公衆号裡問我的問題,遇到的頻率還比較多,如果有其他問題我會後續更新,感謝拉坑出來的小夥伴們。
有問題關注公衆号“pytorch了解與實戰”,直接背景留言或評論即可,或發郵件[email protected]
郵件看的頻次有點低,幾天才會看一次,公衆号背景提醒,我看到比較及時。我看到,肯定回複,盡量提供力所能及的幫助!
強烈建議使用Blender方法!!!
- 授人以魚不如授人以漁 -
寫文章的初衷是我在處理ModelNet的.OFF檔案時遇到太多困難,隻為後來的你減少不必要的麻煩,思路和代碼都是我曆經千辛萬苦才摸索出來的,百度很難找到,代碼現已全部上傳至GitHub。需要特别說明的是,代碼不是拿來即用的,你需要仔細按照你自己的路徑修改
說明
回顧一下ModelNet10/40 .OFF檔案生成多視角圖像的方法,我找到的有兩種方法,實際推薦Blender方法!!!
兩種方法具體步驟:
Blender方法
首先要實作Blender對.OFF檔案的讀取與顯示
https://blog.csdn.net/jorg_zhao/article/details/86309774
然後利用python調用Blender完成多視角資料集的生成
https://blog.csdn.net/jorg_zhao/article/details/88345324
Mat方法
首先将.OFF檔案轉為.MAT檔案(可生成不同視角的.MAT)
https://blog.csdn.net/jorg_zhao/article/details/86647696
然後用python将不同視角的.MAT檔案轉為多視角圖檔
https://blog.csdn.net/jorg_zhao/article/details/88345366
2 python調用Blender生成多視角圖像
2.1 Blender準備工作
為了能夠利用python調用blender,我們需要首先在項目檔案夾下用blender生成一個空的模型blend檔案,在此空模型中,需要提前構造出背景、紋理和燈光等,為了友善,我為你們提供了一個空背景模型,燈光設定成了點光源,并分布于各個角落,這樣可以防止讀入模型時,造成模型表面光影變化太大,以免影響後續分類精度。
圖1 為代碼中附上的blender空背景圖像,添加了8個角度上的點光源

圖1檔案名為phong.blend,此檔案可用blender直接打開,除非你對blender很熟悉,不建議你修改此檔案,實測生成的多視角圖像還是很清晰的。
2.2 python代碼實作.off檔案讀取和投影成像
python的代碼直接放出來吧:
import bpy
import os.path
import math
import sys
C = bpy.context
D = bpy.data
scene = D.scenes['Scene']
# cameras: a list of camera positions
# a camera position is defined by two parameters: (theta, phi),
# where we fix the "r" of (r, theta, phi) in spherical coordinate system.
# 5個固定視角:前 右 後 左 上
# cameras = [(60, 0), (60, 90), (60, 180), (60, 270),(0, 0)]
# 連續視角:固定某一個角度,然後環視3D物體,環視角度間隔inter=30度
fixed_view = 60
inter = 30
cameras = [(fixed_view, i) for i in range(0, 360, inter)] # 這會生成360/30=12個視角圖檔
render_setting = scene.render
# 輸出圖像大小 (W, H)
w = 224
h = 224
render_setting.resolution_x = w*2
render_setting.resolution_y = h*2
'''****************************************************************'''
def main():
argv = sys.argv
argv = argv[argv.index('--') + 1:]
if len(argv) != 2:
print('phong.py args: <3d mesh path> <image dir>')
exit(-1)
model_path = argv[0] # 輸入: 單個 .off 或 dataset.txt
image_dir = argv[1] # 輸出: 儲存多視角圖像的路徑
# blender 對.off檔案沒有原生支援,需要安裝插件
install_off_addon()
init_camera()
fix_camera_to_origin()
'''************* 自動判别輸入的是單個off檔案還是資料集txt檔案 *****************'''
if model_path.split('.')[-1] == 'off':
print('model path is ********', model_path) # model_path:'./airplane.off'
do_model(model_path, image_dir)
elif model_path.split('.')[-1] == 'txt':
with open(model_path) as f:
models = f.read().splitlines()
for model in models:
one_model = model[:-2]
print('model path is ********', one_model) # model_path:'F:\DATA3D\ModelNet10\monitor\train\monitor_0003.off'
do_model(one_model, image_dir)
else:
print('......Please input correct parameters......')
exit(-1)
'''****************************************************************'''
def install_off_addon():
try:
bpy.ops.wm.addon_install(
overwrite=False,
filepath=os.path.dirname(__file__) +
'/blender-off-addon/import_off.py'
)
bpy.ops.wm.addon_enable(module='import_off')
except Exception:
print("""Import blender-off-addon failed.
Did you pull the blender-off-addon submodule?
$ git submodule update --recursive --remote
""")
exit(-1)
def init_camera():
cam = D.objects['Camera']
# select the camera object
scene.objects.active = cam
cam.select = True
# set the rendering mode to orthogonal and scale
C.object.data.type = 'ORTHO'
C.object.data.ortho_scale = 2.
def fix_camera_to_origin():
origin_name = 'Origin'
# create origin
try:
origin = D.objects[origin_name]
except KeyError:
bpy.ops.object.empty_add(type='SPHERE')
D.objects['Empty'].name = origin_name
origin = D.objects[origin_name]
origin.location = (0, 0, 0)
cam = D.objects['Camera']
scene.objects.active = cam
cam.select = True
if 'Track To' not in cam.constraints:
bpy.ops.object.constraint_add(type='TRACK_TO')
cam.constraints['Track To'].target = origin
cam.constraints['Track To'].track_axis = 'TRACK_NEGATIVE_Z'
cam.constraints['Track To'].up_axis = 'UP_Y'
def do_model(model_path, image_dir):
# model_path= 'F:\\DATA3D\ModelNet10_MV\\bathtub\\train\\bathtub_0003.off'
# image_dir = 'F:\\DATA3D\\ModelNet10_MV_32_train\\'
name = load_model(model_path) # -> name = 'bathtub_0003'
center_model(name)
normalize_model(name)
image_subdir = os.path.join(image_dir, name.split('_')[0], name) # path: image_dir\\bathtub\\bathtub_0003
for i, c in enumerate(cameras):
move_camera(c)
render()
save(image_subdir, '%s_%d' % (name, i))
delete_model(name)
def load_model(model_path):
# single .off: model_path='./airplane.off'
# dataset.txt: model_path= 'F:\\DATA3D\ModelNet10_MV\\bathtub\\train\\bathtub_0003.off'
d = os.path.dirname(model_path) # invalide for .off file
ext = model_path.split('.')[-1] # ext: 'off'
# Attention! win10: ..path.split('\\') linux: ..path.split('/')
_model_path_tmp = model_path.split('\\')[-1] # _model_path_tmp: 'bathtub_0003.off'
name = os.path.basename(_model_path_tmp).split('.')[0] # bathtub_0003
# handle weird object naming by Blender for stl files
if ext == 'stl':
name = name.title().replace('_', ' ')
if name not in D.objects:
print('loading :' + name)
if ext == 'stl':
bpy.ops.import_mesh.stl(filepath=model_path, directory=d,
filter_glob='*.stl')
elif ext == 'off':
bpy.ops.import_mesh.off(filepath=model_path, filter_glob='*.off')
elif ext == 'obj':
bpy.ops.import_scene.obj(filepath=model_path, filter_glob='*.obj')
else:
print('Currently .{} file type is not supported.'.format(ext))
exit(-1)
return name # name='airplane' -> 'bathtub_0003'
def delete_model(name):
for ob in scene.objects:
if ob.type == 'MESH' and ob.name.startswith(name):
ob.select = True
else:
ob.select = False
bpy.ops.object.delete()
def center_model(name):
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN')
D.objects[name].location = (0, 0, 0)
def normalize_model(name):
obj = D.objects[name]
dim = obj.dimensions
print('original dim:' + str(dim))
if max(dim) > 0:
dim = dim / max(dim)
obj.dimensions = dim
print('new dim:' + str(dim))
def move_camera(coord):
def deg2rad(deg):
return deg * math.pi / 180.
r = 3.
theta, phi = deg2rad(coord[0]), deg2rad(coord[1])
loc_x = r * math.sin(theta) * math.cos(phi)
loc_y = r * math.sin(theta) * math.sin(phi)
loc_z = r * math.cos(theta)
D.objects['Camera'].location = (loc_x, loc_y, loc_z)
def render():
bpy.ops.render.render()
def save(image_dir, name):
path = os.path.join(image_dir, name + '.png')
D.images['Render Result'].save_render(filepath=path)
print('save to ' + path)
if __name__ == '__main__':
main()
代碼需要你關注的地方 我都已經加了注釋,其餘部分基本不需要你修改,并且我直接加了對輸入的判斷,盡可能減少你們的工作量。
!!!!!!!!!!!!上述代碼不能直接運作!!!!!!!!!!!!
2.3 python和blender聯合使用生成多視角圖像
我之前在寫第一篇blender方法之第一步的時候,是在ubuntu系統上實作的,但是後續我就換到了win10上,是以第一篇我沒有添加win10上的安裝和設定步驟,一沒時間二是步驟基本相同,但是接下來的步驟就要有所不同了,仔細聽我慢慢道來。為了兩個系統我是煞費苦心啊。。。。。
代碼我整理合成了兩種方法:
一種是輸入單個off檔案生成多視角圖像,主要是為了讓你友善調整參數,測試你想要的結果,這也是我最開始操作的方法;
一種是直接輸入dataset.txt檔案,代碼會一次性把資料集全部生成多視角圖像,為了保險起見,強烈建議您先使用單個off檔案輸入方法确定是您想要的結果,再對整個資料集進行處理。
指令行執行說明:
<blender安裝路徑> phong.blend --background --python phong.py -- <輸入off路徑> <輸出儲存多視角圖像路徑>
1
需要注意不同系統,第一個blender的差異,我最開始就蛋疼在這一步! 下面逐一說明具體使用方法。
2.3.1 單個.off檔案生成多視角圖像
ubuntu系統
blender phong.blend --background --python phong.py -- ./single_off_samples/airplane_0001.off ./single_samples_MV
win10系統
"C:\\Program Files\\Blender Foundation\\Blender\\blender.exe" phong.blend --background --python phong.py -- .\\single_off_samples\\airplane_0001.off .\\single_samples_MV
2.3.2 資料集txt生成多視角圖像
ubuntu系統
blender phong.blend --background --python phong.py -- dataset.txt ./dataset_samples_MV
win10系統
"C:\\Program Files\\Blender Foundation\\Blender\\blender.exe" phong.blend --background --python phong.py -- dataset.txt .\\dataset_samples_MV
為了友善你們運作代碼,我上傳代碼同時也上傳了單個off檔案,并且也制作了一個很小的資料集
2.4 最想要的開箱即用代碼
代碼全部上傳至GitHub,包括開箱即用源碼和資料集,代碼可直接使用。
https://github.com/zeaggler/ModelNet_Blender_OFF2Multiview
使用步驟如下:
檔案夾下打開指令行,方法有很多,我為了友善直接右鍵打開了以示說明
指令行中輸入單個off檔案指令
執行過程類似下圖
生成的多視角圖像如下,設定角度間隔為30,是以一共擷取360/30=12個視角的圖像
===========================我是一條分割線===========================
1
問題彙總:
1.blender版本問題
我在文中所用版本為blender v2.79b,其他版本并未測試,如果有網友看到,有用v2.8x版本成功的可以留言确認一下,謝謝了。
blender v2.79b版本下載下傳位址:
https://download.blender.org/release/Blender2.79/blender-2.79b-windows64.zip
其餘os位址可以在下面位址自己查找:
https://download.blender.org/release/Blender2.79/
2. Import blender-off-addon failed
這個問題暫時不知道是什麼原因,在看我解決辦法之前,一定要確定按照我的步驟全部走完了,不然您改了代碼後,還會出現其他問題。
如果addon安裝成功,仍然出現“did you pull the xxxx”,可以注釋phong.py中的下圖這行代碼,跳過錯誤提示即可。
————————————————
版權聲明:本文為CSDN部落客「柚有所思」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/jorg_zhao/article/details/88345324