Files
make2/main_step1.py
T
2024-09-02 16:52:37 +08:00

237 lines
12 KiB
Python

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 tools/downxmps.py {pid}')
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} {pid} 图片下载完成,共费时{libs.diff_time(start_time)}')
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)
if __name__ == '__main__':
# 取云端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:
main(pid, experience=False, makeloop=False,task_distributed_id="",isNoColorTexture=isNoColorTexture)
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)