Browse Source

新的信息

master
dongchangxi 1 year ago
parent
commit
345790cb05
  1. BIN
      export_build_info/__pycache__/export_already_build.cpython-310.pyc
  2. 0
      export_build_info/already.txt
  3. 125
      export_build_info/check.py
  4. 26
      export_build_info/depth_mask_config.xml
  5. 0
      export_build_info/err.pid
  6. 206
      export_build_info/export_already_build.py
  7. 90
      export_build_info/finish.txt
  8. 0
      export_build_info/finished.txt
  9. 124
      export_build_info/gen_xmps_for_build_info.py
  10. 340
      export_build_info/main_step1.py
  11. 267
      export_build_info/main_step2.py
  12. 185
      export_build_info/manual_service.py
  13. 27
      export_build_info/pids/人物.txt
  14. 28
      export_build_info/pids/动物.txt
  15. 393
      export_build_info/pids/单人.txt
  16. 307
      export_build_info/pids/双人.txt
  17. 28
      export_build_info/pids/多人.txt
  18. 42
      export_build_info/registration_export_config.xml
  19. 0
      export_build_info/task_distributed_error.log
  20. 13
      install.txt
  21. 11
      libs/config.py
  22. 48
      libs/libs.py
  23. 83
      libs/libs_db_repeat_texture.py
  24. 30
      libs/libs_db_task_rc.py
  25. 101
      main_repeat_texture.py
  26. 6
      main_step1.py
  27. 13
      main_step2.py
  28. 16
      main_step3.py
  29. 6
      manual_service.py
  30. 4
      manual_single.py
  31. 499
      pid.text
  32. 5
      step.text
  33. 1028
      suwa_cut_foot_cut_normal_data.txt
  34. BIN
      task_distributed_error.log
  35. 29
      test.py
  36. 4
      timer/check_task.py
  37. 74
      timer/get_weight_to_update.py
  38. 8
      timer/init_timer.py
  39. 22
      timer/setup_oem_exe.py
  40. 102
      tools/base_data_fix.py
  41. 36
      tools/cal_weight.py
  42. 43
      tools/get_weight_by_pid.py
  43. 6
      tools/optimize_model/README.txt
  44. 381
      tools/optimize_model/libs.py
  45. 31
      tools/optimize_model/main.py
  46. 244
      tools/optimize_model/optimize_model.py
  47. 5
      tools/optimize_model/requirements.txt
  48. 78
      tools/optimize_model/run.py
  49. 22
      tools/optimize_model/test.py
  50. 55
      tools/push_cmd.py
  51. 41
      建模碎片步骤.txt

BIN
export_build_info/__pycache__/export_already_build.cpython-310.pyc

Binary file not shown.

0
export_build_info/already.txt

125
export_build_info/check.py

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
import os, sys, time, shlex, subprocess, shutil, requests, cv2, numpy as np
from PIL import Image
import platform,socket,atexit
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,common
arrPids = [184219,184215,184209,184206,184201,184199,184164,184087,184076,184069,184059,184029,184013,183993,183952,183888,183882,183868,183824,183817,183815,183812,183791,183777,183715,183705,183670,183613,183573,182974,182983,182985,182989,182997,183007,183051,183060,183054,183053,183097,183119,183108,183139,183141,183155,183163,183169,183180,183191,183196,183214,183244,183266,183278,183275,183309,183402,183422,183440,182974,182964,182958,182956,182916,182855,182854,182820,182787,182800,182809,182780,182772,182770,182766,182754,182742,182740,182723,182707,182647,182643,182614,182595,182563,182557,182547,182546,182538,182530,182517,182498,182478,182452,182386,182352,182285,182266,182260,182230,182224]
r12Pids = [184219,184215,184209,184069,184059,183868,183817,183791,183613,183573,182974,182983,182985,182989,182997,183007,183051,183060,183054,183053,183097,183119,183108,183139,183141,183155,183163,183169,183180,183191,183196,183214,183244,183266,183278,183275,183309,183402,183422,183440,182974,182964,182958,182855,182854]
print(f"处理的数据长度--{len(arrPids)}")
i=0
noPids = ''
for pid in r12Pids:
pid = str(pid)
path = f"D://{pid}/mask"
#判断是否存在文件夹
if not os.path.exists(path):
continue
#判断文件夹是否为空
if len(os.listdir(path)) == 0:
continue
i+=1
#检查 depth 和 mask 的文件创建时间是否差异比较大
fileDepth = f"D://{pid}/depth"
fileMask = f"D://{pid}/mask"
diffDepthTime = []
dfffMaskTime = []
arrTimeDepth = []
arrTimeMask = []
for file in os.listdir(fileDepth):
createTime = os.path.getctime(f"{fileDepth}/{file}")
updateTime = os.path.getmtime(f"{fileDepth}/{file}")
# print(updateTime - createTime)
diffDepthTime.append(updateTime - createTime)
arrTimeDepth.append(os.path.getctime(f"{fileDepth}/{file}"))
for file in os.listdir(fileMask):
createTime = os.path.getctime(f"{fileMask}/{file}")
updateTime = os.path.getmtime(f"{fileMask}/{file}")
dfffMaskTime.append(updateTime - createTime)
arrTimeMask.append(os.path.getctime(f"{fileMask}/{file}"))
#打印出 两者的 最大 和最小的时间信息
print(f"pid: {pid} depth: { (max(arrTimeDepth) - min(arrTimeDepth))/60 }, diffdepth: {max(diffDepthTime)}, mask: { (max(arrTimeMask) - min(arrTimeMask))/60},diffmask: {max(dfffMaskTime)}")
# print(f"pid: {pid} diffdepth: {max(arrTimeDepth)} diffmask: {max(arrTimeMask)}")
diffDepth = (max(arrTimeDepth) - min(arrTimeDepth))/60
diffMask = (max(arrTimeMask) - min(arrTimeMask))/60
if diffDepth > 5 or diffMask > 5:
print(f"异常数据 pid: {pid} depth: {diffDepth} mask: {diffMask}")
break
#复制文件到指定目录
maskPath = f"D://{pid}/mask"
depthPath = f"D://{pid}/depth"
regPath = f"D://{pid}/reg"
imageList = f"D://{pid}/{pid}_imageList.txt"
outFila = f"D://{pid}/reg/{pid}_registration.out"
sourcePath = f"D://model_info/{pid}"
if os.path.exists(sourcePath):
shutil.rmtree(sourcePath)
if not os.path.exists(sourcePath):
os.makedirs(sourcePath)
#复制文件
shutil.copytree(maskPath, f"D://model_info/{pid}/mask")
shutil.copytree(depthPath, f"D://model_info/{pid}/depth")
shutil.copy(imageList, f"D://model_info/{pid}/{pid}_imageList.txt")
shutil.copy(outFila, f"D://model_info/{pid}/{pid}_registration.out")
#遍历reg文件夹
for file in os.listdir(regPath):
if file == f"{pid}_registration.out":
continue
if "_1.jpg" in file:
sourceTempPath = f"D://model_info/{pid}/reg/photo1"
if not os.path.exists(sourceTempPath):
os.makedirs(sourceTempPath)
shutil.copy(f"{regPath}/{file}", f"{sourceTempPath}/{file}")
if "_8.jpg" in file:
sourceTempPath = f"D://model_info/{pid}/reg/photo2"
if not os.path.exists(sourceTempPath):
os.makedirs(sourceTempPath)
shutil.copy(f"{regPath}/{file}", f"{sourceTempPath}/{file}")
#shutil.copy(f"{regPath}/{file}", f"D://model_info/{pid}/reg/{file}")
#移除 reg 里的 {pid}_registration.out
print(f"处理完成 pid: {pid}")
# shutil.copytree(f"D://{pid}", f"D://{pid}_bak")
# cmd = f'{config.rcbin} {config.r2["init"]} -setInstanceName {pid} \
# -load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}"'# -quit
# print(cmd)
# cmd = shlex.split(cmd)
# res = subprocess.run(cmd)
#print(i)

26
export_build_info/depth_mask_config.xml

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
<Configuration id="{2D5793BC-A65D-4318-A1B9-A05044608385}">
<entry key="eiExportImageList" value="true"/>
<entry key="eiNearPlaneDistance" value="0.0"/>
<entry key="calexUndistResMode" value="2"/>
<entry key="calexUndistPrincipal" value="true"/>
<entry key="calexTrans" value="0"/>
<entry key="eiExportFileNaming" value="5"/>
<entry key="calexHasDisabled" value="0x0"/>
<entry key="eiExportMasks" value="true"/>
<entry key="calexRequiresUndistortPrincipal" value="0x0"/>
<entry key="calexRequiresEqualResolution" value="0x0"/>
<entry key="calexDownscale" value="0x1"/>
<entry key="calexUndistMaxPixels" value="-1"/>
<entry key="eiExportImageListFileName" value="imageList.txt"/>
<entry key="calexUndistFitMode" value="2"/>
<entry key="eiFarPlaneDistance" value="1000000.0"/>
<entry key="hasCalexFilePath" value="1"/>
<entry key="calexHasUndistort" value="0"/>
<entry key="calexFileFormat" value="Export Depth and Mask Images"/>
<entry key="calexExportUndistorted" value="true"/>
<entry key="calexFileFormatId" value="{0ABB46B2-4FAA-4CE1-AA39-D96128D39BD9}"/>
<entry key="hasCalexFileName" value="0"/>
<entry key="calexUndistCutOut" value="1.0"/>
<entry key="calexHasImageExport" value="-1"/>
<entry key="eiExportDepths" value="true"/>
</Configuration>

0
export_build_info/err.pid

206
export_build_info/export_already_build.py

@ -0,0 +1,206 @@ @@ -0,0 +1,206 @@
import os, sys, shutil, subprocess, shlex,oss2,requests
sys.path.append('e:\\libs\\')
import config
import xml.etree.ElementTree as ET
import common
def is_already(pid):
if not os.path.exists("D://make2/export_build_info/finished.txt"):
#创建文件
with open("D://make2/export_build_info/finished.txt", 'w') as f:
f.write("")
return False
#读取已经完成的pid
with open("D://make2/export_build_info/finished.txt", 'r') as f:
lines = f.readlines()
for line in lines:
if str(pid) == str(line.strip()):
return True
return False
def writeImageList(pid):
# pid = "185005"
imageListTxt = f"D://{pid}/{pid}_imageList.txt"
if not os.path.exists(imageListTxt):
with open(imageListTxt, 'w') as f:
f.write("")
filePath = f"D://{pid}//{pid}.rcproj"
tree = ET.parse(filePath)
root = tree.getroot()
fileName = []
for input_tag in root.findall(".//input"):
tempFileName = input_tag.get("fileName")
if tempFileName:
fileName.append(tempFileName)
sourceFileNames = []
for sourceFile in fileName:
tempSourceName = sourceFile.replace(f"D:\{pid}\photo1\\","")
tempSourceName = tempSourceName.replace(f"D:\{pid}\photo2\\","")
print("tempSourceName",tempSourceName)
#遍历指定的文件减价
for file in os.listdir(f"D://{pid}/depthAndMask"):
if ".jpg.depth.exr" not in file:
continue
#截取图片名称
tempName = file.replace(".depth.exr","")
if tempName == tempSourceName:
#sourceFileNames.append(sourceFile)
#写入到文件中
print(f"写入到文件-{sourceFile}")
with open(imageListTxt, 'a+') as f:
f.write(f"{sourceFile}\n")
def exportInfo(pid):
newCopyFilePath = f"D://{pid}/{pid}.rcproj"
#判断是否存在目录,不存在则创建
depthMaskPath = f"D://{pid}/depthAndMask"
#删除文件夹
try:
shutil.rmtree(depthMaskPath)
except Exception as e:
print(e)
if not os.path.exists(f"D://{pid}/depthAndMask"):
os.makedirs(f"D://{pid}/depthAndMask")
imageListTxt = f"D://{pid}/{pid}_imageList.txt"
try:
os.remove(imageListTxt)
except Exception as e:
print(e)
if not os.path.exists(imageListTxt):
with open(imageListTxt, 'w') as f:
f.write("")
maskPath = f"D://{pid}/mask"
try:
shutil.rmtree(maskPath)
except Exception as e:
print(f"删除文件夹失败{e}")
if not os.path.exists(f"D://{pid}/mask"):
os.makedirs(f"D://{pid}/mask")
depthPath = f"D://{pid}/depth"
try:
shutil.rmtree(depthPath)
except Exception as e:
print(e)
if not os.path.exists(f"D://{pid}/depth"):
os.makedirs(f"D://{pid}/depth")
registrationPath = f"D://{pid}/reg"
try:
shutil.rmtree(registrationPath)
except Exception as e:
print(e)
if not os.path.exists(registrationPath):
os.makedirs(registrationPath)
#如果存在则执行打开命令
cmd = f'{config.rcbin} {config.r2["init"]} -setInstanceName {pid} -load "{newCopyFilePath}" -exportRegistration "D://{pid}/reg/{pid}_registration.out" "D://make2/config/registration_export_config.xml" -exportDepthAndMask "D://{pid}/depthAndMask" "D://make2/config/depth_mask_config.xml" -quit'
# print(cmd)
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
writeImageList(pid)
#删除掉 depthMaskPath 里 文件名 包含 _1. 的文件
for file in os.listdir(depthMaskPath):
#将遍历出来的文件名进行判断,如果是_8.jpg.mask _1.jpg.mask 写入到pid_imgList.txt中
# if "_8.jpg.mask" in file:
# jpgPath = f"D://{pid}/photo2/"+file.replace(".mask", "")
# jpgPath = jpgPath.replace(".png", "")
# print("_8",jpgPath)
# with open(imageListTxt, 'a+') as f:
# f.write(f"{jpgPath}\n")
# if "_1.jpg.mask" in file:
# jpgPath = f"D://{pid}/photo1/"+file.replace(".mask", "")
# jpgPath = jpgPath.replace(".png", "")
# print("_1",jpgPath)
# with open(imageListTxt, 'a+') as f:
# f.write(f"{jpgPath}\n")
if "_1." in file:
os.remove(f"{depthMaskPath}/{file}")
if "_8.jpg.mask" in file:
try:
shutil.move(f"{depthMaskPath}/{file}",maskPath)
except Exception as e:
print(f"移动文件失败1{e}")
if "_8.jpg.depth" in file:
try:
shutil.move(f"{depthMaskPath}/{file}",depthPath)
except Exception as e:
print(f"移动文件失败2{e}")
writeImageList(str(pid))
#删除已存在数据,防止版本冲突
try:
deleteList = []
for obj in oss2.ObjectIterator(config.oss_bucket,prefix=f'objs/auto/{pid}/model_info_v2'):
deleteList.append(obj.key)
config.oss_bucket.batch_delete_objects(deleteList)
except Exception as e:
print("")
#上传到oss 上
#将 D:\{pid}\{pid}_registration.out 上传到 oss model_info
config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/model_info_v2/{pid}_registration.out', f'D://{pid}/reg/{pid}_registration.out')
# imageList.txt
config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/model_info_v2/{pid}_imageList.txt', imageListTxt)
if os.path.exists(f"{depthMaskPath}/imageList.txt"):
config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/model_info_v2/imageList.txt', f"{depthMaskPath}/imageList.txt")
# depth 和 mask 上传
print("上传 mask")
for file in os.listdir(maskPath):
config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/model_info_v2/mask/{file}', f"{maskPath}/{file}")
print("上传 depth")
for file in os.listdir(depthPath):
config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/model_info_v2/depth/{file}', f"{depthPath}/{file}")
#上传几遍照片
print("上传 reg")
for file in os.listdir(registrationPath):
if "_1.jpg" in file:
config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/model_info_v2/reg/photo1/{file}', f"{registrationPath}/{file}")
if "_8.jpg" in file:
config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/model_info_v2/reg/photo2/{file}', f"{registrationPath}/{file}")
tempFile = f"D://{pid}//finish.txt"
#创建文件
with open(tempFile, 'w') as f:
f.write("")
print(f"完成的PID-{pid}")
#写入到指定的文件中
with open("D://make2/pid.text", 'a+') as f:
f.write(f"{pid},")
#删除文件
# common.removeFolder(str(pid))
# shutil.rmtree(f"D://{pid}",ignore_errors=True)
#插入队列
tempUrl = "https://mp.api.suwa3d.com/api/customerP3dLog/addGaussianRedisQueneu?pid="+str(pid)
requests.get(tempUrl)
# exportInfo("181593")

