增加异步

master
LAPTOP-S9HJSOEB\昊天 8 months ago
parent 399bb4d566
commit 725c869fe6

@ -1,129 +1,130 @@
from datetime import time
import numpy as np
from PIL import Image
import math
import config
from cat import clip_and_rotate_point_cloud, merge_point_clouds
from image import detect_large_holes
import asyncio
def tiff_depth_to_point_clouds(tiff_paths, sn, dedup=True):
"""
将多个 TIFF 深度图转换为点云并拼接在一起后生成 PCD 文件
:param tiff_paths: list of str, TIFF 深度图路径列表
:param sn: str, 设备序列号用于查找配置参数
:param dedup: bool, 是否根据 (x, y) 去重默认开启
:return: list of [x, y, z], 合并后的点云数据
"""
merged_points = []
# Step 1: 遍历每个 TIFF 文件,生成对应的点云
for tiff_path in tiff_paths:
points = tiff_depth_to_point_cloud(tiff_path+".tiff", sn, dedup)
merged_points.extend([points])
# Step 2: 可选:使用 merge_point_clouds 对点云进行 x 轴拼接(若需要)
# 注意:如果每个点云已经带有偏移,则不需要再次拼接
has_voids = True
if hasattr(config, 'CUT_CONFIG_MAP') and isinstance(config.CUT_CONFIG_MAP, dict) and (sn in config.CUT_CONFIG_MAP):
merged_points, xrange = merge_point_clouds(merged_points, config.CUT_CONFIG_MAP[sn],sn)
real_holes = detect_large_holes(merged_points, sn, xrange)
if real_holes.__len__()==0:
has_voids=False
# Step 3: 写入最终的 PCD 文件
output_pcd_path = config.save_path("pcd", f"{sn}_merged.pcd")
write_pcd(output_pcd_path, merged_points)
# print(f"Merged and saved to {output_pcd_path}")
return has_voids
def tiff_depth_to_point_cloud(tiff_path,sn, dedup=True):
"""
TIFF 深度图转换为点云基于给定的视场角计算相机内参
:param tiff_path: str, TIFF 深度图路径
:param hfov_degrees: float or None, 水平视场角单位
:param vfov_degrees: float or None, 垂直视场角单位
:param output_ply_path: str or None, 输出 Pcd 文件路径可选
:param dedup: bool, 是否根据 (x, y) 去重默认开启
:return: list of [x, y, z] 点云数据
"""
hfov_degrees = config.CAMERA_CONFIG_MAP[sn].get("x_angle")
max_z = config.CAMERA_CONFIG_MAP[sn].get("max_z")
vfov_degrees = config.CAMERA_CONFIG_MAP[sn].get("y_angle")
# plane_scaling_ratio = config.CAMERA_CONFIG_MAP[sn].get("plane_scaling_ratio")
# 加载 TIFF 图像
depth_image = Image.open(tiff_path)
depth_array = np.array(depth_image, dtype=np.float32)
height, width = depth_array.shape
# 根据提供的 FOV 计算 fx/fy
if hfov_degrees is not None:
hfov_rad = math.radians(hfov_degrees)
fx = width / (2 * math.tan(hfov_rad / 2))
fy = fx * height / width # 保持像素方形比例
else:
vfov_rad = math.radians(vfov_degrees)
fy = height / (2 * math.tan(vfov_rad / 2))
fx = fy * width / height # 保持像素方形比例
import numpy as np
from scipy.spatial.transform import Rotation as R
cx = width / 2
cy = height / 2
from logConfig import get_logger
print(f"Calculated intrinsics: fx={fx:.2f}, fy={fy:.2f}, cx={cx:.2f}, cy={cy:.2f}")
# 使用示例
logger = get_logger()
points = []
seen_xy = set() # 用于记录已添加的 (x, y)
def apply_rotation(matrix, angle_degrees, axis='x'):
"""
对输入的 3x3 旋转矩阵 应用额外的旋转
# 获取裁剪配置
clip_config = config.CUT_CONFIG_MAP.get(sn)
if clip_config:
min_pt = np.array(clip_config.get("min_pt", [-np.inf] * 3))
max_pt = np.array(clip_config.get("max_pt", [np.inf] * 3))
rotation = np.array(clip_config.get("rotation", [1,0,0,0,1,0,0,0,1])).reshape(3, 3)
else:
min_pt = max_pt = rotation = None
for v in range(height):
for u in range(width):
z = depth_array[v, u] # mm -> m
if z <= 0 or z > max_z:
continue
x = (u - cx) * z / fx
y = (v - cy) * z / fy
# 构造点并旋转(保留浮点精度)
point = np.array([x, y, z])
if clip_config:
rotated_point = (rotation @ point.T).T
if not np.all(rotated_point >= min_pt) or not np.all(rotated_point <= max_pt):
continue
x_final, y_final, z_final = rotated_point
else:
x_final, y_final, z_final = point
# 到这里才进行去重判断
if dedup:
x_int = int(round(x_final))
y_int = int(round(y_final))
z_int = int(round(z_final))
if (x_int, y_int) in seen_xy:
continue
seen_xy.add((x_int, y_int))
# 保留浮点精度写入结果
points.append([x_int, y_int, z_int])
# 可选输出PLY文件用于可视化
if config.CAMERA_CONFIG_MAP[sn].get("save_pcd"):
output_ply_path = config.save_path("pcd",sn+".pcd")
write_pcd(output_ply_path, points)
参数:
matrix (np.ndarray): 原始的 3x3 旋转矩阵
angle_degrees (float): 旋转角度 (单位: )
axis (str): 旋转轴支持 'x', 'y', 'z'
return points
返回:
np.ndarray: 新的 3x3 旋转矩阵
"""
# 创建绕指定轴旋转的旋转对象
rot = R.from_euler(axis, angle_degrees, degrees=True)
# 将当前旋转转换为矩阵
rotation_matrix = rot.as_matrix()
# 合并旋转:新旋转 × 原始矩阵
combined_rotation = np.dot(rotation_matrix, matrix)
return combined_rotation
#
# def tiff_depth_to_point_cloud(tiff_path,sn, dedup=True):
# """
# 将 TIFF 深度图转换为点云,基于给定的视场角计算相机内参
#
# :param tiff_path: str, TIFF 深度图路径
# :param hfov_degrees: float or None, 水平视场角(单位:度)
# :param vfov_degrees: float or None, 垂直视场角(单位:度)
# :param output_ply_path: str or None, 输出 Pcd 文件路径(可选)
# :param dedup: bool, 是否根据 (x, y) 去重,默认开启
# :return: list of [x, y, z] 点云数据
# """
# hfov_degrees = config.CAMERA_CONFIG_MAP[sn].get("x_angle")
# max_z = config.CAMERA_CONFIG_MAP[sn].get("max_z")
# vfov_degrees = config.CAMERA_CONFIG_MAP[sn].get("y_angle")
# # plane_scaling_ratio = config.CAMERA_CONFIG_MAP[sn].get("plane_scaling_ratio")
# # 加载 TIFF 图像
# depth_image = Image.open(tiff_path)
# depth_array = np.array(depth_image, dtype=np.float32)
#
# height, width = depth_array.shape
#
# # 根据提供的 FOV 计算 fx/fy
# if hfov_degrees is not None:
# hfov_rad = math.radians(hfov_degrees)
# fx = width / (2 * math.tan(hfov_rad / 2))
# fy = fx * height / width # 保持像素方形比例
# else:
# vfov_rad = math.radians(vfov_degrees)
# fy = height / (2 * math.tan(vfov_rad / 2))
# fx = fy * width / height # 保持像素方形比例
#
# cx = width / 2
# cy = height / 2
#
# print(f"Calculated intrinsics: fx={fx:.2f}, fy={fy:.2f}, cx={cx:.2f}, cy={cy:.2f}")
#
# points = []
# seen_xy = set() # 用于记录已添加的 (x, y)
#
# # 获取裁剪配置
# clip_config = config.CUT_CONFIG_MAP.get(sn)
# if clip_config:
# min_pt = np.array(clip_config.get("min_pt", [-np.inf] * 3))
# max_pt = np.array(clip_config.get("max_pt", [np.inf] * 3))
# rotation = np.array(clip_config.get("rotation", [1,0,0,0,1,0,0,0,1])).reshape(3, 3)
# else:
# min_pt = max_pt = rotation = None
#
# for v in range(height):
# for u in range(width):
# z = depth_array[v, u] # mm -> m
# if z <= 0 or z > max_z:
# continue
#
# x = (u - cx) * z / fx
# y = (v - cy) * z / fy
#
# # 构造点并旋转(保留浮点精度)
# point = np.array([x, y, z])
# if clip_config:
# rotated_point = (rotation @ point.T).T
# if not np.all(rotated_point >= min_pt) or not np.all(rotated_point <= max_pt):
# continue
# x_final, y_final, z_final = rotated_point
# else:
# x_final, y_final, z_final = point
#
# # 到这里才进行去重判断
# if dedup:
# x_int = int(round(x_final))
# y_int = int(round(y_final))
# z_int = int(round(z_final))
# if (x_int, y_int) in seen_xy:
# continue
# seen_xy.add((x_int, y_int))
# # 保留浮点精度写入结果
# points.append([x_int, y_int, z_int])
#
#
# # 可选输出PLY文件用于可视化
# if config.CAMERA_CONFIG_MAP[sn].get("save_pcd"):
# output_ply_path = config.save_path("pcd",sn+".pcd")
# write_pcd(output_ply_path, points)
#
# return points
# 新增点云数据转换函数
@ -141,67 +142,139 @@ def convert_sdk_points(sValue, width, height):
mask = np.all(np.isfinite(points), axis=1)
return points[mask]
# def process_point_cloud_fast(points, sn, type):
# points = np.array(points, dtype=np.float32)
# # 获取目标高度和容差(来自模板配置)
# template_config = config.TEMPLATE_CONFIG_MAP.get(type, {})
# target_z = template_config.get("height", 0) # 假设 height 是期望的中心高度
# tolerance = template_config.get("tolerance", 50) # 默认容差为 50
#
# # 计算上下限
# z_min = target_z - tolerance
# z_max = target_z + tolerance # 不超过 200
# # Z 值过滤
# valid_mask = ((points[:, 2] > 0)
# & (points[:, 2] <= config.CAMERA_CONFIG_MAP[sn].get("max_z", np.inf))
# )
#
# points = points[valid_mask]
#
# if clip_config := config.CUT_CONFIG_MAP.get(sn):
# rotation = np.array(clip_config["rotation"], dtype=np.float32).reshape(3, 3)
# min_pt = np.array(clip_config["min_pt"], dtype=np.float32)
# max_pt = np.array(clip_config["max_pt"], dtype=np.float32)
# floorHeight = clip_config.get("floorHeight", 0)
#
# # 批量旋转
# rotated = (rotation @ points.T).T
#
# # 裁剪范围过滤
# bounds_mask = np.all((rotated >= min_pt) & (rotated <= max_pt), axis=1)
# rotated = rotated[bounds_mask]
# x_trimmed = np.round(rotated[:, 0], 3)
# y_trimmed = np.round(rotated[:, 1], 3)
# z_trimmed = np.round(floorHeight - rotated[:, 2], 3)
# else:
# x_trimmed = np.round(points[:, 0], 3)
# y_trimmed = np.round(points[:, 1], 3)
# z_trimmed = np.round(points[:, 2], 3)
#
# # 合并为一个数组
# trimmed_points = np.column_stack((x_trimmed, y_trimmed, z_trimmed))
# # 应用 z 值过滤
# final_mask = (
# (trimmed_points[:, 2] >= z_min) &
# (trimmed_points[:, 2] <= z_max)
# )
# filtered_points = trimmed_points[final_mask]
#
# # 去重
# keys = np.column_stack((filtered_points[:, 0], filtered_points[:, 1]))
# _, unique_indices = np.unique(keys, axis=0, return_index=True)
#
# # 返回 list of [x, y, z]
# return filtered_points[unique_indices].tolist()
def process_point_cloud_fast(points, sn, type):
points = np.array(points, dtype=np.float32)
if not len(points):
return []
# 获取配置
template_config = config.TEMPLATE_CONFIG_MAP.get(type, {})
target_z = template_config.get("height", 0)
tolerance = template_config.get("tolerance", 25)
z_min = target_z - tolerance
z_max = target_z + tolerance
# 初始 Z 过滤
valid_mask = (points[:, 2] > 0) & (points[:, 2] <= config.CAMERA_CONFIG_MAP[sn].get("max_z", np.inf))
points = points[valid_mask]
def process_point_cloud(points, sn, dedup=True):
"""
对原始点云应用旋转裁剪和去重
# 获取裁剪配置
clip_config = config.CUT_CONFIG_MAP.get(sn + "_" + type, None) or config.CUT_CONFIG_MAP.get(sn)
:param points: np.ndarray(shape=(N,3)), 原始点云数据
:param sn: str, 设备序列号用于加载配置
:param dedup: bool, 是否启用去重
:return: list of [x, y, z], 处理后的点云列表
"""
# 加载配置参数
clip_config = config.CUT_CONFIG_MAP.get(sn)
if clip_config:
min_pt = np.array(clip_config.get("min_pt", [-np.inf] * 3))
max_pt = np.array(clip_config.get("max_pt", [np.inf] * 3))
rotation = np.array(clip_config.get("rotation", [1, 0, 0, 0, 1, 0, 0, 0, 1])).reshape(3, 3)
rotation = np.array(clip_config["rotation"], dtype=np.float32).reshape(3, 3)
min_pt = np.array(clip_config["min_pt"], dtype=np.float32)
max_pt = np.array(clip_config["max_pt"], dtype=np.float32)
floorHeight = clip_config.get("floorHeight", 0)
# 批量旋转
rotated = (rotation @ points.T).T
# 裁剪范围过滤
bounds_mask = np.all((rotated >= min_pt) & (rotated <= max_pt), axis=1)
rotated = rotated[bounds_mask]
# 计算坐标并应用 floorHeight
x_trimmed = rotated[:, 0]
y_trimmed = rotated[:, 1]
z_trimmed = floorHeight - rotated[:, 2]
else:
min_pt = max_pt = rotation = None
processed_points = []
seen_xy = set()
for point in points:
x, y, z = point
x_trimmed = points[:, 0]
y_trimmed = points[:, 1]
z_trimmed = points[:, 2]
# 无效点过滤Z ≤ 0 或超出最大距离)
if z <= 0 or z > config.CAMERA_CONFIG_MAP[sn].get("max_z", np.inf):
continue
# 合并为一个数组
trimmed_points = np.column_stack((
np.round(x_trimmed, 3),
np.round(y_trimmed, 3),
np.round(z_trimmed, 3)
))
# 应用旋转矩阵
if clip_config:
rotated = rotation @ point
if not np.all(rotated >= min_pt) or not np.all(rotated <= max_pt):
continue
x_final, y_final, z_final = rotated
else:
x_final, y_final, z_final = x, y, z
# 应用 z 值过滤
final_mask = (trimmed_points[:, 2] >= z_min) & (trimmed_points[:, 2] <= z_max)
filtered_points = trimmed_points[final_mask]
# 去重逻辑(保留浮点精度)
if dedup:
# 使用浮点哈希避免离散化损失
key = (round(x_final, 3), round(y_final, 3))
if key in seen_xy:
continue
seen_xy.add(key)
# 去重
keys = filtered_points[:, :2] # 只取 x,y
_, unique_indices = np.unique(keys, axis=0, return_index=True)
processed_points.append([x_final, y_final, z_final])
# 返回 list of [x, y, z]
return filtered_points[unique_indices].tolist()
return processed_points
def sValue_to_pcd(sValue,stPointCloudImage,sn):
def sValue_to_pcd(sValue,stPointCloudImage,sn,type):
# 数据格式转换
points = convert_sdk_points(sValue, stPointCloudImage.nWidth, stPointCloudImage.nHeight)
# 应用旋转、裁剪、去重(假设设备序列号已知)
processed_points = process_point_cloud(points, sn, dedup=True)
processed_points = process_point_cloud_fast(points, sn,type)
output_ply_path = config.save_path("pcd", sn + ".pcd")
# 保存结果
write_pcd(output_ply_path, processed_points)
# Point.py 修改部分
from thread_pool import submit_task
if config.CAMERA_CONFIG_MAP[sn].get("save_pcd"):
output_ply_path = config.save_path("pcd", sn + ".pcd")
# 使用线程池异步执行点云文件写入
submit_task(write_pcd, output_ply_path, processed_points)
if config.CAMERA_CONFIG_MAP[sn].get("save_not_cut", True):
output_ply_path = config.save_path("pcd", sn + "_original.pcd")
submit_task(write_pcd, output_ply_path, points)
return output_ply_path,processed_points
def write_pcd(filename, points):
@ -214,23 +287,21 @@ def write_pcd(filename, points):
with open(filename, 'w') as f:
# 写入 PCD 文件头
f.write("# .PCD v0.7 - Point Cloud Data file format\n")
f.write(f"VERSION 0.7\n")
f.write("VERSION 0.7\n")
f.write("FIELDS x y z\n")
f.write("SIZE 4 4 4\n") # float 类型的大小是 4 字节
f.write("TYPE F F F\n") # 每个字段的数据类型
f.write(f"COUNT 1 1 1\n") # 每个字段的数量
f.write(f"WIDTH {len(points)}\n") # 点数量
f.write("HEIGHT 1\n") # 单行表示无结构点云
f.write("VIEWPOINT 0 0 0 1 0 0 0\n") # 默认视角参数
f.write(f"POINTS {len(points)}\n") # 总点数
f.write("DATA ascii\n") # 数据部分以 ASCII 形式存储
f.write("SIZE 4 4 4\n")
f.write("TYPE F F F\n")
f.write("COUNT 1 1 1\n")
f.write(f"WIDTH {len(points)}\n")
f.write(f"HEIGHT 1\n")
f.write("VIEWPOINT 0 0 0 1 0 0 0\n")
f.write(f"POINTS {len(points)}\n")
f.write("DATA ascii\n")
# 写入点数据
for point in points:
f.write(f"{point[0]} {point[1]} {point[2]}\n")
print(f"Saved point cloud to {filename}")
logger.info(f"Saved point cloud to {filename}")
if __name__ == '__main__':
tiff_depth_to_point_cloud("D:/git/test/hik3d-python/image/2025-06-26/depth/191330147_-Depth.tiff", "00DA6823936")

