16 changed files with 634 additions and 91 deletions
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
<Configuration id="{2D5793BC-A65D-4318-A1B9-A05044608385}"> |
||||
<entry key="MvsExportIsGeoreferenced" value="0x0"/> |
||||
<entry key="MvsExportMoveX" value="0.0"/> |
||||
<entry key="MvsExportMoveY" value="0.0"/> |
||||
<entry key="MvsExportMoveZ" value="0.0"/> |
||||
<entry key="MvsExportScaleX" value="1.0"/> |
||||
<entry key="calexFileFormat" value="Internal/External camera parameters"/> |
||||
<entry key="calexExportSettingsVisible" value="1"/> |
||||
<entry key="MvsExportScaleY" value="1.0"/> |
||||
<entry key="calexHasDisabled" value="0x0"/> |
||||
<entry key="MvsExportScaleZ" value="1.0"/> |
||||
<entry key="calexHasUndistort" value="0x0"/> |
||||
<entry key="MvsExportIsModelCoordinates" value="0"/> |
||||
</Configuration> |
||||
@ -0,0 +1,149 @@
@@ -0,0 +1,149 @@
|
||||
import bpy |
||||
import bmesh |
||||
|
||||
|
||||
def active_object(obj): |
||||
bpy.context.view_layer.objects.active = obj |
||||
obj.select_set(True) |
||||
|
||||
|
||||
def get_obj_max_foot(workdir,filename,filename_tex): |
||||
# 1.模型导入和初始化 |
||||
# 删除当前场景中的所有对象: |
||||
# use_global=False表示只删除当前场景中的对象,而不会影响到其他场景中的对象;confirm=False表示删除时不需要确认。 |
||||
bpy.ops.object.delete(use_global=False, confirm=False) |
||||
bpy.ops.import_scene.obj(filepath=filename) # 导入指定路径的 OBJ 格式模型文件 |
||||
|
||||
bpy.context.scene.unit_settings.scale_length = 0.001 # 将场景的长度单位缩放为0.001,相当于将长度单位从默认的米缩小为毫米 |
||||
bpy.context.scene.unit_settings.length_unit = 'CENTIMETERS' # 将场景的长度单位设置为厘米 |
||||
bpy.context.scene.unit_settings.mass_unit = 'GRAMS' # 将场景的质量单位设置为克 |
||||
|
||||
obj = bpy.context.selected_objects[0] # 获取了当前选中的对象列表,然后通过 [0] 取得列表中的第一个对象 |
||||
bpy.context.view_layer.objects.active = obj # 将变量 obj 设置为当前活动对象 |
||||
obj.select_set(True) # 将变量 obj 的选择状态设置为 True,表示选中该对象 |
||||
pid = obj.name # 获取该对象的名字 |
||||
|
||||
# 对选定的对象进行对齐操作 |
||||
bpy.ops.object.align(align_mode='OPT_1', relative_to='OPT_1', align_axis={'Z'}) |
||||
# 设置选中对象的原点,参数1:将原点设置为对象的质心,参数2:使用对象的几何中心作为参考 |
||||
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN') |
||||
# 将选中对象的位置坐标分别设置为 (0, 0),即将对象移动到世界坐标系的原点位置 |
||||
obj.location[0] = 0 |
||||
obj.location[1] = 0 |
||||
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) # 将选中对象的位置、旋转和缩放应用到对象的数据中 |
||||
|
||||
# 2.选择要复制的对象 |
||||
obj_duplicate = obj.copy() |
||||
obj_duplicate.data = obj.data.copy() |
||||
bpy.context.collection.objects.link(obj_duplicate) |
||||
# obj_duplicate.location.x += 5.0 |
||||
bpy.ops.object.select_all(action='DESELECT') # 取消选中全部对象 |
||||
|
||||
# 3.处理复制的对象的脚底缝合边 |
||||
# 选中复制对象 |
||||
bpy.context.view_layer.objects.active = obj_duplicate |
||||
obj_duplicate.select_set(True) |
||||
|
||||
selected_obj = bpy.context.active_object # 获取当前选中的对象 |
||||
bpy.context.view_layer.objects.active = selected_obj # 将对象转换到编辑模式 |
||||
|
||||
# 切换到3D视图编辑模式 |
||||
bpy.context.area.type = 'VIEW_3D' |
||||
bpy.ops.object.mode_set(mode='EDIT') |
||||
bpy.ops.mesh.select_all(action='SELECT') # 选择所有的边 |
||||
|
||||
# 切换到UV编辑器 |
||||
bpy.context.area.type = 'IMAGE_EDITOR' |
||||
pid_img = f"{pid}Tex1.jpg" |
||||
bpy.ops.image.open(filepath=filename_tex, directory=workdir, |
||||
files=[{"name": pid_img, "name": pid_img}], relative_path=True, |
||||
show_multiview=False) |
||||
bpy.context.area.ui_type = 'UV' |
||||
bpy.ops.uv.select_all(action='SELECT') # 选择所有UV贴图顶点 |
||||
# 标记所有沿孤岛的边为缝合边 |
||||
bpy.ops.uv.seams_from_islands() |
||||
bpy.context.area.type = 'VIEW_3D' |
||||
bpy.ops.object.mode_set(mode='OBJECT') |
||||
|
||||
# 获取世界坐标系下z轴接近0的顶点的索引 |
||||
z_zero_vertex_indices = [] |
||||
for i, vertex in enumerate(selected_obj.data.vertices): |
||||
world_vertex = selected_obj.matrix_world @ vertex.co |
||||
if abs(world_vertex.z) < 0.2: |
||||
z_zero_vertex_indices.append(i) |
||||
# 将对象转换回对象模式 |
||||
bpy.ops.object.mode_set(mode='OBJECT') |
||||
# 创建一个新的顶点组,并将z_zero_vertices中的顶点添加到该顶点组中 |
||||
vg = selected_obj.vertex_groups.new(name="z_zero_vertices") |
||||
for index in z_zero_vertex_indices: |
||||
vg.add([index], 1.0, 'REPLACE') |
||||
# 将选中的顶点设置为活动顶点 |
||||
bpy.ops.object.mode_set(mode='EDIT') |
||||
bpy.ops.mesh.select_all(action='DESELECT') |
||||
bpy.ops.object.vertex_group_select() # 选中待处理的顶点 |
||||
bpy.ops.mesh.mark_seam(clear=True) # 取消所选区域内的缝合边 |
||||
bpy.ops.mesh.region_to_loop() # 选择选定面周围的边界边!!! |
||||
bpy.ops.mesh.select_mode(type="EDGE") # 转换为线模式 |
||||
bpy.ops.mesh.mark_seam(clear=False) # 标记所选的线为缝合边 |
||||
|
||||
# 选中脚底顶点组 |
||||
bpy.ops.uv.select_all(action='DESELECT') |
||||
bpy.ops.object.vertex_group_set_active(group='z_zero_vertices') # 设置活动顶点组 |
||||
bpy.ops.object.vertex_group_select() # 选择分配给活动顶点组的所有顶点 |
||||
bpy.ops.uv.unwrap() |
||||
|
||||
# 处理贴图脚底部分孤岛,其他孤岛保持不变 |
||||
# (1)反选模型顶点,方便贴图固定不需要处理的区域 |
||||
bpy.ops.mesh.select_all(action='INVERT') |
||||
bpy.context.area.type = 'IMAGE_EDITOR' # 切换到贴图模式 |
||||
bpy.context.area.ui_type = 'UV' |
||||
bpy.ops.uv.pin(clear=False) |
||||
bpy.ops.object.vertex_group_set_active(group='z_zero_vertices') # 设置活动顶点组 |
||||
bpy.ops.object.vertex_group_select() # 选择分配给活动顶点组的所有顶点 |
||||
# (2)脚底部位UV展开,平均孤岛比例,重新排列孤岛 |
||||
bpy.ops.uv.select_all(action='SELECT') |
||||
bpy.ops.uv.average_islands_scale() |
||||
bpy.ops.uv.pack_islands(margin=0.001) |
||||
|
||||
bpy.context.area.type = 'VIEW_3D' |
||||
bpy.ops.object.mode_set(mode='OBJECT') |
||||
|
||||
# 4. 烘焙模式,参数设置 |
||||
bpy.ops.object.select_all(action='DESELECT') # 取消选中全部对象 |
||||
# # 选中原始对象 |
||||
bpy.context.view_layer.objects.active = obj |
||||
obj.select_set(True) |
||||
# 选中复制对象 |
||||
bpy.context.view_layer.objects.active = obj_duplicate |
||||
obj_duplicate.select_set(True) |
||||
bpy.context.scene.render.engine = 'CYCLES' |
||||
bpy.context.scene.cycles.device = 'GPU' |
||||
bpy.context.scene.cycles.preview_samples = 1 |
||||
bpy.context.scene.cycles.samples = 1 |
||||
bpy.context.scene.cycles.bake_type = 'DIFFUSE' |
||||
bpy.context.scene.render.bake.use_pass_direct = False |
||||
bpy.context.scene.render.bake.use_pass_indirect = False |
||||
bpy.context.scene.render.bake.use_selected_to_active = True |
||||
bpy.context.scene.render.bake.cage_extrusion = 0.01 |
||||
bpy.ops.object.bake(type='DIFFUSE') # 开始 Bake |
||||
|
||||
# 5. 导出模型和贴图 |
||||
bpy.ops.object.select_all(action='DESELECT') # 取消选中全部对象 |
||||
# 选中复制对象 |
||||
bpy.context.view_layer.objects.active = obj_duplicate |
||||
obj_duplicate.select_set(True) |
||||
bpy.ops.wm.obj_export(filepath=filename, export_selected_objects=True) |
||||
bpy.context.area.type = 'IMAGE_EDITOR' # 切换到 |
||||
bpy.ops.image.save_as(filepath=filename_tex) |
||||
bpy.context.area.type = 'TEXT_EDITOR' # 切换到文本编辑器 |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
workdir = 'E:\\117080\\print_model' |
||||
# filename = f'{workdir}\\117080_12cm_x1.obj' |
||||
filename = f'{workdir}\\117080.obj' |
||||
filename_tex = f'{workdir}\\117080Tex1.jpg' |
||||
save_obj = f"{workdir}\\bake\\117080Tex1.obj" |
||||
save_tex = f"{workdir}\\bake\\117080Tex1.jpg" |
||||
|
||||
get_obj_max_foot() |
||||
@ -0,0 +1,147 @@
@@ -0,0 +1,147 @@
|
||||
import os, sys, time, shlex, subprocess, shutil, requests, cv2, numpy as np |
||||
from PIL import Image |
||||
import platform |
||||
if platform.system() == 'Windows': |
||||
sys.path.append('e:\\libs\\') |
||||
#sys.path.append('libs') |
||||
else: |
||||
sys.path.append('/data/deploy/make3d/make2/libs/') |
||||
import config, libs, libs_db,main_service_db |
||||
# 2. 手动操作建模做成建模 |
||||
# 2.0 检测是否存在项目,不存在就下载,存在就清除项目其它无用的文件 |
||||
# 2.1 初始化工程, 根据参数 加入 photo1 或者 photo 2 的 照片, 对齐 , 导出坐标, 将坐标复制到 另外一个文件夹, 测距, 重建区域, 然后调用step2 |
||||
|
||||
#根据pid 检测是否存在项目,不存在就下载,存在就清除项目其它无用的文件 |
||||
def check_pid_file(pid): |
||||
#检测是否存在目录 |
||||
path = os.path.join(config.workdir, pid) |
||||
if not os.path.exists(path): |
||||
#不存在就在就下载目录 |
||||
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 开始计算相机位姿...') |
||||
start_time = time.time() |
||||
libs.down_from_oss(config.oss_bucket, config.workdir, pid,100,"2") |
||||
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} 图片下载完成,共费时{libs.diff_time(start_time)}') |
||||
else: |
||||
#存在的话就检测是否有photo1 和 photo2 之外的目录或者文件,有的话就删除 |
||||
for file in os.listdir(path): |
||||
if file != 'photo1' and file != 'photo2': |
||||
if os.path.isfile(os.path.join(path, file)): |
||||
os.remove(os.path.join(path, file)) |
||||
else: |
||||
shutil.rmtree(os.path.join(path, file)) |
||||
|
||||
#判断photo1 和 photo2 目录里的文件是否存在xmp 文件,存在的话就删除 |
||||
for file in os.listdir(os.path.join(path, 'photo1')): |
||||
if file.endswith('.xmp'): |
||||
os.remove(os.path.join(path, 'photo1', file)) |
||||
|
||||
for file in os.listdir(os.path.join(path, 'photo2')): |
||||
if file.endswith('.xmp'): |
||||
os.remove(os.path.join(path, 'photo2', file)) |
||||
|
||||
|
||||
#根据参数初始化操作 |
||||
def cmd_run(pid,usePhoto = "2",lock=False): |
||||
pid = str(pid) |
||||
#检测文件并且下载处理文件 |
||||
check_pid_file(pid) |
||||
|
||||
start_time = time.time() |
||||
#文件路径 |
||||
#photo1_path = os.path.join(config.workdir, pid, 'photo1') |
||||
photo2_path = os.path.join(config.workdir, pid, 'photo2') |
||||
#计算文件里的数量 |
||||
#photos1_count = len(os.listdir(photo1_path)) |
||||
photos2_count = len(os.listdir(photo2_path)) |
||||
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} photo2数量{photos2_count}') |
||||
|
||||
#xmp 坐标是要用 lock的 还是 unlock 的 |
||||
if lock: |
||||
exportxmp = ' -exportXMP "D:\\make2\\config\\exportXMP.config.lock.xml" ' |
||||
else: |
||||
exportxmp = ' -exportXMP "D:\\make2\\config\\exportXMP.config.xml" ' |
||||
|
||||
usePhoto = "photo"+str(usePhoto) |
||||
|
||||
#执行命令 |
||||
cmd = f'{config.rcbin} {config.r2["init"]} -setInstanceName "{pid}" \ |
||||
-save "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" \ |
||||
-addFolder "{os.path.join(config.workdir, pid, usePhoto)}" -selectAllImages \ |
||||
-detectMarkers "D:\\make2\\config\\detectMarkers.config.xml" \ |
||||
-align -align \ |
||||
{exportxmp} \ |
||||
-save "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" -quit' |
||||
print(cmd) |
||||
cmd = shlex.split(cmd) |
||||
res = subprocess.run(cmd) |
||||
|
||||
#根据参数转变路劲,复制photo1 里的xmp 文件到 photo2 里,或者 photo2 里的xmp 文件到 photo1 里 |
||||
# sourceFile = photo1_path |
||||
targetFile = photo2_path |
||||
# if usePhoto == "photo2": |
||||
# sourceFile = photo2_path |
||||
# targetFile = photo1_path |
||||
# #复制xmp文件 |
||||
# for xmp in os.listdir(sourceFile): |
||||
# if xmp.endswith('.xmp'): |
||||
# if usePhoto == "photo1": |
||||
# shutil.copy(os.path.join(sourceFile, xmp), os.path.join(targetFile,xmp.replace('_1.xmp', '_8.xmp'))) |
||||
|
||||
# if usePhoto == "photo2": |
||||
# shutil.copy(os.path.join(sourceFile, xmp), os.path.join(targetFile,xmp.replace('_8.xmp', '_1.xmp'))) |
||||
|
||||
#如果是photo2的话,就要将photo2 的 xmp 重命名成 _8.xmp |
||||
# if usePhoto == "photo2": |
||||
# for xmp in os.listdir(sourceFile): |
||||
# if xmp.endswith('.xmp'): |
||||
# #重名名.xmp 结尾的文件 |
||||
# os.rename(os.path.join(sourceFile, xmp), os.path.join(sourceFile,xmp.replace('_1.xmp', '_8.xmp'))) |
||||
# print("坐标复制完成") |
||||
# exit() |
||||
|
||||
#将两组图片进行重新对齐 然后重建区域 |
||||
psid = libs.getPSid(pid) |
||||
cmd = f'{config.rcbin} -setInstanceName {pid} \ |
||||
-load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}"\ |
||||
-detectMarkers "D:\\make2\\config\\detectMarkers.config.xml" \ |
||||
{libs.get_defineDistances(psid)} -update -align -align -align -align -align -align {config.r2["setRegion"]} \ |
||||
{exportxmp} \ |
||||
-exportReconstructionRegion "{os.path.join(config.workdir, pid, f"{pid}.rcbox")}" \ |
||||
-selectImage "{os.path.join(config.workdir,pid,"photo2")}/*" -enableTexturingAndColoring true \ |
||||
-save "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" -quit' |
||||
|
||||
|
||||
|
||||
|
||||
print(cmd) |
||||
cmd = shlex.split(cmd) |
||||
res = subprocess.run(cmd) |
||||
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} step1完成,共费时{libs.diff_time(start_time)}') |
||||
|
||||
#调用step2 |
||||
time.sleep(2) |
||||
os.system(f'python main_step2.py {pid}') |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
if len(sys.argv) == 2: |
||||
pids = sys.argv[1].split(',') |
||||
for pid in pids: |
||||
cmd_run(pid,usePhoto = "1",lock=False) |
||||
elif len(sys.argv) == 3: |
||||
pids = sys.argv[1].split(',') |
||||
for pid in pids: |
||||
if sys.argv[2] == '2': |
||||
cmd_run(pid,usePhoto = "2",lock=False) |
||||
else: |
||||
cmd_run(pid,usePhoto = "1",lock=False) |
||||
elif len(sys.argv) == 4: |
||||
pids = sys.argv[1].split(',') |
||||
usePhoto = sys.argv[2] |
||||
lock = sys.argv[3] |
||||
for pid in pids: |
||||
cmd_run(pid,usePhoto = usePhoto,lock=lock) |
||||
|
||||
else: |
||||
print(f'useage: python {sys.argv[0]} pid1,pid2,pid3 photo = 1/2 lock = True/False') |
||||
sys.exit(1) |
||||
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
|
||||
#建模完成,需要减面 smooth 封闭洞 清理模型 贴图 |
||||
%bin% -delegateTo %pid% -simplify 3000000 -smooth -closeHoles -cleanModel -calculateTexture -save "D:\123446\123446.rcproj" -exportSelectedModel "D:\123446\output\123446.obj" "d:\make2\config\ModelExportParams.xml" -quit |
||||
Loading…
Reference in new issue