90
export_build_info/finish.txt

@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
146134
146134
146598
183716
185381
183400
187752
184871
184956
185326
187651
187802
187811
187800
183096
187804
184956
187808
187898
187865
187870
187886
187912
185102
185102
185102
187450
185102
187989
188170
188117
188128
188200
188297
188310
188344
185101
188425
188428
188431
188560
188494
188564
188757
188779
188807
188865
188827
188910
188907
188913
188942
188964
189045
189051
189203
189214
189218
189228
189246
189242
189373
189312
189388
189913
189911
189932
189946
189106
186427
186544
190092
190112
188681
190138
188688
189172
183292
189178
184093
183080
189608
189625
189618
189170
189623
190151
183309
190214
188521

0
export_build_info/finished.txt

124
export_build_info/gen_xmps_for_build_info.py

@ -0,0 +1,124 @@ @@ -0,0 +1,124 @@
import os, sys, time, shutil, subprocess, shlex, json,oss2
import platform
if platform.system() == 'Windows':
sys.path.append('e:\\libs\\')
else:
sys.path.append('/data/deploy/make3d/make2/libs/')
import config, libs, libs_db
def upload_xmp(pid):
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 上传xmp文件之前先删除oss上的xmp文件所在目录...')
pid = str(pid)
psid = libs.getPSid(pid)
#移除掉旧的文件夹
#config.oss_bucket.delete_object(f'xmps/{pid}/')
#删除oss 上的文件夹里的内容
#判断是否存在该目录
if config.oss_bucket.object_exists(f'xmps/{psid}/') == True:
object_list = oss2.ObjectIterator(config.oss_bucket, prefix=f'xmps/{psid}/')
if not any(object_list):
config.oss_bucket.batch_delete_objects([obj.key for obj in object_list])
start_time = time.time()
workdir = os.path.join(config.workdir, pid)
##psid = libs.getPSid(pid)
config.oss_bucket.put_object_from_file(f'xmps/{psid}/{psid}.rcbox', os.path.join(workdir, f'{pid}.rcbox'))
for xmp in os.listdir(os.path.join(workdir, 'photo1')):
if xmp.endswith('.xmp'):
config.oss_bucket.put_object_from_file(f'xmps/{psid}/mesh/{xmp}', os.path.join(workdir, 'photo1', xmp))
for xmp in os.listdir(os.path.join(workdir, 'photo2')):
if xmp.endswith('.xmp'):
config.oss_bucket.put_object_from_file(f'xmps/{psid}/texture/{xmp}', os.path.join(workdir, 'photo2', xmp))
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} xmp文件上传完成,共费时{time.time() - start_time}')
def main(pid, lock=False):
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)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} 图片下载完成,共费时{libs.diff_time(start_time)}')
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))
# if photos1_count + photos2_count < 164:
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} photo1数量{photos1_count} photo2数量{photos2_count},未能覆盖所有相机,是否继续计算相机位姿?')
# continue_or_not = input('是否继续计算相机位姿?(y/n)')
# if continue_or_not == 'y':
# pass
# else:
# sys.exit(0)
if lock:
exportxmp = ' -exportXMP "D:\\make2\\config\\exportXMP.config.lock.xml" '
else:
exportxmp = ' -exportXMP "D:\\make2\\config\\exportXMP.config.xml" '
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, "photo1")}" -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)
# TODO:加入report相机位姿质量评估
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} photo1相机位姿完成,共费时{libs.diff_time(start_time)}')
for xmp in os.listdir(photo1_path):
if xmp.endswith('.xmp'):
shutil.copy(os.path.join(photo1_path, xmp), os.path.join(photo2_path, xmp.replace('_1.xmp', '_8.xmp')))
psid = libs.getPSid(pid)
cmd = f'{config.rcbin} {config.r2["init"]} -setInstanceName {pid} \
-load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" {config.r["setTextureFalse"]} \
-addFolder "{os.path.join(config.workdir, pid, "photo2")}" -selectAllImages \
-detectMarkers "D:\\make2\\config\\detectMarkers.config.xml" \
{libs.get_defineDistances(psid)} -update -align -align {config.r2["setRegion"]} \
{exportxmp} \
-exportReconstructionRegion "{os.path.join(config.workdir, pid, f"{pid}.rcbox")}" \
-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} photo2相机位姿完成,共费时{libs.diff_time(start_time)}')
# # TODO:加入report相机位姿质量评估
# if not lock:
# upload_or_not = input('是否上传oss?(y/n)')
# if upload_or_not == 'y':
# upload_xmp(pid)
# #上传坐标的话要判断该影棚是否走新的建模系统,如果不是走新的建模系统,就要更新为走新的建模系统
# libs_db.change_to_new_make_psid(psid)
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} xmp文件上传完成,共费时{libs.diff_time(start_time)}')
# delete_or_not = input('是否删除本地文件?(y/n)')
# if delete_or_not == 'y':
# shutil.rmtree(os.path.join(config.workdir, pid))
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} 本地文件已删除')
# else:
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} 本地文件未删除')
if __name__ == '__main__':
if len(sys.argv) == 2:
pids = sys.argv[1].split(',')
for pid in pids:
main(pid)
elif len(sys.argv) == 3:
pids = sys.argv[1].split(',')
for pid in pids:
if sys.argv[2] == 'lock':
main(pid, lock=True)
else:
main(pid, lock=False)
else:
print(f'useage: python {sys.argv[0]} pid1,pid2,pid3 [lock]')
sys.exit(1)

340
export_build_info/main_step1.py

@ -0,0 +1,340 @@ @@ -0,0 +1,340 @@
import os, sys, time, shlex, subprocess, shutil, requests, cv2, numpy as np
from PIL import Image
import platform,socket,atexit
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,common
def filter_dark_texture_image(pid):
start_time = time.time()
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 开始检测射灯异常图片...')
def get_image_v(image):
# 图片左上角和右上角各取200*200区域,计算V通道均值
left_rect = image[0:200, 0:200]
right_rect = image[0:200, -200:]
left_hsv = cv2.cvtColor(left_rect, cv2.COLOR_BGR2HSV)
left_v = left_hsv[:, :, 2]
left_avg_v = np.mean(left_v)
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 图片左上角V通道均值:{left_avg_v}')
right_hsv = cv2.cvtColor(right_rect, cv2.COLOR_BGR2HSV)
right_v = right_hsv[:, :, 2]
right_avg_v = np.mean(right_v)
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 图片右上角V通道均值:{right_avg_v}')
return (left_avg_v + right_avg_v) / 2
v_list = []
for filename in os.listdir(os.path.join(config.workdir, pid, 'photo2')):
if filename.endswith(".jpg"):
image = cv2.imread(os.path.join(config.workdir, pid, 'photo2', filename))
v = get_image_v(image)
item = {'filename': filename, 'v': v}
v_list.append(item)
v_list.sort(key=lambda x: x['v'])
v_list = v_list[5: -5]
avg_v = np.mean([item['v'] for item in v_list])
for item in v_list:
if abs(item['v'] - avg_v) > 50:
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 图片{item["filename"]} V通道值{item["v"]},低于平均值{avg_v},将不参与贴图')
libs.set_photo_join_type(config.workdir, pid, 'photo2', item['filename'].split('_')[0], mesh='1', texture='0')
# 复制xmp文件到photo3目录,如果photo3目录存在的话
if os.path.exists(os.path.join(config.workdir, pid, 'photo3')):
shutil.copyfile(os.path.join(config.workdir, pid, 'photo2', item['filename'].replace('jpg', 'xmp')), os.path.join(config.workdir, pid, 'photo3', item['filename'].replace('jpg', 'xmp')))
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 射灯异常图片检测完成,共费时{libs.diff_time(start_time)}')
def detect_markers(psid, pid):
def fix_region():
region_filename = os.path.join(config.workdir, pid, f'{pid}.rcbox')
with open(region_filename, 'r') as f:
lines = f.readlines()
lines = [line.replace('"NONE" globalCoordinateSystemWkt="NONE" globalCoordinateSystemName="NONE"', '"+proj=geocent +ellps=WGS84 +no_defs" globalCoordinateSystemName="local:1 - Euclidean"') for line in lines]
start_time = time.time()
add_photo3 = ' '
textpicCmd = ' '
if os.path.exists(os.path.join(config.workdir, pid, 'photo3')):
add_photo3 = ' -addFolder "' + os.path.join(config.workdir, pid, 'photo3') + '" '
textpicCmd ='-selectImage "'+os.path.join(config.workdir,pid,'photo3')+'\*" -enableTexturingAndColoring true'
textpicCmd ='-selectImage "'+os.path.join(config.workdir,pid,'photo2')+'\*" -enableTexturingAndColoring false'
else:
textpicCmd ='-selectImage "'+os.path.join(config.workdir,pid,'photo2')+'\*" -enableTexturingAndColoring true'
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, "photo1")}" {config.r["setTextureFalse"]} -align -addFolder "{os.path.join(config.workdir, pid, "photo2")}" \
{add_photo3} -align -selectAllImages \
-detectMarkers "D:\\make2\\config\\detectMarkers.config.xml" \
{libs.get_defineDistances(psid)} -align -align -update {config.r2["setRegion"]} \
-exportXMP "D:\\make2\\config\\exportXMP.config.xml" \
-exportControlPointsMeasurements "{os.path.join(config.workdir, pid, f"{pid}.controlPoints.csv")}" "D:\\make2\\config\\exportControlPoints.config.xml" \
-exportReconstructionRegion "{os.path.join(config.workdir, pid, f"{pid}.rcbox")}" \
{textpicCmd} -save "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" -quit'
print(cmd)
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
time.sleep(3)
fix_region()
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 定位点检测完成, 共费时{libs.diff_time(start_time)}')
if os.path.exists(os.path.join(config.workdir, pid, 'photo3')):
for filename in os.listdir(os.path.join(config.workdir, pid, 'photo2')):
if filename.endswith('_8.xmp'):
# photo3 exist, 设置photo2的xmp文件,不参与贴图
libs.set_photo_join_type(config.workdir, pid, 'photo2', filename.split('_')[0], mesh='1', texture='0')
for filename in os.listdir(os.path.join(config.workdir, pid, 'photo3')):
if filename.endswith('_8.xmp'):
# photo3 exist, 设置photo3的xmp文件,不参与建模
libs.set_photo_join_type(config.workdir, pid, 'photo3', filename.split('_')[0], mesh='0', texture='1')
def step1(pid, experience=False, makeloop=True,task_distributed_id="",isNoColorTexture=""):
libs_db.start_task({"task_type": "make", "task_key": pid})
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 开始处理{pid}建模任务')
psid = libs.getPSid(pid)
# 更新云端任务状态
res = requests.post(config.urls['update_status_modeling_url'], data={'id': pid})
print('更新建模中状态:', res.text)
# 下载图片
start_time = time.time()
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} 开始下载图片...')
libs.down_from_oss(config.oss_bucket, config.workdir, pid)
try:
if str(psid) == "86":
#移除指定文件
os.remove(f"D:\{pid}\photo1\\21_1.jpg")
os.remove(f"D:\{pid}\photo2\\21_8.jpg")
if str(psid) == "29":
#移除指定文件
os.remove(f"D:\{pid}\photo1\\15_1.jpg")
os.remove(f"D:\{pid}\photo2\\15_8.jpg")
except Exception as e:
print("移除异常")
#旋转图片
os.system(f'python D:\\make2\\photo2rotate.py -w d:\ -p {pid} -i photo1 -o photo1')
os.system(f'python D:\\make2\\photo2rotate.py -w d:\ -p {pid} -i photo2 -o photo2')
os.system(f'python D:\\make2\\export_build_info\\gen_xmps_for_build_info.py {pid}')
#print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} 图片下载完成,共费时{libs.diff_time(start_time)}')
os.system(f'python main_step2.py {pid}')
# start_time = time.time()
# # TODO: 上报图片采集数量,更新影棚相机状态
# # 处理图片,如果experience=True,将图片缩减一半,已节省建模时间和算力成本
# # if experience:
# # libs.resize_photos(os.path.join(config.workdir, pid, 'photo1'))
# # libs.resize_photos(os.path.join(config.workdir, pid, 'photo2'))
# # 根据配置调整photo2曝光,均衡贴图亮度,可能产生photo3
# libs.adjust_photos(config.workdir, pid)
# # TODO: 检测模糊异常图片,上报微信通知
# # TODO: 处理图片,去反光算法
# # 检测图片定位点,定位异常及时上报微信通知给客服人员,人工判断是否需要重新拍摄或更换地贴。定义定位点距离,导出相机位姿信息
# detect_markers(psid, pid)
# # 处理图片,检测photo2中的异常图片不参与贴图,以免破坏贴图效果,默认不检测射灯异常图片,以节省算力成本
# if not makeloop:
# filter_dark_texture_image(pid)
# # 处理图片,暗部提亮,提高贴图效果
# # TODO: 处理图片,去遮挡处理,提高建模与贴图质量
# # 加入photo2,计算重建区域,导出重建区域与相机位姿配置信息
# # cal_reconstruction_region(psid, pid)
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} step1图片预处理完成,共费时{libs.diff_time(start_time)}')
# if os.path.exists(os.path.join(config.sharedir, pid)):
# shutil.rmtree(os.path.join(config.sharedir, pid), ignore_errors=True)
# shutil.copytree(os.path.join(config.workdir, pid), os.path.join(config.sharedir, pid))
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} step1任务完成,移动到共享目录')
# #指定photo2某些图片不参与贴图
# #是否不参与贴图,true 不参与贴图
# if isNoColorTexture == "NoColorTexture":
# arrNoTextureColorPics = config.noTextureColorPics
# if arrNoTextureColorPics is not None and len(arrNoTextureColorPics) > 0:
# for camcerIndex in arrNoTextureColorPics:
# #拼装坐标文件名称
# filename = os.path.join(config.sharedir, pid,"photo2",str(camcerIndex)+"_8.xmp")
# #判断文件是否存在
# if os.path.exists(filename):
# #存在就设置不参与贴图
# libs.set_photo_join_type(config.workdir, pid, 'photo2', camcerIndex, mesh='0', texture='0')
# #移除当前文件夹
# shutil.rmtree(os.path.join(config.workdir, pid))
# # TODO: 更新本地step1任务状态,加入step2任务队列
# if task_distributed_id == "":#不是分布式任务的时候就自动往下个步骤走,是分布式任务的时候就就执行当前任务
# if makeloop:
# os.system(f'python main_step2.py {pid}')
# else:
# os.system(f'python main_step2.py {pid}')
# # if os.path.exists(os.path.join(config.sharedir, pid)):
# # shutil.rmtree(os.path.join(config.sharedir, pid), ignore_errors=True)
# # shutil.move(os.path.join(config.workdir, pid), config.sharedir)
# # print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} step1任务完成,移动到共享目录')
# else:
# #分布式服务执行完后,需要更新任务状态,更新字表的finished_at字段
# main_service_db.update_task_distributed_detail({"task_distributed_id":task_distributed_id,"finished_at":time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())})
# print("step1完成,休息6s")
# time.sleep(4)
# return
def main(pid, experience=False, makeloop=True,task_distributed_id="",isNoColorTexture=""):
if pid == '0':
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 开始进入本地任务值守模式...')
while True:
# 取云端redis多个key任务,TODO:后续要改为api调用
experience = False
pid = libs_db.get_task('make_experience')
if pid == '':
time.sleep(3)
pid = libs_db.get_task('make')
if pid == '':
time.sleep(3)
continue
else:
experience = False
step1(pid, experience, makeloop,task_distributed_id,isNoColorTexture)
else:
step1(pid, experience, makeloop,task_distributed_id,isNoColorTexture)
def is_already(pid):
#读取已经完成的pid
with open("D://make2/export_build_info/finished.txt", 'r') as f:
lines = f.readlines()
for line in lines:
print("line",str(line.strip()))
if str(pid) == str(line.strip()):
print("匹配成功")
return True
return False
if __name__ == '__main__':
isNoColorTexture = ""
if len(sys.argv) == 2:
v = sys.argv[1]
#判断是否是数字
if v.isdigit():
#print(f"正在处理输入的pid-{v}")
main(str(v), experience=False, makeloop=False,task_distributed_id="",isNoColorTexture=isNoColorTexture)
else:
filePath = f"D://make2/export_build_info/pids/{v}.txt"
if not os.path.exists(filePath):
print(f"{filePath} 文件不存在")
strPids = ""
with open("D://make2/pid.text","r") as f:
lines = f.readlines()
for line in lines:
strPids = str(line.strip())
errPids = ""
with open("D://make2/errPid.text","r") as f:
lines = f.readlines()
for line in lines:
errPids = str(line.strip())
arrErrPids = errPids.split(",")
arrPids = strPids.split(",")
ii = 0
with open(filePath, 'r') as f:
lines = f.readlines()
for line in lines:
pid = str(line.strip())
if pid == "":
break
#判断是否存在了目录或者已经是处理过了
# tempFile = f"D://{pid}//finish.txt"
# if os.path.exists(tempFile):
# continue
if str(pid) in arrErrPids:
continue
if str(pid) in arrPids:
# print(f"已处理过{pid}")
ii += 1
continue
print(f"正在处理{pid}- 完成{ii}")
main(str(pid), experience=False, makeloop=False,task_distributed_id="",isNoColorTexture=isNoColorTexture)
ii += 1
print(f"已经完成-{ii}")
else:
print("cmd like python main_step1.py pid/单人/多人/双人/动物/人物")
# # 取云端redis任务,完成第一步的数据预处理后,将数据放入共享存储目录,将第二步任务塞入本地mysql队列
# # 默认循环值守,可传参数运行单一任务,以方便调试
# #atexit.register(common.notify,socket.gethostname()+"建模任务已经停止")
# # pid = '0'
# isNoColorTexture = ""
# # if len(sys.argv) == 2:
# # pids = sys.argv[1].split(',')
# # for pid in pids:
# already = [184219,184215,184209,184069,184059,183868,183817,183791,183613,183054,182855,182854,184206,184201,184199,184164,184087,184076,184029,184013,183993,183952,183888,183882,183824,183815,183812]
# arrPids = [184219,184215,184209,184206,184201,184199,184164,184087,184076,184069,184059,184029,184013,183993,183952,183888,183882,183868,183824,183817,183815,183812,183791,183777,183715,183705,183670,183613,183573,182974,182983,182985,182989,182997,183007,183051,183060,183054,183053,183097,183119,183108,183139,183141,183155,183163,183169,183180,183191,183196,183214,183244,183266,183278,183275,183309,183402,183422,183440,182974,182964,182958]
# #,182956,182916,182855,182854,182820,182787,182800,182809,182780,182772,182770,182766,182754,182742,182740,182723,182707,182647,182643,182614,182595,182563,182557,182547,182546,182538,182530,182517,182498,182478,182452,182386,182352,182285,182266,182260,182230,182224
# i = 0
# for pid in arrPids:
# if pid in already:
# continue
# print("正在处理-",pid)
# if is_already(str(pid)) == True:
# continue
# # i += 1
# # continue
# #写入到
# with open("D://make2/export_build_info/finished.txt", 'a+') as f:
# f.write(f"{pid}\n")
# main(str(pid), experience=False, makeloop=False,task_distributed_id="",isNoColorTexture=isNoColorTexture)
# print("已处理-",i)
# #exit()
# # if len(sys.argv) == 3:
# # experience = False
# # if sys.argv[2] == '1':
# # print('演示测试...')
# # experience = False
# # elif sys.argv[2] == 'NoColorTexture':
# # isNoColorTexture = "NoColorTexture"
# # pids = sys.argv[1].split(',')
# # for pid in pids:
# # main(pid, experience=experience, makeloop=False,task_distributed_id="",isNoColorTexture=isNoColorTexture)
# # exit()
# # main(pid, experience=False, makeloop=True,task_distributed_id="",isNoColorTexture=isNoColorTexture)