@ -5,6 +5,7 @@ import ctypes
import time
import os
import struct
from thread_pool import submit_task
from ctypes import *
from datetime import datetime
import Point as point
@ -17,17 +18,47 @@ from Mv3dRgbdImport.Mv3dRgbdDefine import DeviceType_Ethernet, DeviceType_USB, D
import config as configMap
# 全局变量
SN_MAP = {} # {sn: camera_instance}
import time
import random
from ctypes import *
from logConfig import get_logger
def initialize_devices():
nDeviceNum = ctypes.c_uint(0)
# 使用示例
logger = get_logger()
def reconnect_device(sn, max_retries=5, base_delay=1.0, max_delay=10.0):
"""
重新连接指定序列号的设备
Args:
sn (str): 设备序列号
max_retries (int): 最大重试次数
base_delay (float): 初始延迟时间()
max_delay (float): 最大延迟时间()
Returns:
bool: 重连是否成功
"""
camera = SN_MAP.get(sn)
# 如果设备已存在,先尝试关闭
try:
camera.MV3D_RGBD_CloseDevice()
except:
pass # 忽略关闭时可能的错误
# 获取设备信息(需要重新枚举设备)
nDeviceNum = c_uint(0)
ret = Mv3dRgbd.MV3D_RGBD_GetDeviceNumber(
DeviceType_Ethernet | DeviceType_USB | DeviceType_Ethernet_Vir | DeviceType_USB_Vir,
byref(nDeviceNum)
)
if ret != MV3D_RGBD_OK or nDeviceNum.value == 0:
print("Failed to get device number or no devices found.")
return
logger.error("Failed to get device number or no devices found.")
return False
stDeviceList = MV3D_RGBD_DEVICE_INFO_LIST()
Mv3dRgbd.MV3D_RGBD_GetDeviceList(
@ -35,115 +66,280 @@ def initialize_devices():
pointer(stDeviceList.DeviceInfo[0]), 20, byref(nDeviceNum)
)
# 查找对应序列号的设备
target_device_info = None
for i in range(nDeviceNum.value):
serial_number = ''.join(chr(c) for c in stDeviceList.DeviceInfo[i].chSerialNumber).rstrip('\x00')
print(f"Found device [{i}]: Serial Number: {serial_number}")
device_sn = ''.join(chr(c) for c in stDeviceList.DeviceInfo[i].chSerialNumber).rstrip('\x00')
if device_sn == sn:
target_device_info = stDeviceList.DeviceInfo[i]
break
camera = Mv3dRgbd()
if not target_device_info:
logger.error(f"Device with SN: {sn} not found during reconnection attempt")
return False
# 打开设备
ret = camera.MV3D_RGBD_OpenDevice(pointer(stDeviceList.DeviceInfo[i]))
if ret != MV3D_RGBD_OK:
print(f"Failed to open device with SN: {serial_number}. Error code: {ret:#x}")
continue
# 尝试重连
for attempt in range(max_retries):
try:
# 创建新的相机实例
new_camera = Mv3dRgbd()
# 存入全局 map
SN_MAP[serial_number] = camera
print(f"Successfully added device {serial_number} to SN_MAP")
# 尝试打开设备
ret = new_camera.MV3D_RGBD_OpenDevice(pointer(target_device_info))
if ret == MV3D_RGBD_OK:
# 更新全局映射
SN_MAP[sn] = new_camera
logger.info(f"Successfully reconnected to device {sn}")
return True
else:
logger.info(f"Failed to reconnect to device {sn}. Error code: {ret:#x}")
def pic(sn):
except Exception as e:
logger.info(f"Exception during reconnection attempt {attempt + 1}: {e}")
# 如果不是最后一次尝试,等待后重试
if attempt < max_retries - 1:
# 指数退避延迟
delay = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
logger.info(f"Retrying reconnection in {delay:.2f} seconds...")
time.sleep(delay)
logger.info(f"Failed to reconnect to device {sn} after {max_retries} attempts")
return False
def retry_initialize_devices(max_retries=3, base_delay=2.0):
"""
重试初始化设备
Args:
max_retries (int): 最大重试次数
base_delay (float): 初始延迟时间()
Returns:
bool: 初始化是否成功
"""
for attempt in range(max_retries):
try:
# 清空现有设备映射
SN_MAP.clear()
nDeviceNum = c_uint(0)
ret = Mv3dRgbd.MV3D_RGBD_GetDeviceNumber(
DeviceType_Ethernet | DeviceType_USB | DeviceType_Ethernet_Vir | DeviceType_USB_Vir,
byref(nDeviceNum)
)
if ret != MV3D_RGBD_OK or nDeviceNum.value == 0:
logger.info("Failed to get device number or no devices found.")
if attempt < max_retries - 1:
delay = base_delay * (2 ** attempt)
logger.info(f"Retrying device initialization in {delay} seconds...")
time.sleep(delay)
continue
stDeviceList = MV3D_RGBD_DEVICE_INFO_LIST()
Mv3dRgbd.MV3D_RGBD_GetDeviceList(
DeviceType_Ethernet | DeviceType_USB | DeviceType_Ethernet_Vir | DeviceType_USB_Vir,
pointer(stDeviceList.DeviceInfo[0]), 20, byref(nDeviceNum)
)
success_count = 0
for i in range(nDeviceNum.value):
serial_number = ''.join(chr(c) for c in stDeviceList.DeviceInfo[i].chSerialNumber).rstrip('\x00')
logger.info(f"Found device [{i}]: Serial Number: {serial_number}")
camera = Mv3dRgbd()
# 打开设备
ret = camera.MV3D_RGBD_OpenDevice(pointer(stDeviceList.DeviceInfo[i]))
if ret != MV3D_RGBD_OK:
logger.info(f"Failed to open device with SN: {serial_number}. Error code: {ret:#x}")
continue
# 存入全局 map
SN_MAP[serial_number] = camera
logger.info(f"Successfully added device {serial_number} to SN_MAP")
success_count += 1
if success_count > 0:
logger.info(f"Successfully initialized {success_count} devices")
return True
else:
logger.info("No devices were successfully initialized")
except Exception as e:
logger.info(f"Exception during device initialization attempt {attempt + 1}: {e}")
if attempt < max_retries - 1:
delay = base_delay * (2 ** attempt)
logger.info(f"Retrying device initialization in {delay} seconds...")
time.sleep(delay)
logger.info(f"Failed to initialize devices after {max_retries} attempts")
return False
def enhanced_pic(sn, type):
"""
增强版的图片采集函数包含重连机制和点云数据重试机制
"""
camera = SN_MAP.get(sn)
if not camera:
print(f"No camera found for SN: {sn}")
return
logger.info(f"No camera found for SN: {sn}, attempting reconnection...")
if not reconnect_device(sn):
logger.info(f"Failed to reconnect to device {sn}")
return None
camera = SN_MAP.get(sn)
config = configMap.CAMERA_CONFIG_MAP.get(sn)
if not config:
print(f"No config found for SN: {sn}")
return
logger.info(f"No config found for SN: {sn}")
return None
time_on = config.get("time_on", 0) # 延时开始(毫秒)
print(f"Delaying start by {time_on}ms...")
time.sleep(time_on / 1000.0) # 转成秒
time_on = config.get("time_on", 0)
logger.info(f"Delaying start by {time_on}ms...")
time.sleep(time_on / 1000.0)
saved_files = {
"depth": [],
"color": [],
"pcd": []
"sn": sn,
"depth": "",
"color": "",
"pcd": "",
"point": []
}
# 开始取流
# 尝试开始取流,如果失败则尝试重连
ret = camera.MV3D_RGBD_Start()
if ret != MV3D_RGBD_OK:
print(f"Failed to start grabbing. Error code: {ret:#x}")
return
logger.info(f"Failed to start grabbing. Error code: {ret:#x}")
logger.info("Attempting reconnection...")
if reconnect_device(sn):
camera = SN_MAP.get(sn)
ret = camera.MV3D_RGBD_Start()
if ret != MV3D_RGBD_OK:
logger.info(f"Failed to start grabbing after reconnection. Error code: {ret:#x}")
return saved_files
else:
logger.info("Reconnection failed")
return saved_files
try:
stFrameData = MV3D_RGBD_FRAME_DATA()
# 获取单帧数据
ret = camera.MV3D_RGBD_FetchFrame(pointer(stFrameData), 5000)
if ret == MV3D_RGBD_OK:
for i in range(stFrameData.nImageCount):
image_info = stFrameData.stImageData[i]
# 保存深度图
if image_info.enImageType == ImageType_Depth:
file_name = configMap.save_path("depth", "-Depth")
ret_save = camera.MV3D_RGBD_SaveImage(pointer(image_info), FileType_TIFF, file_name)
print("Saved depth image." if ret_save == MV3D_RGBD_OK else "Failed to save depth image.")
if ret_save == MV3D_RGBD_OK:
saved_files["depth"].append(file_name)
# 点云转换与保存
stPointCloudImage = MV3D_RGBD_IMAGE_DATA()
ret = camera.MV3D_RGBD_MapDepthToPointCloud(pointer(stFrameData.stImageData[i]), pointer(stPointCloudImage))
if MV3D_RGBD_OK != ret:
print("_MapDepthToPointCloud() Run failed...")
else:
print(
"_MapDepthToPointCloud() Run Succeed: framenum (%d) height(%d) width(%d) len (%d)!" % (
stPointCloudImage.nFrameNum,
stPointCloudImage.nHeight, stPointCloudImage.nWidth, stPointCloudImage.nDataLen))
strMode = string_at(stPointCloudImage.pData, stPointCloudImage.nDataLen)
sValue = struct.unpack('f' * int(stPointCloudImage.nHeight * stPointCloudImage.nWidth * 3),
strMode)
pcd_file = point.sValue_to_pcd(sValue, stPointCloudImage, sn)
if pcd_file:
saved_files["pcd"].append(pcd_file)
# 保存彩色图
elif image_info.enImageType in (
ImageType_RGB8_Planar, ImageType_YUV420SP_NV12,
ImageType_YUV420SP_NV21, ImageType_YUV422
):
file_name = configMap.save_path("color", "-_Color")
ret_save = camera.MV3D_RGBD_SaveImage(pointer(image_info), FileType_BMP, file_name)
print("Saved color image." if ret_save == MV3D_RGBD_OK else "Failed to save color image.")
if ret_save == MV3D_RGBD_OK:
saved_files["color"].append(file_name)
# 最多重试10次获取有效的点云数据
max_retries = 10
retry_count = 0
point_cloud_success = False
else:
print("Failed to fetch frame.")
# 用于存储最后一次成功的彩色图数据
last_color_image_info = None
last_color_file_name = None
while retry_count < max_retries and not point_cloud_success:
stFrameData = MV3D_RGBD_FRAME_DATA()
# 获取单帧数据
ret = camera.MV3D_RGBD_FetchFrame(pointer(stFrameData), 5000)
if ret == MV3D_RGBD_OK:
has_depth_data = False
current_color_image_info = None
current_color_file_name = None
flag = True
for i in range(stFrameData.nImageCount):
image_info = stFrameData.stImageData[i]
# 保存深度图
if image_info.enImageType == ImageType_Depth:
has_depth_data = True
stPointCloudImage = MV3D_RGBD_IMAGE_DATA()
ret = camera.MV3D_RGBD_MapDepthToPointCloud(pointer(stFrameData.stImageData[i]),
pointer(stPointCloudImage))
if MV3D_RGBD_OK != ret:
logger.info(f"_MapDepthToPointCloud() Run failed... Retry: {retry_count + 1}/{max_retries}")
else:
logger.info(
"_MapDepthToPointCloud() Run Succeed: framenum (%d) height(%d) width(%d) len (%d)!" % (
stPointCloudImage.nFrameNum,
stPointCloudImage.nHeight, stPointCloudImage.nWidth, stPointCloudImage.nDataLen))
strMode = string_at(stPointCloudImage.pData, stPointCloudImage.nDataLen)
sValue = struct.unpack('f' * int(stPointCloudImage.nHeight * stPointCloudImage.nWidth * 3),
strMode)
pcd_file, processed_points = point.sValue_to_pcd(sValue, stPointCloudImage, sn, type)
if pcd_file and len(processed_points) > 0:
saved_files["pcd"] = pcd_file
saved_files["point"] = processed_points
point_cloud_success = True # 成功获取点云数据
flag = False
# 记录彩色图信息,但不立即保存
elif image_info.enImageType in (
ImageType_RGB8_Planar, ImageType_YUV420SP_NV12,
ImageType_YUV420SP_NV21, ImageType_YUV422
):
file_name = configMap.save_path("color", sn+"_Color")
if config.get("save_image"):
submit_task(camera.MV3D_RGBD_SaveImage,pointer(image_info), FileType_BMP, file_name)
saved_files["color"] = file_name + ".bmp"
logger.info(f"Color image saved successfully: {saved_files['color']}")
if flag:break
# 如果没有深度数据或点云处理失败,增加重试次数
if not has_depth_data:
logger.info(f"No depth data found in frame. Retry: {retry_count + 1}/{max_retries}")
retry_count += 1
time.sleep(0.1) # 短暂等待后重试
elif not point_cloud_success:
retry_count += 1
time.sleep(0.1) # 短暂等待后重试
else:
logger.info(f"Failed to fetch frame. Error code: {ret:#x}. Retry: {retry_count + 1}/{max_retries}")
retry_count += 1
time.sleep(0.1) # 短暂等待后重试
except Exception as e:
logger.error(f"Error during frame capture for device {sn}: {e}")
finally:
camera.MV3D_RGBD_Stop()
print("Single capture completed.")
# 输出结果路径
print("Saved files:")
for key, paths in saved_files.items():
if paths:
print(f" {key.upper()}:")
for path in paths:
print(f" - {path}")
# logger.info(f"Single capture completed. Results: {saved_files}")
return saved_files
initialize_devices()
def initialize_devices():
nDeviceNum = ctypes.c_uint(0)
ret = Mv3dRgbd.MV3D_RGBD_GetDeviceNumber(
DeviceType_Ethernet | DeviceType_USB | DeviceType_Ethernet_Vir | DeviceType_USB_Vir,
byref(nDeviceNum)
)
if ret != MV3D_RGBD_OK or nDeviceNum.value == 0:
logger.info("Failed to get device number or no devices found.")
return
if __name__ == '__main__':
pic("00DA6823936")
stDeviceList = MV3D_RGBD_DEVICE_INFO_LIST()
Mv3dRgbd.MV3D_RGBD_GetDeviceList(
DeviceType_Ethernet | DeviceType_USB | DeviceType_Ethernet_Vir | DeviceType_USB_Vir,
pointer(stDeviceList.DeviceInfo[0]), 20, byref(nDeviceNum)
)
for i in range(nDeviceNum.value):
serial_number = ''.join(chr(c) for c in stDeviceList.DeviceInfo[i].chSerialNumber).rstrip('\x00')
logger.info(f"Found device [{i}]: Serial Number: {serial_number}")
camera = Mv3dRgbd()
# 打开设备
ret = camera.MV3D_RGBD_OpenDevice(pointer(stDeviceList.DeviceInfo[i]))
if ret != MV3D_RGBD_OK:
logger.info(f"Failed to open device with SN: {serial_number}. Error code: {ret:#x}")
continue
# 存入全局 map
SN_MAP[serial_number] = camera
logger.info(f"Successfully added device {serial_number} to SN_MAP")
initialize_devices()

