589 lines
26 KiB
Python
589 lines
26 KiB
Python
#!/usr/bin/python
|
|
import oss2, os, sys, redis, time, cv2, numpy, piexif, requests, shlex, subprocess, datetime, shutil, json, psutil
|
|
from threading import Thread
|
|
from matplotlib import pyplot as plt
|
|
from PIL import Image, ImageEnhance
|
|
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 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 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 diff_time(start_time, end_time):
|
|
d = end_time - start_time
|
|
m = d.microseconds
|
|
return str(d.seconds // 60) + ":" + str(d.seconds % 60) + ":" + str(m)[:-3]
|
|
|
|
def down_from_oss(pid):
|
|
start_time = datetime.datetime.now()
|
|
path = os.path.join(workdir, pid)
|
|
if os.path.exists(path): return
|
|
os.makedirs(path)
|
|
os.mkdir(os.path.join(path, 'photo1'))
|
|
os.mkdir(os.path.join(path, 'photo2'))
|
|
|
|
psid = getPSid(pid)
|
|
# 根据前缀获取文件列表
|
|
prefix = f'photos/{pid}/'
|
|
filelist = oss2.ObjectIteratorV2(oss_client, prefix=prefix)
|
|
for file in filelist:
|
|
filename = file.key.split('/')[-1]
|
|
if psid == '9' and filename in ('135_8.jpg', '135_1.jpg'): continue
|
|
if psid == '16' and filename in ('92_8.jpg', '92_1.jpg'): continue
|
|
if psid == '25' and filename in ('13_8.jpg', '13_1.jpg'): continue
|
|
if psid == '34' and filename in ('154_8.jpg', '154_1.jpg'): continue
|
|
if psid == '44' and filename in ('31_8.jpg', '31_1.jpg'): continue
|
|
if psid == '63' and filename in ('123_8.jpg', '123_1.jpg'): continue
|
|
if psid == '70' and filename in ('73_8.jpg', '73_1.jpg'): continue
|
|
print('正在下载:', file.key)
|
|
if not filename.endswith('jpg'): continue
|
|
if filename.endswith('_1.jpg'):
|
|
localfile = os.path.join(path, 'photo1', filename)
|
|
else:
|
|
localfile = os.path.join(path, 'photo2', filename)
|
|
oss_client.get_object_to_file(file.key, localfile)
|
|
|
|
print('下载完成')
|
|
end_time = datetime.datetime.now()
|
|
print('下载耗时:', diff_time(start_time, end_time))
|
|
|
|
def down_xmps_from_oss(psid):
|
|
def need_down():
|
|
filename = f'xmps/{psid}/{psid}.rcbox'
|
|
if not oss_client.object_exists(filename):
|
|
print(f'未找到{filename}, 请检查是否已经上传{psid}号影棚坐标文件')
|
|
time.sleep(5)
|
|
return False
|
|
oss_file_last_modified = float(oss_client.get_object_meta(filename).last_modified)
|
|
local_file = os.path.join(config_path, 'xmps', psid, f'{psid}.rcbox')
|
|
if not os.path.exists(local_file):
|
|
print(f'未找到{local_file}, 需要下载影棚坐标文件')
|
|
os.makedirs(os.path.join(config_path, 'xmps', psid), exist_ok=True)
|
|
oss_client.get_object_to_file(filename, local_file)
|
|
return True
|
|
local_file_last_modified = os.path.getmtime(local_file)
|
|
if oss_file_last_modified > local_file_last_modified:
|
|
print(f'本地{local_file}文件已过期, 需要下载影棚坐标文件')
|
|
oss_client.get_object_to_file(filename, local_file)
|
|
return True
|
|
|
|
if not need_down(): return
|
|
|
|
print('正在下载影棚坐标文件')
|
|
dest_path = os.path.join(config_path, 'xmps', psid)
|
|
|
|
os.makedirs(os.path.join(dest_path, 'mesh'), exist_ok=True)
|
|
os.makedirs(os.path.join(dest_path, 'texture'), exist_ok=True)
|
|
|
|
prefix = f'xmps/{psid}/mesh/'
|
|
filelist = oss2.ObjectIteratorV2(oss_client, prefix=prefix)
|
|
for file in filelist:
|
|
if file.key.endswith('.xmp'):
|
|
filename = file.key.split('/')[-1]
|
|
print('正在下载:', file.key)
|
|
oss_client.get_object_to_file(file.key, os.path.join(dest_path, 'mesh', filename))
|
|
|
|
prefix = f'xmps/{psid}/texture/'
|
|
filelist = oss2.ObjectIteratorV2(oss_client, prefix=prefix)
|
|
for file in filelist:
|
|
if file.key.endswith('.xmp'):
|
|
filename = file.key.split('/')[-1]
|
|
print('正在下载:', file.key)
|
|
oss_client.get_object_to_file(file.key, os.path.join(dest_path, 'texture', filename))
|
|
|
|
print('下载完成')
|
|
|
|
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
|
|
|
|
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(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(pid):
|
|
start_time = datetime.datetime.now()
|
|
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
|
|
os.makedirs(os.path.join(workdir, pid, 'photo3'), exist_ok=True)
|
|
|
|
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("Done")
|
|
end_time = datetime.datetime.now()
|
|
print('调整照片耗时:', diff_time(start_time, end_time))
|
|
return True
|
|
|
|
def get_ps_type(pid):
|
|
# return 1:圆形影棚 2:方形影棚
|
|
res = requests.get(get_ps_type_url, params={'pid': pid})
|
|
return res.json()['data']['type']
|
|
|
|
def getPSid(pid):
|
|
res = requests.get(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(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 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 = oss_client.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 = oss_client.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 set_photos_join_type(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 rc_make(pid, psid, key):
|
|
status = True
|
|
# 建模
|
|
start = datetime.datetime.now()
|
|
|
|
xmps_mesh_path = config_path + f'xmps\\{psid}\\mesh\\'
|
|
xmps_texture_path = config_path + f'xmps\\{psid}\\texture\\'
|
|
|
|
input_path = os.path.join(workdir, pid)
|
|
output_path = os.path.join(input_path, 'output')
|
|
ImagesGeometry = os.path.join(input_path, "photo1")
|
|
ImagesTexture = os.path.join(input_path, "photo2")
|
|
photo3 = os.path.join(input_path, "photo3")
|
|
|
|
ps_region = os.path.join(config_path, 'xmps', psid, f'{psid}.rcbox')
|
|
|
|
shutil.rmtree(output_path, ignore_errors=True)
|
|
os.system('mkdir ' + output_path)
|
|
|
|
ps_fix_list = ('10', '12', '13', '16', '18', '19', '20', '22', '23', '29', '30', '31')
|
|
os.system('xcopy /Y ' + xmps_mesh_path + '* ' + ImagesGeometry)
|
|
os.system('xcopy /Y ' + xmps_texture_path + '* ' + ImagesTexture)
|
|
|
|
simplify_value = str(getHeadCount(pid) * 100 * 10000)
|
|
|
|
if aliyun_face(pid) and get_ps_type(pid) == 1:
|
|
calulate_type = 'calculateHighModel'
|
|
else:
|
|
calulate_type = 'calculateNormalModel'
|
|
|
|
if adjust_photos(pid):
|
|
print('已调整照片,产生出photo3图片组,让photo1和photo2参与建模,photo3仅参与贴图')
|
|
# os.system('xcopy /Y ' + xmps_texture_path + '* ' + photo3)
|
|
set_photos_join_type(pid, 'photo1', mesh='1', texture='0')
|
|
set_photos_join_type(pid, 'photo2', mesh='1', texture='0')
|
|
# set_photos_join_type(pid, 'photo3', mesh='0', texture='1')
|
|
print('rcver:', get_rcver())
|
|
if get_rcver() == 2:
|
|
cmd = rcbin + \
|
|
' -disableOnlineCommunication ' + \
|
|
' -setInstanceName ' + pid + \
|
|
' -addFolder "' + ImagesGeometry + '"' + \
|
|
' -selectAllImages -enableTexturingAndColoring false ' + \
|
|
' -set "sfmEnableCameraPrior=True" -set "sfmMaxFeaturesPerMpx=20000" -set "sfmMaxFeaturesPerImage=200000" -set "sfmImagesOverlap=High" -set "MvsDoCorrectColors=false" -set "MvsIgnoreCorrectColors=false" -set "sfmMaxFeatureReprojectionError=1" ' + \
|
|
' -align ' + \
|
|
' -addFolder "' + ImagesTexture + '" -selectAllImages -enableTexturingAndColoring false ' + \
|
|
' -align ' + \
|
|
' -addFolder "' + photo3 + '" ' + \
|
|
' -align -align ' + \
|
|
' -setReconstructionRegion "' + ps_region + '" ' + \
|
|
' -setGroundPlaneFromReconstructionRegion ' + \
|
|
' -set "mvsMinSampleDistance=0.00001" ' + \
|
|
' -' + calulate_type + ' ' + \
|
|
' -selectLargestModelComponent -invertTrianglesSelection -removeSelectedTriangles -closeHoles -cleanModel ' + \
|
|
' -smooth ' + \
|
|
' -simplify ' + simplify_value + ' ' + \
|
|
' -calculateTexture ' + \
|
|
' -exportSelectedModel "' + output_path + '\\' + pid + '.obj" "' + config_path + 'ModelExportParams.xml" ' + \
|
|
' -quit'
|
|
else:
|
|
cmd = rcbin + \
|
|
' -disableOnlineCommunication ' + \
|
|
' -silent ' + output_path + \
|
|
' -addFolder "' + ImagesGeometry + '"' + \
|
|
' -set "sfmMaxFeaturesPerMpx=20000" -set "sfmMaxFeaturesPerImage=200000" -set "sfmImagesOverlap=High" -set "sfmMaxFeatureReprojectionError=1" ' + \
|
|
' -align ' + \
|
|
' -addFolder "' + ImagesTexture + '"' + \
|
|
' -align ' + \
|
|
' -addFolder "' + photo3 + '"' + \
|
|
' -align -align' + \
|
|
' -setReconstructionRegion "' + ps_region + '" ' + \
|
|
' -mvs ' + \
|
|
' -modelSelectMaximalConnectedComponent -modelInvertSelection -modelRemoveSelectedTriangles -closeHoles -clean ' + \
|
|
' -simplify ' + simplify_value + ' ' + \
|
|
' -smooth -unwrap ' + \
|
|
' -calculateTexture ' + \
|
|
' -renameModel ' + pid + ' ' + \
|
|
' -exportModel ' + pid + ' "' + output_path + '\\' + pid + '.obj" "' + config_path + 'ModelExportParams102.xml" ' + \
|
|
' -quit'
|
|
else:
|
|
print('未调整照片,仍然使用photo1和photo2建模,photo2参与贴图模式')
|
|
set_photos_join_type(pid, 'photo1', mesh='1', texture='0')
|
|
set_photos_join_type(pid, 'photo2', mesh='1', texture='1')
|
|
if get_rcver() == 2:
|
|
cmd = rcbin + \
|
|
' -disableOnlineCommunication ' + \
|
|
' -setInstanceName ' + pid + \
|
|
' -addFolder "' + ImagesGeometry + '"' + \
|
|
' -selectAllImages -enableTexturingAndColoring false ' + \
|
|
' -set "sfmEnableCameraPrior=True" -set "sfmMaxFeaturesPerMpx=20000" -set "sfmMaxFeaturesPerImage=200000" -set "sfmImagesOverlap=High" -set "MvsDoCorrectColors=false" -set "MvsIgnoreCorrectColors=false" -set "sfmMaxFeatureReprojectionError=1" ' + \
|
|
' -align ' + \
|
|
' -addFolder "' + ImagesTexture + '"' + \
|
|
' -align -align' + \
|
|
' -selectMaximalComponent ' + \
|
|
' -importGroundControlPoints "' + config_path + 'GCPsDetectedMarkers.txt" "' + config_path + 'GCPImportParams.xml" ' + \
|
|
' -setReconstructionRegion "' + ps_region + '" ' + \
|
|
' -setGroundPlaneFromReconstructionRegion ' + \
|
|
' -set "mvsMinSampleDistance=0.00001" ' + \
|
|
' -' + calulate_type + ' ' + \
|
|
' -selectLargestModelComponent -invertTrianglesSelection -removeSelectedTriangles -closeHoles -cleanModel ' + \
|
|
' -smooth ' + \
|
|
' -simplify ' + simplify_value + ' ' + \
|
|
' -calculateTexture ' + \
|
|
' -exportSelectedModel "' + output_path + '\\' + pid + '.obj" "' + config_path + 'ModelExportParams.xml" ' + \
|
|
' -quit'
|
|
else:
|
|
cmd = rcbin + \
|
|
' -disableOnlineCommunication ' + \
|
|
' -silent ' + output_path + \
|
|
' -addFolder "' + ImagesGeometry + '"' + \
|
|
' -set "sfmMaxFeaturesPerMpx=20000" -set "sfmMaxFeaturesPerImage=200000" -set "sfmImagesOverlap=High" -set "sfmMaxFeatureReprojectionError=1" ' + \
|
|
' -align ' + \
|
|
' -addFolder "' + ImagesTexture + '"' + \
|
|
' -align -align' + \
|
|
' -setReconstructionRegion "' + ps_region + '" ' + \
|
|
' -mvs ' + \
|
|
' -modelSelectMaximalConnectedComponent -modelInvertSelection -modelRemoveSelectedTriangles -closeHoles -clean ' + \
|
|
' -simplify ' + simplify_value + ' ' + \
|
|
' -smooth -unwrap ' + \
|
|
' -calculateTexture ' + \
|
|
' -renameModel ' + pid + ' ' + \
|
|
' -exportModel ' + pid + ' "' + output_path + '\\' + pid + '.obj" "' + config_path + 'ModelExportParams102.xml" ' + \
|
|
' -quit'
|
|
|
|
print(cmd)
|
|
cmd = shlex.split(cmd)
|
|
res = subprocess.run(cmd)
|
|
print(res)
|
|
|
|
end = datetime.datetime.now()
|
|
print('重建耗时:', diff_time(start, end))
|
|
|
|
return status
|
|
|
|
def fix_mtl_file(pid):
|
|
if os.path.exists(os.path.join(workdir, pid, 'output', f'{pid}_u0_v0_diffuse.jpg')):
|
|
texture_filename_end = '_u0_v0_diffuse.jpg'
|
|
elif os.path.exists(os.path.join(workdir, pid, 'output', f'{pid}_u1_v1.jpg')):
|
|
texture_filename_end = '_u1_v1.jpg'
|
|
path = os.path.join(workdir, pid)
|
|
mtl_file = os.path.join(path, 'output', pid + '.mtl')
|
|
os.rename(os.path.join(path, 'output', pid + texture_filename_end), os.path.join(path, 'output', pid + '.jpg'))
|
|
with open(os.path.join(path, mtl_file), 'r') as f:
|
|
lines = f.readlines()
|
|
lines = [line.replace(texture_filename_end, '.jpg') for line in lines]
|
|
with open(os.path.join(path, mtl_file), 'w') as f:
|
|
f.writelines(lines)
|
|
|
|
def delete_lines_in_file(filename, count):
|
|
with open(filename, 'r') as f:
|
|
lines = f.readlines()
|
|
lines = lines[count:]
|
|
with open(filename, 'w') as f:
|
|
f.writelines(lines)
|
|
|
|
def find_gray(img):
|
|
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
gray = gray[2800:, :]
|
|
hist = cv2.calcHist([gray], [0], None, [256], [0, 256])
|
|
plt.plot(hist)
|
|
|
|
def find_color_area(img, lower_color, upper_color):
|
|
color = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
color = color[2800:, :]
|
|
mask = cv2.inRange(color, lower_color, upper_color)
|
|
area = cv2.countNonZero(mask)
|
|
return round(area / (color.shape[0] * color.shape[1]), 4)
|
|
|
|
def clean_photo2(psid, pid):
|
|
path = os.path.join(workdir, pid, 'photo2')
|
|
print('正在处理psid:', psid, '的颜色配置:', config.ps_lights.get(psid))
|
|
if config.ps_lights.get(psid) is None:
|
|
ps_lights = config.ps_lights['0']
|
|
else:
|
|
ps_lights = config.ps_lights[psid]
|
|
|
|
for filename in os.listdir(path):
|
|
if not filename.endswith('_8.jpg'): continue
|
|
img = cv2.imread(os.path.join(path, filename))
|
|
white_area = find_color_area(img.copy(), ps_lights['lower_white'], ps_lights['upper_white'])
|
|
gray_area = find_color_area(img.copy(), ps_lights['lower_gray'], ps_lights['upper_gray'])
|
|
print('file:', os.path.join(path, filename), 'white_area:', white_area, 'gray_area:', gray_area)
|
|
if filename == '25_8.jpg':
|
|
print('file:', os.path.join(path, filename), 'white_area:', white_area, 'gray_area:', gray_area)
|
|
if white_area < gray_area or gray_area > ps_lights['gray_threshold']:
|
|
print('删除亮度异常图片:', os.path.join(path, filename), '亮度:', white_area, '灰度:', gray_area)
|
|
os.remove(os.path.join(path, filename))
|
|
|
|
def is_makeing():
|
|
for p in psutil.process_iter(['name']):
|
|
if p.info['name'] == 'RealityCapture.exe':
|
|
return True
|
|
return False
|
|
|
|
def resize_photos(pid, photoN, ratio, quality_value=90):
|
|
path = os.path.join(workdir, photoN, pid)
|
|
for file in os.listdir(path):
|
|
if file.endswith('.jpg'):
|
|
img = Image.open(os.path.join(path, file))
|
|
width, height = img.size
|
|
img = img.resize((int(width*ratio), int(height*ratio)))
|
|
img.save(os.path.join(path, file), optimize=True, quality=quality_value)
|
|
print(f'调整{photoN}照片尺寸:{file} to {int(width*ratio)}x{int(height*ratio)} 完成')
|
|
|
|
def auto_make_3d(r, key):
|
|
while True:
|
|
process_3d = False
|
|
# 检测是否已经有任务在进行,没有的话处理一下3D相册建模队列
|
|
try:
|
|
if r.llen('model:make_experience') == 0:
|
|
time.sleep(5)
|
|
if r.llen(key) == 0:
|
|
time.sleep(5)
|
|
continue
|
|
else:
|
|
pid = r.lpop(key)
|
|
if pid is None: continue
|
|
else:
|
|
pid = r.lpop('model:make_experience')
|
|
if pid is None: continue
|
|
process_3d = True
|
|
except Exception as e:
|
|
print(e)
|
|
time.sleep(5)
|
|
r = redis.Redis(host='106.14.158.208', password='kcV2000', port=6379, db=6)
|
|
continue
|
|
pid = pid.decode('utf-8')
|
|
psid = getPSid(pid)
|
|
|
|
# 定义需要走新的建模流程的影棚,将建模任务加入新的本地队列,原有建模任务跳过
|
|
if libs_db.is_new_make_psids(psid):
|
|
print(f'pid:{pid} psid:{psid} 需要走新的建模流程')
|
|
if process_3d:
|
|
task_type = 'make_experience'
|
|
else:
|
|
task_type = 'make'
|
|
libs_db.add_task({"task_type": task_type, "task_key": pid,"psid":psid})
|
|
continue
|
|
|
|
down_xmps_from_oss(psid)
|
|
|
|
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())), f'pid:{pid} 模型重建 start')
|
|
res = requests.post(update_status_modeling_url, data={'id': pid})
|
|
print('更新建模中状态:', res.text)
|
|
|
|
# 从oss下载图片
|
|
down_from_oss(pid)
|
|
|
|
if process_3d:
|
|
print(f'准备处理3D相册pid:{pid}的照片')
|
|
resize_photos(pid, 'photo1', 0.5)
|
|
resize_photos(pid, 'photo2', 0.5)
|
|
|
|
# 调用rc建模
|
|
if rc_make(pid, psid, key):
|
|
fix_mtl_file(pid)
|
|
os.system(f'{blenderbin} -b -P d:\\apps\\blender\\autofix.py -- {pid}')
|
|
os.system(f'gltfpack -c -i {os.path.join(workdir, pid, "output", pid + ".obj")} -o {os.path.join(workdir, pid, "output", pid + ".glb")}')
|
|
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())), f'pid:{pid} 建模完成,开始上传到oss')
|
|
print('建模成功: ' + pid, '开始上传模型文件...')
|
|
oss_client = oss2.Bucket(oss2.Auth(AccessKeyId, AccessKeySecret), Endpoint, Bucket)
|
|
oss_client.put_object_from_file(f'objs/auto/{pid}/{pid}.obj.rcInfo', os.path.join(workdir, pid, 'output', pid + '.obj.rcInfo'))
|
|
oss_client.put_object_from_file(f'objs/auto/{pid}/{pid}.obj', os.path.join(workdir, pid, 'output', pid + '.obj'))
|
|
oss_client.put_object_from_file(f'objs/auto/{pid}/{pid}.mtl', os.path.join(workdir, pid, 'output', pid + '.mtl'))
|
|
oss_client.put_object_from_file(f'objs/auto/{pid}/{pid}.jpg', os.path.join(workdir, pid, 'output', pid + '.jpg'))
|
|
oss_client.put_object_from_file(f'glbs/auto/{pid}.glb', os.path.join(workdir, pid, 'output', pid + '.glb'))
|
|
res = requests.post(update_status_modelsuccess_url, data={'id': pid})
|
|
print('上传完成更新建模成功状态:', res.text)
|
|
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'pid:{pid} 建模完成,上传模型及更新状态 end')
|
|
else:
|
|
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), f'pid:{pid} 建模失败')
|
|
# 建模失败,放回队列,微信通知技术人员介入处理
|
|
r.lpush(key, pid)
|
|
res = requests.post(update_status_modelfailed_url, data={'id': pid})
|
|
|
|
# 清空本地缓存
|
|
shutil.rmtree(os.path.join(workdir, pid), ignore_errors=True)
|
|
if get_rcver() == 1 : shutil.rmtree(temp_path, ignore_errors=True)
|
|
time.sleep(1)
|
|
|
|
if __name__ == '__main__':
|
|
AccessKeyId = 'LTAI5tSReWm8hz7dSYxxth8f'
|
|
AccessKeySecret = '8ywTDF9upPAtvgXtLKALY2iMYHIxdS'
|
|
Endpoint = 'oss-cn-shanghai.aliyuncs.com'
|
|
Bucket = 'suwa3d-securedata'
|
|
oss_client = oss2.Bucket(oss2.Auth(AccessKeyId, AccessKeySecret), Endpoint, Bucket)
|
|
|
|
r = redis.Redis(host='106.14.158.208', password='kcV2000', port=6379, db=6)
|
|
update_status_modeling_url = 'https://mp.api.suwa3d.com/api/customerP3dLog/toModeling'
|
|
update_status_modelsuccess_url = 'https://repair.api.suwa3d.com/api/modelRepairOrder/toModelMakeSucceed'
|
|
update_status_modelfailed_url = 'https://mp.api.suwa3d.com/api/customerP3dLog/toModelMakeFailed'
|
|
get_psid_url = 'https://mp.api.suwa3d.com/api/customerP3dLog/photoStudio'
|
|
get_printinfo_url = 'https://mp.api.suwa3d.com/api/customerP3dLog/printInfo'
|
|
update_status_printstatus_url = 'https://mp.api.suwa3d.com/api/customerP3dLog/updateBuildPrintModelStatus'
|
|
get_ps_adjust_photo_para_url = 'https://mp.api.suwa3d.com/api/equipment/configForColor' # 获取ps调整图片参数的接口
|
|
get_ps_type_url = "https://mp.api.suwa3d.com/api/takephotoOrder/photoStudioInfo" # 获取ps类型的接口
|
|
workdir = 'D:\\'
|
|
rcbin = '"C:\\Program Files\\Capturing Reality\\RealityCapture\\RealityCapture.exe"'
|
|
blenderbin = find_blender_bin_path()
|
|
|
|
config_path = 'D:\\apps\\config\\'
|
|
temp_path = 'D:\\RealityCapture.Temp\\'
|
|
|
|
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), '3D重建程序 start ', )
|
|
|
|
key = 'model:make'
|
|
if len(sys.argv) > 1:
|
|
key = sys.argv[1]
|
|
if key not in ['model:make', 'model:make10']:
|
|
print('参数错误,只能是model:make或者model:make10')
|
|
sys.exit(1)
|
|
auto_make_3d(r, key)
|
|
|