267
export_build_info/main_step2.py

@ -0,0 +1,267 @@ @@ -0,0 +1,267 @@
import os, sys, time, shutil, subprocess, shlex
import platform
import pyautogui as ag
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,common,main_service_db,computerRecboxCenterByPoint
import export_already_build
redisLocal = config.redis_local
def load_model(pid):
cmd = f'{config.rcbin} {config.r1["init"]} -load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}"'
print(cmd)
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
def get_rcver():
rcbin = '"C:\\Program Files\\Capturing Reality\\RealityCapture\\RealityCapture.exe"'
if os.path.getsize(rcbin[1:-1]) == 20783616:
return 1
else:
return 2
def make3d(pid):
if get_rcver() == 1: # old version
#修改重建区域的大小
common.change_rcbox_s(pid,"1")
#获取影棚id
# psid = libs.getPSid(pid)
# if int(psid) == 80:
# change_rcbox_deepth(str(pid),0.03)
psid = libs.getPSid(pid)
simplify_value = 1000000 * libs.getHeadCount(pid)
add_photo3 = ' '
#判断是否存在photo3
if os.path.exists(os.path.join(config.workdir, pid, 'photo3')):
add_photo3 = ' -addFolder "' + os.path.join(config.workdir, pid, 'photo3') + '" -align -align '
#存在photo3 的情况下,photo2 不参与贴图
#遍历获取photo2 目录下的所有文件
directory = os.path.join(config.workdir, pid, 'photo2')
for root, dirs, files in os.walk(directory):
for file in files:
#判断file 是否以 _8.xmp 结尾
if file.endswith("_8.xmp") == False:
continue
#修改文件内容不参与贴图
libs.set_photo_join_type(config.workdir, pid, 'photo2', file.split("_")[0], mesh='0', texture='0')
else:
pass
#设置photo2参与贴图,因为有的时候贴图会黑
directory = os.path.join(config.workdir, pid, 'photo2')
for root, dirs, files in os.walk(directory):
for file in files:
#判断file 是否以 _8.xmp 结尾
if file.endswith("_8.xmp") == False:
continue
#修改文件内容不参与贴图
libs.set_photo_join_type(config.workdir, pid, 'photo2', file.split("_")[0], mesh='0', texture='1')
if get_rcver() == 1: # old version
#判断oss 上是否存在 controlpoints 文件
isExistPoint = common.isExistControlPointsOss(pid)
cmd = f'{config.rcbin} {config.r1["init"]} \
-addFolder "{os.path.join(config.workdir, pid, "photo1")}" -addFolder "{os.path.join(config.workdir, pid, "photo2")}" {add_photo3} \
-importControlPointsMeasurements "{os.path.join(config.workdir, pid, f"{pid}.controlPoints.csv")}" \
-align -exportRegistration "{os.path.join(config.workdir,"make2", "config","exportRegistration.xml")}" "{os.path.join(config.workdir, pid,str(pid)+"_align.csv")}" -save'
cmd = cmd + f' "{os.path.join(config.workdir, pid, f"{pid}_wait.rcproj")}"'
print(cmd)
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
time.sleep(2)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 定位点导入完成')
time.sleep(3)
# defind_distance
#死循环阻塞获取
while True:
print("循环阻塞开始")
time.sleep(3)
#判断是否有 pid_1 的的值
print(pid+"_1")
if redisLocal.lpos('model:auto_distance',pid+"_1") == None:
continue
shutil.move(os.path.join(config.workdir, pid, f'{pid}_wait.rcproj'), os.path.join(config.workdir, pid, f'{pid}.rcproj'))
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 定义定位点距离完成')
#将 controlpoints_0.dat 文件拷贝到 oss 上作为公共的使用
common.uploadControlPointsOss(pid)
#最后处理掉redis中的值
redisLocal.lrem('model:auto_distance', 0, pid+"_1")
break
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),"循环阻塞结束,判断是否对齐成功")
#查看对齐的数量
alignRes = common.isAlignNums(str(pid))
if alignRes == "rebuild":
os.system(f'python d:\\make2\\tools\push_cmd.py rebuild {pid}')
os.system(f'python d:\\make2\\main_service.py')
return
#区域的设置 建模
#update
cmdSmall = "-align"
#使用公共point文件的时候,就不能使用update , 而是要用 align
if isExistPoint == True:
cmdSmall = "-align"
#{config.r1["init"]}
if common.task_need_high_model(pid):
if str(psid) == "41" or str(psid) == "85":
calulate_type = "-mvs"
else:
calulate_type = '-mvsHigh'
else:
calulate_type = '-mvs'
#翻转相机的线向下
cmd = f'{config.rcbin} -load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" {cmdSmall} \
-set "sfmEnableCameraPrior=True" -align -set "sfmEnableCameraPrior=False" -align -save "{os.path.join(config.workdir, pid, f"{pid}_point.rcproj")}" '
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
#执行完成后命令会触发导出点云的定时程序
while True:
print("判断是否导出点云文件循环阻塞开始")
time.sleep(3)
#判断是否有 pid_1 的的值
print(pid+"_3")
if redisLocal.lpos('model:auto_distance',pid+"_3") == None:
continue
shutil.move(os.path.join(config.workdir, pid, f'{pid}_point.rcproj'), os.path.join(config.workdir, pid, f'{pid}.rcproj'))
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 导出点云文件完成')
#最后处理掉redis中的值
redisLocal.lrem('model:auto_distance', 0, pid+"_3")
break
#处理点云文件
centerRcboxValue = computerRecboxCenterByPoint.boxCenter(pid)
if centerRcboxValue > 0:
print("修改中心点的坐标",centerRcboxValue)
#修改中心点的值
common.change_rcbox_center(pid,centerRcboxValue)
cmd = f'{config.rcbin} -load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" -align \
-set "sfmEnableCameraPrior=True" -align -set "sfmEnableCameraPrior=False" -align -setReconstructionRegion "{os.path.join(config.workdir, pid, f"{pid}.rcbox")}" \
{calulate_type} -modelSelectMaximalConnectedComponent -modelInvertSelection -modelRemoveSelectedTriangles -closeHoles -clean -simplify {simplify_value} -smooth -unwrap -calculateTexture -renameModel {pid} -save "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" -quit'
print(cmd)
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
#保存在导出
# common.saveScreenImg(pid)
# time.sleep(1)
# ag.hotkey('alt', 'f4')
time.sleep(3)
#修改rcproj文件
flag = common.changeRcprojFile(pid)
if flag == False:
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} rcproj文件不存在')
return
#复制文件
shutil.copy(os.path.join(config.workdir, pid, f'{pid}.rcproj'), os.path.join(config.workdir, pid, f'{pid}_screen.rcproj'))
time.sleep(2)
#打开工程文件
cmd = f'{config.rcbin} -load "{os.path.join(config.workdir, pid, f"{pid}_screen.rcproj")}"'
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
#创建指定文件夹
if not os.path.exists(os.path.join(config.workdir, pid, "output")):
os.makedirs(os.path.join(config.workdir, pid, "output"))
#判断output目录下是否有文件,有的话删除
files = os.listdir(os.path.join(config.workdir, pid, "output"))
#执行导出
cmd = f'{config.rcbin} -load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}"\
-exportModel "{pid}" "{os.path.join(config.workdir, pid, "output", f"{pid}.obj")}" "d:\\make2\\config\\ModelExportParams102.xml" -quit'
print(cmd)
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
else: # new version
#判断是否要进行高精模
if common.task_need_high_model(pid):
if str(psid) == "41" or str(psid) == "85":
calulate_type = "calculateNormalModel"
else:
calulate_type = 'calculateHighModel'
else:
calulate_type = 'calculateNormalModel'
#创建指定文件夹
if not os.path.exists(os.path.join(config.workdir, pid, "output")):
os.makedirs(os.path.join(config.workdir, pid, "output"))
cmd = f'{config.rcbin} {config.r2["init"]} -setInstanceName {pid} \
-load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" \
-{calulate_type} \
-selectLargestModelComponent -invertTrianglesSelection -removeSelectedTriangles -simplify {simplify_value} -smooth -closeHoles -cleanModel -calculateTexture \
-save "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" \
-exportSelectedModel "{os.path.join(config.workdir, pid, "output", f"{pid}.obj")}" "d:\\make2\\config\\ModelExportParams.xml" -quit'# -quit
print(cmd)
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
export_already_build.exportInfo(pid)
# #阻塞判断是否导出完成
# while True:
# #判断 output 目录下是否存在 三个文件
# files = os.listdir(os.path.join(config.workdir, pid, "output"))
# if len(files) >= 3:
# break
def step2(pid,task_distributed_id=""):
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 开始建模任务step2')
#判断是否要从共享目录拷贝数据
if os.path.exists(os.path.join(config.sharedir, pid)) and not os.path.exists(os.path.join(config.workdir, pid)):
shutil.move(os.path.join(config.sharedir, pid), config.workdir)
else:
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 目录{os.path.join(config.sharedir, pid)}不存在,或{os.path.join(config.workdir, pid)}已存在')
# return
#最后还是要判断有没有存在目录
if not os.path.exists(os.path.join(config.workdir, pid)):
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 目录{os.path.join(config.workdir, pid)}不存在')
return
start_time = time.time()
make3d(pid)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 建模任务step2完成,共费时{libs.diff_time(start_time)},任务已提交到step3')
# # 更新本地任务状态,加入step3任务队列
# if task_distributed_id == "":
# os.system(f'python d:\\make2\\main_step3.py {pid}')
# else:
# #暂时 step2 step3 一起连续执行
# print('step2 执行完,开始执行step3')
# os.system(f'python d:\\make2\\main_step3.py {pid}')
# main_service_db.update_task_distributed({"id":task_distributed_id,"status":2,"finished_at":time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())})
# main_service_db.update_task_distributed_detail({"task_distributed_id":task_distributed_id,"finished_at":time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())})
# #return
def main(pid):
if pid == '0':
while True:
# 取本地mysql队列任务,完成第二步的建模任务
step2(pid)
else:
step2(pid)
if __name__ == '__main__':
# 取本地mysql队列任务,完成第二步的建模任务
# 默认循环值守,可传参数运行单一任务,以方便调试
pid = '0'
if len(sys.argv) > 1:
pids = sys.argv[1].split(',')
for pid in pids:
main(pid)
exit()
main(pid)

185
export_build_info/manual_service.py

@ -0,0 +1,185 @@ @@ -0,0 +1,185 @@
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)
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 = "1",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} photo1数量{photos1_count} 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 -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")}" {config.r["setTextureFalse"]} \
-addFolder "{targetFile}" -selectAllImages \
-detectMarkers "D:\\make2\\config\\detectMarkers.config.xml" \
{libs.get_defineDistances(psid)} -update -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}')
os.system(f'python D://make2/export_build_info/main_step2.py {pid}')
def is_already(pid):
#读取已经完成的pid
with open("D://make2/export_build_info/finished.txt", 'r') as f:
lines = f.readlines()
for line in lines:
print("line",str(line.strip()))
if str(pid) == str(line.strip()):
print("匹配成功")
return True
return False
if __name__ == '__main__':
already = [184219,184215,184209,184069,184059,183868,183817,183791,183613,183054,182855,182854,184206,184201,184199,184164,184087,184076,184029,184013,183993,183952,183888,183882,183824,183815,183812]
arrPids = [184219,184215,184209,184206,184201,184199,184164,184087,184076,184069,184059,184029,184013,183993,183952,183888,183882,183868,183824,183817,183815,183812,183791,183777,183715,183705,183670,183613,183573,182974,182983,182985,182989,182997,183007,183051,183060,183054,183053,183097,183119,183108,183139,183141,183155,183163,183169,183180,183191,183196,183214,183244,183266,183278,183275,183309,183402,183422,183440,182974,182964,182958,182956,182916,182855,182854,182820,182787,182800,182809,182780,182772,182770,182766,182754,182742,182740,182723,182707,182647,182643,182614,182595,182563,182557,182547,182546,182538,182530,182517,182498,182478,182452,182386,182352,182285,182266,182260,182230,182224]
for pid in arrPids:
if pid in already:
continue
print("正在处理-",pid)
if is_already(str(pid)) == True:
continue
# i += 1
# continue
#写入到
with open("D://make2/export_build_info/finished.txt", 'a+') as f:
f.write(f"{pid}\n")
cmd_run(str(pid),usePhoto = "1",lock=False)
# 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)

27
export_build_info/pids/人物.txt

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
181561
181559
180990
180772
180538
180256
179927
179657
179627
178838
178714
178616
178604
178332
177920
176655
184102
183728
183538
183524
183274
183316
183345
182867
182658
182638
182560

28
export_build_info/pids/动物.txt

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
181307
181287
181267
180402
179617
179613
178991
178892
178814
178787
178471
178469
178400
178156
177899
177894
176236
184133
184039
183848
183769
183637
183127
183238
182450
182031
181977
181960

393
export_build_info/pids/单人.txt