Binary file not shown.

Binary file not shown.

@ -6,7 +6,7 @@ from datetime import datetime
CAMERA_CONFIG_MAP = {} # {sn: config_dict}
CUT_CONFIG_MAP = {} # {filename_without_ext: config_dict}
DIRECTION_CAMERA = {}
TEMPLATE_MAP = {}
TEMPLATE_CONFIG_MAP = {}
def load_camera_configs(config_dir="./config/camera"):
"""
@ -50,7 +50,7 @@ def load_template_configs(config_dir="./config/template"):
config = json.load(f)
type = config.get("type")
if type:
TEMPLATE_MAP[type] = config
TEMPLATE_CONFIG_MAP[type] = config
print(f"Loaded camera config: {type}")
else:
print(f"[WARN] No 'sn' found in {filename}")

@ -1,13 +1,10 @@
{
"sn": "00DA6823936",
"direction": "1",
"x_angle": 125,
"y_angle": 75,
"save_pcd": true,
"save_image": true,
"resolution": 8,
"max_z": 1800,
"reverse_order": false,
"time_on": 100,
"time_off": 5500,
"time_hop": 800
"max_z": 2000,
"time_on": 0,
"save_not_cut": true
}

@ -0,0 +1,10 @@
{
"sn": "00DA6823953",
"direction": "2",
"save_pcd": true,
"save_image": true,
"resolution": 8,
"max_z": 2000,
"time_on": 0,
"save_not_cut": true
}

@ -0,0 +1,24 @@
{
"floorHeight": 1920,
"max_pt": [
550.1860961914062,
-325.56182861328125,
1564.596435546875
],
"min_pt": [
-560.0139770507812,
-1206.5701904296875,
344.9464111328125
],
"rotation": [
1,
0,
0,
0,
0.7197034358978271,
-0.6942816376686096,
0,
0.6942816376686096,
0.7197034358978271
]
}

@ -0,0 +1,24 @@
{
"floorHeight": 1920,
"max_pt": [
400.86029052734375,
-500.30865478515625,
1564.596435546875
],
"min_pt": [
-530.2582397460938,
-968.01953125,
344.9464111328125
],
"rotation": [
1,
0,
0,
0,
0.7197034358978271,
-0.6942816376686096,
0,
0.6942816376686096,
0.7197034358978271
]
}

@ -1,24 +0,0 @@
{
"floorHeight": 1,
"max_pt": [
103.20252990722656,
-169.6024932861328,
182.84439086914062
],
"min_pt": [
16.854652404785156,
-1234.1793212890625,
153.4544677734375
],
"rotation": [
-0.006754159927368164,
-0.9998819828033447,
0.013793319463729858,
0.43973052501678467,
-0.015358209609985352,
-0.8979983329772949,
0.8981043100357056,
0,
0.4397825002670288
]
}

@ -1,24 +0,0 @@
{
"floorHeight": 1,
"max_pt": [
59.17729568481445,
-177.37328052520752,
823.2836303710938
],
"min_pt": [
0,
-1263.9830322265625,
200.47930908203125
],
"rotation": [
-0.0070345401763916016,
-0.9998821020126343,
0.013652533292770386,
0.4579751193523407,
-0.015358328819274902,
-0.8888324499130249,
0.88893723487854,
-2.9802322387695312e-08,
0.45802903175354004
]
}

@ -0,0 +1,24 @@
{
"floorHeight": 1920,
"max_pt": [
512.0901489257812,
-500.2588500976562,
1564.596435546875
],
"min_pt": [
-508.4150390625,
-1008.01953125,
344.9464111328125
],
"rotation": [
1,
0,
0,
0,
0.7197034358978271,
-0.6942816376686096,
0,
0.6942816376686096,
0.7197034358978271
]
}

@ -0,0 +1,24 @@
{
"floorHeight": 1920,
"max_pt": [
450.0901489257812,
-500.2588500976562,
1564.596435546875
],
"min_pt": [
-460.4150390625,
-908.01953125,
344.9464111328125
],
"rotation": [
1,
0,
0,
0,
0.7197034358978271,
-0.6942816376686096,
0,
0.6942816376686096,
0.7197034358978271
]
}

@ -1,6 +1,8 @@
{
"type": "45",
"width":"299",
"length":"355",
"high":"314"
"width":299,
"length":355,
"height": 1540 ,
"min_area": 50,
"tolerance": 60
}

@ -0,0 +1,8 @@
{
"type": "46",
"width": 140,
"length": 138,
"height": 1070,
"min_area": 120,
"tolerance": 150
}

@ -0,0 +1,8 @@
{
"type": "47",
"width": 299,
"length": 355,
"height": 1370,
"min_area": 500,
"tolerance": 150
}

@ -0,0 +1,190 @@
以下是您当前 Flask 应用中已实现的两个主要接口的 **API 接口文档**,采用标准 RESTful 风格描述。
---
## 🌐 接口文档
### 1. 更新配置 `/config/update`
#### ✅ 方法
- `GET`
#### 📦 描述
- 重新加载所有配置文件(相机、裁剪、模板等),用于刷新服务端配置。
#### 📤 响应示例
```json
{
"message": "Hello, this service config update!",
"status": "OK"
}
```
---
### 2. 添加/更新模板配置 `/api/addTemplate`
#### ✅ 方法
- `POST`
#### 📦 描述
- 接收一个 JSON 对象,以 `"type"` 字段作为文件名,保存为 `./config/template/{type}.json`。
- 支持覆盖写入已有模板。
- 写入成功后自动调用 [config.load_configs()](file://D:\git\test\hik3d-python\config.py#L82-L89) 刷新配置。
#### 📥 请求体JSON
| 字段名 | 类型 | 必填 | 示例值 | 描述 |
|-------------|--------|------|-----------|--------------------|
| type | string | ✅ | "45" | 模板名称 |
| width | string | ❌ | "299" | 模板宽度(暂无作用) |
| length | string | ❌ | "355" | 模板长度(暂无作用) |
| height | number | ✅ | 314 | 最高高度(单位:毫米)|
| min_area | number | ✅ | 20 | 空洞最小面积 |
| tolerance | number | ✅ | 30 | 容差范围(单位:毫米)|
##### 示例请求体:
```json
{
"type": "45",
"width": "299",
"length": "355",
"height": 314,
"min_area": 20,
"tolerance": 30
}
```
#### 📤 成功响应
```json
{
"status": "OK",
"message": "Template '45' saved successfully."
}
```
#### 📤 错误响应
- 缺少数据:
```json
{
"status": "ERROR",
"message": "No data provided"
}
```
- 缺少 `type`
```json
{
"status": "ERROR",
"message": "Missing 'type' field"
}
```
- 写入失败:
```json
{
"status": "ERROR",
"message": "Failed to save template: [错误信息]"
}
```
---
### 3. 图像处理与空洞检测 `/api/picCompute`
#### ✅ 方法
- `POST`
#### 📦 描述
- 根据设备编号和模板类型,获取点云并检测是否存在大空洞。
- 调用了 [SimpleView_SaveImage.pic()](file://D:\git\test\hik3d-python\SimpleView_SaveImage.py#L53-L137) 和 [image.detect_large_holes()](file://D:\git\test\hik3d-python\image.py#L187-L208)。
#### 📥 请求体JSON
| 字段名 | 类型 | 必填 | 示例值 | 描述 |
|--------|--------|------|------------|----------------|
| sn | string | ✅ | "00DA6823936" | 设备序列号 |
| type | string | ✅ | "45" | 模板类型(对应模板配置) |
##### 示例请求体:
```json
{
"sn": "00DA6823936",
"type": "45"
}
```
#### 📤 成功响应
```json
{
"message": true,
"status": "OK"
}
```
> `message` 表示是否检测到空洞:
> - `true`:有空洞
> - `false`:无空洞
#### 📤 错误响应
- 缺少参数:
```json
{
"message": "",
"status": "ERROR",
"error": "Missing required parameter: 'sn'"
}
```
- 模板不存在:
```json
{
"message": "",
"status": "ERROR",
"error": "Missing required parameter: 'type'"
}
```
- 其他异常:
```json
{
"message": "",
"status": "ERROR",
"error": "Failed to get TIFF paths: [错误信息]"
}
```
---
## ⚠️ 全局异常处理
所有未捕获的异常都会被全局异常处理器捕获,并返回如下格式:
```json
{
"message": "",
"status": "ERROR",
"error": "[错误信息]"
}
```
---

@ -2,13 +2,26 @@ camera文档
{
"sn": "00DA6823936",#sn
"direction": "1",#方向
"x_angle": 55,#相机的水平视场角(相机自身的)
"y_angle": 84,#相机的垂直视场角
"save_pcd": true,#是否保存pcd
"resolution": 8,#像素大小(可以调整来区别
"resolution": 8,#像素大小(可以调整生成的图片,根据生成图片识别空洞
"max_z": 2000,#最大深度(裁剪之前的
"reverse_order": false,#是否pcd组成的图片是否翻转
"time_on": 300,#开始时间
"time_off": 3500,#结束时间
"time_hop": 500#时间间隔
}
"save_not_cut": true #基础的没有裁剪的pcd是否保存
}
cut 裁剪文档
名称sn_template
当template没有的时候读取sn.json
template 模版文档
{
"type": "45", #模版名称
"width":"299",#模版横 暂无作用
"length":"355",#模版宽 暂无作用
"height": 314 ,#最高高度从裁剪文档里的floorHeight为0
"min_area": 20 ,#空洞的最小面积
"tolerance": 30 #冗余,将判断在最高的位置附近,单位毫米
}
先进行最低的位置写入floorHeight和旋转参数

@ -1,12 +1,50 @@
import numpy as np
import cv2
import matplotlib.pyplot as plt
import threading
from thread_pool import submit_task
from scipy.ndimage import label
import config
from logConfig import get_logger
# 使用示例
logger = get_logger()
#
# def point_cloud_to_2d_image(points, resolution=1.0, x_range=(17, 275), y_range=(-129, -1227)):
# """
# 将点云转换为 2D 图像X-Y 平面),每个像素值表示对应位置的 Z 值平均值
# """
# if not isinstance(points, np.ndarray):
# points = np.array(points)
#
# if len(points) == 0:
# raise ValueError("点云为空")
#
# x_min, x_max = x_range
# y_min, y_max = y_range
#
# width = int((x_max - x_min) / resolution) + 1
# height = int((y_max - y_min) / resolution) + 1
#
# image = np.zeros((height, width), dtype=np.float32)
# count_map = np.zeros((height, width), dtype=np.int32)
#
# for x, y, z in points:
# xi = int((x - x_min) / resolution)
# yi = int((y - y_min) / resolution)
#
# if 0 <= xi < width and 0 <= yi < height:
# image[yi, xi] += z
# count_map[yi, xi] += 1
#
# # 防止除零错误
# count_map[count_map == 0] = 1
# image /= count_map
#
# return image, (x_min, y_min)
# 优化 point_cloud_to_2d_image 函数
def point_cloud_to_2d_image(points, resolution=1.0, x_range=(17, 275), y_range=(-129, -1227)):
"""
将点云转换为 2D 图像X-Y 平面每个像素值表示对应位置的 Z 值平均值
@ -23,16 +61,32 @@ def point_cloud_to_2d_image(points, resolution=1.0, x_range=(17, 275), y_range=(
width = int((x_max - x_min) / resolution) + 1
height = int((y_max - y_min) / resolution) + 1
# 使用向量化操作替代循环
x_coords = points[:, 0]
y_coords = points[:, 1]
z_coords = points[:, 2]
# 计算像素坐标
xi = ((x_coords - x_min) / resolution).astype(int)
yi = ((y_coords - y_min) / resolution).astype(int)
# 筛选有效坐标
valid_mask = (xi >= 0) & (xi < width) & (yi >= 0) & (yi < height)
xi = xi[valid_mask]
yi = yi[valid_mask]
z_coords = z_coords[valid_mask]
# 使用直方图统计替代循环累加
image = np.zeros((height, width), dtype=np.float32)
count_map = np.zeros((height, width), dtype=np.int32)
for x, y, z in points:
xi = int((x - x_min) / resolution)
yi = int((y - y_min) / resolution)
# 使用 bincount 进行快速统计
indices = yi * width + xi
z_sums = np.bincount(indices, weights=z_coords, minlength=height * width)
counts = np.bincount(indices, minlength=height * width)
if 0 <= xi < width and 0 <= yi < height:
image[yi, xi] += z
count_map[yi, xi] += 1
image.flat[:] = z_sums
count_map.flat[:] = counts
# 防止除零错误
count_map[count_map == 0] = 1
@ -41,50 +95,30 @@ def point_cloud_to_2d_image(points, resolution=1.0, x_range=(17, 275), y_range=(
return image, (x_min, y_min)
def detect_holes_by_density(density_map, density_threshold_ratio=0.5, min_area=100):
"""
基于点云密度图识别空洞区域
def stitch(imagePath1, imagePath2):
# 读取两张图像
image1 = cv2.imread(imagePath1)
image2 = cv2.imread(imagePath2)
:param density_map: 2D numpy array, 每个像素表示该位置点云密度
:param density_threshold_ratio: 密度低于均值的 ratio 倍时视为空洞候选
:param min_area: 最小空洞面积像素数
:return: list of ((cx, cy), area)空洞中心和面积图像坐标
"""
# 计算邻域平均密度3x3窗口
avg_density = np.zeros_like(density_map)
for i in range(density_map.shape[0]):
for j in range(density_map.shape[1]):
# 取 3x3 邻域
neighbors = density_map[
max(0, i - 1):min(i + 2, density_map.shape[0]),
max(0, j - 1):min(j + 2, density_map.shape[1])
]
avg_density[i, j] = np.mean(neighbors)
# 构建空洞候选区:密度低于邻域平均值的 50%
binary_map = (density_map < avg_density * density_threshold_ratio).astype(np.uint8)
# 连通域分析
structure = np.array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
labeled_map, num_features = label(binary_map, structure=structure)
# 创建 Stitcher 对象
stitcher = cv2.Stitcher_create()
holes = []
for label_id in range(1, num_features + 1):
coords = np.where(labeled_map == label_id)
hole_pixel_count = len(coords[0])
# 拼接图像
(status, stitched) = stitcher.stitch((image1, image2))
if hole_pixel_count >= min_area:
cx = np.mean(coords[1]) # x 坐标(列)
cy = np.mean(coords[0]) # y 坐标(行)
area = hole_pixel_count
holes.append(((cx, cy), area))
# 检查拼接结果
if status == cv2.Stitcher_OK:
cv2.imwrite('stitched_output.jpg', stitched)
print("图像拼接成功!")
else:
print(f"图像拼接失败,错误代码: {status}")
if __name__ == '__main__':
stitch('D:/git/test/hik3d-python/image/2025-07-01/color/105601193_-_Color.bmp'
, 'D:/git/test/hik3d-python/image/2025-07-01/color/164646720_-_Color.bmp')
return holes
def detect_black_regions(binary_mask, min_area=10):
def detect_black_regions(binary_mask, min_area=10,box_area=10):
"""
检测图像中的黑色连通区域值为 0 的区域
@ -111,19 +145,18 @@ def detect_black_regions(binary_mask, min_area=10):
labeled_map, num_features = label(binary, structure=structure)
regions = []
count = 0
for label_id in range(1, num_features + 1):
coords = np.where(labeled_map == label_id)
area = len(coords[0])
if area >= min_area:
cx = np.mean(coords[1]) # x 坐标(列)
cy = np.mean(coords[0]) # y 坐标(行)
logger.info(f"区域: {label_id} 中心: {cx, cy} 面积: {area}")
regions.append(((cx, cy),area))
return regions
count += ( area/box_area)
return regions,count
def convert_image_holes_to_real(holes, offset, resolution):
real_holes = []
x_min, y_min = offset
@ -138,23 +171,39 @@ def visualize_holes_on_image(image, holes, output_path=None):
"""
在图像上画出检测到的空洞中心和轮廓
"""
# 彩色化灰度图用于可视化
color_image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
for (cx, cy), _ in holes:
# 绘制圆形标注空洞中心
cv2.circle(color_image, (int(cx), int(cy)), radius=5, color=(0, 0, 255), thickness=-1)
# 显示图像
# plt.figure(figsize=(10, 8))
plt.imshow(cv2.cvtColor(color_image, cv2.COLOR_BGR2RGB))
# plt.title("Detected Holes")
plt.axis("off")
output_path = config.save_path("image", "_holes.png")
if output_path:
plt.savefig(output_path, bbox_inches='tight', dpi=200)
print(f"Saved visualization to {output_path}")
# plt.show()
try:
# 确保图像数据有效
if image is None or len(image) == 0:
print("Warning: Empty image data for visualization")
return
# 彩色化灰度图用于可视化
if len(image.shape) == 2: # 灰度图
color_image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
else:
color_image = image.copy()
# 绘制空洞标记
if holes:
for (cx, cy), _ in holes:
# 确保坐标有效
if 0 <= int(cx) < color_image.shape[1] and 0 <= int(cy) < color_image.shape[0]:
cv2.circle(color_image, (int(cx), int(cy)), radius=5, color=(0, 0, 255), thickness=-1)
# 生成输出路径
if output_path is None:
output_path = config.save_path("image", "_holes.png")
# 保存图像
success = cv2.imwrite(output_path, color_image)
if success:
print(f"Saved visualization to {output_path}")
else:
print(f"Failed to save visualization to {output_path}")
except Exception as e:
print(f"Error in visualize_holes_on_image: {e}")
def read_pcd_points(pcd_path):
"""
@ -183,30 +232,44 @@ def read_pcd_points(pcd_path):
continue
return points
def detect_large_holes(points,sn, x_max):
def detect_large_holes(points, sn, type):
# 获取裁剪配置
cat_map = config.CUT_CONFIG_MAP.get(sn + "_" + type, None) or config.CUT_CONFIG_MAP.get(sn)
template_map = config.TEMPLATE_CONFIG_MAP[type]
camera_map = config.CAMERA_CONFIG_MAP[sn]
# 2. 生成 2D 图像
x_range = (config.CUT_CONFIG_MAP[sn]["min_pt"][0],x_max) # 手动指定 X 范围
y_range = (config.CUT_CONFIG_MAP[sn]["min_pt"][1], config.CUT_CONFIG_MAP[sn]["max_pt"][1]) # 注意:这里要保证 y_min < y_max否则反转一下
x_range = (cat_map["min_pt"][0], cat_map["max_pt"][0])
y_range = (cat_map["min_pt"][1], cat_map["max_pt"][1])
resolution = config.CAMERA_CONFIG_MAP[sn].get("resolution")
image, offset = point_cloud_to_2d_image(points, resolution=resolution, x_range=x_range, y_range=y_range)
# 3. 图像归一化用于可视化
normalized_image = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
min_area = min(template_map["min_area"], (template_map["width"] * template_map["height"]) /(2*camera_map["resolution"]*camera_map["resolution"]))
# 4. 检测空洞
holes = detect_black_regions(normalized_image, min_area=20)
holes, count = detect_black_regions(normalized_image, min_area, (template_map["width"] * template_map["height"]) / 2)
if config.CAMERA_CONFIG_MAP[sn].get("save_image"):
# 创建数据副本确保异步执行时数据完整性
image_copy = normalized_image.copy()
holes_copy = list(holes) # 创建holes的副本
# 5. 可视化空洞
visualize_holes_on_image(normalized_image, holes)
# 预先生成输出路径
output_path = config.save_path("image", f"_{sn}_holes.png")
# 使用线程池异步执行可视化操作
submit_task(visualize_holes_on_image, image_copy, holes_copy, output_path)
# 6. 输出真实世界坐标
real_holes = convert_image_holes_to_real(holes, offset, resolution)
return real_holes
return real_holes, count
if __name__ == '__main__':
points = read_pcd_points("D:/PycharmProjects/Hik3D/image/2025-06-25/pcd/182109899_00DA6823936_merged.pcd")
sn = "00DA6823936"
x_max = 326
detect_large_holes(points,sn, x_max)
# if __name__ == '__main__':
# points = read_pcd_points("D:/PycharmProjects/Hik3D/image/2025-06-25/pcd/182109899_00DA6823936_merged.pcd")
# sn = "00DA6823936"
# x_max = 326
# detect_large_holes(points,sn, x_max)

@ -0,0 +1,64 @@
import logging
from logging.handlers import TimedRotatingFileHandler
import asyncio
import time
import os
# 确保 logs 目录存在
def ensure_logs_directory():
logs_dir = "logs"
if not os.path.exists(logs_dir):
os.makedirs(logs_dir)
return logs_dir
# 配置日志
def setup_logger(name, log_file, level=logging.INFO):
# 确保 logs 目录存在
ensure_logs_directory()
# 构建完整的日志文件路径
logs_dir = "logs"
full_log_path = os.path.join(logs_dir, log_file)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# 创建按时间轮转的文件处理器
handler = TimedRotatingFileHandler(
full_log_path, # 使用完整路径
when="midnight", # 每天午夜轮转
interval=1, # 间隔1天
backupCount=30 # 保留30天的日志
)
handler.setFormatter(formatter)
logger = logging.getLogger(name)
logger.setLevel(level)
# 避免重复添加 handler
if not logger.handlers:
logger.addHandler(handler)
return logger
# 创建全局logger实例
logger = setup_logger('hik3d', 'app.log')
def get_logger():
"""
获取全局logger实例
"""
return logger
# 异步写入日志的包装函数
async def async_log(logger, level, message):
# 在线程池中执行日志写入,避免阻塞事件循环
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, getattr(logger, level), message)
# # 使用示例
# logger = setup_logger('my_app', 'app.log')
# 运行
# asyncio.run(main())

@ -0,0 +1,374 @@
2025-08-15 14:58:42,508 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-15 14:58:43,733 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-15 14:58:43,733 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-15 14:58:44,957 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-15 14:58:45,411 - hik3d - INFO - 服务启动中...
2025-08-15 14:58:45,412 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 15:36:29,232 - hik3d - INFO - Failed to get device number or no devices found.
2025-08-15 15:36:29,679 - hik3d - INFO - 服务启动中...
2025-08-15 15:36:29,680 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 15:37:16,115 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-15 15:37:17,490 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-15 15:37:17,490 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-15 15:37:18,713 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-15 15:37:19,071 - hik3d - INFO - 服务启动中...
2025-08-15 15:37:19,072 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 15:37:32,450 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 15:37:32,453 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 15:37:32,454 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:37:32,454 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 15:37:32,455 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:37:32,754 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:37:32,991 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:37:34,600 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 2.146 秒,发现空洞: False
2025-08-15 15:37:35,121 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 2.668 秒,发现空洞: False
2025-08-15 15:37:35,198 - hik3d - INFO - 全设备图片计算完成,总耗时 2.747 秒,结果: False
2025-08-15 15:37:36,739 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153733795_00DA6823953.pcd
2025-08-15 15:37:39,054 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153734206_00DA6823936.pcd
2025-08-15 15:37:41,353 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153734217_00DA6823936_original.pcd
2025-08-15 15:37:41,502 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153733799_00DA6823953_original.pcd
2025-08-15 15:37:49,321 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 15:37:49,322 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 15:37:49,322 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:37:49,322 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 15:37:49,322 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:37:49,540 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:37:49,703 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:37:50,722 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.401 秒,发现空洞: False
2025-08-15 15:37:51,015 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.692 秒,发现空洞: False
2025-08-15 15:37:51,023 - hik3d - INFO - 全设备图片计算完成,总耗时 1.702 秒,结果: False
2025-08-15 15:37:52,630 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153750100_00DA6823953.pcd
2025-08-15 15:37:54,952 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153750465_00DA6823936.pcd
2025-08-15 15:37:55,908 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 15:37:55,913 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 15:37:55,927 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:37:55,928 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 15:37:55,937 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:37:56,225 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:37:56,430 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:37:58,020 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 2.093 秒,发现空洞: False
2025-08-15 15:37:58,468 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 2.555 秒,发现空洞: False
2025-08-15 15:37:58,482 - hik3d - INFO - 全设备图片计算完成,总耗时 2.571 秒,结果: False
2025-08-15 15:37:59,779 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 15:37:59,790 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 15:37:59,794 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:37:59,799 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 15:37:59,810 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:38:00,140 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:38:00,354 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:38:00,621 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153757193_00DA6823953.pcd
2025-08-15 15:38:02,657 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 2.858 秒,发现空洞: True
2025-08-15 15:38:02,670 - hik3d - INFO - 设备 00DA6823953 发现空洞,停止其他任务
2025-08-15 15:38:02,686 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 2.896 秒,发现空洞: False
2025-08-15 15:38:02,695 - hik3d - INFO - 全设备图片计算完成,总耗时 2.91 秒,结果: True
2025-08-15 15:38:03,478 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153750469_00DA6823936_original.pcd
2025-08-15 15:38:04,460 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153750102_00DA6823953_original.pcd
2025-08-15 15:38:06,804 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153801589_00DA6823953.pcd
2025-08-15 15:38:07,354 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153757607_00DA6823936.pcd
2025-08-15 15:38:11,996 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153757201_00DA6823953_original.pcd
2025-08-15 15:38:12,311 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153801613_00DA6823936.pcd
2025-08-15 15:38:13,728 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153757647_00DA6823936_original.pcd
2025-08-15 15:38:15,130 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153801599_00DA6823953_original.pcd
2025-08-15 15:38:15,862 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153801622_00DA6823936_original.pcd
2025-08-15 15:39:37,573 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 15:39:37,574 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 15:39:37,574 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:39:37,575 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 15:39:37,575 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:39:37,812 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:39:37,996 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:39:39,036 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.461 秒,发现空洞: True
2025-08-15 15:39:39,039 - hik3d - INFO - 设备 00DA6823953 发现空洞,停止其他任务
2025-08-15 15:39:39,232 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.658 秒,发现空洞: False
2025-08-15 15:39:39,234 - hik3d - INFO - 全设备图片计算完成,总耗时 1.662 秒,结果: True
2025-08-15 15:39:40,263 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153938358_00DA6823953.pcd
2025-08-15 15:39:42,346 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153938671_00DA6823936.pcd
2025-08-15 15:39:46,206 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153938676_00DA6823936_original.pcd
2025-08-15 15:39:46,463 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\153938359_00DA6823953_original.pcd
2025-08-15 15:42:02,249 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-15 15:42:03,473 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-15 15:42:03,474 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-15 15:42:04,712 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-15 15:42:05,112 - hik3d - INFO - 服务启动中...
2025-08-15 15:42:05,112 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 15:42:06,533 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 15:42:06,534 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 15:42:06,535 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:42:06,535 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 15:42:06,536 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:42:06,771 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:42:06,922 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:42:08,164 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.629 秒,发现空洞: False
2025-08-15 15:42:08,582 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 2.048 秒,发现空洞: False
2025-08-15 15:42:08,669 - hik3d - INFO - 全设备图片计算完成,总耗时 2.135 秒,结果: False
2025-08-15 15:42:10,387 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\154207390_00DA6823953.pcd
2025-08-15 15:42:11,069 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 15:42:11,072 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 15:42:11,077 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:42:11,077 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 15:42:11,086 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 15:42:11,340 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:42:11,560 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 15:42:13,340 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 2.263 秒,发现空洞: False
2025-08-15 15:42:13,597 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 2.525 秒,发现空洞: False
2025-08-15 15:42:13,616 - hik3d - INFO - 全设备图片计算完成,总耗时 2.547 秒,结果: False
2025-08-15 15:42:14,486 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\154207737_00DA6823936.pcd
2025-08-15 15:42:15,688 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\154212842_00DA6823953.pcd
2025-08-15 15:42:20,353 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\154212845_00DA6823936.pcd
2025-08-15 15:42:21,444 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\154207750_00DA6823936_original.pcd
2025-08-15 15:42:21,700 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\154207485_00DA6823953_original.pcd
2025-08-15 15:42:25,242 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\154212848_00DA6823953_original.pcd
2025-08-15 15:42:25,928 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\154212853_00DA6823936_original.pcd
2025-08-15 17:46:24,253 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-15 17:46:25,489 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-15 17:46:25,489 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-15 17:46:26,713 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-15 17:46:27,162 - hik3d - INFO - 服务启动中...
2025-08-15 17:46:27,163 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 17:50:05,524 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-15 17:50:06,758 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-15 17:50:06,758 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-15 17:50:07,990 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-15 17:50:08,348 - hik3d - INFO - 服务启动中...
2025-08-15 17:50:08,349 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 17:50:33,128 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 17:50:33,129 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 17:50:33,129 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 17:50:37,567 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (90) height(720) width(1280) len (11059200)!
2025-08-15 17:50:40,334 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\175038509_00DA6823936.pcd
2025-08-15 17:50:41,451 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\175038513_00DA6823936_original.pcd
2025-08-15 17:50:42,486 - hik3d - INFO - Point cloud data acquired but no color image found in frames
2025-08-15 17:50:42,578 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 9.449 秒,发现空洞: False
2025-08-15 17:50:42,579 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 17:50:42,579 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 17:50:42,861 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 17:50:43,284 - hik3d - INFO - Point cloud data acquired but no color image found in frames
2025-08-15 17:50:43,403 - hik3d - INFO - 区域: 2 中心: (np.float64(3.015873015873016), np.float64(18.261904761904763)) 面积: 126
2025-08-15 17:50:43,436 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 0.857 秒,发现空洞: True
2025-08-15 17:50:43,439 - hik3d - INFO - 设备 00DA6823953 发现空洞,停止其他任务
2025-08-15 17:50:43,440 - hik3d - INFO - 全设备图片计算完成,总耗时 10.311 秒,结果: True
2025-08-15 17:50:44,119 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\175043283_00DA6823953.pcd
2025-08-15 17:50:45,877 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\175043283_00DA6823953_original.pcd
2025-08-15 17:52:55,797 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-15 17:52:57,003 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-15 17:52:57,004 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-15 17:52:58,218 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-15 17:52:58,595 - hik3d - INFO - 服务启动中...
2025-08-15 17:52:58,595 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 17:53:48,204 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 17:53:48,205 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 17:53:48,205 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 17:53:48,467 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 17:53:50,800 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\175349071_00DA6823936.pcd
2025-08-15 17:53:52,037 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\175349073_00DA6823936_original.pcd
2025-08-15 17:55:39,217 - hik3d - ERROR - Error during frame capture for device 00DA6823936: _type_ must have storage info
2025-08-15 17:55:39,420 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 111.215 秒,发现空洞: False
2025-08-15 17:55:39,421 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 17:55:39,421 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 17:55:39,681 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 17:55:41,181 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\175540199_00DA6823953.pcd
2025-08-15 17:55:43,090 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\175540200_00DA6823953_original.pcd
2025-08-15 17:57:37,611 - hik3d - ERROR - Error during frame capture for device 00DA6823953: _type_ must have storage info
2025-08-15 17:57:37,683 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 118.262 秒,发现空洞: False
2025-08-15 17:57:37,683 - hik3d - INFO - 全设备图片计算完成,总耗时 229.479 秒,结果: False
2025-08-15 18:00:03,885 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-15 18:00:05,105 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-15 18:00:05,105 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-15 18:00:06,337 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-15 18:00:06,699 - hik3d - INFO - 服务启动中...
2025-08-15 18:00:06,699 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 18:03:31,258 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:03:31,258 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:03:31,258 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:03:31,515 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:03:33,852 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\180332128_00DA6823936.pcd
2025-08-15 18:03:36,009 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\180332130_00DA6823936_original.pcd
2025-08-15 18:04:15,069 - hik3d - ERROR - Error during frame capture for device 00DA6823936: 'NoneType' object has no attribute 'encode'
2025-08-15 18:04:15,199 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 43.94 秒,发现空洞: False
2025-08-15 18:04:15,200 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 18:04:15,200 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:04:15,445 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:04:15,844 - hik3d - ERROR - Error during frame capture for device 00DA6823953: 'NoneType' object has no attribute 'encode'
2025-08-15 18:04:15,982 - hik3d - INFO - 区域: 2 中心: (np.float64(3.015748031496063), np.float64(17.755905511811022)) 面积: 127
2025-08-15 18:04:16,016 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 0.817 秒,发现空洞: True
2025-08-15 18:04:16,018 - hik3d - INFO - 设备 00DA6823953 发现空洞,停止其他任务
2025-08-15 18:04:16,021 - hik3d - INFO - 全设备图片计算完成,总耗时 44.763 秒,结果: True
2025-08-15 18:04:16,688 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\180415840_00DA6823953.pcd
2025-08-15 18:04:18,438 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\180415841_00DA6823953_original.pcd
2025-08-15 18:04:19,070 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:04:19,070 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:04:19,070 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:04:19,284 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:04:19,748 - hik3d - ERROR - Error during frame capture for device 00DA6823936: 'NoneType' object has no attribute 'encode'
2025-08-15 18:04:20,001 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 0.931 秒,发现空洞: False
2025-08-15 18:04:20,004 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 18:04:20,006 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:04:20,404 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:04:20,888 - hik3d - ERROR - Error during frame capture for device 00DA6823953: 'NoneType' object has no attribute 'encode'
2025-08-15 18:04:21,096 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.092 秒,发现空洞: False
2025-08-15 18:04:21,102 - hik3d - INFO - 全设备图片计算完成,总耗时 2.032 秒,结果: False
2025-08-15 18:04:22,477 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\180420876_00DA6823953.pcd
2025-08-15 18:04:22,775 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\180419746_00DA6823936.pcd
2025-08-15 18:04:26,212 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\180419747_00DA6823936_original.pcd
2025-08-15 18:04:27,027 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\180420879_00DA6823953_original.pcd
2025-08-15 18:10:39,234 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-15 18:10:40,467 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-15 18:10:40,468 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-15 18:10:41,697 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-15 18:10:42,091 - hik3d - INFO - 服务启动中...
2025-08-15 18:10:42,091 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 18:10:44,554 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:10:44,554 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:10:44,555 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:10:44,831 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:10:45,486 - hik3d - ERROR - Error during frame capture for device 00DA6823936: unsupported operand type(s) for +: 'NoneType' and 'str'
2025-08-15 18:10:45,762 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.208 秒,发现空洞: False
2025-08-15 18:10:45,764 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 18:10:45,766 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:10:46,024 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:10:46,428 - hik3d - ERROR - Error during frame capture for device 00DA6823953: unsupported operand type(s) for +: 'NoneType' and 'str'
2025-08-15 18:10:46,650 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 0.886 秒,发现空洞: False
2025-08-15 18:10:46,651 - hik3d - INFO - 全设备图片计算完成,总耗时 2.097 秒,结果: False
2025-08-15 18:10:48,189 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181046397_00DA6823953.pcd
2025-08-15 18:10:48,746 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181045458_00DA6823936.pcd
2025-08-15 18:10:50,855 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181045461_00DA6823936_original.pcd
2025-08-15 18:10:51,277 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181046399_00DA6823953_original.pcd
2025-08-15 18:16:38,887 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-15 18:16:40,103 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-15 18:16:40,103 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-15 18:16:41,320 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-15 18:16:41,661 - hik3d - INFO - 服务启动中...
2025-08-15 18:16:41,661 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 18:16:45,462 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:16:45,463 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:16:45,463 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:16:45,701 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:16:46,339 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\181646336_00DA6823936_Color.bmp
2025-08-15 18:16:46,627 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.163 秒,发现空洞: False
2025-08-15 18:16:46,629 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 18:16:46,631 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:16:46,903 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:16:47,323 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\181647323_00DA6823953_Color.bmp
2025-08-15 18:16:47,482 - hik3d - INFO - 区域: 1 中心: (np.float64(3.1548387096774193), np.float64(16.929032258064517)) 面积: 155
2025-08-15 18:16:47,547 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 0.918 秒,发现空洞: True
2025-08-15 18:16:47,551 - hik3d - INFO - 设备 00DA6823953 发现空洞,停止其他任务
2025-08-15 18:16:47,555 - hik3d - INFO - 全设备图片计算完成,总耗时 2.092 秒,结果: True
2025-08-15 18:16:48,974 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181647310_00DA6823953.pcd
2025-08-15 18:16:49,964 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181646329_00DA6823936.pcd
2025-08-15 18:16:54,723 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181646331_00DA6823936_original.pcd
2025-08-15 18:16:54,887 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181647312_00DA6823953_original.pcd
2025-08-15 18:18:58,924 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-15 18:19:00,158 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-15 18:19:00,158 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-15 18:19:01,382 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-15 18:19:01,782 - hik3d - INFO - 服务启动中...
2025-08-15 18:19:01,782 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-15 18:19:23,167 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:19:23,168 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:19:23,168 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:19:23,433 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:19:24,043 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\181924040_00DA6823936_Color.bmp
2025-08-15 18:19:24,313 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.145 秒,发现空洞: False
2025-08-15 18:19:24,314 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 18:19:24,318 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:19:24,592 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:19:25,026 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\181925024_00DA6823953_Color.bmp
2025-08-15 18:19:25,237 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 0.923 秒,发现空洞: False
2025-08-15 18:19:25,241 - hik3d - INFO - 全设备图片计算完成,总耗时 2.073 秒,结果: False
2025-08-15 18:19:26,553 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:19:26,559 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:19:26,566 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:19:26,987 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:19:27,267 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181925011_00DA6823953.pcd
2025-08-15 18:19:28,068 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\181928068_00DA6823936_Color.bmp
2025-08-15 18:19:28,673 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 2.114 秒,发现空洞: False
2025-08-15 18:19:28,674 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 18:19:28,679 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:19:28,939 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181924033_00DA6823936.pcd
2025-08-15 18:19:28,971 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:19:29,794 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\181929794_00DA6823953_Color.bmp
2025-08-15 18:19:30,064 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.39 秒,发现空洞: False
2025-08-15 18:19:30,069 - hik3d - INFO - 全设备图片计算完成,总耗时 3.51 秒,结果: False
2025-08-15 18:19:31,271 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:19:31,276 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:19:31,276 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:19:31,542 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:19:32,607 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\181932607_00DA6823936_Color.bmp
2025-08-15 18:19:33,200 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.924 秒,发现空洞: False
2025-08-15 18:19:33,205 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 18:19:33,210 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:19:33,482 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:19:34,339 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\181934339_00DA6823953_Color.bmp
2025-08-15 18:19:34,610 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.404 秒,发现空洞: False
2025-08-15 18:19:34,613 - hik3d - INFO - 全设备图片计算完成,总耗时 3.338 秒,结果: False
2025-08-15 18:19:35,691 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181928053_00DA6823936.pcd
2025-08-15 18:19:36,188 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:19:36,197 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:19:36,206 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:19:36,503 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:19:37,495 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\181937495_00DA6823936_Color.bmp
2025-08-15 18:19:38,204 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 2.007 秒,发现空洞: False
2025-08-15 18:19:38,213 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 18:19:38,219 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:19:38,702 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:19:39,359 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\181939359_00DA6823953_Color.bmp
2025-08-15 18:19:39,387 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181924035_00DA6823936_original.pcd
2025-08-15 18:19:39,577 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181929774_00DA6823953.pcd
2025-08-15 18:19:39,684 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.472 秒,发现空洞: False
2025-08-15 18:19:39,694 - hik3d - INFO - 全设备图片计算完成,总耗时 3.497 秒,结果: False
2025-08-15 18:19:41,579 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181925016_00DA6823953_original.pcd
2025-08-15 18:19:45,468 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181928060_00DA6823936_original.pcd
2025-08-15 18:19:45,525 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181932590_00DA6823936.pcd
2025-08-15 18:19:47,666 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181934323_00DA6823953.pcd
2025-08-15 18:19:50,543 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181929785_00DA6823953_original.pcd
2025-08-15 18:19:50,887 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181937478_00DA6823936.pcd
2025-08-15 18:19:51,124 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181932598_00DA6823936_original.pcd
2025-08-15 18:19:52,495 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181939341_00DA6823953.pcd
2025-08-15 18:19:53,789 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181934331_00DA6823953_original.pcd
2025-08-15 18:19:55,718 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181937487_00DA6823936_original.pcd
2025-08-15 18:19:55,969 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\181939350_00DA6823953_original.pcd
2025-08-15 18:20:28,544 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:20:28,544 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:20:28,544 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:20:28,763 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:20:29,247 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\182029247_00DA6823936_Color.bmp
2025-08-15 18:20:29,515 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 0.971 秒,发现空洞: False
2025-08-15 18:20:29,519 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 18:20:29,521 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:20:29,756 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:20:30,185 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\182030185_00DA6823953_Color.bmp
2025-08-15 18:20:30,393 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 0.874 秒,发现空洞: False
2025-08-15 18:20:30,397 - hik3d - INFO - 全设备图片计算完成,总耗时 1.852 秒,结果: False
2025-08-15 18:20:31,892 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\182030178_00DA6823953.pcd
2025-08-15 18:20:32,965 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\182029244_00DA6823936.pcd
2025-08-15 18:20:37,227 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:20:37,229 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:20:37,231 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:20:37,494 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:20:37,787 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\182029245_00DA6823936_original.pcd
2025-08-15 18:20:38,279 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\182038279_00DA6823936_Color.bmp
2025-08-15 18:20:38,473 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\182030181_00DA6823953_original.pcd
2025-08-15 18:20:38,666 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.437 秒,发现空洞: False
2025-08-15 18:20:38,666 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-15 18:20:38,667 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:20:39,120 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:20:39,788 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\182039788_00DA6823953_Color.bmp
2025-08-15 18:20:40,061 - hik3d - INFO - 区域: 1 中心: (np.float64(6.953488372093023), np.float64(5.005813953488372)) 面积: 172
2025-08-15 18:20:40,124 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.458 秒,发现空洞: True
2025-08-15 18:20:40,130 - hik3d - INFO - 设备 00DA6823953 发现空洞,停止其他任务
2025-08-15 18:20:40,139 - hik3d - INFO - 全设备图片计算完成,总耗时 2.91 秒,结果: True
2025-08-15 18:20:42,058 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\182039776_00DA6823953.pcd
2025-08-15 18:20:43,158 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\182038265_00DA6823936.pcd
2025-08-15 18:20:47,244 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\182038269_00DA6823936_original.pcd
2025-08-15 18:20:47,958 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\182039781_00DA6823953_original.pcd
2025-08-15 18:20:54,497 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-15 18:20:54,498 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-15 18:20:54,498 - hik3d - INFO - Delaying start by 0ms...
2025-08-15 18:20:54,745 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-15 18:20:55,503 - hik3d - INFO - Color image saved successfully: .\image\2025-08-15\color\182055502_00DA6823936_Color.bmp
2025-08-15 18:20:55,764 - hik3d - INFO - 区域: 4 中心: (np.float64(130.0084985835694), np.float64(10.51841359773371)) 面积: 353
2025-08-15 18:20:55,852 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.354 秒,发现空洞: True
2025-08-15 18:20:55,852 - hik3d - INFO - 设备 00DA6823936 发现空洞,停止其他任务
2025-08-15 18:20:55,860 - hik3d - INFO - 全设备图片计算完成,总耗时 1.361 秒,结果: True
2025-08-15 18:20:58,111 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\182055494_00DA6823936.pcd
2025-08-15 18:21:00,396 - hik3d - INFO - Saved point cloud to .\image\2025-08-15\pcd\182055498_00DA6823936_original.pcd

@ -0,0 +1,31 @@
2025-08-13 16:12:20,821 - my_app - INFO - ??????????...
2025-08-13 16:12:20,822 - my_app - INFO - ????????????????????: http://0.0.0.0:5000
2025-08-13 16:15:30,880 - my_app - INFO - ???????????????????
2025-08-13 16:15:30,880 - my_app - INFO - ????????? 00DA6823953 ???? 46 ????????
2025-08-13 16:15:32,037 - my_app - INFO - ?? 00DA6823953 ????????????????: True
2025-08-13 16:16:18,432 - my_app - INFO - ???????????????????
2025-08-13 16:16:18,432 - my_app - INFO - ????????? 00DA6823953 ???? 46 ????????
2025-08-13 16:18:41,293 - my_app - INFO - ?? 00DA6823953 ????????????????: True
2025-08-13 16:19:50,738 - my_app - INFO - ???????????????????
2025-08-13 16:19:50,738 - my_app - INFO - ????????? 00DA6823953 ???? 46 ????????
2025-08-13 16:22:36,790 - my_app - INFO - ?? 00DA6823953 ????????????????: True
2025-08-13 16:22:43,332 - my_app - INFO - ???????????????????
2025-08-13 16:22:43,333 - my_app - INFO - ????????? 00DA6823953 ???? 46 ????????
2025-08-13 16:32:29,290 - my_app - INFO - ?? 00DA6823953 ????????????????: True
2025-08-13 16:34:45,693 - my_app - INFO - ??????????...
2025-08-13 16:34:45,693 - my_app - INFO - ????????????????????: http://0.0.0.0:5000
2025-08-13 16:34:48,018 - my_app - INFO - ???????????????????
2025-08-13 16:34:48,019 - my_app - INFO - ????????? 00DA6823953 ???? 46 ????????
2025-08-13 16:37:21,400 - my_app - INFO - ??????????...
2025-08-13 16:37:21,400 - my_app - INFO - ????????????????????: http://0.0.0.0:5000
2025-08-13 16:37:25,853 - my_app - INFO - ???????????????????
2025-08-13 16:37:25,853 - my_app - INFO - ????????? 00DA6823953 ???? 46 ????????
2025-08-13 16:39:18,660 - my_app - INFO - ??????????...
2025-08-13 16:39:18,660 - my_app - INFO - ????????????????????: http://0.0.0.0:5000
2025-08-13 16:39:20,967 - my_app - INFO - ???????????????????
2025-08-13 16:39:20,967 - my_app - INFO - ????????? 00DA6823953 ???? 46 ????????
2025-08-13 16:42:12,161 - my_app - INFO - ??????????...
2025-08-13 16:42:12,161 - my_app - INFO - ????????????????????: http://0.0.0.0:5000
2025-08-13 16:42:12,686 - my_app - INFO - ???????????????????
2025-08-13 16:42:12,686 - my_app - INFO - ????????? 00DA6823953 ???? 46 ????????
2025-08-13 16:43:58,412 - my_app - INFO - ?? 00DA6823953 ????????????????: True

@ -0,0 +1,129 @@
2025-08-14 10:53:41,032 - my_app - INFO - 接收到全设备图片计算请求
2025-08-14 10:53:41,063 - my_app - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-14 10:53:42,203 - my_app - ERROR - 未捕获的异常: 'NoneType' object has no attribute 'get'
2025-08-14 10:53:58,406 - my_app - ERROR - 未捕获的异常: 405 Method Not Allowed: The method is not allowed for the requested URL.
2025-08-14 10:54:02,996 - my_app - INFO - 接收到全设备图片计算请求
2025-08-14 10:54:02,997 - my_app - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-14 10:54:04,023 - my_app - ERROR - 未捕获的异常: 'NoneType' object has no attribute 'get'
2025-08-14 11:08:48,337 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-14 11:08:49,581 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-14 11:08:49,582 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-14 11:08:50,815 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-14 11:08:51,290 - hik3d - INFO - 服务启动中...
2025-08-14 11:08:51,290 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-14 11:09:14,203 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-14 11:09:15,432 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-14 11:09:15,432 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-14 11:09:16,673 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-14 11:09:17,005 - hik3d - INFO - 服务启动中...
2025-08-14 11:09:17,005 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-14 11:09:30,806 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-14 11:09:32,021 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-14 11:09:32,021 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-14 11:09:33,242 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-14 11:09:33,563 - hik3d - INFO - 服务启动中...
2025-08-14 11:09:33,563 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-14 11:11:28,300 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-14 11:11:28,303 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-14 11:11:28,304 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:11:28,304 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-14 11:11:28,304 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:11:28,604 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:11:28,955 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:11:29,844 - hik3d - INFO - Single capture completed.
2025-08-14 11:11:29,890 - hik3d - INFO - Single capture completed.
2025-08-14 11:11:32,596 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111129675_00DA6823953.pcd
2025-08-14 11:11:32,999 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111129813_00DA6823936.pcd
2025-08-14 11:11:37,728 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111129826_00DA6823936_original.pcd
2025-08-14 11:11:37,912 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111129679_00DA6823953_original.pcd
2025-08-14 11:11:41,891 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 13.588 秒,发现空洞: False
2025-08-14 11:11:41,891 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 13.587 秒,发现空洞: False
2025-08-14 11:11:41,901 - hik3d - INFO - 全设备图片计算完成,总耗时 13.601 秒,结果: False
2025-08-14 11:11:48,424 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-14 11:11:48,425 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-14 11:11:48,425 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:11:48,425 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-14 11:11:48,425 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:11:48,680 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:11:48,738 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:11:49,370 - hik3d - INFO - Single capture completed.
2025-08-14 11:11:49,373 - hik3d - INFO - Single capture completed.
2025-08-14 11:11:49,679 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.254 秒,发现空洞: False
2025-08-14 11:11:49,684 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.259 秒,发现空洞: False
2025-08-14 11:11:49,693 - hik3d - INFO - 全设备图片计算完成,总耗时 1.269 秒,结果: False
2025-08-14 11:11:51,210 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111149339_00DA6823953.pcd
2025-08-14 11:11:51,587 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111149339_00DA6823936.pcd
2025-08-14 11:11:57,141 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111149341_00DA6823936_original.pcd
2025-08-14 11:11:57,405 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111149340_00DA6823953_original.pcd
2025-08-14 11:12:13,342 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-14 11:12:13,343 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-14 11:12:13,343 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:12:13,344 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-14 11:12:13,344 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:12:13,565 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:12:13,702 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:12:14,209 - hik3d - INFO - Single capture completed.
2025-08-14 11:12:14,244 - hik3d - INFO - Single capture completed.
2025-08-14 11:12:14,491 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.148 秒,发现空洞: False
2025-08-14 11:12:14,687 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.343 秒,发现空洞: True
2025-08-14 11:12:14,691 - hik3d - INFO - 设备 00DA6823953 发现空洞,停止其他任务
2025-08-14 11:12:14,698 - hik3d - INFO - 全设备图片计算完成,总耗时 1.355 秒,结果: True
2025-08-14 11:12:15,847 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111214178_00DA6823953.pcd
2025-08-14 11:12:16,160 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111214178_00DA6823936.pcd
2025-08-14 11:12:21,519 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111214180_00DA6823936_original.pcd
2025-08-14 11:12:21,798 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111214182_00DA6823953_original.pcd
2025-08-14 11:13:01,133 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-14 11:13:01,134 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-14 11:13:01,135 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:13:01,135 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-14 11:13:01,135 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:13:01,356 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:13:01,508 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:13:02,036 - hik3d - INFO - Single capture completed.
2025-08-14 11:13:02,143 - hik3d - INFO - Single capture completed.
2025-08-14 11:13:02,325 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.19 秒,发现空洞: False
2025-08-14 11:13:02,376 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.242 秒,发现空洞: False
2025-08-14 11:13:02,390 - hik3d - INFO - 全设备图片计算完成,总耗时 1.257 秒,结果: False
2025-08-14 11:13:03,712 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111301877_00DA6823953.pcd
2025-08-14 11:13:04,157 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111302097_00DA6823936.pcd
2025-08-14 11:13:09,521 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111302102_00DA6823936_original.pcd
2025-08-14 11:13:09,693 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\111301877_00DA6823953_original.pcd
2025-08-14 11:21:14,864 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-14 11:21:14,865 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-14 11:21:14,865 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:21:14,865 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-14 11:21:14,866 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:21:15,111 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:21:15,278 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:21:15,884 - hik3d - INFO - Single capture completed.
2025-08-14 11:21:16,011 - hik3d - INFO - Single capture completed.
2025-08-14 11:21:16,345 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.48 秒,发现空洞: False
2025-08-14 11:21:16,358 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.493 秒,发现空洞: False
2025-08-14 11:21:16,370 - hik3d - INFO - 全设备图片计算完成,总耗时 1.506 秒,结果: False
2025-08-14 11:21:17,908 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\112115786_00DA6823953.pcd
2025-08-14 11:21:18,291 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\112115958_00DA6823936.pcd
2025-08-14 11:21:24,472 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\112115965_00DA6823936_original.pcd
2025-08-14 11:21:24,647 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\112115786_00DA6823953_original.pcd
2025-08-14 11:25:19,160 - hik3d - INFO - Found device [0]: Serial Number: 00DA6823936
2025-08-14 11:25:20,425 - hik3d - INFO - Successfully added device 00DA6823936 to SN_MAP
2025-08-14 11:25:20,425 - hik3d - INFO - Found device [1]: Serial Number: 00DA6823953
2025-08-14 11:25:21,666 - hik3d - INFO - Successfully added device 00DA6823953 to SN_MAP
2025-08-14 11:25:22,165 - hik3d - INFO - 服务启动中...
2025-08-14 11:25:22,165 - hik3d - INFO - 服务启动成功,监听地址: http://0.0.0.0:5000
2025-08-14 11:25:43,026 - hik3d - INFO - 接收到全设备图片计算请求
2025-08-14 11:25:43,028 - hik3d - INFO - 开始处理设备 00DA6823936 的图片计算
2025-08-14 11:25:43,028 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:25:43,029 - hik3d - INFO - 开始处理设备 00DA6823953 的图片计算
2025-08-14 11:25:43,029 - hik3d - INFO - Delaying start by 0ms...
2025-08-14 11:25:43,265 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:25:43,531 - hik3d - INFO - _MapDepthToPointCloud() Run Succeed: framenum (1) height(720) width(1280) len (11059200)!
2025-08-14 11:25:44,154 - hik3d - INFO - Single capture completed.
2025-08-14 11:25:44,277 - hik3d - INFO - Single capture completed.
2025-08-14 11:25:44,474 - hik3d - INFO - 设备 00DA6823953 处理完成,耗时 1.445 秒,发现空洞: False
2025-08-14 11:25:44,991 - hik3d - INFO - 设备 00DA6823936 处理完成,耗时 1.963 秒,发现空洞: True
2025-08-14 11:25:44,995 - hik3d - INFO - 设备 00DA6823936 发现空洞,停止其他任务
2025-08-14 11:25:45,035 - hik3d - INFO - 全设备图片计算完成,总耗时 2.009 秒,结果: True
2025-08-14 11:25:45,852 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\112543933_00DA6823953.pcd
2025-08-14 11:25:47,209 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\112544229_00DA6823936.pcd
2025-08-14 11:25:49,519 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\112544234_00DA6823936_original.pcd
2025-08-14 11:25:49,681 - hik3d - INFO - Saved point cloud to .\image\2025-08-14\pcd\112544008_00DA6823953_original.pcd

@ -1,52 +1,316 @@
# 这是一个示例 Python 脚本。
import json
import os
# 按 Shift+F10 执行或将其替换为您的代码。
# 按 双击 Shift 在所有地方搜索类、文件、工具窗口、操作和设置。
import SimpleView_SaveImage as simple
import config
from Point import tiff_depth_to_point_clouds
import image
import time # 在文件顶部导入 time 模块
from flask import Flask, jsonify, request
from logConfig import get_logger
app = Flask(__name__)
import concurrent.futures
from functools import partial
# 使用示例
logger = get_logger()
# 示例接口GET 请求
@app.route("/config/update")
def home():
logger.info("配置更新请求")
config.load_configs()
return "Hello, this service config update!"
# 示例接口:返回 JSON 数据
@app.route("/api/data")
def get_data():
data = {"message": "This is some data", "status": "OK"}
return jsonify(data)
# 示例接口:接收参数
# 示例接口:接收参数
@app.route("/api/compute/<direction>")
def compute(direction):
try:
sn = config.DIRECTION_CAMERA[direction]
except KeyError:
return jsonify({"message": "", "status": "ERROR", "error": f"Direction '{direction}' not found in DIRECTION_CAMERA"}), 400
logger.info("配置更新完成")
return {"message": "Hello, this service config update!", "status": "OK"}
@app.route("/api/addTemplate", methods=["POST"])
def save_template():
logger.info("接收到添加模板请求")
data = request.get_json()
# 验证必要字段
if not data:
logger.error("添加模板失败:未提供数据")
return jsonify({"status": "ERROR", "message": "No data provided"}), 400
template_type = data.get("type")
if not template_type:
logger.error("添加模板失败:缺少'type'字段")
return jsonify({"status": "ERROR", "message": "Missing 'type' field"}), 400
CONFIG_DIR = "./config/template"
# 构造文件路径
filename = f"{template_type}.json"
file_path = os.path.join(CONFIG_DIR, filename)
# 写入文件
try:
tiff_paths = simple.pic(sn)
with open(file_path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
config.load_configs()
logger.info(f"模板 '{template_type}' 保存成功")
return jsonify({"status": "OK", "message": f"Template '{template_type}' saved successfully."}), 200
except Exception as e:
return jsonify({"message": "", "status": "ERROR", "error": f"Failed to get TIFF paths: {str(e)}"}), 500
logger.error(f"保存模板失败: {str(e)}")
return jsonify({"status": "ERROR", "message": f"Failed to save template: {str(e)}"}), 500
@app.route("/api/initDevice", methods=['POST'])
def initDevice():
logger.info("设备初始化请求")
simple.initialize_devices()
logger.info("设备初始化完成")
#
# @app.route("/api/picComputeAll", methods=['POST'])
# def picComputeAll():
# logger.info("接收到全设备图片计算请求")
# start_time_total = time.time()
#
# # 输入参数
# # sn:设备编号
# # type:类型
#
# # 获取 JSON 数据
# data = request.get_json()
# type = data['type']
# template = config.TEMPLATE_CONFIG_MAP.get(type)
# if not template:
# logger.error("缺少模板配置: 'type'")
# return jsonify({
# "message": "",
# "status": "ERROR",
# "error": "Missing required parameter: 'type'"
# }), 400
# all_sn_list = list(config.CAMERA_CONFIG_MAP.keys())
#
# # 遍历每个 sn 并判断是否都有 hole
# all_have_holes = False
# color_list = [] # 新增:用于保存所有 sn 的 color
#
# count_assemble = 0
# for sn in all_sn_list:
# start_time = time.time() # 开始计时
# logger.info(f"开始处理设备 {sn} 的图片计算")
# pic_info = simple.enhanced_pic(sn, type)
# points = pic_info.get("point")
# if points is None:
# logger.warning(f"设备 {sn} 未返回点云数据")
# all_have_holes = True
# break
#
# # 提取 color 并加入列表
# color = pic_info.get("color")
# if color is not None:
# color_list.append(color)
#
# try:
# real_holes, count = image.detect_large_holes(points, sn, type)
# # count_assemble += count
#
# if len(real_holes) != 0:
# all_have_holes = True
# # 计算耗时
# elapsed_time = round(time.time() - start_time, 3)
# # 输出日志
# logger.info(f"[INFO] picComputeAll executed in {elapsed_time} seconds {sn}")
# break # 判断到空洞就直接退出
# except Exception as e:
# all_have_holes = True
# logger.error(f"Failed to process request: {str(e)} sn{sn}")
#
# # 计算总耗时
# total_elapsed_time = round(time.time() - start_time_total, 3)
# logger.info(f"全设备图片计算完成,总耗时 {total_elapsed_time} 秒,结果: {all_have_holes}")
#
# # 返回结果中包含 color 列表
# return jsonify({
# "message": all_have_holes,
# "lack": all_have_holes,
# "type": type,
# "count": count_assemble,
# "colors": color_list, # 添加 color 列表
# "status": "OK"
# })
#
@app.route("/api/picComputeAll", methods=['POST'])
def picComputeAll():
logger.info("接收到全设备图片计算请求")
start_time_total = time.time()
# 获取 JSON 数据
data = request.get_json()
type = data['type']
template = config.TEMPLATE_CONFIG_MAP.get(type)
if not template:
logger.error("缺少模板配置: 'type'")
return jsonify({
"message": "",
"status": "ERROR",
"error": "Missing required parameter: 'type'"
}), 400
all_sn_list = list(config.CAMERA_CONFIG_MAP.keys())
# 同步处理每个设备
all_have_holes = False
color_list = []
count_assemble = 0
# 逐个同步处理设备
for sn in all_sn_list:
try:
start_time = time.time()
logger.info(f"开始处理设备 {sn} 的图片计算")
# 同步采集图片信息
pic_info = simple.enhanced_pic(sn, type)
points = pic_info.get("point")
if points is None:
logger.warning(f"设备 {sn} 未返回点云数据")
all_have_holes = True
break
# 提取 color 并加入列表
if pic_info.get("color") is not None:
color_list.append(pic_info["color"])
# 检测空洞
real_holes, count = image.detect_large_holes(points, sn, type)
elapsed_time = round(time.time() - start_time, 3)
logger.info(f"设备 {sn} 处理完成,耗时 {elapsed_time} 秒,发现空洞: {len(real_holes) != 0}")
# 检查是否发现空洞
if len(real_holes) != 0:
all_have_holes = True
count_assemble += count
logger.info(f"设备 {sn} 发现空洞,停止其他任务")
break # 发现空洞就直接退出
except Exception as e:
logger.error(f"处理设备 {sn} 时发生异常: {str(e)}")
all_have_holes = True
break
# 计算总耗时
total_elapsed_time = round(time.time() - start_time_total, 3)
logger.info(f"全设备图片计算完成,总耗时 {total_elapsed_time} 秒,结果: {all_have_holes}")
# 返回结果中包含 color 列表
return jsonify({
"message": all_have_holes,
"lack": all_have_holes,
"type": type,
"count": count_assemble,
"colors": color_list,
"status": "OK"
})
@app.route("/api/picBitCloudy", methods=['POST'])
def picBitCloudy():
logger.info("接收到picBitCloudy请求")
# 输入参数
# sn:设备编号
# type:类型
# 获取 JSON 数据
data = request.get_json()
direction = data.get('direction')
type = data.get('type')
all_sn_list = list(config.CAMERA_CONFIG_MAP.keys())
# 遍历每个 sn 并判断是否都有 hole
all_have_holes = False
color_list = [] # 新增:用于保存所有 sn 的 color
count_assemble = 0
for sn in all_sn_list:
if direction and config.CAMERA_CONFIG_MAP[sn].get("direction") != direction:
logger.debug(f"设备 {sn} 方向不匹配,跳过")
continue
start_time = time.time() # 开始计时
logger.info(f"开始处理设备 {sn} 的图片计算")
pic_info = simple.enhanced_pic(sn, type)
points = pic_info.get("point")
if points is None or len(points) < 300:
logger.warning(f"设备 {sn} 点云数据不足")
all_have_holes = True
break
# 提取 color 并加入列表
color = pic_info.get("color")
if color is not None:
color_list.append(color)
logger.info(f"picBitCloudy处理完成结果: {all_have_holes}")
# 返回结果中包含 color 列表
return jsonify({
"message": all_have_holes,
"lack": all_have_holes,
"colors": color_list, # 添加 color 列表
"status": "OK"
})
@app.route("/api/picCompute", methods=['POST'])
def picCompute():
logger.info("接收到单设备图片计算请求")
# 输入参数
# sn:设备编号
# type:类型
try:
rest = tiff_depth_to_point_clouds(tiff_paths, sn, dedup=True)
# 获取 JSON 数据
data = request.get_json()
if not data or 'sn' not in data:
logger.error("缺少必需参数: 'sn'")
return jsonify({
"message": "",
"status": "ERROR",
"error": "Missing required parameter: 'sn'"
}), 400
sn = data['sn']
type = data['type']
logger.info(f"开始处理设备 {sn} 类型 {type} 的图片计算")
template = config.TEMPLATE_CONFIG_MAP.get(type)
if not template:
logger.error(f"缺少模板配置: {type}")
return jsonify({
"message": "",
"status": "ERROR",
"error": "Missing required parameter: 'type'"
}), 400
pic_info = simple.enhanced_pic(sn, type)
real_holes, count = image.detect_large_holes(pic_info["point"], sn, type)
result = len(real_holes) != 0
logger.info(f"设备 {sn} 图片计算完成,检测到空洞: {result}")
return jsonify({"message": result,
"lack": result, "status": "OK"})
except Exception as e:
return jsonify({"message": "", "status": "ERROR", "error": f"Point cloud processing failed: {str(e)}"}), 500
logger.error(f"图片计算失败: {str(e)}")
return jsonify({"message": "", "status": "ERROR", "error": f"Failed to get TIFF paths: {str(e)}"}), 500
return jsonify({"message": True, "lack": True, "status": "OK"})
print(rest)
return jsonify({"message": rest, "status": "OK"})
@app.errorhandler(Exception)
def handle_exception(e):
# 处理所有未被捕获的异常
logger.error(f"未捕获的异常: {str(e)}")
return jsonify({
"message": "",
"status": "ERROR",
@ -57,6 +321,7 @@ def handle_exception(e):
if __name__ == "__main__":
from waitress import serve
logger.info("服务启动中...")
print("Serving on http://0.0.0.0:5000")
logger.info("服务启动成功,监听地址: http://0.0.0.0:5000")
serve(app, host='0.0.0.0', port=5000)

@ -0,0 +1,74 @@
# thread_pool.py
import concurrent.futures
import threading
from typing import Callable, Any
class ThreadPoolManager:
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super(ThreadPoolManager, cls).__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self):
if not self._initialized:
# 创建线程池最大4个线程
self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=4)
self._initialized = True
def submit(self, fn: Callable, *args, **kwargs) -> concurrent.futures.Future:
"""
提交任务到线程池执行
:param fn: 要执行的函数
:param args: 函数的位置参数
:param kwargs: 函数的关键字参数
:return: Future对象
"""
if kwargs:
# 如果有关键字参数,需要包装函数
def wrapper():
return fn(*args, **kwargs)
return self.executor.submit(wrapper)
else:
return self.executor.submit(fn, *args)
def shutdown(self, wait=True):
"""
关闭线程池
:param wait: 是否等待所有任务完成
"""
self.executor.shutdown(wait=wait)
# 创建全局线程池管理器实例
_thread_pool_manager = ThreadPoolManager()
def get_thread_pool() -> ThreadPoolManager:
"""
获取线程池管理器实例
:return: ThreadPoolManager实例
"""
return _thread_pool_manager
def submit_task(fn: Callable, *args, **kwargs) -> concurrent.futures.Future:
"""
提交任务到线程池执行的便捷函数
:param fn: 要执行的函数
:param args: 函数的位置参数
:param kwargs: 函数的关键字参数
:return: Future对象
"""
return _thread_pool_manager.submit(fn, *args, **kwargs)
Loading…
Cancel
Save