建模程序 多个定时程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

282 lines
13 KiB

import os, sys, time, shlex, subprocess, shutil, requests, cv2, numpy as np
from PIL import Image
import json
with open('config.json', 'r') as f:
config = json.load(f)
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 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 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},将不参与贴图')
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} 射灯异常图片检测完成,共费时{diff_time(start_time)}')
def detect_markers(psid, pid):
def fix_region():
#判断是否存在rcbox
region_filename = os.path.join(config["workdir"], pid, f"{pid}.rcbox")
while True:
if os.path.exists(region_filename):
print("region_filename",region_filename)
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]
break
else:
time.sleep(10)
print(f"不存在{region_filename}")
start_time = time.time()
textpicCmd ='-selectImage "'+os.path.join(config['workdir'],pid,'photo2')+'\*" -enableTexturingAndColoring true'
#获取当前的工作目录
dirCurr = os.getcwd()
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"]} \
-addFolder "{os.path.join(config["workdir"], pid, "photo2")}" -align -detectMarkers "{dirCurr}\detectMarkers_1.5.config.xml" \
-align -align -align -align -selectAllImages -detectMarkers "{dirCurr}\detectMarkers_1.5.config.xml" \
-defineDistance 36h11:001 36h11:002 1 -defineDistance 36h11:002 36h11:004 1 -defineDistance 36h11:004 36h11:003 1 -defineDistance 36h11:003 36h11:001 1 -align -align -update {config["r2"]["setRegion"]} \
-exportXMP "{dirCurr}\exportXMP.1.5.draft.config.xml" \
-exportControlPointsMeasurements "{os.path.join(config["workdir"], pid, f"{pid}.controlPoints.csv")}" "{dirCurr}\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)
time.sleep(3)
fix_region()
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid: {pid} 定位点检测完成, 共费时{diff_time(start_time)}')
def step1(pid,headsCount):
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 开始处理{pid}建模任务')
start_time = time.time()
# 检测图片定位点,定位异常及时上报微信通知给客服人员,人工判断是否需要重新拍摄或更换地贴。定义定位点距离,导出相机位姿信息
detect_markers(0, pid)
# 处理图片,检测photo2中的异常图片不参与贴图,以免破坏贴图效果,默认不检测射灯异常图片,以节省算力成本
filter_dark_texture_image(pid)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} step1图片预处理完成,共费时{diff_time(start_time)}')
# os.system(f'python {os.getcwd()}/main_step2.py {pid}')
step2(pid,headsCount)
def step2(pid,headsCount):
dirCurr = os.getcwd()
simplify_value = 1000000 * int(headsCount)
calulate_type = 'calculateNormalModel'
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")}" "{dirCurr}\\ModelExportParams.xml" -quit'
print(cmd)
cmd = shlex.split(cmd)
res = subprocess.run(cmd)
print("res",res)
#阻塞判断是否导出完成
while True:
try:
#判断 output 目录下是否存在 三个文件
files = os.listdir(os.path.join(config['workdir'], pid, "output"))
if len(files) >= 3:
time.sleep(5)
break
except Exception as e:
time.sleep(5)
continue
#将导出的文件移动到指定目录
sourceDir = config["local_complate_build"]
#判断目录是否存在,不存在就创建
if os.path.exists(os.path.join(sourceDir,pid)):
#删除
os.removedirs(os.path.join(sourceDir,pid))
os.makedirs(os.path.join(sourceDir,pid))
#将 output 目录里的文件移动到指定目录
shutil.move(os.path.join(config['workdir'], pid, "output"),os.path.join(sourceDir,pid))
#发起请求告知后端建模完成
try:
res = requests.post(url, data={'id': pid,'status':5000})
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid:{pid} 任务完成- {res.text}')
except Exception as e:
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid:{pid} - 建模完成状态变更失败 - {e}')
#做xmps的坐标
def getXmps(pid):
#从共享盘上下载对齐信息,判断是否有
print(f"判断是否存在 {os.path.join(config['workdir'], 'xmps','texture')} -- {os.path.exists(os.path.join(config['workdir'], 'xmps','texture'))}")
if os.path.exists(os.path.join(config['workdir'], 'xmps','texture')) == False or os.path.exists(os.path.join(config['workdir'], 'xmps','mesh')) == False:
print(f"检测不到对齐坐标,请先人工建一次模进行对齐,创建坐标,创建制定的坐标到 {os.path.join(config['workdir'], 'xmps','mesh')}{os.path.join(config['workdir'], 'xmps','texture')}")
return False
else:
#将共享盘的对齐信息复制到工作目录,photo1 和 photo2
shutil.copytree(os.path.join(config['workdir'], 'xmps','mesh'), os.path.join(config['workdir'], pid, 'photo1'),dirs_exist_ok=True)
shutil.copytree(os.path.join(config['workdir'], 'xmps','texture'), os.path.join(config['workdir'], pid, 'photo2'),dirs_exist_ok=True)
return True
def main(pid,headsCount):
step1(pid, headsCount)
if __name__ == '__main__':
# step1("235558",1)
# exit()
try:
url = config['urls']['update_status_modelsuccess_url']
if url == "":
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 请配置建模完成回调地址')
exit()
# 取云端redis任务,完成第一步的数据预处理后,将数据放入共享存储目录,将第二步任务塞入本地mysql队列
# 默认循环值守,可传参数运行单一任务,以方便调试
pid = '0'
if len(sys.argv) == 3:
pids = sys.argv[1].split(',')
headsCount = sys.argv[2]
for pid in pids:
main(pid,headsCount)
exit()
#获取文件夹下的所有文件
needBuildDir = config['local_need_build']
workdir = config['workdir']
if workdir == '':
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 请配置建模工作目录')
exit()
#不存在就创建工作目录
if not os.path.exists(workdir):
os.makedirs(workdir)
if not os.path.exists(needBuildDir):
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 需要建模目录不存在- {needBuildDir}')
exit()
except Exception as e:
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 初始化异常 - {e}')
#遍历文件夹下的所有文件进行处理
try:
while True:
time.sleep(5)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 建模任务循环开始,{needBuildDir}')
for pid in os.listdir(needBuildDir):
print("pid=",pid)
res = getXmps(pid)
if res == False:
break
if not os.path.isdir(os.path.join(needBuildDir,pid)):
continue
#判断是否存在 canDo.txt 文件,如果不存在就跳过
if not os.path.exists(os.path.join(needBuildDir,pid,"canDo.txt")):
print(f'不存在 canDo.txt- {os.path.join(needBuildDir,pid,"canDo.txt")}')
continue
#读取 canDo.txt 文件内容
headsCounts = 1
with open(os.path.join(needBuildDir,pid,"canDo.txt"),"r") as f:
headsCounts = f.read()
#判断文件夹里是否存在 do.txt , 如果存在就跳过,不存在就创建
if os.path.exists(os.path.join(needBuildDir,pid,"do.txt")):
print("存在 do.txt 。则跳过处理")
continue
else:
with open(os.path.join(needBuildDir,pid,"do.txt"),"w") as f:
f.write("1")
#判断是否已经存在了,存在就删除
if os.path.exists(os.path.join(workdir,pid)):
shutil.rmtree(os.path.join(workdir,pid))
#将文件夹移动到工作目录
shutil.move(os.path.join(needBuildDir,pid),os.path.join(workdir,pid))
res = getXmps(pid)
if res == False:
break
#执行建模流程,建模中的流程
try:
requests.post(url, data={'id': pid,'status':4000})
except Exception as e:
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} pid:{pid} - 状态变更失败 - {e}')
#continue
main(pid,headsCounts)
except Exception as e:
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 建模任务循环异常 - {e}')
exit()