@ -0,0 +1,393 @@ @@ -0,0 +1,393 @@
181763
181757
181754
181687
181652
181642
181619
181597
181574
181542
181526
181515
181482
181435
181421
181408
181391
181388
181367
181333
181329
181327
181304
181274
181261
181257
181248
181232
181231
181229
181205
181204
181203
181202
181191
181188
181177
181176
181145
181143
181139
181117
181115
181108
181097
181062
181050
181046
181040
181039
181023
181020
180961
180958
180944
180943
180904
180903
180869
180864
180862
180846
180839
180819
180781
180776
180771
180770
180670
180661
180648
180593
180591
180588
180581
180461
180455
180450
180429
180424
180394
180327
180314
180308
180297
180292
180291
180281
180273
180225
180185
180167
180156
180145
180125
180085
180084
180082
179980
179978
179975
179942
179935
179895
179861
179850
179849
179815
179722
179704
179695
179688
179676
179652
179646
179623
179621
179585
179555
179551
179493
179489
179474
179471
179470
179461
179457
179451
179430
179355
179344
179331
179316
179282
179229
179226
179219
179205
179204
179166
179160
179151
179149
179147
179139
178752
178743
178677
178675
178674
178624
178606
178594
178591
178528
178526
178521
178520
178519
178493
178457
178452
178447
178390
178388
178369
178364
178349
178348
178347
178330
178319
178303
178302
178294
178287
178269
178236
178220
178219
178214
178203
178191
178187
178164
178159
178129
178100
178098
178054
178051
178048
178042
178034
178016
177467
177465
177453
177449
177447
177443
177431
177430
177412
177360
177353
177350
177337
177327
177309
178008
177999
177998
177992
177991
177984
177973
177972
177971
177948
177852
177830
177820
177812
177763
177706
177681
177659
177648
177647
177641
177628
177613
177611
177550
177293
177288
177280
177277
177265
177262
177257
177225
177213
177198
177172
177159
177146
177152
177108
177095
177092
177048
177046
177035
176822
176752
176739
176688
176678
176631
176609
176602
176525
176338
176333
176314
176305
176249
176238
184219
184215
184209
184206
184201
184199
184164
184087
184076
184069
184059
184029
184013
183993
183952
183888
183882
183868
183824
183817
183815
183812
183791
183777
183715
183705
183670
183613
183573
182974
182983
182985
182989
182997
183007
183051
183060
183054
183053
183097
183119
183108
183139
183141
183155
183163
183169
183180
183191
183196
183214
183244
183266
183278
183275
183309
183402
183422
183440
182974
182964
182958
182956
182916
182855
182854
182820
182787
182800
182809
182780
182772
182770
182766
182754
182742
182740
182723
182707
182647
182643
182614
182595
182563
182557
182547
182546
182538
182530
182517
182498
182478
182452
182386
182352
182285
182266
182260
182230
182224
182223
182191
182185
182182
182179
182106
182101
182072
181966
181965
181937
181928
181925
181924
181923
181900
181895
181860
181847
181836
181833
181811
181809

307
export_build_info/pids/双人.txt

@ -0,0 +1,307 @@ @@ -0,0 +1,307 @@
181593
181384
181337
181318
181263
181240
181211
181197
181187
181140
181103
181091
181054
181027
180763
180690
180684
180677
180599
180576
180389
180342
180337
180277
180265
180253
180101
180083
179905
179842
179811
179808
179791
179786
179700
179634
179593
179576
179485
179459
179400
179351
178995
178898
178750
178746
178723
178680
178673
178654
178527
178482
178465
178430
178413
178409
178297
178286
178281
178105
178062
178026
178025
178019
178017
178004
177851
177678
177677
177646
177545
177520
177300
177080
176757
176743
176648
176290
176280
176273
176247
184082
184074
184068
184061
184041
183893
183890
183810
183755
183680
183656
183592
183591
183589
183025
183086
183104
183162
183444
182907
182915
182871
182804
182778
182718
182675
182664
182625
182623
182542
182510
182473
182455
182388
182365
182343
182316
181957
181948
181941

28
export_build_info/pids/多人.txt

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
180891
180673
180584
180468
180164
180091
179992
179962
178627
178416
178255
178066
177983
177722
183832
183677
183183
183351
183361
183360
182853
182715
182630
182367
182253
182057
181868
181856

42
export_build_info/registration_export_config.xml

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
<Configuration id="{2D5793BC-A65D-4318-A1B9-A05044608385}">
<entry key="calexUndistResMode" value="2"/>
<entry key="calexTrans" value="1"/>
<entry key="calexUndistortNaming" value="5"/>
<entry key="calexUndistortPixelFormat" value="24bppBGR"/>
<entry key="calexHasDisabled" value="0x0"/>
<entry key="calexRequiresUndistortPrincipal" value="0x1"/>
<entry key="calexExportImages" value="true"/>
<entry key="calexUndistortImageFormat" value="jpg"/>
<entry key="MvsExportScaleZ" value="1.0"/>
<entry key="MvsExportIsGeoreferenced" value="0x0"/>
<entry key="MvsExportIsModelCoordinates" value="0"/>
<entry key="calexRequiresColorCorrection" value="0x0"/>
<entry key="MvsExportScaleY" value="1.0"/>
<entry key="calexDownscale" value="0x1"/>
<entry key="calexRequiresEqualResolution" value="0x0"/>
<entry key="calexUndistMaxPixels" value="0"/>
<entry key="calexInputHasLayers" value="0"/>
<entry key="MvsExportScaleX" value="1.0"/>
<entry key="calexUndistFitMode" value="2"/>
<entry key="MvsExportRotationY" value="0.0"/>
<entry key="MvsExportcoordinatesystemtype" value="0"/>
<entry key="MvsExportNormalFlipZ" value="false"/>
<entry key="MvsExportRotationX" value="0.0"/>
<entry key="hasCalexFilePath" value="1"/>
<entry key="calexFolderCustom" value="false"/>
<entry key="MvsExportNormalFlipY" value="false"/>
<entry key="MvsExportNormalSpace" value="Mikktspace"/>
<entry key="calexHasUndistort" value="2"/>
<entry key="MvsExportNormalFlipX" value="false"/>
<entry key="MvsExportRotationZ" value="0.0"/>
<entry key="calexFileFormat" value="Bundler v0.3"/>
<entry key="MvsExportMoveZ" value="0.0"/>
<entry key="calexFileFormatId" value="{ECC4131A-1665-466C-93BE-66DF2EBC9086}"/>
<entry key="hasCalexFileName" value="1"/>
<entry key="calexUndistCutOut" value="1.0"/>
<entry key="calexHasImageExport" value="1"/>
<entry key="calexUndistBackColor" value="0"/>
<entry key="MvsExportMoveX" value="0.0"/>
<entry key="MvsExportNormalRange" value="ZeroToOne"/>
<entry key="MvsExportMoveY" value="0.0"/>
</Configuration>

0
export_build_info/task_distributed_error.log

13
install.txt

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip config set install.trusted-host pypi.tuna.tsinghua.edu.cn
python -m pip install --upgrade pip
pip install oss2 redis MySQLdb pillow numpy opencv-python bpy tqdm pyautogui psutil pywin32 pymysql
config
set bin="C:\Program Files\Capturing Reality\RealityCapture\RealityCapture.exe"
%bin% -disableOnlineCommunication -setInstanceName %pid%
%bin% -disableOnlineCommunication -delegateTo %pid%
%bin% -set "appCacheLocation=ProjectFolder"

11
libs/config.py

