增加异步

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

@ -1,129 +1,130 @@
from datetime import time
import numpy as np import numpy as np
from PIL import Image from PIL import Image
import math import math
import config import config
from cat import clip_and_rotate_point_cloud, merge_point_clouds import asyncio
from image import detect_large_holes
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 # 保持像素方形比例
cx = width / 2
cy = height / 2
print(f"Calculated intrinsics: fx={fx:.2f}, fy={fy:.2f}, cx={cx:.2f}, cy={cy:.2f}")
points = [] import numpy as np
seen_xy = set() # 用于记录已添加的 (x, y) from scipy.spatial.transform import Rotation as R
# 获取裁剪配置
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
# 构造点并旋转(保留浮点精度) from logConfig import get_logger
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: logger = get_logger()
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])
def apply_rotation(matrix, angle_degrees, axis='x'):
"""
对输入的 3x3 旋转矩阵 应用额外的旋转
# 可选输出PLY文件用于可视化 参数:
if config.CAMERA_CONFIG_MAP[sn].get("save_pcd"): matrix (np.ndarray): 原始的 3x3 旋转矩阵
output_ply_path = config.save_path("pcd",sn+".pcd") angle_degrees (float): 旋转角度 (单位: )
write_pcd(output_ply_path, points) 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) mask = np.all(np.isfinite(points), axis=1)
return points[mask] 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: if clip_config:
min_pt = np.array(clip_config.get("min_pt", [-np.inf] * 3)) rotation = np.array(clip_config["rotation"], dtype=np.float32).reshape(3, 3)
max_pt = np.array(clip_config.get("max_pt", [np.inf] * 3)) min_pt = np.array(clip_config["min_pt"], dtype=np.float32)
rotation = np.array(clip_config.get("rotation", [1, 0, 0, 0, 1, 0, 0, 0, 1])).reshape(3, 3) 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: else:
min_pt = max_pt = rotation = None x_trimmed = points[:, 0]
y_trimmed = points[:, 1]
processed_points = [] z_trimmed = points[:, 2]
seen_xy = set()
for point in points:
x, y, z = point
# 无效点过滤Z ≤ 0 或超出最大距离) # 合并为一个数组
if z <= 0 or z > config.CAMERA_CONFIG_MAP[sn].get("max_z", np.inf): trimmed_points = np.column_stack((
continue np.round(x_trimmed, 3),
np.round(y_trimmed, 3),
np.round(z_trimmed, 3)
))
# 应用旋转矩阵 # 应用 z 值过滤
if clip_config: final_mask = (trimmed_points[:, 2] >= z_min) & (trimmed_points[:, 2] <= z_max)
rotated = rotation @ point filtered_points = trimmed_points[final_mask]
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
# 去重逻辑(保留浮点精度)
if dedup:
# 使用浮点哈希避免离散化损失
key = (round(x_final, 3), round(y_final, 3))
if key in seen_xy:
continue
seen_xy.add(key)
processed_points.append([x_final, y_final, z_final]) # 去重
keys = filtered_points[:, :2] # 只取 x,y
_, unique_indices = np.unique(keys, axis=0, return_index=True)
return processed_points # 返回 list of [x, y, z]
return filtered_points[unique_indices].tolist()
def sValue_to_pcd(sValue,stPointCloudImage,sn): def sValue_to_pcd(sValue,stPointCloudImage,sn,type):
# 数据格式转换 # 数据格式转换
points = convert_sdk_points(sValue, stPointCloudImage.nWidth, stPointCloudImage.nHeight) 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") 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): def write_pcd(filename, points):
@ -214,23 +287,21 @@ def write_pcd(filename, points):
with open(filename, 'w') as f: with open(filename, 'w') as f:
# 写入 PCD 文件头 # 写入 PCD 文件头
f.write("# .PCD v0.7 - Point Cloud Data file format\n") 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("FIELDS x y z\n")
f.write("SIZE 4 4 4\n") # float 类型的大小是 4 字节 f.write("SIZE 4 4 4\n")
f.write("TYPE F F F\n") # 每个字段的数据类型 f.write("TYPE F F F\n")
f.write(f"COUNT 1 1 1\n") # 每个字段的数量 f.write("COUNT 1 1 1\n")
f.write(f"WIDTH {len(points)}\n") # 点数量 f.write(f"WIDTH {len(points)}\n")
f.write("HEIGHT 1\n") # 单行表示无结构点云 f.write(f"HEIGHT 1\n")
f.write("VIEWPOINT 0 0 0 1 0 0 0\n") # 默认视角参数 f.write("VIEWPOINT 0 0 0 1 0 0 0\n")
f.write(f"POINTS {len(points)}\n") # 总点数 f.write(f"POINTS {len(points)}\n")
f.write("DATA ascii\n") # 数据部分以 ASCII 形式存储 f.write("DATA ascii\n")
# 写入点数据 # 写入点数据
for point in points: for point in points:
f.write(f"{point[0]} {point[1]} {point[2]}\n") 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 time
import os import os
import struct import struct
from thread_pool import submit_task
from ctypes import * from ctypes import *
from datetime import datetime from datetime import datetime
import Point as point import Point as point
@ -17,17 +18,47 @@ from Mv3dRgbdImport.Mv3dRgbdDefine import DeviceType_Ethernet, DeviceType_USB, D
import config as configMap import config as configMap
# 全局变量 # 全局变量
SN_MAP = {} # {sn: camera_instance} 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( ret = Mv3dRgbd.MV3D_RGBD_GetDeviceNumber(
DeviceType_Ethernet | DeviceType_USB | DeviceType_Ethernet_Vir | DeviceType_USB_Vir, DeviceType_Ethernet | DeviceType_USB | DeviceType_Ethernet_Vir | DeviceType_USB_Vir,
byref(nDeviceNum) byref(nDeviceNum)
) )
if ret != MV3D_RGBD_OK or nDeviceNum.value == 0: if ret != MV3D_RGBD_OK or nDeviceNum.value == 0:
print("Failed to get device number or no devices found.") logger.error("Failed to get device number or no devices found.")
return return False
stDeviceList = MV3D_RGBD_DEVICE_INFO_LIST() stDeviceList = MV3D_RGBD_DEVICE_INFO_LIST()
Mv3dRgbd.MV3D_RGBD_GetDeviceList( Mv3dRgbd.MV3D_RGBD_GetDeviceList(
@ -35,115 +66,280 @@ def initialize_devices():
pointer(stDeviceList.DeviceInfo[0]), 20, byref(nDeviceNum) pointer(stDeviceList.DeviceInfo[0]), 20, byref(nDeviceNum)
) )
# 查找对应序列号的设备
target_device_info = None
for i in range(nDeviceNum.value):
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
if not target_device_info:
logger.error(f"Device with SN: {sn} not found during reconnection attempt")
return False
# 尝试重连
for attempt in range(max_retries):
try:
# 创建新的相机实例
new_camera = Mv3dRgbd()
# 尝试打开设备
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}")
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): for i in range(nDeviceNum.value):
serial_number = ''.join(chr(c) for c in stDeviceList.DeviceInfo[i].chSerialNumber).rstrip('\x00') serial_number = ''.join(chr(c) for c in stDeviceList.DeviceInfo[i].chSerialNumber).rstrip('\x00')
print(f"Found device [{i}]: Serial Number: {serial_number}") logger.info(f"Found device [{i}]: Serial Number: {serial_number}")
camera = Mv3dRgbd() camera = Mv3dRgbd()
# 打开设备 # 打开设备
ret = camera.MV3D_RGBD_OpenDevice(pointer(stDeviceList.DeviceInfo[i])) ret = camera.MV3D_RGBD_OpenDevice(pointer(stDeviceList.DeviceInfo[i]))
if ret != MV3D_RGBD_OK: if ret != MV3D_RGBD_OK:
print(f"Failed to open device with SN: {serial_number}. Error code: {ret:#x}") logger.info(f"Failed to open device with SN: {serial_number}. Error code: {ret:#x}")
continue continue
# 存入全局 map # 存入全局 map
SN_MAP[serial_number] = camera SN_MAP[serial_number] = camera
print(f"Successfully added device {serial_number} to SN_MAP") 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 pic(sn):
def enhanced_pic(sn, type):
"""
增强版的图片采集函数包含重连机制和点云数据重试机制
"""
camera = SN_MAP.get(sn) camera = SN_MAP.get(sn)
if not camera: if not camera:
print(f"No camera found for SN: {sn}") logger.info(f"No camera found for SN: {sn}, attempting reconnection...")
return 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) config = configMap.CAMERA_CONFIG_MAP.get(sn)
if not config: if not config:
print(f"No config found for SN: {sn}") logger.info(f"No config found for SN: {sn}")
return return None
time_on = config.get("time_on", 0) # 延时开始(毫秒) time_on = config.get("time_on", 0)
print(f"Delaying start by {time_on}ms...") logger.info(f"Delaying start by {time_on}ms...")
time.sleep(time_on / 1000.0) # 转成秒 time.sleep(time_on / 1000.0)
saved_files = { saved_files = {
"depth": [], "sn": sn,
"color": [], "depth": "",
"pcd": [] "color": "",
"pcd": "",
"point": []
} }
# 开始取流 # 尝试开始取流,如果失败则尝试重连
ret = camera.MV3D_RGBD_Start() ret = camera.MV3D_RGBD_Start()
if ret != MV3D_RGBD_OK: if ret != MV3D_RGBD_OK:
print(f"Failed to start grabbing. Error code: {ret:#x}") logger.info(f"Failed to start grabbing. Error code: {ret:#x}")
return 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: try:
# 最多重试10次获取有效的点云数据
max_retries = 10
retry_count = 0
point_cloud_success = False
# 用于存储最后一次成功的彩色图数据
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() stFrameData = MV3D_RGBD_FRAME_DATA()
# 获取单帧数据 # 获取单帧数据
ret = camera.MV3D_RGBD_FetchFrame(pointer(stFrameData), 5000) ret = camera.MV3D_RGBD_FetchFrame(pointer(stFrameData), 5000)
if ret == MV3D_RGBD_OK: 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): for i in range(stFrameData.nImageCount):
image_info = stFrameData.stImageData[i] image_info = stFrameData.stImageData[i]
# 保存深度图 # 保存深度图
if image_info.enImageType == ImageType_Depth: if image_info.enImageType == ImageType_Depth:
file_name = configMap.save_path("depth", "-Depth") has_depth_data = True
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() stPointCloudImage = MV3D_RGBD_IMAGE_DATA()
ret = camera.MV3D_RGBD_MapDepthToPointCloud(pointer(stFrameData.stImageData[i]), pointer(stPointCloudImage)) ret = camera.MV3D_RGBD_MapDepthToPointCloud(pointer(stFrameData.stImageData[i]),
pointer(stPointCloudImage))
if MV3D_RGBD_OK != ret: if MV3D_RGBD_OK != ret:
print("_MapDepthToPointCloud() Run failed...") logger.info(f"_MapDepthToPointCloud() Run failed... Retry: {retry_count + 1}/{max_retries}")
else: else:
print( logger.info(
"_MapDepthToPointCloud() Run Succeed: framenum (%d) height(%d) width(%d) len (%d)!" % ( "_MapDepthToPointCloud() Run Succeed: framenum (%d) height(%d) width(%d) len (%d)!" % (
stPointCloudImage.nFrameNum, stPointCloudImage.nFrameNum,
stPointCloudImage.nHeight, stPointCloudImage.nWidth, stPointCloudImage.nDataLen)) stPointCloudImage.nHeight, stPointCloudImage.nWidth, stPointCloudImage.nDataLen))
strMode = string_at(stPointCloudImage.pData, stPointCloudImage.nDataLen) strMode = string_at(stPointCloudImage.pData, stPointCloudImage.nDataLen)
sValue = struct.unpack('f' * int(stPointCloudImage.nHeight * stPointCloudImage.nWidth * 3), sValue = struct.unpack('f' * int(stPointCloudImage.nHeight * stPointCloudImage.nWidth * 3),
strMode) strMode)
pcd_file = point.sValue_to_pcd(sValue, stPointCloudImage, sn) pcd_file, processed_points = point.sValue_to_pcd(sValue, stPointCloudImage, sn, type)
if pcd_file: if pcd_file and len(processed_points) > 0:
saved_files["pcd"].append(pcd_file) saved_files["pcd"] = pcd_file
saved_files["point"] = processed_points
point_cloud_success = True # 成功获取点云数据
flag = False
# 保存彩色图 # 记录彩色图信息,但不立即保存
elif image_info.enImageType in ( elif image_info.enImageType in (
ImageType_RGB8_Planar, ImageType_YUV420SP_NV12, ImageType_RGB8_Planar, ImageType_YUV420SP_NV12,
ImageType_YUV420SP_NV21, ImageType_YUV422 ImageType_YUV420SP_NV21, ImageType_YUV422
): ):
file_name = configMap.save_path("color", "-_Color") file_name = configMap.save_path("color", sn+"_Color")
ret_save = camera.MV3D_RGBD_SaveImage(pointer(image_info), FileType_BMP, file_name) if config.get("save_image"):
print("Saved color image." if ret_save == MV3D_RGBD_OK else "Failed to save color image.") submit_task(camera.MV3D_RGBD_SaveImage,pointer(image_info), FileType_BMP, file_name)
if ret_save == MV3D_RGBD_OK: saved_files["color"] = file_name + ".bmp"
saved_files["color"].append(file_name) 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: else:
print("Failed to fetch frame.") 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: finally:
camera.MV3D_RGBD_Stop() camera.MV3D_RGBD_Stop()
print("Single capture completed.") # logger.info(f"Single capture completed. Results: {saved_files}")
# 输出结果路径
print("Saved files:")
for key, paths in saved_files.items():
if paths:
print(f" {key.upper()}:")
for path in paths:
print(f" - {path}")
return 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
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
if __name__ == '__main__': # 存入全局 map
pic("00DA6823936") 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} CAMERA_CONFIG_MAP = {} # {sn: config_dict}
CUT_CONFIG_MAP = {} # {filename_without_ext: config_dict} CUT_CONFIG_MAP = {} # {filename_without_ext: config_dict}
DIRECTION_CAMERA = {} DIRECTION_CAMERA = {}
TEMPLATE_MAP = {} TEMPLATE_CONFIG_MAP = {}
def load_camera_configs(config_dir="./config/camera"): def load_camera_configs(config_dir="./config/camera"):
""" """
@ -50,7 +50,7 @@ def load_template_configs(config_dir="./config/template"):
config = json.load(f) config = json.load(f)
type = config.get("type") type = config.get("type")
if type: if type:
TEMPLATE_MAP[type] = config TEMPLATE_CONFIG_MAP[type] = config
print(f"Loaded camera config: {type}") print(f"Loaded camera config: {type}")
else: else:
print(f"[WARN] No 'sn' found in {filename}") print(f"[WARN] No 'sn' found in {filename}")

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

@ -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", "type": "45",
"width":"299", "width":299,
"length":"355", "length":355,
"high":"314" "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 "sn": "00DA6823936",#sn
"direction": "1",#方向 "direction": "1",#方向
"x_angle": 55,#相机的水平视场角(相机自身的)
"y_angle": 84,#相机的垂直视场角
"save_pcd": true,#是否保存pcd "save_pcd": true,#是否保存pcd
"resolution": 8,#像素大小(可以调整来区别 "resolution": 8,#像素大小(可以调整生成的图片,根据生成图片识别空洞
"max_z": 2000,#最大深度(裁剪之前的 "max_z": 2000,#最大深度(裁剪之前的
"reverse_order": false,#是否pcd组成的图片是否翻转
"time_on": 300,#开始时间 "time_on": 300,#开始时间
"time_off": 3500,#结束时间 "save_not_cut": true #基础的没有裁剪的pcd是否保存
"time_hop": 500#时间间隔
} }
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 numpy as np
import cv2 import cv2
import matplotlib.pyplot as plt
import threading
from thread_pool import submit_task
from scipy.ndimage import label from scipy.ndimage import label
import config 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)): def point_cloud_to_2d_image(points, resolution=1.0, x_range=(17, 275), y_range=(-129, -1227)):
""" """
将点云转换为 2D 图像X-Y 平面每个像素值表示对应位置的 Z 值平均值 将点云转换为 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 width = int((x_max - x_min) / resolution) + 1
height = int((y_max - y_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) image = np.zeros((height, width), dtype=np.float32)
count_map = np.zeros((height, width), dtype=np.int32) count_map = np.zeros((height, width), dtype=np.int32)
for x, y, z in points: # 使用 bincount 进行快速统计
xi = int((x - x_min) / resolution) indices = yi * width + xi
yi = int((y - y_min) / resolution) 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.flat[:] = z_sums
image[yi, xi] += z count_map.flat[:] = counts
count_map[yi, xi] += 1
# 防止除零错误 # 防止除零错误
count_map[count_map == 0] = 1 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) 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)
# 连通域分析 # 创建 Stitcher 对象
structure = np.array([[1, 1, 1], stitcher = cv2.Stitcher_create()
[1, 1, 1],
[1, 1, 1]])
labeled_map, num_features = label(binary_map, structure=structure)
holes = [] # 拼接图像
for label_id in range(1, num_features + 1): (status, stitched) = stitcher.stitch((image1, image2))
coords = np.where(labeled_map == label_id)
hole_pixel_count = len(coords[0])
if hole_pixel_count >= min_area: # 检查拼接结果
cx = np.mean(coords[1]) # x 坐标(列) if status == cv2.Stitcher_OK:
cy = np.mean(coords[0]) # y 坐标(行) cv2.imwrite('stitched_output.jpg', stitched)
area = hole_pixel_count print("图像拼接成功!")
holes.append(((cx, cy), area)) 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 的区域 检测图像中的黑色连通区域值为 0 的区域
@ -111,19 +145,18 @@ def detect_black_regions(binary_mask, min_area=10):
labeled_map, num_features = label(binary, structure=structure) labeled_map, num_features = label(binary, structure=structure)
regions = [] regions = []
count = 0
for label_id in range(1, num_features + 1): for label_id in range(1, num_features + 1):
coords = np.where(labeled_map == label_id) coords = np.where(labeled_map == label_id)
area = len(coords[0]) area = len(coords[0])
if area >= min_area: if area >= min_area:
cx = np.mean(coords[1]) # x 坐标(列) cx = np.mean(coords[1]) # x 坐标(列)
cy = np.mean(coords[0]) # y 坐标(行) cy = np.mean(coords[0]) # y 坐标(行)
logger.info(f"区域: {label_id} 中心: {cx, cy} 面积: {area}")
regions.append(((cx, cy),area)) regions.append(((cx, cy),area))
count += ( area/box_area)
return regions,count
return regions
def convert_image_holes_to_real(holes, offset, resolution): def convert_image_holes_to_real(holes, offset, resolution):
real_holes = [] real_holes = []
x_min, y_min = offset x_min, y_min = offset
@ -138,23 +171,39 @@ def visualize_holes_on_image(image, holes, output_path=None):
""" """
在图像上画出检测到的空洞中心和轮廓 在图像上画出检测到的空洞中心和轮廓
""" """
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) color_image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
else:
color_image = image.copy()
# 绘制空洞标记
if holes:
for (cx, cy), _ in 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) cv2.circle(color_image, (int(cx), int(cy)), radius=5, color=(0, 0, 255), thickness=-1)
# 显示图像 # 生成输出路径
# plt.figure(figsize=(10, 8)) if output_path is None:
plt.imshow(cv2.cvtColor(color_image, cv2.COLOR_BGR2RGB))
# plt.title("Detected Holes")
plt.axis("off")
output_path = config.save_path("image", "_holes.png") output_path = config.save_path("image", "_holes.png")
if output_path:
plt.savefig(output_path, bbox_inches='tight', dpi=200) # 保存图像
success = cv2.imwrite(output_path, color_image)
if success:
print(f"Saved visualization to {output_path}") print(f"Saved visualization to {output_path}")
# plt.show() 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): def read_pcd_points(pcd_path):
""" """
@ -183,30 +232,44 @@ def read_pcd_points(pcd_path):
continue continue
return points 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 图像 # 2. 生成 2D 图像
x_range = (config.CUT_CONFIG_MAP[sn]["min_pt"][0],x_max) # 手动指定 X 范围 x_range = (cat_map["min_pt"][0], cat_map["max_pt"][0])
y_range = (config.CUT_CONFIG_MAP[sn]["min_pt"][1], config.CUT_CONFIG_MAP[sn]["max_pt"][1]) # 注意:这里要保证 y_min < y_max否则反转一下 y_range = (cat_map["min_pt"][1], cat_map["max_pt"][1])
resolution = config.CAMERA_CONFIG_MAP[sn].get("resolution") 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) image, offset = point_cloud_to_2d_image(points, resolution=resolution, x_range=x_range, y_range=y_range)
# 3. 图像归一化用于可视化 # 3. 图像归一化用于可视化
normalized_image = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) 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. 检测空洞 # 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. 输出真实世界坐标 # 6. 输出真实世界坐标
real_holes = convert_image_holes_to_real(holes, offset, resolution) real_holes = convert_image_holes_to_real(holes, offset, resolution)
return real_holes return real_holes, count
if __name__ == '__main__': # if __name__ == '__main__':
points = read_pcd_points("D:/PycharmProjects/Hik3D/image/2025-06-25/pcd/182109899_00DA6823936_merged.pcd") # points = read_pcd_points("D:/PycharmProjects/Hik3D/image/2025-06-25/pcd/182109899_00DA6823936_merged.pcd")
sn = "00DA6823936" # sn = "00DA6823936"
x_max = 326 # x_max = 326
detect_large_holes(points,sn, x_max) # 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 脚本。 # 这是一个示例 Python 脚本。
import json
import os
# 按 Shift+F10 执行或将其替换为您的代码。 # 按 Shift+F10 执行或将其替换为您的代码。
# 按 双击 Shift 在所有地方搜索类、文件、工具窗口、操作和设置。 # 按 双击 Shift 在所有地方搜索类、文件、工具窗口、操作和设置。
import SimpleView_SaveImage as simple import SimpleView_SaveImage as simple
import config import config
from Point import tiff_depth_to_point_clouds import image
import time # 在文件顶部导入 time 模块
from flask import Flask, jsonify, request from flask import Flask, jsonify, request
from logConfig import get_logger
app = Flask(__name__) app = Flask(__name__)
import concurrent.futures
from functools import partial
# 使用示例
logger = get_logger()
# 示例接口GET 请求 # 示例接口GET 请求
@app.route("/config/update") @app.route("/config/update")
def home(): def home():
logger.info("配置更新请求")
config.load_configs() config.load_configs()
return "Hello, this service config update!" logger.info("配置更新完成")
return {"message": "Hello, this service config update!", "status": "OK"}
# 示例接口:返回 JSON 数据
@app.route("/api/data")
def get_data(): @app.route("/api/addTemplate", methods=["POST"])
data = {"message": "This is some data", "status": "OK"} def save_template():
return jsonify(data) logger.info("接收到添加模板请求")
data = request.get_json()
# 示例接口:接收参数
# 示例接口:接收参数 # 验证必要字段
@app.route("/api/compute/<direction>") if not data:
def compute(direction): 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: try:
sn = config.DIRECTION_CAMERA[direction] with open(file_path, "w", encoding="utf-8") as f:
except KeyError: json.dump(data, f, ensure_ascii=False, indent=4)
return jsonify({"message": "", "status": "ERROR", "error": f"Direction '{direction}' not found in DIRECTION_CAMERA"}), 400 config.load_configs()
logger.info(f"模板 '{template_type}' 保存成功")
return jsonify({"status": "OK", "message": f"Template '{template_type}' saved successfully."}), 200
except Exception as e:
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: try:
tiff_paths = simple.pic(sn) 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: except Exception as e:
return jsonify({"message": "", "status": "ERROR", "error": f"Failed to get TIFF paths: {str(e)}"}), 500 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: 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: 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) @app.errorhandler(Exception)
def handle_exception(e): def handle_exception(e):
# 处理所有未被捕获的异常 # 处理所有未被捕获的异常
logger.error(f"未捕获的异常: {str(e)}")
return jsonify({ return jsonify({
"message": "", "message": "",
"status": "ERROR", "status": "ERROR",
@ -57,6 +321,7 @@ def handle_exception(e):
if __name__ == "__main__": if __name__ == "__main__":
from waitress import serve from waitress import serve
logger.info("服务启动中...")
print("Serving on http://0.0.0.0:5000") 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) 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