程序优化

This commit is contained in:
dongchangxi committed 2023-12-09 15:47:49 +08:00
1 parent e83deda268
commit e1a7647fcb
16 files changed
+634 -91

No files matched your search

+163 -8
View File
@@ -1,5 +1,8 @@
import redis,sys,os,re,oss2,shutil,time
import redis,sys,os,re,oss2,shutil,time,cv2
import json
import requests
import platform
import numpy as np
import xml.etree.ElementTree as ET
from PIL import ImageGrab
if platform.system() == 'Windows':
@@ -222,14 +225,14 @@ def uploadControlPointsOss(pid):
#截屏保存
def saveScreenImg(pid):
#获取当前的日志
if not os.path.exists(os.path.join(config.workdir,"screen", time.strftime("%y%m%d" time.localtime()))):
os.makedirs(os.path.join(config.workdir,"screen", time.strftime("%y%m%d" time.localtime())))
if not os.path.exists(os.path.join(config.workdir,"screen", time.strftime("%y%m%d",time.localtime()))):
os.makedirs(os.path.join(config.workdir,"screen", time.strftime("%y%m%d",time.localtime())))
screenshot = ImageGrab .grab()
screenshot.save(os.path.join(config.workdir,"screen", time.strftime("%y%m%d" time.localtime())),str(pid)+".png")
screenshot.save(os.path.join(config.workdir,"screen", time.strftime("%y%m%d",time.localtime()))+"/"+str(pid)+".png")
#移动到e盘
if not os.path.exists(os.path.join(config.sharedir,"screen", time.strftime("%y%m%d" time.localtime()))):
os.makedirs(os.path.join(config.sharedir,"screen", time.strftime("%y%m%d" time.localtime())))
shutil.copytree(os.path.join(config.workdir,"screen", time.strftime("%y%m%d" time.localtime())), os.path.join(config.sharedir,"screen", time.strftime("%y%m%d" time.localtime())))
if not os.path.exists(os.path.join(config.sharedir,"screen", time.strftime("%y%m%d",time.localtime()))):
os.makedirs(os.path.join(config.sharedir,"screen", time.strftime("%y%m%d",time.localtime())))
shutil.copy(os.path.join(config.workdir,"screen", time.strftime("%y%m%d",time.localtime()))+"\\"+str(pid)+".png", os.path.join(config.sharedir,"screen", time.strftime("%y%m%d",time.localtime())))
#文件夹的移动和删除
@@ -247,4 +250,156 @@ def removeFolder(pid):
file_time = os.path.getmtime(os.path.join(config.workdir, 'finished', file))
now_time = time.time()
if (now_time - file_time) > 259200:
shutil.rmtree(os.path.join(config.workdir, 'finished', file), ignore_errors=True)
shutil.rmtree(os.path.join(config.workdir, 'finished', file), ignore_errors=True)
def find_last_x(image, slope_threshold = 1000):
x = []
y = []
hist, bins = np.histogram(image, bins=256, range=[0, 256])
#找到50以内的最高峰
max_y = 0
max_i = 5
for i in range(5, 50):
if hist[i] > max_y:
max_y = hist[i]
max_i = i
print(f'50以内最高峰值y:{max_y},最高峰位置x:{max_i}')
for i in range(2, max_i):
x.append(i)
y.append(hist[i])
slopes = [abs(y[i + 1] - y[i]) for i in range(len(x) - 1)]
current_interval = []
max_interval = []
max_x = {}
for i, slope in enumerate(slopes):
current_interval.append(slope)
if slope >= slope_threshold:
if len(current_interval) > len(max_interval):
max_interval = current_interval.copy()
max_x[x[i]] = slope
current_interval = []
print(max_x)
last_x = list(max_x)[-1]
last_y = max_x[last_x]
return last_x, last_y
def high_find_histogram_range(image, target_frequency):
'''
循环查找在 target_frequency (y)频次限制下的直方图区间值(x)
:param image: 导入图片
:param target_frequency: 直方图 y 频次限制条件
:return: 直方图区间 x,和 该区间频次 y
'''
# 计算灰度直方图
hist, bins = np.histogram(image, bins=256, range=[0, 256])
# 初始化区间和频次
interval = 255
frequency = hist[255]
while frequency < target_frequency:
# 更新区间和频次
interval -= 1
# 检查直方图的频次是否为None,如果频次是None,则将其设为0,这样可以避免将None和int进行比较报错。
frequency = hist[interval] if hist[interval] is not None else 0
frequency += hist[interval] if hist[interval] is not None else 0
# 如果频次接近10000则停止循环
if target_frequency - 2000 <= frequency <= target_frequency + 2000:
break
return interval, frequency
def ps_color_scale_adjustment(image, shadow=0, highlight=255, midtones=1):
'''
模拟 PS 的色阶调整; 0 <= Shadow < Highlight <= 255
:param image: 传入的图片
:param shadow: 黑场(0-Highlight)
:param highlight: 白场(Shadow-255)
:param midtones: 灰场(9.99-0.01)
:return: 图片
'''
if highlight > 255:
highlight = 255
if shadow < 0:
shadow = 0
if shadow >= highlight:
shadow = highlight - 2
if midtones > 9.99:
midtones = 9.99
if midtones < 0.01:
midtones = 0.01
image = np.array(image, dtype=np.float16)
# 计算白场 黑场离差
Diff = highlight - shadow
image = image - shadow
image[image < 0] = 0
image = (image / Diff) ** (1 / midtones) * 255
image[image > 255] = 255
image = np.array(image, dtype=np.uint8)
return image
def remove_gray_and_sharpening(jpg_path):
#low_y_limit = 25000
high_y_limit = 13000
input_image = cv2.imread(jpg_path)
# low_x_thresh, low_y_frequency = low_find_histogram_range(input_image, low_y_limit)
low_x_thresh, low_y_frequency = find_last_x(input_image, 1000)
high_x_thresh, high_y_frequency = high_find_histogram_range(input_image, high_y_limit)
print(f"{low_x_thresh} 区间, {low_y_frequency} 频次")
print(f"{high_x_thresh} 区间, {high_y_frequency} 频次")
high_output_image = ps_color_scale_adjustment(input_image, shadow=low_x_thresh, highlight=high_x_thresh, midtones=1)
cv2.imwrite(jpg_path, high_output_image, [cv2.IMWRITE_JPEG_QUALITY, 95]) # 保存图片的质量是原图的 95%
#读取指定路径判断是否对齐成功
def isAlignNums(strPid):
#拼接路径
csvPath = os.path.join(config.workdir, strPid, strPid+"_align.csv")
print(csvPath)
#判断文件是否存在
if os.path.exists(csvPath) == False:
return "rebuild"
#读取文件行数
lines = ""
with open(csvPath, 'r') as f:
lines = f.readlines()
#获取长度
lines = len(lines) - 1
#获取pid对应的 photo1 和 photo2 的数量
photo1Num = 0
photo2Num = 0
for file in os.listdir(os.path.join(config.workdir, strPid, 'photo1')):
if file.endswith('.jpg'):
photo1Num += 1
for file in os.listdir(os.path.join(config.workdir, strPid, 'photo2')):
if file.endswith('.jpg'):
photo2Num += 1
#获取图片总数
totalPhotos = photo1Num + photo2Num
#比对对齐数量
if totalPhotos - lines >= 4:
return "rebuild"
return True
#消息通知
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)
+149
View File
@@ -0,0 +1,149 @@
import bpy
import bmesh
def active_object(obj):
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
def get_obj_max_foot(workdir,filename,filename_tex):
# 1.模型导入和初始化
# 删除当前场景中的所有对象:
# use_global=False表示只删除当前场景中的对象,而不会影响到其他场景中的对象;confirm=False表示删除时不需要确认。
bpy.ops.object.delete(use_global=False, confirm=False)
bpy.ops.import_scene.obj(filepath=filename) # 导入指定路径的 OBJ 格式模型文件
bpy.context.scene.unit_settings.scale_length = 0.001 # 将场景的长度单位缩放为0.001,相当于将长度单位从默认的米缩小为毫米
bpy.context.scene.unit_settings.length_unit = 'CENTIMETERS' # 将场景的长度单位设置为厘米
bpy.context.scene.unit_settings.mass_unit = 'GRAMS' # 将场景的质量单位设置为克
obj = bpy.context.selected_objects[0] # 获取了当前选中的对象列表,然后通过 [0] 取得列表中的第一个对象
bpy.context.view_layer.objects.active = obj # 将变量 obj 设置为当前活动对象
obj.select_set(True) # 将变量 obj 的选择状态设置为 True,表示选中该对象
pid = obj.name # 获取该对象的名字
# 对选定的对象进行对齐操作
bpy.ops.object.align(align_mode='OPT_1', relative_to='OPT_1', align_axis={'Z'})
# 设置选中对象的原点,参数1:将原点设置为对象的质心,参数2:使用对象的几何中心作为参考
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN')
# 将选中对象的位置坐标分别设置为 (0, 0),即将对象移动到世界坐标系的原点位置
obj.location[0] = 0
obj.location[1] = 0
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) # 将选中对象的位置、旋转和缩放应用到对象的数据中
# 2.选择要复制的对象
obj_duplicate = obj.copy()
obj_duplicate.data = obj.data.copy()
bpy.context.collection.objects.link(obj_duplicate)
# obj_duplicate.location.x += 5.0
bpy.ops.object.select_all(action='DESELECT') # 取消选中全部对象
# 3.处理复制的对象的脚底缝合边
# 选中复制对象
bpy.context.view_layer.objects.active = obj_duplicate
obj_duplicate.select_set(True)
selected_obj = bpy.context.active_object # 获取当前选中的对象
bpy.context.view_layer.objects.active = selected_obj # 将对象转换到编辑模式
# 切换到3D视图编辑模式
bpy.context.area.type = 'VIEW_3D'
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT') # 选择所有的边
# 切换到UV编辑器
bpy.context.area.type = 'IMAGE_EDITOR'
pid_img = f"{pid}Tex1.jpg"
bpy.ops.image.open(filepath=filename_tex, directory=workdir,
files=[{"name": pid_img, "name": pid_img}], relative_path=True,
show_multiview=False)
bpy.context.area.ui_type = 'UV'
bpy.ops.uv.select_all(action='SELECT') # 选择所有UV贴图顶点
# 标记所有沿孤岛的边为缝合边
bpy.ops.uv.seams_from_islands()
bpy.context.area.type = 'VIEW_3D'
bpy.ops.object.mode_set(mode='OBJECT')
# 获取世界坐标系下z轴接近0的顶点的索引
z_zero_vertex_indices = []
for i, vertex in enumerate(selected_obj.data.vertices):
world_vertex = selected_obj.matrix_world @ vertex.co
if abs(world_vertex.z) < 0.2:
z_zero_vertex_indices.append(i)
# 将对象转换回对象模式
bpy.ops.object.mode_set(mode='OBJECT')
# 创建一个新的顶点组,并将z_zero_vertices中的顶点添加到该顶点组中
vg = selected_obj.vertex_groups.new(name="z_zero_vertices")
for index in z_zero_vertex_indices:
vg.add([index], 1.0, 'REPLACE')
# 将选中的顶点设置为活动顶点
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.vertex_group_select() # 选中待处理的顶点
bpy.ops.mesh.mark_seam(clear=True) # 取消所选区域内的缝合边
bpy.ops.mesh.region_to_loop() # 选择选定面周围的边界边!!!
bpy.ops.mesh.select_mode(type="EDGE") # 转换为线模式
bpy.ops.mesh.mark_seam(clear=False) # 标记所选的线为缝合边
# 选中脚底顶点组
bpy.ops.uv.select_all(action='DESELECT')
bpy.ops.object.vertex_group_set_active(group='z_zero_vertices') # 设置活动顶点组
bpy.ops.object.vertex_group_select() # 选择分配给活动顶点组的所有顶点
bpy.ops.uv.unwrap()
# 处理贴图脚底部分孤岛,其他孤岛保持不变
# (1)反选模型顶点,方便贴图固定不需要处理的区域
bpy.ops.mesh.select_all(action='INVERT')
bpy.context.area.type = 'IMAGE_EDITOR' # 切换到贴图模式
bpy.context.area.ui_type = 'UV'
bpy.ops.uv.pin(clear=False)
bpy.ops.object.vertex_group_set_active(group='z_zero_vertices') # 设置活动顶点组
bpy.ops.object.vertex_group_select() # 选择分配给活动顶点组的所有顶点
# (2)脚底部位UV展开,平均孤岛比例,重新排列孤岛
bpy.ops.uv.select_all(action='SELECT')
bpy.ops.uv.average_islands_scale()
bpy.ops.uv.pack_islands(margin=0.001)
bpy.context.area.type = 'VIEW_3D'
bpy.ops.object.mode_set(mode='OBJECT')
# 4. 烘焙模式,参数设置
bpy.ops.object.select_all(action='DESELECT') # 取消选中全部对象
# # 选中原始对象
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
# 选中复制对象
bpy.context.view_layer.objects.active = obj_duplicate
obj_duplicate.select_set(True)
bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.cycles.device = 'GPU'
bpy.context.scene.cycles.preview_samples = 1
bpy.context.scene.cycles.samples = 1
bpy.context.scene.cycles.bake_type = 'DIFFUSE'
bpy.context.scene.render.bake.use_pass_direct = False
bpy.context.scene.render.bake.use_pass_indirect = False
bpy.context.scene.render.bake.use_selected_to_active = True
bpy.context.scene.render.bake.cage_extrusion = 0.01
bpy.ops.object.bake(type='DIFFUSE') # 开始 Bake
# 5. 导出模型和贴图
bpy.ops.object.select_all(action='DESELECT') # 取消选中全部对象
# 选中复制对象
bpy.context.view_layer.objects.active = obj_duplicate
obj_duplicate.select_set(True)
bpy.ops.wm.obj_export(filepath=filename, export_selected_objects=True)
bpy.context.area.type = 'IMAGE_EDITOR' # 切换到
bpy.ops.image.save_as(filepath=filename_tex)
bpy.context.area.type = 'TEXT_EDITOR' # 切换到文本编辑器
if __name__ == '__main__':
workdir = 'E:\\117080\\print_model'
# filename = f'{workdir}\\117080_12cm_x1.obj'
filename = f'{workdir}\\117080.obj'
filename_tex = f'{workdir}\\117080Tex1.jpg'
save_obj = f"{workdir}\\bake\\117080Tex1.obj"
save_tex = f"{workdir}\\bake\\117080Tex1.jpg"
get_obj_max_foot()
+40 -6
View File
@@ -1,7 +1,9 @@
import os, time, json, requests, shutil, oss2, psutil
from tqdm import tqdm
from PIL import Image, ImageEnhance
import config,libs_db
import config,libs_db,common
import threading
from concurrent.futures import ThreadPoolExecutor
def find_blender_bin_path():
base_path = 'C:\\Program Files\\Blender Foundation\\'
@@ -222,7 +224,7 @@ def set_photo_join_type(workdir, pid, photoN, camera_id, mesh = '0', texture='0'
with open(filename, 'w') as f:
f.writelines(lines)
def down_from_oss(oss_client, workdir, pid, per=100):
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):
@@ -237,20 +239,52 @@ def down_from_oss(oss_client, workdir, pid, per=100):
filelist = oss2.ObjectIteratorV2(oss_client, prefix=prefix)
for file in tqdm(filelist):
filename = file.key.split('/')[-1]
localfile = ""
# print('正在下载:', file.key)
if filename.endswith('_1.jpg'):
localfile = os.path.join(path, 'photo1', filename)
if photoPath == "":
if filename.endswith('_1.jpg'):
localfile = os.path.join(path, 'photo1', filename)
else:
localfile = os.path.join(path, 'photo2', filename)
else:
localfile = os.path.join(path, 'photo2', filename)
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(';')
+22 -4
View File
@@ -17,8 +17,7 @@ def get_task(task_type):
try:
with pymysqlAlias() as conn:
cursor = conn.cursor()
sql = f'select task_key from tasks where status = 0 order by priority desc, id asc limit 1'
sql = f'select task_key from tasks where status = 0 order by priority desc, id asc limit 1 for update'
# print(f'sql: {sql}')
cursor.execute(sql)
data = cursor.fetchone()
@@ -49,6 +48,9 @@ def add_task(data):
#新增任务到分布式处理任务表中 {"task_type":key,"task_key":pid,"psid":psid}
def add_task_distributed(data):
flag = isInTaskDistributed(data["task_key"])
if flag:
return "already"
try:
with pymysqlAlias() as conn:
cursor = conn.cursor()
@@ -66,8 +68,8 @@ def start_task(data):
cursor = conn.cursor()
hostname = socket.gethostname()
sql = f'update tasks set status = 1, hostname = "{hostname}", started_at = now(), updated_at = now() where task_key = "{data["task_key"]} and status = 0"'
# print(f'sql: {sql}')
sql = f'update tasks set status = 1, hostname = "{hostname}", started_at = now(), updated_at = now() where status = 0 and task_key = {data["task_key"]}'
print(f'开始任务sql: {sql}')
cursor.execute(sql)
conn.commit()
except Exception as e:
@@ -158,4 +160,20 @@ def isStudioConfigDistribute(psid):
return True
except Exception as e:
print(f"{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} 执行change_to_new_make_psid()异常: {str(e)}")
return "error"
#判断是否已经存在了
def isInTaskDistributed(task_key):
try:
with pymysqlAlias() as conn:
cursor = conn.cursor()
sql = f'select count(*) from task_distributed where status = 0 and task_key = "{task_key}"'
cursor.execute(sql)
result = cursor.fetchone()
if result[0] == 0:
return False
else:
return True
except Exception as e:
print(f"{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} 执行isInTaskDistributed()异常: {str(e)}")
return "error"
+1 -4
View File
@@ -192,10 +192,7 @@ def get_task_distributed_step1():
try:
with pymysqlAlias() as conn:
cursor = conn.cursor(pymysql.cursors.DictCursor)
sql = 'select * from task_distributed where status =0 order by priority desc limit 1'
if where:
sql += f' and {where}'
sql = 'select * from task_distributed where status =0 order by priority desc limit 1 for update'
cursor.execute(sql)
result = cursor.fetchone()
# 关闭游标和连接