@ -49,6 +49,15 @@ mysql_dong = { @@ -49,6 +49,15 @@ mysql_dong = {
"charset": "utf8mb4"
}
mysql_task_rc = {
"host": '172.31.1.254',#"172.16.20.13",
"port": 23306,
"user": "pi",
"password": "ph2008",
"db": "suwa3d",
"charset": "utf8mb4"
}
if platform.system() == 'Windows':
workdir = 'D:\\'
sharedir = 'E:\\'
@ -115,7 +124,7 @@ r2 = { @@ -115,7 +124,7 @@ r2 = {
#new_make_psids = ['1', '17', '29', '44', '54', '55', '63', '65', '77', '79', '80', '85', '86']
#企业微信通知人员
notify_user_Ids = ["DongZhangXi","YouShui"]
notify_user_Ids = ["DongZhangXi"]
#任务运行超时时间设定 ,单位秒
task_run_timeout = {

48
libs/libs.py

@ -331,3 +331,51 @@ def down_obj_from_oss_for_fix(workdir, pid, action): @@ -331,3 +331,51 @@ def down_obj_from_oss_for_fix(workdir, pid, action):
localfile = os.path.join(workdir, action, pid, filename)
config.oss_bucket.get_object_to_file(file.key, localfile)
return obj_filename
def down_obj_from_oss_for_repeat_texture(workdir, pid, action):
print(os.path.join(workdir, pid))
if not os.path.exists(os.path.join(workdir, pid)):
print("目录不存在,无法处理")
return "error"
#判断是否有专门新建的目录用来重新贴图
newPath = os.path.join(workdir, pid,'repeat_texture','completion_cloud')
if not os.path.exists(newPath):
os.makedirs(newPath)
# 根据前缀获取文件列表
prefix = f'objs/{action}/{pid}/ai/repeat_texture/completion_cloud'
filelist = oss2.ObjectIteratorV2(config.oss_bucket, prefix=prefix)
print('正在下载:', prefix)
for file in filelist:
filename = file.key.split('/')[-1]
if filename == "":
continue
localfile = os.path.join(newPath, filename)
config.oss_bucket.get_object_to_file(file.key, localfile)
return newPath
def down_obj_from_oss_auto(pid,action,pathStr):
#pathStr = os.path.join(workdir, str(pid)+"_ai")
if not os.path.exists(pathStr):
os.makedirs(pathStr)
# 根据前缀获取文件列表
prefix = f'objs/{action}/{pid}'
filelist = oss2.ObjectIteratorV2(config.oss_bucket, prefix=prefix)
print('正在下载:', prefix)
for file in filelist:
filename = file.key.split('/')[-1]
if filename == "":
continue
if filename != f"{pid}.jpg" and filename != f"{pid}.obj" and filename != f"{pid}.mtl":
continue
print(filename)
localfile = os.path.join(pathStr, filename)
config.oss_bucket.get_object_to_file(file.key, localfile)

83
libs/libs_db_repeat_texture.py

@ -0,0 +1,83 @@ @@ -0,0 +1,83 @@
# mysql数据库常用任务函数封装
import pymysql, socket, time
import config
#公共连接库
def pymysqlAlias():
return pymysql.connect(
host=config.mysql_gpu['host'],
port=config.mysql_gpu['port'],
user=config.mysql_gpu['user'],
password=config.mysql_gpu['password'],
db=config.mysql_gpu['db'],
charset=config.mysql_gpu['charset'],)
# 新增新的任务
def add_reapeat_texture_task(data):
try:
resExist = is_exist(data["pid"])
if resExist == True:
return
with pymysqlAlias() as conn:
cursor = conn.cursor()
sql = f'insert into task_repeat_texture (pid,heads,createTime) values ("{data["pid"]}","{data["heads"]}","{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}")'
print(f'sql: {sql}')
cursor.execute(sql)
conn.commit()
except Exception as e:
print(f"{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} 执行add_task({data})异常: {str(e)}")
#
def is_exist(pid):
try:
with pymysqlAlias() as conn:
cursor = conn.cursor()
sql = f'select count(*) from task_repeat_texture where pid = {pid} and status = 0'
print(f'sql: {sql}')
cursor.execute(sql)
result = cursor.fetchone()
if result[0] > 0:
return True
else:
return False
except Exception as e:
print(f"{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} 执行is_new_make_psid()异常: {str(e)}")
return "error"
def get_pid_task():
try:
with pymysqlAlias() as conn:
cursor = conn.cursor()
sql = f'select * from task_repeat_texture where status = 1 limit 1'
print(f'sql: {sql}')
cursor.execute(sql)
result = cursor.fetchone()
if result:
return result
else:
return None
except Exception as e:
print(f"{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} 执行get_pid_task()异常: {str(e)}")
return "error"
#更新状态
def update_status(id,status):
try:
with pymysqlAlias() as conn:
cursor = conn.cursor()
hostname = socket.gethostname()
sql = f'update task_repeat_texture set status = {status},updateTime = now() where id = {id}'
print(f'开始任务sql: {sql}')
cursor.execute(sql)
conn.commit()
except Exception as e:
print(f"{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} 执行update_status()异常: {str(e)}")

30
libs/libs_db_task_rc.py

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
# mysql数据库常用任务函数封装
import pymysql, socket, time
import config
#公共连接库
def pymysqlAlias():
return pymysql.connect(
host=config.mysql_task_rc['host'],
port=config.mysql_task_rc['port'],
user=config.mysql_task_rc['user'],
password=config.mysql_task_rc['password'],
db=config.mysql_task_rc['db'],
charset=config.mysql_task_rc['charset'],)
# 获取新的任务
def get_task_rc_count():
try:
with pymysqlAlias() as conn:
cursor = conn.cursor()
sql = f'select count(*) from task_distributed where status != 2 and created_at >= "2024-09-02 00:00:00"'
# print(f'sql: {sql}')
cursor.execute(sql)
data = cursor.fetchone()
if data:
return data[0]
else:
return ''
except Exception as e:
print(f"{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} get_task_rc_count()异常: {str(e)}")
return ''

101
main_repeat_texture.py

@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
#读取需要重新贴图的数据
import os,sys,time,shlex,subprocess,shutil
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 libs_db_repeat_texture
import libs,config
#读取 数据库的信息
def get_pid():
data = libs_db_repeat_texture.get_pid_task()
if data != None and data != "error":
return data[0],data[1]
else:
return None,None
#开始处理任务
def start_task(pid):
#下载Obj数据
print(f"处理{pid}任务")
print("开始下载{pid}数据")
# pid = str("175635")
complateCloudPath = libs.down_obj_from_oss_for_repeat_texture(config.workdir, pid,"auto")
if complateCloudPath == "error":
return -1,"error-从oss上下载出问题"
#下载下来之后重新加载obj 和texture
print("complateCloudPath",complateCloudPath)
outPath = os.path.join(config.workdir, pid, "output")
if os.path.exists(outPath):
print("移除文件夹")
#移除文件夹
shutil.rmtree(outPath)
cmd = f'{config.rcbin} {config.r2["init"]} -setInstanceName {pid} \
-load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" \
-importModel "{os.path.join(complateCloudPath, f"{pid}.obj")}" \
-calculateTexture -exportSelectedModel "{os.path.join(config.workdir, pid, "output", f"{pid}.obj")}" "d:\\make2\\config\\ModelExportParams0722.xml" -quit'
print(cmd)
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
#检查out目录文件夹是否有多个 贴图文件。如果是的话只保留最新的一个,并且重命名为初始图像的名称
outFilePath = os.path.join(config.workdir, pid, "output")
arrTempImage = []
for file in os.listdir(outFilePath):
if file.endswith(".jpg") or file.endswith(".png"):
#字符串替换
fileTempName = file.replace(f"{pid}_u0_v0_diffuse","")
fileTempName = fileTempName.replace(".jpg","")
fileTempName = fileTempName.replace(".png","")
if "_" in fileTempName:
fileTempName = fileTempName.replace("_","")
arrTempImage.append(fileTempName)
print(arrTempImage)
if len(arrTempImage) > 1:
#获取 arrTempImage 中最大的值
arrTempImage.sort()
print(arrTempImage)
#获取最大值
maxValue = arrTempImage[-1]
for i in arrTempImage:
if i == "":
filePath1 = os.path.join(config.workdir, pid, "output",pid+"_u0_v0_diffuse.jpg")
filePath2 = os.path.join(config.workdir, pid, "output",pid+"_u0_v0_diffuse.png")
else:
filePath1 = os.path.join(config.workdir, pid, "output",pid+"_u0_v0_diffuse_"+str(i)+".jpg")
filePath2 = os.path.join(config.workdir, pid, "output",pid+"_u0_v0_diffuse_"+str(i)+".png")
if i != maxValue:
if os.path.exists(filePath1):
os.remove(filePath1)
if os.path.exists(filePath2):
os.remove(filePath2)
else:
if os.path.exists(filePath1):
os.rename(filePath1,os.path.join(config.workdir, pid, "output",pid+"_u0_v0_diffuse.jpg"))
if os.path.exists(filePath2):
os.rename(filePath2,os.path.join(config.workdir, pid, "output",pid+"_u0_v0_diffuse.jpg"))
#执行step3
os.system(f'python d:\\make2\\main_step3.py {pid}')
return 3,"success"
if __name__ == '__main__':
while True:
id,pid = get_pid()
print(f"读取的数据{pid}")
if pid != None:
#更新状态为2
libs_db_repeat_texture.update_status(id,2)
statusres,res = start_task(str(pid))
libs_db_repeat_texture.update_status(id,statusres)
else:
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}-没有任务')
time.sleep(10)

6
main_step1.py

@ -110,16 +110,14 @@ def step1(pid, experience=False, makeloop=True,task_distributed_id="",isNoColorT @@ -110,16 +110,14 @@ def step1(pid, experience=False, makeloop=True,task_distributed_id="",isNoColorT
libs.down_from_oss(config.oss_bucket, config.workdir, pid)
try:
if str(psid) == "86":
#移除指定文件
os.remove(f"D:\{pid}\photo1\\21_1.jpg")
os.remove(f"D:\{pid}\photo2\\21_8.jpg")
if str(psid) == "29":
#移除指定文件
os.remove(f"D:\{pid}\photo1\\15_1.jpg")
os.remove(f"D:\{pid}\photo2\\15_8.jpg")
except Exception as e:
print("移除异常")
print("移除照片异常")
os.system(f'python tools/downxmps.py {pid}')
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} 图片下载完成,共费时{libs.diff_time(start_time)}')

13
main_step2.py

@ -1,12 +1,13 @@ @@ -1,12 +1,13 @@
import os, sys, time, shutil, subprocess, shlex
import platform
import pyautogui as ag
from export_build_info import export_already_build
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,common,main_service_db,computerRecboxCenterByPoint
import config, libs, libs_db,common,main_service_db,computerRecboxCenterByPoint,libs_db_repeat_texture
redisLocal = config.redis_local
def load_model(pid):
cmd = f'{config.rcbin} {config.r1["init"]} -load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}"'
@ -216,6 +217,16 @@ def make3d(pid): @@ -216,6 +217,16 @@ def make3d(pid):
if len(files) >= 3:
break
# #插入需要重新贴图的任务表
# libs_db_repeat_texture.add_reapeat_texture_task({"pid":pid,"heads":libs.getHeadCount(pid)})
# #然后将导出的obj文件上传到oss上
# config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/ai/repeat_texture/{pid}.obj', os.path.join(config.workdir, pid, 'output', f'{pid}.obj'))
# config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/ai/repeat_texture/{pid}.mtl', os.path.join(config.workdir, pid, 'output', f'{pid}.mtl'))
# config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/ai/repeat_texture/{pid}_u0_v0_diffuse.jpg', os.path.join(config.workdir, pid, 'output', f'{pid}_u0_v0_diffuse.jpg'))
# config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/ai/repeat_texture/{pid}.obj.rcInfo', os.path.join(config.workdir, pid, 'output', f'{pid}.obj.rcInfo'))
# #导出建模信息
export_already_build.exportInfo(str(pid))
def step2(pid,task_distributed_id=""):
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 开始建模任务step2')

16
main_step3.py

@ -206,12 +206,10 @@ def step3(pid,task_distributed_id=""): @@ -206,12 +206,10 @@ def step3(pid,task_distributed_id=""):
export_and_update_obj(pid)
resize_texture_and_reload_obj(pid)
export_and_update_glbs(pid)
#向gpu数据库task 插入任务,用于开始执行AI修模
headcount = libs.getHeadCount(pid)
#if headcount == 1:
libs_db_gpu.add_task(data={"pid":pid,"cut_body":"face","heads":headcount})
#向gpu服务器数据库添加一条数据用于AI自动修模,目前显示修复脸,不能上传更新建模状态,防止任务进入到修模部,人数为1才进行处理
headCount = libs.getHeadCount(pid)
#if headCount == 1:
libs_db_gpu.add_task(data={"pid":pid,"cut_body":"face","heads":headCount})
# 更新本地任务状态,更新云端任务状态
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 模型后道处理完成,共费时{libs.diff_time(start_time)}')
@ -228,6 +226,12 @@ def step3(pid,task_distributed_id=""): @@ -228,6 +226,12 @@ def step3(pid,task_distributed_id=""):
print("step3 已执行完成")
#return
common.removeFolder(str(pid))
os.system(f"python D:/make2/tools/get_weight_by_pid.py {pid}")
#执行模型优化,异步调用,再ai_repair 服务区上执行
os.system(f"python D://make2/tools/optimize_model/main.py {pid}")
def main(pid):
if pid == '0':
while True:

6
manual_service.py

@ -68,7 +68,7 @@ def cmd_run(pid,usePhoto = "1",lock=False): @@ -68,7 +68,7 @@ def cmd_run(pid,usePhoto = "1",lock=False):
-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 -align -align \
-align -align \
{exportxmp} \
-save "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" -quit'
print(cmd)
@ -90,8 +90,6 @@ def cmd_run(pid,usePhoto = "1",lock=False): @@ -90,8 +90,6 @@ def cmd_run(pid,usePhoto = "1",lock=False):
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):
@ -107,7 +105,7 @@ def cmd_run(pid,usePhoto = "1",lock=False): @@ -107,7 +105,7 @@ def cmd_run(pid,usePhoto = "1",lock=False):
-load "{os.path.join(config.workdir, pid, f"{pid}.rcproj")}" {config.r["setTextureFalse"]} \
-addFolder "{targetFile}" -selectAllImages \
-detectMarkers "D:\\make2\\config\\detectMarkers.config.xml" \
{libs.get_defineDistances(psid)} -update -align -align -align -align {config.r2["setRegion"]} \
{libs.get_defineDistances(psid)} -update -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 \

4
manual_single.py

@ -61,7 +61,7 @@ def cmd_run(pid,usePhoto = "2",lock=False): @@ -61,7 +61,7 @@ def cmd_run(pid,usePhoto = "2",lock=False):
else:
exportxmp = ' -exportXMP "D:\\make2\\config\\exportXMP.config.xml" '
usePhoto = "photo"+str(usePhoto)
usePhoto = "photo2"
#执行命令
cmd = f'{config.rcbin} {config.r2["init"]} -setInstanceName "{pid}" \
@ -104,7 +104,7 @@ def cmd_run(pid,usePhoto = "2",lock=False): @@ -104,7 +104,7 @@ def cmd_run(pid,usePhoto = "2",lock=False):
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 {config.r2["setRegion"]} \
{libs.get_defineDistances(psid)} -update -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 \

499
pid.text

@ -0,0 +1,499 @@ @@ -0,0 +1,499 @@
189002
189819
190152
190141
190204
190210
190221
190234
190257
190264
190297
190377
190238
190409
190417
190144
190233
189879
190227
190463
190510
190531
164671
190241
190547
188521
190609
184467
188521
189772
188521
190724
190506
190509
190511
190578
183895
190584
190605
190611
190620
190635
190683
190684
190694
190697
190708
190726
183494
185507
188521
183494
190751
183895
190754
183895
189002
190784
190783
190795
190812
183895
190823
190837
190910
190838
190866
190905
190915
190927
190944
190939
190932
190379
190948
190959
190980
190975
190927
190996
190981
191001
190927
190992
182361
185080
191045
185416
191069
191082
191081
191103
191118
191116
191152
191180
191125
191227
191238
191246
191234
191275
191320
191283
191354
191388
191435
191441
191431
191380
191340
191350
191297
191472
191255
191268
191501
191192
191156
191517
191515
191525
191532
191261
191422
191024
191542
191587
191597
191676
191678
191711
191736
186628
191874
191937
191924
191945
191887
191868
191981
191885
191838
191882
191965
191822
191870
191920
191894
191811
191739
191681
191790
191738
191699
191781
191733
191746
191793
191829
191834
191907
191927
191969
191990
191998
192005
192021
192023
192026
191771
190829
192038
191906
192095
192107
192098
192123
191066
192150
192161
192178
191210
191849
191832
192093
192199
192208
192202
192213
192211
192204
183783
192220
192267
192223
190880
192288
188877
192283
192291
192079
192077
192072
192063
188201
192343
192353
192367
192373
192222
192399
192392
189979
189988
189996
190692
190709
191955
191912
192444
192438
187727
192479
192473
192469
192476
192140
192143
192158
192498
192169
192175
192186
192187
192197
192214
190362
192236
192239
192241
192242
192244
192248
192304
192261
192421
192425
192514
192162
192548
192550
184779
192495
192490
192583
192586
192591
192593
192595
184756
192235
187195
192378
192622
192129
192570
192566
192480
192481
192484
192482
192532
192624
192630
192682
192674
192690
192701
188185
192725
192729
192608
192732
192717
192609
192611
192612
192615
192744
192643
192650
192653
192659
192776
192664
192676
192680
192758
192759
192767
192775
192782
192783
185658
192838
192873
192875
192905
192895
192869
187718
188167
192929
192940
192955
192947
192907
192908
192887
192979
193038
193003
193005
192875
193112
193101
193085
193082
192986
192944
193132
193141
193058
193160
193074
193217
193239
192208
193285
193260
193287
193288
193298
193281
193335
193332
193349
193165
193185
193010
193231
193364
193295
193313
193339
193354
193357
193360
193375
193376
193377
193378
193353
193193
193454
192317
193405
193468
193475
193483
193479
193486
193508
193504
193511
193503
193520
193562
193571
193560
193237
193569
193591
193590
193593
193617
193615
193637
193625
193642
193646
193683
193671
193677
193616
193702
193700
193604
193721
193745
193770
193768
193758
193762
193636
193652
190141
193771
193781
193813
193806
193812
193818
193835
193863
193907
193832
193896
193903
193906
193380
193383
193384
193925
193386
193480
193387
193666
193711
193757
193934
193778
193795
193809
193822
193817
193843
193918
193876
193922
193567
193564
193551
192320
193117
193961
193969
193524
193547
193990
193995
194012
194022
194027
194021
194069
194048
194035
194070
194015
194018
194093
194098
194144
194104
194112
194119
194108
194126
194153
194163
194044
194047
194206
194004
194229
194218
194240
194242
194278
194271
194293
194081
194173
194176
194211
194245
194270
194285
194292
194294
194296
194300
194347
190480
190483
194258
194266,194276,194444,194419,194454,194471,194470,194473,194475,194480,194493,194497,194499,194480,194460,192716,194465,194514,194515,194527,194501,194500,194526,194531,194536,194540,194551,194564,194577,194582,194580,187324,194599,194601,194628,194625,194623,189048,186982,194627,194508,194510,189048,194640,194642,194654,194685,194686,194707,194720,194719,194744,194734,194634,194738,194760,194765,194764,194768,194774,190697,194566,194356,194365,194369,194806,194376,194064,194772,194097,194773,194100,194103,194812,194810,194223,194181,194178,194589,194588,186685,194831,194830,194832,194834,194854,194817,194878,191283,191321,194900,194904,194858,194901,194885,194916,194924,194925,194802,194927,194932,194906,194908,194911,194912,194914,194915,194917,194920,194953,194926,194928,194930,194935,194957,194817,190531,189819,194989,194987,194995,194996,192305,194998,195015,195013,195023,195018,195021,195032,195005,195050,189864,195067,195072,195091,195026,195031,195104,195029,195102,195051,195063,195093,195125,195146,193800,195160,195172,195154,195184,194210,186610,191005,187854,193794,

5
step.text

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
old version
init:
'"C:\\Program Files\\Capturing Reality\\RealityCapture\\RealityCapture.exe" -disableOnlineCommunication -set \"sfmEnableCameraPrior=False\" -set \"sfmMaxFeaturesPerMpx=20000\" -set \"sfmMaxFeaturesPerImage=200000\" -set \"sfmImagesOverlap=High\" -set \"sfmMaxFeatureReprojectionError=1\" -addFolder "D:\\{pid}\\photo1" -addFolder "D:\\{pid}\\photo2" -importControlPointsMeasurements "D:\\{pid}\\{pid}..controlPoints.csv" -align -save'

1028
suwa_cut_foot_cut_normal_data.txt

File diff suppressed because it is too large Load Diff

BIN
task_distributed_error.log

Binary file not shown.

29
test.py

@ -1,15 +1,18 @@ @@ -1,15 +1,18 @@
import psutil
import re
# 获取硬盘分区列表
partitions = psutil.disk_partitions()
def extract_o_option(file_path):
pattern = re.compile(r'o\s+(\S+)')
with open(file_path, 'r') as file:
for line in file:
match = pattern.search(line)
if match:
return match.group(1)
return None
for partition in partitions:
print("分区信息",partition)
# 获取指定分区(比如'C:')的使用情况
if partition.mountpoint == 'G:\\': # 更改为您要检测的硬盘分区
usage = psutil.disk_usage(partition.mountpoint)
print(f"Total: {usage.total / (1024**3):.2f} GB")
print(f"Used: {usage.used / (1024**3):.2f} GB")
print(f"Free: {usage.free / (1024**3):.2f} GB")
print(f"Percentage: {usage.percent}%")
# 使用示例
file_path = 'C:/Users/Administrator/Desktop/29282/29282_9cm_x1.obj'
result = extract_o_option(file_path)
if result:
print(f'Found -o option with value: {result}')
else:
print('No -o option found')

4
timer/check_task.py

@ -158,8 +158,8 @@ def get_time_out(hostname,step): @@ -158,8 +158,8 @@ def get_time_out(hostname,step):
if __name__ == '__main__':
#开启死循环
while True:
check_task_distributed_detail()
check_task()
# check_task_distributed_detail()
# check_task()
#两分钟检测一次
time.sleep(120)
print("检测是否存在运行时间超长的任务,进行消息通知")

74
timer/get_weight_to_update.py

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
import redis,time,requests,json,os
def getOrderInfoByOrderId(orderId):
try:
url = "https://mp.api.suwa3d.com/api/physical/infoModelSizeByOrderId?order_id="+str(orderId)
print("url:",url)
res = requests.get(url)
if res.status_code != 200:
print('获取失败,程序退出')
return "error","error"
print("res",res)
res = json.loads(res.text)
print("res",res)
#获取到model_size
modelSize = res['data']['model_size']
pid = res['data']['pid']
return pid,modelSize
except Exception as e:
print(f"获取订单信息异常: {str(e)}")
return "error","error"
if __name__ == '__main__':
r = redis.Redis(host="106.14.158.208",password="kcV2000",port=6379,db=6)
while True:
print(f"时间-{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}")
if r.llen('model:weight') == 0:
print('队列为空,等待10秒')
time.sleep(10)
continue
# info 的数据格式为有以下几种情况 1. orderId 2 orderId_print_9,1.2,45,27 3. orderId_auto_9,1.2,45,27
info = r.lpop('model:weight')
if info is None:
print('队列为空,等待10秒')
time.sleep(10)
info = info.decode('utf-8')
orderId = 0
pid = 0
modelSize = []
typeModel = "print"
#判断info是什么类型的数据
arrInfo = info.split("_")
if len(arrInfo) == 1:
orderId = arrInfo[0]
pid,modelSize = getOrderInfoByOrderId(orderId)
if pid == "error":
print("获取订单信息失败")
continue
elif len(arrInfo) == 3:
orderId = arrInfo[0]
pid,temp = getOrderInfoByOrderId(orderId)
if pid == "error":
print("获取订单信息失败")
continue
typeModel = arrInfo[1]
modelSize = arrInfo[2]
if typeModel != "print" and typeModel != "auto":
print("typeModel类型不对")
continue
if int(orderId) == 0 or int(pid) == 0 or len(modelSize) == 0:
print("orderId pid modelSize 有出现问题")
continue
#转成数组
arrModelSize = modelSize.split(",")
print(f'执行脚本--- "python D:/make2/tools/cal_weight.py {typeModel} {pid} {modelSize} {orderId}"')
#发起计算请求
os.system(f"python D:/make2/tools/cal_weight.py {typeModel} {pid} {modelSize} {orderId}")

8
timer/init_timer.py

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
import time,os
if __name__ == '__main__':
#开启死循环
while True:
#检测当前打印 和 脚底板 和 gs 队列长度
os.system("python E:\\make2\\tools\\push_cmd.py auto_view")
#一个小时检测一次
time.sleep(60*60)

22
timer/setup_oem_exe.py

@ -3,7 +3,7 @@ import redis,requests,json,os,sys @@ -3,7 +3,7 @@ import redis,requests,json,os,sys
import platform
if platform.system() == 'Windows':
sys.path.append('e:\\libs\\')
sys.path.append('e:\\make2\\libs\\')
else:
sys.path.append('/data/deploy/make3d/make2/libs/')
import config
@ -66,32 +66,32 @@ def main(): @@ -66,32 +66,32 @@ def main():
print(data['data'])
#pythob 进入到 E:\wails\oemProject ,将 data 数据写入到 wails.json 文件中的 ext_oem 字段中
with open("D:\\oemProject\\wails.json","r",encoding="utf-8") as f:
with open("E:\\make2\\oemProject\\wails.json","r",encoding="utf-8") as f:
wailsData = json.load(f)
wailsData['ext_oem'] = data['data']
wailsData['name'] = data['data']['brand_name']
wailsData["outputfilename"] = str(data['data']['id'])
with open("D:\\oemProject\\wails.json","w",encoding="utf-8") as f:
with open("E:\\make2\\oemProject\\wails.json","w",encoding="utf-8") as f:
json.dump(wailsData,f,ensure_ascii=False,indent=4)
# #将图片下载到本地
getExeImg(data['data']['logo'], "D:\\oemProject\\build\\appicon.png")
getExeImg(data['data']['exe_logo'], "E:\\make2\\oemProject\\build\\appicon.png")
#删除 D:\\oemProject\\build\\bin 目录下的所有exe 文件,不包含子目录
delete_exe_files_in_dir("D:\\oemProject\\build\\bin")
delete_exe_files_in_dir("E:\\make2\\oemProject\\build\\bin")
# #重命名文件
# os.system(f"cd D:\\oemProject && ren build\\bin\\{data['data']['brand_name']}amd64-installer.exe "+str(data['data']['id'])+".exe")
#写入成功后在 E:\\wails\\oemProject\\ 目录下执行 wails build 命令 -debug
os.system("cd D:\\oemProject && wails build -nsis")
os.system("cd E:\\make2\\oemProject && wails build -nsis -devtools")
time.sleep(35)
#删除指定目录下的多余产生的文件
os.system("cd D:\\oemProject && del /s/q/f build\\bin\\"+str(data['data']['id'])+".exe")
os.system("cd E:\\make2\\oemProject && del /s/q/f build\\bin\\"+str(data['data']['id'])+".exe")
#打包压缩指定文件夹
# 指定要打包的文件夹路径
folder_to_zip = 'D:\\oemProject\\build\\bin'
folder_to_zip = 'E:\\make2\\oemProject\\build\\bin'
# 指定生成的压缩包名称和路径
zip_filename = f"{str(data['data']['id'])}.zip"
@ -104,7 +104,7 @@ def main(): @@ -104,7 +104,7 @@ def main():
#上传成功后,调用接口,告诉mp,已经生成exe及上传成功
requests.get(url+"/api/oem/infoSetupUpdate",params={"id":oemId})
#
os.system("cd D:\\make2 && del /s/q/f timer\\"+str(data['data']['id'])+".zip")
os.system("cd E:\\make2 && del /s/q/f timer\\"+str(data['data']['id'])+".zip")
def getExeImg(image_url, output_path):
@ -118,10 +118,10 @@ def getExeImg(image_url, output_path): @@ -118,10 +118,10 @@ def getExeImg(image_url, output_path):
# 保存图片为PNG格式
resized_image.save(output_path, 'PNG')
#转换格式
transToIco(output_path,"D:\\oemProject\\build\\windows\\icon.ico")
transToIco(output_path,"E:\\make2\\oemProject\\build\\windows\\icon.ico")
#复制图片到指定目录
time.sleep(3)
shutil.copy("D:\\oemProject\\build\\windows\\icon.ico","D:\\oemProject\\build\\bin\\icon.ico",)
shutil.copy("E:\\make2\\oemProject\\build\\windows\\icon.ico","E:\\make2\\oemProject\\build\\bin\\icon.ico",)
else:
print(f"Failed to download image. Status code: {response.status_code}")

102
tools/base_data_fix.py

@ -0,0 +1,102 @@ @@ -0,0 +1,102 @@
import platform,sys,redis,time,requests,json,atexit
sys.path.append('../libs/')
import config,libs,libs_db_temp,common
import os, sys, time, argparse, requests, json, re, oss2, probreg
import bpy, bmesh
import open3d as o3d
import numpy as np
import cupy as cp
from mathutils import Matrix
import math
import logging
import matplotlib.pyplot as plt
#获取真实身高
def get_real_height(input_path):
get_real_height_url = 'https://mp.api.suwa3d.com/api/physical/infoByPid'
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: Getting real height from {input_path}')
pid = re.findall(r'(\d+)', input_path)[0]
print(f'pid: {pid}')
res = requests.get(get_real_height_url, params={'pid': pid})
res = json.loads(res.text)
if res['code'] == -1:
print(f'Error: {res["message"]}, return default height 160')
return 160
height = res['data']['height']
if height == 0:
print(f'Error: height=0, return default height 160')
return 160
print(f'height: {height}')
return height
def base_fix(input_path):
if not os.path.exists(input_path):
print(f'Error: {input_path} does not exist.')
sys.exit(1)
bpy.ops.wm.read_homefile()
bpy.ops.object.delete(use_global=False, confirm=False)
bpy.ops.wm.obj_import(filepath=input_path)
bpy.context.scene.unit_settings.scale_length = 1
bpy.context.scene.unit_settings.length_unit = 'CENTIMETERS'
bpy.context.scene.unit_settings.mass_unit = 'GRAMS'
obj = bpy.context.selected_objects[0]
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
# 脚底贴地
bpy.ops.object.align(align_mode='OPT_1', relative_to='OPT_1', align_axis={'Z'})
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
real_height = get_real_height(input_path)
print(obj.dimensions)
scale = real_height / obj.dimensions[2] / 100 # 除以100是因为单位是厘米
bpy.context.object.scale = (scale, scale, scale)
bpy.context.object.rotation_euler = (0, 0, 0)
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_VOLUME', center='MEDIAN')
bpy.context.object.location[0] = 0 # 移动到特定位置(1m, 1m)是为了让human3d可以正确识别
bpy.context.object.location[1] = 0
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
# # bpy.ops.wm.save_mainfile(filepath=args.input_path.replace('.obj', '.blend'))
output_file = input_path.replace('.obj', '_baseFixed.obj')
bpy.ops.wm.obj_export(filepath=output_file)
return obj
def readTask():
# #读取数据库的任务
# pid = libs_db_temp.get_task_by_level()
# pid = str(pid)
# #下载pid的对应的oss端的文件
# tempName = libs.down_obj_from_oss_for_fix("E://obj_fix", pid, "print")
# if tempName == "":
# print("找不到对应的obj文件")
# #记录状态为异常 -1
# libs_db_temp.update_fix_status(pid,-1)
# return ""
# #记录状态为处理中
# libs_db_temp.update_fix_status(pid,1)
# #处理逻辑
# return pid
pid=7013
base_fix(f'E://obj_fix/{pid}/{pid}.obj')
# print(pid)
# print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())+"-读取数据库任务")
#程序主入口
if __name__ == '__main__':
#atexit.register(common.notify,"处理数据校准任务已经停止")
readTask()
# while True:
# print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())+"-开始执行任务")
# pid = readTask()
# if pid != "":
# break

36
tools/cal_weight.py

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import os, sys, time, bpy, bmesh, shutil
import os, sys, time, bpy, bmesh, shutil,requests,json
import platform
if platform.system() == 'Windows':
sys.path.append('e:\\libs\\')
@ -64,16 +64,35 @@ def cal_weight(obj, size): @@ -64,16 +64,35 @@ def cal_weight(obj, size):
model_info['volume'] = round(bm.calc_volume() / 1000)
model_info['weight'] = round(model_info['volume'] * 1.226)
print(f'{size/10}cm:体积 {model_info["volume"]}cm³, 克重 {model_info["weight"]}g')
return model_info["weight"]
def main(action, pid, sizes):
def main(action, pid, sizes,orderId=0):
libs.down_obj_from_oss(config.workdir, pid, action)
obj = reload_obj(pid, action)
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
print(f'模型{pid}的体积与克重估算信息:')
arrData = {}
for size in sizes:
size = float(size)
cal_weight(obj, size)
weight = cal_weight(obj, size)
size = str(size/10)+"cm"
arrData[size] = str(weight)+"g"
#请求接口进行更新数据
arrParams = {"pid":pid,"order_id":orderId}
if action == "auto":
arrParams["auto_weight"] = json.dumps(arrData)
if action == "print":
arrParams["print_weight"] = json.dumps(arrData)
#发起请求
print(f"请求的参数-{arrParams}")
url = "https://mp.api.suwa3d.com/api/physical/addPhysicalWeight"
res = requests.post(url,data=arrParams)
print('res:', res.text)
if __name__ == '__main__':
sizes = (90, 120, 150, 180)
@ -83,10 +102,19 @@ if __name__ == '__main__': @@ -83,10 +102,19 @@ if __name__ == '__main__':
pids = sys.argv[2].split(',')
for pid in pids:
main(action, pid, sizes)
elif len(sys.argv) == 5:
action = sys.argv[1]
pids = sys.argv[2].split(',')
sizes = sys.argv[3].split(',')
orderId = sys.argv[4]
for pid in pids:
main(action, pid, sizes,orderId)
print('Usage: python cal_weight.py print <pids> order_id 自定义尺寸/默认四个尺寸就不填')
elif len(sys.argv) == 4:
action = sys.argv[1]
pids = sys.argv[2].split(',')
sizes = sys.argv[3].split(',')
for pid in pids:
main(action, pid, sizes)
print('Usage: python cal_weight.py print <pids> 自定义尺寸/默认四个尺寸就不填')
print('Usage: python cal_weight.py print <pids> order_id 自定义尺寸/默认四个尺寸就不填')

43
tools/get_weight_by_pid.py

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
import os,sys,requests,json
if __name__ == "__main__":
#获取参数
args = sys.argv
print("args:",args)
if len(args) != 2:
print("参数错误")
exit()
pid = args[1]
print("pid",pid)
#根据pid查询order_id的集合
url="https://mp.api.suwa3d.com/api/physical/listOrderIdByPid?pid="+str(pid)
res=requests.get(url)
if res.status_code != 200:
print('获取失败,程序退出')
exit()
res = json.loads(res.text)
print("res",res)
if res["code"] != 1000:
exit()
orderIds = res['data']
print("orderIds:",orderIds)
#循环处理
for orderId in orderIds:
#os.system(f"python D:/make2/tools/cal_weight.py print {pid} {orderId}")
url = "https://mp.api.suwa3d.com/api/physical/infoModelSizeByOrderId?order_id="+str(orderId)
print("url:",url)
res = requests.get(url)
if res.status_code != 200:
print('获取失败,程序退出')
continue
print("res",res)
res = json.loads(res.text)
print("res",res)
#获取到model_size
modelSize = res['data']['model_size']
pid = res['data']['pid']
print(f"执行脚本 python D:/make2/tools/cal_weight.py auto {pid} {modelSize} {orderId}")
os.system(f"python D:/make2/tools/cal_weight.py auto {pid} {modelSize} {orderId}")
# python D:/make2/tools/get_weight_by_pid.py

6
tools/optimize_model/README.txt

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
1. pip install -r requirements.txt安装requirements.txt所需的python包 (python3.10)
2. 使用python optimize_model.py -ip 输入的obj路径 -op 输出的obj路径
python optimize_model.py -ip "D:\finished\190104\output\190104.obj" -op "D:\finished\190104\output\190104_new.obj"

381
tools/optimize_model/libs.py

@ -0,0 +1,381 @@ @@ -0,0 +1,381 @@
import os, time, json, requests, shutil, oss2, psutil
from tqdm import tqdm
from PIL import Image, ImageEnhance
import config,libs_db,common
import threading
from concurrent.futures import ThreadPoolExecutor
def find_blender_bin_path():
base_path = 'C:\\Program Files\\Blender Foundation\\'
if os.path.exists(base_path):
for dir in os.listdir(base_path):
if dir.startswith('Blender'):
blender_bin_path = base_path + dir + '\\blender.exe'
return f'"{blender_bin_path}"'
else:
print('未找到blender安装目录')
exit(1)
def resize_photos(photo_path, ratio=0.5):
for filename in os.listdir(photo_path):
if filename.endswith('.jpg'):
img = Image.open(os.path.join(photo_path, filename))
img = rotate_image(img)
w, h = img.size
img = img.resize((int(w * ratio), int(h * ratio)))
img.save(os.path.join(photo_path, filename))
def rotate_image(image):
# 检查图像的EXIF数据是否包含方向信息
try:
exif = image._getexif()
orientation = exif.get(0x0112)
except:
orientation = None
# 根据方向信息旋转图像
if orientation == 3:
image = image.rotate(180, expand=True)
elif orientation == 6:
image = image.rotate(270, expand=True)
elif orientation == 8:
image = image.rotate(90, expand=True)
return image
def get_ps_adjust_photo_para(psid):
res = requests.get(config.urls['get_ps_adjust_photo_para_url'], params={'id': psid})
print(res.json())
paras = res.json()['data']
brightness_factor, saturation_factor, temperature_factor = float(paras['brightness']), float(paras['saturation']), float(paras['colorTemperature'])
return brightness_factor, saturation_factor, temperature_factor
def adjust_photos(workdir, pid):
def adjust_brightness(image, brightness_factor):
if brightness_factor == 1 or brightness_factor == 0 :
return image
enhancer = ImageEnhance.Brightness(image)
adjusted_image = enhancer.enhance(brightness_factor)
return adjusted_image
def adjust_saturation(image, saturation_factor):
if saturation_factor == 1:
return image
enhancer = ImageEnhance.Color(image)
adjusted_image = enhancer.enhance(saturation_factor)
return adjusted_image
def adjust_temperature(image, temperature_factor):
if temperature_factor == 1:
return image
r, g, b = image.split()
r = r.point(lambda i: i * temperature_factor)
adjusted_image = Image.merge("RGB", (r, g, b))
return adjusted_image
if not os.path.exists(os.path.join(workdir, pid, 'photo2')):
print(f"Directory {os.path.join(workdir, pid, 'photo2')} does not exist")
return False
psid = getPSid(pid)
brightness_factor, saturation_factor, temperature_factor = get_ps_adjust_photo_para(psid)
if (brightness_factor == 1 and saturation_factor == 1 and temperature_factor == 1):
print("No need to adjust")
return False
if os.path.exists(os.path.join(workdir, pid, 'photo3')):
print(f'{os.path.join(workdir, pid, "photo3")}目录已存在,跳过')
return
os.makedirs(os.path.join(workdir, pid, 'photo3'), exist_ok=True)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 开始调整图片曝光...')
start_time = time.time()
for filename in os.listdir(os.path.join(workdir, pid, 'photo2')):
if filename.endswith(".jpg"):
# print(f"Adjusting {filename}:brightness={brightness_factor}, saturation={saturation_factor}, temperature={temperature_factor}")
image = Image.open(os.path.join(workdir, pid, 'photo2', filename))
image = rotate_image(image)
brightened_image = adjust_brightness(image, brightness_factor)
saturated_image = adjust_saturation(brightened_image, saturation_factor)
adjusted_image = adjust_temperature(saturated_image, temperature_factor)
adjusted_image.save(os.path.join(workdir, pid, 'photo3', filename))
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 图片曝光调整完成,共费时{diff_time(start_time)}')
return True
def getPSid(pid):
res = requests.get(config.urls['get_psid_url'], params={'pid': pid})
print('get_psid_url:', res.url)
print('res:', res.text)
res = json.loads(res.text)
return str(res['data'])
def getHeadCount(pid):
res = requests.get(config.urls['get_printinfo_url'], params={'id': pid})
print('get_printinfo_url:', res.url)
print('res:', res.text)
if res.status_code != 200:
print('获取人数失败,程序退出')
exit(1)
res = json.loads(res.text)
return res['data']['headcount']
def get_ps_type(pid):
# return 1:圆形影棚 2:方形影棚
res = requests.get(config.urls['get_ps_type_url'], params={'pid': pid})
return res.json()['data']['type']
def find_valid_camera_on_oss(pid):
if get_ps_type(pid) == 1:
print('当前拍照影棚为:圆形影棚')
cameras = (103, 93, 113)
else:
print('当前拍照影棚为:方形影棚')
cameras = (74, 64, 84)
find_camera = 0
for camera in cameras:
objectkey = f'photos/{pid}/photo2/{camera}_8.jpg'
find = config.oss_bucket.object_exists(objectkey)
if find:
find_camera = camera
break
print('找到有效正脸相机:', find_camera)
if find_camera == 0:
print('{cameras}没有找到照片,程序退出')
exit(1)
return find_camera
def aliyun_face(pid):
high = False
style = 'imm/detectface'
camera = find_valid_camera_on_oss(pid)
objectkey = f'photos/{pid}/photo2/{camera}_8.jpg'
try:
res = config.oss_bucket.get_object(objectkey, process=style)
except oss2.exceptions.NoSuchKey:
print('没有找到文件:', objectkey)
return high
res = json.loads(res.read())
if res['success']:
if res['Faces'] is None:
print('no face')
return None
else:
print('faces num:', len(res['Faces']))
for face in res['Faces']:
print('-' * 20)
print('face_id:', face['FaceId'])
print('gender:', face['Gender'])
print('age:', face['Age'])
if face['Gender'] == 'FEMALE' and face['Age'] < 22: high = True
if face['Gender'] == 'MALE' and face['Age'] < 15: high = True
else:
print('face detect failed...')
return high
def down_obj_from_oss(workdir, pid, action):
if os.path.exists(os.path.join(workdir, action, pid)):
print(f'目录{os.path.join(workdir, action, pid)}已存在,跳过')
return
else:
os.makedirs(os.path.join(workdir, action, pid))
# 根据前缀获取文件列表
prefix = f'objs/{action}/{pid}/'
filelist = oss2.ObjectIteratorV2(config.oss_bucket, prefix=prefix)
print('正在下载:', prefix)
obj_filename = ""
for file in filelist:
filename = file.key.split('/')[-1]
if filename.endswith('.obj'):
obj_filename = filename
# print('正在下载:', file.key)
localfile = os.path.join(workdir, action, pid, filename)
config.oss_bucket.get_object_to_file(file.key, localfile)
return obj_filename
def set_photos_join_type(workdir, pid, photoN, mesh = '0', texture='0'):
photoN_path = os.path.join(workdir, pid, photoN)
for xmp in os.listdir(photoN_path):
if xmp.endswith('.xmp'):
xmp_path = os.path.join(photoN_path, xmp)
with open(xmp_path, 'r') as f:
lines = f.readlines()
lines = [line.replace('xcr:InMeshing="0"', f'xcr:InMeshing="{mesh}"') for line in lines]
lines = [line.replace('xcr:InMeshing="1"', f'xcr:InMeshing="{mesh}"') for line in lines]
lines = [line.replace('xcr:InTexturing="0"', f'xcr:InTexturing="{texture}"') for line in lines]
lines = [line.replace('xcr:InTexturing="1"', f'xcr:InTexturing="{texture}"') for line in lines]
with open(xmp_path, 'w') as f:
f.writelines(lines)
def set_photo_join_type(workdir, pid, photoN, camera_id, mesh = '0', texture='0'):
if photoN == 'photo1':
filename = os.path.join(workdir, pid, photoN, f'{camera_id}_1.xmp')
else:
filename = os.path.join(workdir, pid, photoN, f'{camera_id}_8.xmp')
with open(filename, 'r') as f:
lines = f.readlines()
lines = [line.replace('xcr:InMeshing="0"', f'xcr:InMeshing="{mesh}"') for line in lines]
lines = [line.replace('xcr:InMeshing="1"', f'xcr:InMeshing="{mesh}"') for line in lines]
lines = [line.replace('xcr:InTexturing="0"', f'xcr:InTexturing="{texture}"') for line in lines]
lines = [line.replace('xcr:InTexturing="1"', f'xcr:InTexturing="{texture}"') for line in lines]
with open(filename, 'w') as f:
f.writelines(lines)
def down_from_oss(oss_client, workdir, pid, per=100,photoPath=""):
start_time = time.time()
path = os.path.join(workdir, pid)
if os.path.exists(path):
print(f"Directory {path} already exists, skip")
return
os.makedirs(os.path.join(path, 'photo1'))
os.makedirs(os.path.join(path, 'photo2'))
psid = getPSid(pid)
# 根据前缀获取文件列表
prefix = f'photos/{pid}/'
filelist = oss2.ObjectIteratorV2(oss_client, prefix=prefix)
for file in tqdm(filelist):
filename = file.key.split('/')[-1]
localfile = ""
# print('正在下载:', file.key)
if photoPath == "":
if filename.endswith('_1.jpg'):
localfile = os.path.join(path, 'photo1', filename)
else:
localfile = os.path.join(path, 'photo2', filename)
else:
if photoPath=="1":
if filename.endswith('_1.jpg'):
localfile = os.path.join(path, 'photo1', filename)
else:
if filename.endswith('_8.jpg'):
localfile = os.path.join(path, 'photo2', filename)
if localfile == "":
continue
style = f'image/resize,p_{per}'
if per == 100:
oss_client.get_object_to_file(file.key, localfile)
else:
oss_client.get_object_to_file(file.key, localfile, process=style)
#判断localfile 是否有包含 photo2
#遍历处理photo2的数数据
# if str(psid) == "96" or str(pid) == "118994":
# path = os.path.join(workdir, pid, 'photo2')
# files = []
# for fileName in os.listdir(path):
# if ".jpg" in fileName:
# files.append(path+"\\"+fileName)
# beginTime = time.time()
# with ThreadPoolExecutor(max_workers=6) as executor:
# executor.map(process_image, files)
# print(f'{localfile}灰度处理费时{diff_time(beginTime)}')
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 图片下载完成, 共费时{diff_time(start_time)}')
#灰度处理图片
def process_image(localfile):
if ".jpg" in localfile:
common.remove_gray_and_sharpening(localfile)
def get_defineDistances(psid):
res = ''
distances = libs_db.get_floor_sticker_distances(psid).split(';')
print("distances",distances)
for d in distances:
p1, p2, distance = d.split(' ')
res = res + f' -defineDistance {p1} {p2} {distance}'
return res.strip()
def is_running(psname):
for p in psutil.process_iter(['name']):
if psname.strip() in p.info['name']:
return True
return False
def diff_time(start_time):
# 按照分:秒的方式返回时间差
end_time = time.time()
diff = end_time - start_time
m, s = divmod(diff, 60)
return f'{int(m)}{int(s)}'
def down_obj_from_oss_for_fix(workdir, pid, action):
if os.path.exists(os.path.join(workdir, action, pid)):
print(f'目录{os.path.join(workdir, action, pid)}已存在,跳过')
return
else:
os.makedirs(os.path.join(workdir, action, pid))
# 根据前缀获取文件列表
prefix = f'objs/{action}/{pid}/'
filelist = oss2.ObjectIteratorV2(config.oss_bucket, prefix=prefix)
print('正在下载:', prefix)
obj_filename = ""
for file in filelist:
filename = file.key.split('/')[-1]
if filename.endswith(f'{pid}.obj') == False:
continue
if filename.endswith('.obj'):
obj_filename = filename
# print('正在下载:', file.key)
localfile = os.path.join(workdir, action, pid, filename)
config.oss_bucket.get_object_to_file(file.key, localfile)
return obj_filename
def down_obj_from_oss_for_repeat_texture(workdir, pid, action):
print(os.path.join(workdir, pid))
if not os.path.exists(os.path.join(workdir, pid)):
print("目录不存在,无法处理")
return "error"
#判断是否有专门新建的目录用来重新贴图
newPath = os.path.join(workdir, pid,'repeat_texture','completion_cloud')
if not os.path.exists(newPath):
os.makedirs(newPath)
# 根据前缀获取文件列表
prefix = f'objs/{action}/{pid}/ai/repeat_texture/completion_cloud'
filelist = oss2.ObjectIteratorV2(config.oss_bucket, prefix=prefix)
print('正在下载:', prefix)
for file in filelist:
filename = file.key.split('/')[-1]
if filename == "":
continue
localfile = os.path.join(newPath, filename)
config.oss_bucket.get_object_to_file(file.key, localfile)
return newPath
def down_obj_from_oss_auto(pid,action,pathStr):
#pathStr = os.path.join(workdir, str(pid)+"_ai")
if not os.path.exists(pathStr):
os.makedirs(pathStr)
# 根据前缀获取文件列表
prefix = f'objs/{action}/{pid}'
filelist = oss2.ObjectIteratorV2(config.oss_bucket, prefix=prefix)
print('正在下载:', prefix)
for file in filelist:
filename = file.key.split('/')[-1]
if filename == "":
continue
if filename != f"{pid}.jpg" and filename != f"{pid}.obj" and filename != f"{pid}.mtl":
continue
print(filename)
localfile = os.path.join(pathStr, filename)
config.oss_bucket.get_object_to_file(file.key, localfile)

31
tools/optimize_model/main.py

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
import paramiko,time,sys
def main_optimize_model(pid):
try:
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在known_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
print('start connect')
# 连接服务器
ssh.connect('connect.bjc1.seetacloud.com', username='root', password='QoQA8q3Ds2VB', port=33733)
print('connect success')
# 使用nohup执行命令,并将输出重定向到文件
command = f'nohup seg_python /data/code/optimize_model_xj/optimize_model.py -pid {pid} >{pid}.log 2>&1&'
stdin, stdout, stderr = ssh.exec_command(command)
# 打印命令是否启动成功
print("Command executed")
finally:
# 确保连接被关闭
if ssh:
time.sleep(1)
ssh.close()
if __name__ == '__main__':
if len(sys.argv) == 2:
pid = sys.argv[1]
main_optimize_model(pid)

244
tools/optimize_model/optimize_model.py

@ -0,0 +1,244 @@ @@ -0,0 +1,244 @@
import bpy
import sys
import open3d as o3d
import numpy as np
from sklearn.neighbors import NearestNeighbors
import os
import argparse
def estimate_point_curvatures(point_cloud, k=30):
point_cloud_points = np.asarray(point_cloud.points)
# Initialize the nearest neighbors finder
nn = NearestNeighbors(n_neighbors=k)
nn.fit(point_cloud_points)
curvatures = {i: 0 for i in range(len(point_cloud.points))}
for i, point in enumerate(point_cloud_points):
# Find the k-nearest neighbors (including the point itself)
distances, indices = nn.kneighbors([point])
neighbors = point_cloud_points[indices[0]]
# Compute the covariance matrix
covariance_matrix = np.cov(neighbors - neighbors.mean(axis=0), rowvar=False)
# Compute the eigenvalues (sorted)
eigenvalues, _ = np.linalg.eigh(covariance_matrix)
eigenvalues.sort()
# Calculate curvature using the smallest eigenvalue
curvature = eigenvalues[0] / sum(eigenvalues)
curvatures[i] = curvature
return curvatures
def compute_adjacent_normal_angle_variance(pcd, pcd_normal, distance_scale):
kdtree = o3d.geometry.KDTreeFlann(pcd)
distances = []
for i in range(len(pcd.points)):
[k, idx, dist] = kdtree.search_knn_vector_3d(pcd.points[i], 2)
dist = dist[1:] # distances to the actual neighbors
distances.append(dist)
mean_distance = np.mean(distances)
adjacent_normal_angles_variance = {i: 0 for i in range(len(np.asarray(pcd.points)))}
for i, point in enumerate(pcd.points):
# Search for the k-nearest neighbors of the point, up to 1500
k, idx, dist = kdtree.search_knn_vector_3d(point, 200)
idx = np.asarray(idx)
indices = idx[dist < mean_distance * distance_scale]
current_normal = pcd_normal[i]
# Calculate dot products between the current normal and its neighbors' normals
dot_products = np.dot(pcd_normal[indices], current_normal)
# Handle any potential NaN values in dot products
valid_dot_products = np.isfinite(dot_products)
dot_products = dot_products[valid_dot_products]
# Clip dot product values to valid range for arccos
dot_products = np.clip(dot_products, -1.0, 1.0)
# Compute angles in degrees and adjust for any NaNs which might be due to numerical errors
angles_array = np.degrees(np.arccos(dot_products))
# Set the angle with itself to zero since it's not meaningful
angles_array[indices == i] = 0
# Calculate the mean angle excluding the zero for the current point
valid_angles = angles_array[indices != i]
if valid_angles.size > 0:
adjacent_normal_angles_variance[i] = np.std(valid_angles)
else:
adjacent_normal_angles_variance[i] = 0 # Default to 0 if no valid neighbors exist
return adjacent_normal_angles_variance
def compute_adjacent_point_vector_degrees_mean(pcd, pcd_normal, distance_scale):
kdtree = o3d.geometry.KDTreeFlann(pcd)
distances = []
for i in range(len(pcd.points)):
[k, idx, dist] = kdtree.search_knn_vector_3d(pcd.points[i], 2)
dist = dist[1:] # distances to the actual neighbors
distances.append(dist)
mean_distance = np.mean(distances)
adjacent_point_vector_degrees_mean = {i: 0 for i in range(len(np.asarray(pcd.points)))}
for i, point in enumerate(pcd.points):
# Search for the k-nearest neighbors of the point, up to 200
k, idx, dist = kdtree.search_knn_vector_3d(point, 200)
idx = np.asarray(idx)
indices = idx[dist < mean_distance * distance_scale]
indices = indices[indices != i]
# Retrieve the normal of the current point
current_normal = pcd_normal[i]
adjacent_point_vector = np.asarray(pcd.points)[indices] - point
adjacent_point_vector_cos = np.dot(adjacent_point_vector, current_normal) / np.linalg.norm(adjacent_point_vector, axis = 1) * 1
valid_adjacent_point_vector_cos = np.isfinite(adjacent_point_vector_cos)
adjacent_point_vector_cos = adjacent_point_vector_cos[valid_adjacent_point_vector_cos]
if len(adjacent_point_vector_cos) > 0:
adjacent_point_vector_degrees = np.degrees(np.arccos(adjacent_point_vector_cos))
adjacent_point_vector_mean_degrees = np.mean(adjacent_point_vector_degrees)
adjacent_point_vector_degrees_mean[i] = adjacent_point_vector_mean_degrees
else:
adjacent_point_vector_degrees_mean[i] = 0
return adjacent_point_vector_degrees_mean
def spread_point(pcd, selected_index, distance_scale, count = False):
kdtree = o3d.geometry.KDTreeFlann(pcd)
distances = []
for i in range(len(pcd.points)):
[k, idx, dist] = kdtree.search_knn_vector_3d(pcd.points[i], 2)
dist = dist[1:] # distances to the actual neighbors
distances.append(dist)
mean_distance = np.mean(distances)
if count is False:
spread_selected_index = set()
for i in selected_index:
k, idx, dist = kdtree.search_knn_vector_3d(pcd.points[i], 200)
idx = np.asarray(idx)
dist = np.asarray(dist)
indices = idx[dist < mean_distance * distance_scale]
spread_selected_index.update(indices)
spread_selected_index = np.array(list(spread_selected_index))
else:
spread_selected_index = {i: 0 for i in range(len(np.asarray(pcd.points)))}
for i in selected_index:
k, idx, dist = kdtree.search_knn_vector_3d(pcd.points[i], 200)
idx = np.asarray(idx)
dist = np.asarray(dist)
indices = idx[dist < mean_distance * distance_scale]
for indice in indices:
spread_selected_index[indice] += 1
return spread_selected_index
def ApplySmoothEffort(object, selected_vertice_indices = None, factor = 0.5, iterations = 30):
if selected_vertice_indices is not None:
# Assuming 'mesh' is already defined, e.g., mesh = bpy.context.object.data
selected_vertices_index = set() # Initialize an empty set to store unique vertex indices
# Iterate over each index in the list of polygon indices
for idx in selected_vertice_indices:
polygon = object.data.polygons[idx]
for vert_idx in polygon.vertices:
selected_vertices_index.add(vert_idx)
# Switch to Edit mode
bpy.ops.object.mode_set(mode='EDIT')
# Ensure we're dealing with the latest data
bpy.ops.object.mode_set(mode='OBJECT')
for i, vertex in enumerate(object.data.vertices):
vertex.select = False
if i in selected_vertices_index:
vertex.select = True
# Update the object to reflect changes
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.object.mode_set(mode='OBJECT')
# Add a Smooth modifier and set it to use the vertex group
smooth_mod = object.modifiers.new(name="SmoothMod", type='SMOOTH')
if selected_vertice_indices is not None:
# Create a new vertex group
group = object.vertex_groups.new(name='Smooth Group')
# Add selected vertices to the vertex group
group.add([v.index for v in object.data.vertices if v.select], weight=1.0, type='ADD')
smooth_mod.vertex_group = 'Smooth Group'
smooth_mod.factor = factor
smooth_mod.iterations = iterations
# bpy.ops.object.modifier_apply(modifier="SmoothMod")
# if selected_vertice_indices is not None:
# object.vertex_groups.clear()
def process(input_mesh_path, output_mesh_path):
# Select and delete all objects in the current scene to start fresh
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(confirm=False)
# Path to the OBJ file to be imported
bpy.ops.wm.obj_import(filepath=input_mesh_path)
# Set the current object to the newly imported mesh
current_obj = bpy.context.object
# Retrieve the mesh data from the current object
mesh_data = current_obj.data
bpy.context.view_layer.update()
# Convert Blender mesh vertices to a NumPy array
vertices_array = np.array([vertex.co[:] for vertex in mesh_data.vertices])
# Convert Blender mesh polygons to a NumPy array of triangles
triangles_array = np.array([polygon.vertices[:] for polygon in mesh_data.polygons])
# Create an Open3D mesh object from the arrays
open3d_mesh = o3d.geometry.TriangleMesh()
open3d_mesh.vertices = o3d.utility.Vector3dVector(vertices_array)
open3d_mesh.triangles = o3d.utility.Vector3iVector(triangles_array)
open3d_mesh.compute_triangle_normals()
# Retrieve and store the normals as a NumPy array
triangle_normals_array = np.asarray(open3d_mesh.triangle_normals)
# Compute centroids for each face of the mesh
triangle_centroids_array = np.array([
np.mean(vertices_array[triangle], axis=0)
for triangle in open3d_mesh.triangles
])
# Create a point cloud of face centroids
pcd_triangle_centroid = o3d.geometry.PointCloud()
pcd_triangle_centroid.points = o3d.utility.Vector3dVector(triangle_centroids_array)
point_curvatures = estimate_point_curvatures(pcd_triangle_centroid, 30)
np_point_curvatures = np.array(list(point_curvatures.values()))
point_curvatures_index = np.arange(len(np_point_curvatures))[np_point_curvatures > 0.25]
spread_point_curvatures_index = spread_point(pcd_triangle_centroid, point_curvatures_index, 50)
ApplySmoothEffort(current_obj, spread_point_curvatures_index, 0.5, 30)
adjacent_normal_angle_variance = compute_adjacent_normal_angle_variance(pcd_triangle_centroid, triangle_normals_array, 40)
adjacent_point_vector_degrees_mean = compute_adjacent_point_vector_degrees_mean(pcd_triangle_centroid, triangle_normals_array, 40)
array_adjacent_point_vector_degrees_mean = np.array(list(adjacent_point_vector_degrees_mean.values()))
array_adjacent_normal_angle_variance = np.array(list(adjacent_normal_angle_variance.values()))
use_data = np.where(array_adjacent_point_vector_degrees_mean < 90, array_adjacent_normal_angle_variance, 0)
# Calculate the minimum and maximum values in the angle array, ignoring NaNs.
min_angle = np.nanmin(use_data)
max_angle = np.nanmax(use_data)
# Perform min-max normalization on the angles to scale them between 0 and 1.
# This normalization helps in comparing values on a common scale.
normalized_angles = (use_data - min_angle) / (max_angle - min_angle)
first_select_thread = normalized_angles > 0.2
first_select_thread_number = first_select_thread.astype(np.float64)
thread_normalized_angles_index = np.arange(len(first_select_thread))[first_select_thread]
spread_point_count = spread_point(pcd_triangle_centroid, thread_normalized_angles_index, 3, count=True)
overlapp_trigular_points = np.array(list(spread_point_count.values())) > 3
overlapp_trigular_points_index = np.arange(len(overlapp_trigular_points))[overlapp_trigular_points]
ApplySmoothEffort(current_obj, overlapp_trigular_points_index, 0.5, 30)
ApplySmoothEffort(current_obj, factor=0.5, iterations=30)
bpy.ops.wm.obj_export(filepath=output_mesh_path)
def process_meshes(input_path, output_path):
"""
Processes each mesh file in the input directory and saves the cleaned meshes in the output directory.
Args:
input_path (str): Directory containing the input meshes or a single mesh file.
output_path (str): Directory where the cleaned meshes will be saved.
"""
if os.path.isdir(input_path):
for filename in sorted(os.listdir(input_path)):
full_input_path = os.path.join(input_path, filename)
full_output_path = os.path.join(output_path, filename)
process(full_input_path, full_output_path)
else:
process(input_path, output_path)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Processes mesh files.")
parser.add_argument("-ip", "--input_path", type=str, required=True, help="Input path for the mesh file or directory.")
parser.add_argument("-op", "--output_path", type=str, required=True, help="Output path for the cleaned mesh file or directory.")
args = parser.parse_args()
process_meshes(args.input_path, args.output_path)

5
tools/optimize_model/requirements.txt

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
open3d
numpy
sklearn
argparse
bpy

78
tools/optimize_model/run.py

@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
import os,sys,time,shlex,subprocess,shutil,requests,json
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 libs,config
def main(pid = 0):
print(f'开始时间-{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}')
if pid == 0:
#获取要处理PID的url
url = "https://repair.api.suwa3d.com/api/modelRepairOrder/getRepairOrderListByPriority"
#发起请求
res = requests.get(url)
print('res:', res.text)
if res.status_code != 200:
print('获取失败,程序退出')
return
res = json.loads(res.text)
pid = 0
try:
pid = res['data']['pid']
except Exception as e:
return 0
if pid == 0:
return 0
#调用oss下载功能,下载对应的文件
pathStr = os.path.join(config.workdir,str(pid)+"_ai")
libs.down_obj_from_oss_auto(str(pid),"auto",pathStr)
#检查是否存在产生的对应的文件
if not os.path.exists(os.path.join(pathStr,f'{pid}.obj')):
print(f"找不到{pid}obj文件")
return
if not os.path.exists(os.path.join(pathStr,f'{pid}.mtl')):
print(f"找不到{pid}mtl文件")
return
#下载完成后调用
os.system(f"python optimize_model.py -ip {pathStr}/{pid}.obj -op {pathStr}/{pid}_ai.obj")
#检查是否存在产生的对应的文件
if not os.path.exists(os.path.join(pathStr,f'{pid}_ai.obj')):
print(f"找不到{pid}ai_obj文件")
return
if not os.path.exists(os.path.join(pathStr,f'{pid}_ai.mtl')):
print(f"找不到{pid}ai_mtl文件")
return
#处理完成完后上传到oss指定目录
config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/ai/fix_mesh/{pid}_ai.obj', os.path.join(pathStr,f'{pid}_ai.obj'))
config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/ai/fix_mesh/{pid}_ai.mtl', os.path.join(pathStr,f'{pid}_ai.mtl'))
config.oss_bucket.put_object_from_file(f'objs/auto/{pid}/ai/fix_mesh/{pid}.jpg', os.path.join(pathStr,f'{pid}.jpg'))
#更新处理结果
url = "https://repair.api.suwa3d.com/api/modelRepairOrder/updateShootOrderBuildModelType?pid="+str(pid)
#发起请求
requests.get(url)
#移除文件夹
shutil.rmtree(pathStr)
print(f'结束时间-{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}')
if __name__ == '__main__':
if len(sys.argv) == 2:
pid = sys.argv[1]
main(pid)
print(f"{pid}-处理结束")
else:
while True:
res = main()
if res == 0:
print("休眠60s")
time.sleep(60)

22
tools/optimize_model/test.py

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
import paramiko
try:
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在known_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
print('start connect')
# 连接服务器
ssh.connect('connect.bjc1.seetacloud.com', username='root', password='QoQA8q3Ds2VB', port=33733)
print('connect success')
# 使用nohup执行命令,并将输出重定向到文件
command = 'nohup seg_python /data/code/optimize_model_xj/optimize_model.py -pid 189813 > output.log 2>&1 &'
stdin, stdout, stderr = ssh.exec_command(command)
# 打印命令是否启动成功
print("Command executed")
finally:
# 确保连接被关闭
if ssh:
ssh.close()

55
tools/push_cmd.py

@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
import redis, os, sys,requests,platform
import redis, os, sys,requests,platform,json
if platform.system() == 'Windows':
sys.path.append('e:\\libs\\')
sys.path.append('E:\\make2\\libs\\')
#sys.path.append('libs')
else:
sys.path.append('/data/deploy/make3d/make2/libs/')
import config, libs,libs_db
import config, libs,libs_db,libs_db_task_rc
def main(cmd, order_id):
if cmd == 'print': #order_id
@ -19,8 +19,19 @@ def main(cmd, order_id): @@ -19,8 +19,19 @@ def main(cmd, order_id):
key = 'model:foot'
elif cmd == 'rebuild': #pid
key = 'model:rebuild'
elif cmd == 'gs':
key = 'ai:ai_build'
if order_id == 'view':
if cmd == "rc_model_build":
nums = libs_db_task_rc.get_task_rc_count()
print(f'当前{cmd}队列长度:{nums}')
notify(f'当前{cmd}队列长度:{nums}')
else:
print(f'当前{cmd}队列长度:{r.llen(key)}')
notify(f'当前{cmd}队列长度:{r.llen(key)}')
for i in r.lrange(key, 0, -1):
print(i)
print(f'当前{key}队列长度:{r.llen(key)}')
@ -30,6 +41,23 @@ def main(cmd, order_id): @@ -30,6 +41,23 @@ def main(cmd, order_id):
r.lpush(key, order_id)
print(f'已推送{order_id}{key}, 当前队列长度:{r.llen(key)}')
def notify(content):
if content == "":
return "content 不能为空"
for user_agent_id in config.notify_user_Ids:
data = {
'userId': user_agent_id,
'message': content,
}
headers = {'Content-Type': 'application/json'}
message_send_url = "https://mp.api.suwa3d.com/api/qyNotify/sendMessage?userId="+user_agent_id+"&message="+content
response = requests.post(message_send_url, data=json.dumps(data), headers=headers)
def cmd(cmdName,pid):
if pid == "view":
key = ""
@ -43,6 +71,14 @@ def cmd(cmdName,pid): @@ -43,6 +71,14 @@ def cmd(cmdName,pid):
key = 'model:make10'
elif cmdName == 'foot': # print_id
key = 'model:foot'
if pid == 'view':
# for i in r.lrange(key, 0, -1):
# print(i)
print(f'当前{cmd}队列长度:{r.llen(key)}')
notify(f'当前{cmd}队列长度:{r.llen(key)}')
exit()
else:
for i in r.lrange(key, 0, -1):
print(i)
print(f'当前{key}队列长度:{r.llen(key)}')
@ -135,13 +171,24 @@ def listDataToStr(data,cmdName): @@ -135,13 +171,24 @@ def listDataToStr(data,cmdName):
if __name__ == '__main__':
r = config.redis_remote
if len(sys.argv) == 3:
cmdName = sys.argv[1]
pid = sys.argv[2]
elif len(sys.argv) == 2:
cmd = sys.argv[1]
order_id = 'view'
if cmd == "auto_view":
arrCmd = ["print","foot","gs","rc_model_build"]
for cmdV in arrCmd:
main(cmdV, order_id)
exit(1)
else:
print('用法:python push_cmd.py <cmd> <order_id>')
exit(1)
r = config.redis_remote
#pid 可能是多个的,用逗号分隔,查询的时候接口应该也要支持多个的
if cmdName == 'make3d' or cmdName == 'make3d10' or cmdName == 'rebuild':

41
建模碎片步骤.txt

@ -1,3 +1,42 @@ @@ -1,3 +1,42 @@
#建模完成,需要减面 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
%bin% -delegateTo 161082 -simplify 2000000 -smooth -closeHoles -cleanModel -calculateTexture -save "D:\161082\161082.rcproj" -exportSelectedModel "D:\161082\output\161082.obj" "d:\make2\config\ModelExportParams.xml"
%bin% -delegateTo 161082 -defineDistance 36h11:007 36h11:008 0.21 -update -align -align -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:003 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml"
%bin% -delegateTo 156600 -defineDistance 36h11:001 36h11:002 1 -update -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:004 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml"
%bin% -delegateTo 156600 -defineDistance 36h11:007 36h11:008 0.21 -update -align -align -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:004 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml" -exportReconstructionRegion "D:\156600\156600.rcbox" -selectImage "D:\156600\photo2/*" -enableTexturingAndColoring true -save "D:\156600\156600.rcproj"
%bin% -delegateTo 156600 -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:003 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml" -exportControlPointsMeasurements "D:\156600\156600.controlPoints.csv" "D:\make2\config\exportControlPoints.config.xml" -exportReconstructionRegion "D:\156600\156600.rcbox" -selectImage "D:\156600\photo2\*" -enableTexturingAndColoring true -save "D:\156600\156600.rcproj"
-defineDistance 36h11:007 36h11:008 0.21 -update -align -align -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:003 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml" -exportReconstructionRegion "D:\140241\140241.rcbox" -selectImage "D:\140241\photo2/*" -enableTexturingAndColoring true -save "D:\140241\140241.rcproj"
-defineDistance 36h11:007 36h11:008 0.21 -align -align -update -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:003 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml" -exportControlPointsMeasurements "D:\147024\147024.controlPoints.csv" "D:\make2\config\exportControlPoints.config.xml" -exportReconstructionRegion "D:\147024\147024.rcbox" -selectImage "D:\147024\photo2\*" -enableTexturingAndColoring true -save "D:\147024\147024.rcproj"
%bin% -delegateTo 155007 -defineDistance 36h11:007 36h11:008 0.21 -update -align -align -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:004 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml" -exportReconstructionRegion "D:\155007\155007.rcbox" -save "D:\155007\155007.rcproj"
%bin% -delegateTo 153982 -defineDistance 36h11:007 36h11:008 0.21 -update -align -align -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:004 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml" -exportReconstructionRegion "D:\153982\153982.rcbox" -selectImage "D:\153982\photo2/*" -enableTexturingAndColoring true -save "D:\153982\153982.rcproj"
%bin% -delegateTo 155686 -defineDistance 36h11:007 36h11:008 0.21 -align -align -update -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:004 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml" -exportControlPointsMeasurements "D:\155686\155686.controlPoints.csv" "D:\make2\config\exportControlPoints.config.xml" -exportReconstructionRegion "D:\155686\155686.rcbox" -selectImage "D:\155686\photo2\*" -enableTexturingAndColoring true -save "D:\155686\155686.rcproj"
%bin% -delegateTo 155686 -defineDistance 36h11:007 36h11:008 0.21 -defineDistance 36h11:002 36h11:004 1 -defineDistance 36h11:004 36h11:003 1 -defineDistance 36h11:003 36h11:001 1 -align -align -update -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:003 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml" -exportControlPointsMeasurements "D:\155686\155686.controlPoints.csv" "D:\make2\config\exportControlPoints.config.xml" -exportReconstructionRegion "D:\155686\155686.rcbox" -selectImage "D:\155686\photo2\*" -enableTexturingAndColoring true -save "D:\155686\155686.rcproj"
%bin% -delegateTo 158508 -defineDistance 36h11:007 36h11:008 0.21 -align -align -update -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:004 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml" -exportControlPointsMeasurements "D:\158508\158508.controlPoints.csv" "D:\make2\config\exportControlPoints.config.xml" -exportReconstructionRegion "D:\158508\158508.rcbox" -selectImage "D:\158508\photo2\*" -enableTexturingAndColoring true -save "D:\158508\158508.rcproj"
%bin% -delegateTo 161086 -defineDistance 36h11:007 36h11:008 0.21 -align -align -update -setReconstructionRegionOnCPs 36h11:001 36h11:002 36h11:004 2.1 -moveReconstructionRegion 0 0 -2.1 -rotateReconstructionRegion 180 0 180 -setGroundPlaneFromReconstructionRegion -scaleReconstructionRegion 1.8 1.6 2.1 absolute center -moveReconstructionRegion 0 0 0.0025 -exportXMP "D:\make2\config\exportXMP.config.xml" -exportControlPointsMeasurements "D:\161086\161086.controlPoints.csv" "D:\make2\config\exportControlPoints.config.xml" -exportReconstructionRegion "D:\161086\161086.rcbox" -selectImage "D:\161086\photo2\*" -enableTexturingAndColoring true -save "D:\161086\161086.rcproj"
Loading…
Cancel
Save