first commit

This commit is contained in:
leon 2025-02-25 10:15:21 +08:00
commit 5ca747feed
27 changed files with 1690 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
result/
.idea/
.vscode/

BIN
1_roi_image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 KiB

BIN
2_roi_image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 KiB

BIN
Open3D.dll Normal file

Binary file not shown.

5
app.log Normal file
View File

@ -0,0 +1,5 @@
2025-02-20 17:05:14 - clog.py:53 - DEBUG:my_logger:This is a debug message
2025-02-20 17:05:14 - clog.py:54 - INFO:my_logger:This is an info message
2025-02-20 17:05:14 - clog.py:55 - WARNING:my_logger:This is a warning message
2025-02-20 17:05:14 - clog.py:56 - ERROR:my_logger:This is an error message
2025-02-20 17:05:14 - clog.py:57 - CRITICAL:my_logger:This is a critical message

272
bm_struct_array.json Normal file
View File

@ -0,0 +1,272 @@
[
{
"code": "1",
"type": "250x1450",
"x": "196.0",
"y": 0,
"center": "351",
"w": "1450",
"h": "250",
"angle": "0\u00b0"
},
{
"code": "2",
"type": "300x300",
"x": "174.0",
"y": 0,
"center": "754",
"w": "300",
"h": "300",
"angle": "0\u00b0"
},
{
"code": "3",
"type": "501x500",
"x": "889.5",
"y": 0,
"center": "1054.5",
"w": "500",
"h": "501",
"angle": "0\u00b0"
},
{
"code": "4",
"type": "250x648",
"x": "-32.0",
"y": 0,
"center": "1149",
"w": "648",
"h": "250",
"angle": "0\u00b0"
},
{
"code": "5",
"type": "250x250",
"x": "588.0",
"y": 0,
"center": "1543",
"w": "250",
"h": "250",
"angle": "0\u00b0"
},
{
"code": "6",
"type": "249x249",
"x": "1031.5",
"y": 0,
"center": "1750.5",
"w": "249",
"h": "249",
"angle": "0\u00b0"
},
{
"code": "7",
"type": "400x399",
"x": "-199.5",
"y": 0,
"center": "1955",
"w": "399",
"h": "400",
"angle": "0\u00b0"
},
{
"code": "8",
"type": "300x302",
"x": "394.0",
"y": 0,
"center": "2159",
"w": "302",
"h": "300",
"angle": "0\u00b0"
},
{
"code": "9",
"type": "300x302",
"x": "996.0",
"y": 0,
"center": "2157",
"w": "302",
"h": "300",
"angle": "0\u00b0"
},
{
"code": "10",
"type": "248x1447",
"x": "2190.0",
"y": 0,
"center": "345",
"w": "1447",
"h": "248",
"angle": "0\u00b0"
},
{
"code": "11",
"type": "298x297",
"x": "2198.5",
"y": 0,
"center": "747",
"w": "297",
"h": "298",
"angle": "0\u00b0"
},
{
"code": "12",
"type": "499x499",
"x": "2891.0",
"y": 0,
"center": "1040.5",
"w": "499",
"h": "499",
"angle": "0\u00b0"
},
{
"code": "13",
"type": "245x648",
"x": "1994.5",
"y": 0,
"center": "1146.5",
"w": "648",
"h": "245",
"angle": "0\u00b0"
},
{
"code": "14",
"type": "247x247",
"x": "2589.5",
"y": 0,
"center": "1550.5",
"w": "247",
"h": "247",
"angle": "0\u00b0"
},
{
"code": "15",
"type": "246x247",
"x": "2998.5",
"y": 0,
"center": "1757",
"w": "247",
"h": "246",
"angle": "0\u00b0"
},
{
"code": "16",
"type": "398x392",
"x": "1799.5",
"y": 0,
"center": "1955",
"w": "392",
"h": "398",
"angle": "0\u00b0"
},
{
"code": "17",
"type": "300x293",
"x": "2394.5",
"y": 0,
"center": "2147",
"w": "293",
"h": "300",
"angle": "0\u00b0"
},
{
"code": "18",
"type": "298x297",
"x": "3001.5",
"y": 0,
"center": "2144",
"w": "297",
"h": "298",
"angle": "0\u00b0"
},
{
"code": "19",
"type": "245x1447",
"x": "4191.5",
"y": 0,
"center": "344.5",
"w": "1447",
"h": "245",
"angle": "0\u00b0"
},
{
"code": "20",
"type": "295x300",
"x": "4175.0",
"y": 0,
"center": "743.5",
"w": "300",
"h": "295",
"angle": "0\u00b0"
},
{
"code": "21",
"type": "498x495",
"x": "4897.5",
"y": 0,
"center": "1030",
"w": "495",
"h": "498",
"angle": "0\u00b0"
},
{
"code": "22",
"type": "245x648",
"x": "3977.0",
"y": 0,
"center": "1150.5",
"w": "648",
"h": "245",
"angle": "0\u00b0"
},
{
"code": "23",
"type": "245x246",
"x": "4547.5",
"y": 0,
"center": "1541.5",
"w": "246",
"h": "245",
"angle": "0\u00b0"
},
{
"code": "24",
"type": "245x245",
"x": "4992.5",
"y": 0,
"center": "1735.5",
"w": "245",
"h": "245",
"angle": "0\u00b0"
},
{
"code": "25",
"type": "398x392",
"x": "3796.5",
"y": 0,
"center": "1955",
"w": "392",
"h": "398",
"angle": "0\u00b0"
},
{
"code": "26",
"type": "298x296",
"x": "4392.5",
"y": 0,
"center": "2142",
"w": "296",
"h": "298",
"angle": "0\u00b0"
},
{
"code": "27",
"type": "297x295",
"x": "4991.5",
"y": 0,
"center": "2146.5",
"w": "295",
"h": "297",
"angle": "0\u00b0"
}
]

167
capture_img_ply.py Normal file
View File

@ -0,0 +1,167 @@
# -- coding: utf-8 --
import time
import os
import paramiko
from scp import SCPClient
import threading
from os import abort
from pathlib import Path
from clog import logger
HOST = "192.168.100.254"
PORT = 22
USERNAME = "root"
PASSWORD = "ebaina"
CLOUD_COUNTS = [400000, 500000, 600000]
DEFAULT_COUNT = 300000
EXPS = [200 * 1000, 300 * 1000, 400 * 1000]
DEFAULT_EXP = 100 * 1000
PARENT_DIR_NAME = "test_2"
SAVE_DIR_NAME = ""
def ssh_execute_command(host, port, username, password, command):
ret = False
# 创建SSH客户端
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(host, port, username, password)
# 执行命令
stdin, stdout, stderr = client.exec_command(command)
# 读取输出结果
output = stdout.read().decode()
error = stderr.read().decode()
if output:
logger.info(f"{output}")
if error:
logger.error(f"{error}")
# 关闭连接
client.close()
return True
def scp_get_file(host, port, username, password, remote_path, local_path):
ret = False
# 创建SSH客户端
client = paramiko.Transport((host, port))
client.connect(username=username, password=password)
# 创建SCP客户端
scp_client = SCPClient(client)
# 拉取文件
try:
scp_client.get(remote_path, local_path)
except Exception as e:
print(e)
return False
# 关闭连接
scp_client.close()
client.close()
return True
def cameraCap(exp):
start_time = time.time()
ret = ssh_execute_command(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
command="cd /root/app/detect-gui/ \n" +
f"/root/miniconda3/bin/python cap.py --exp={exp}\n"
)
if not ret:
return False
end_time = time.time() # 记录结束时间
execution_time = end_time - start_time # 计算执行时间
print(f"ssh_execute_command 程序执行时间:{execution_time}")
time.sleep(1) # 等待操作系统保存图像完毕
ret = scp_get_file(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
remote_path="/root/app/detect-gui/output.jpg",
local_path=Path(__file__).parent / "result" / PARENT_DIR_NAME / SAVE_DIR_NAME
)
if not ret:
return False
end_time = time.time() # 记录结束时间
execution_time = end_time - start_time # 计算执行时间
print(f"cameraCap 程序执行时间:{execution_time}")
def lidarCap(cloud_count):
start_time = time.time()
print(f"./lidar_driver {cloud_count}\n")
ret = ssh_execute_command(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
command="cd /root/calibration_tools \n" +
f"./lidar_driver {cloud_count}\n"
)
ret = scp_get_file(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
remote_path="/root/calibration_tools/output.ply",
local_path=Path(__file__).parent / "result" / PARENT_DIR_NAME / SAVE_DIR_NAME
)
ret = ssh_execute_command(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
command="cd /root/calibration_tools \n " +
"rm output.ply \n"
)
end_time = time.time() # 记录结束时间
execution_time = end_time - start_time # 计算执行时间
print(f"lidarCap 程序执行时间:{execution_time}")
def cap(exp=DEFAULT_EXP, cloud_count=DEFAULT_COUNT):
global SAVE_DIR_NAME
print(f"曝光时间{exp}")
print(f"点云数量:{cloud_count}")
SAVE_DIR_NAME = f"exp_{exp}_cn_{cloud_count}"
# 如果文件夹不存在则创建
if not os.path.exists(Path(__file__).parent / "result" / PARENT_DIR_NAME / SAVE_DIR_NAME):
os.makedirs(Path(__file__).parent / "result" / PARENT_DIR_NAME / SAVE_DIR_NAME)
# 雷达线程
t_lidar = threading.Thread(target=lidarCap, args=(cloud_count,))
t_lidar.start()
# 相机
cameraCap(exp)
# 等待雷达线程结束
t_lidar.join()
if __name__ == '__main__':
# 加载驱动
ssh_execute_command(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
command="/opt/HuarayTech/MVviewer/module/loadAllDrv.sh \n"
)
for cloud_count in CLOUD_COUNTS:
logger.info("开始采集")
cap(cloud_count = cloud_count)
logger.info("采集完毕===========")
for exp in EXPS:
logger.info("开始采集")
cap(exp = exp)
logger.info("采集完毕===========")

258
capture_img_ply_txt.py Normal file
View File

@ -0,0 +1,258 @@
# -- coding: utf-8 --
import sys
import time
import os
import paramiko
from scp import SCPClient
import threading
from os import abort
from pathlib import Path
from clog import logger, set_logger_file_handler
HOST = "192.168.100.254"
PORT = 22
USERNAME = "root"
PASSWORD = "ebaina"
# CLOUD_COUNTS = [600000,800000,1000000,1500000,2000000]
CLOUD_COUNTS = [1500000]
DEFAULT_COUNT = 1500000
EXPS = [2*1000,3*1000]
# EXPS = [100 * 1000]
DEFAULT_EXP = int(3 * 1000)
PARENT_DIR_NAME = "拼接测试_位置3_1平角度_天气_晴天大太阳下午_driverV2_om3"
# PARENT_DIR_NAME = "test_1"
SAVE_DIR_NAME = ""
TEST_CLOUD = False
TEST_EXP = True
def ssh_execute_command(host, port, username, password, command):
ret = False
# 创建SSH客户端
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(host, port, username, password)
# 执行命令
stdin, stdout, stderr = client.exec_command(command)
# 实时读取标准输出
for line in iter(stdout.readline, ""):
print(line, end="") # 实时打印
sys.stdout.flush() # 刷新缓冲区,确保立即输出到终端
# 实时读取标准错误(如果有)
for line in iter(stderr.readline, ""):
print(f"ERROR: {line}", end="")
sys.stdout.flush()
# 关闭连接
client.close()
return True
def scp_get_file(host, port, username, password, remote_path, local_path):
ret = False
# 创建SSH客户端
client = paramiko.Transport((host, port))
client.connect(username=username, password=password)
# 创建SCP客户端
scp_client = SCPClient(client)
# 拉取文件
try:
scp_client.get(remote_path, local_path)
except Exception as e:
print(e)
return False
# 关闭连接
scp_client.close()
client.close()
return True
def scp_get_multi_file(host, port, username, password, remote_path, local_path):
ret = False
# 创建SSH客户端
client = paramiko.Transport((host, port))
client.connect(username=username, password=password)
# 创建SCP客户端
scp_client = SCPClient(client)
# 拉取文件
try:
for rp in remote_path:
scp_client.get(rp, local_path)
except Exception as e:
logger.error(f"拉取文件失败:{e}")
return False
# 关闭连接
scp_client.close()
client.close()
return True
def cap(exp=DEFAULT_EXP, cloud_count=DEFAULT_COUNT):
global SAVE_DIR_NAME
logger.debug(f"===================开处理============================")
# 先删除旧数据
logger.debug("删除旧数据")
ssh_execute_command(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
command="cd /root/app/detect-gui/ \n " +
"rm output.jpg \n" +
"rm output.ply \n" +
"rm roi_conners.txt \n"
)
logger.debug("删除旧数据完成")
logger.debug(f"曝光时间设置为:{exp}")
logger.debug(f"点云数量设置为:{cloud_count}")
SAVE_DIR_NAME = f"exp_{exp}_cn_{cloud_count}"
logger.debug(f"保存路径为:{SAVE_DIR_NAME}")
# 如果文件夹不存在则创建
if not os.path.exists(Path(__file__).parent / "result" / PARENT_DIR_NAME / SAVE_DIR_NAME):
os.makedirs(Path(__file__).parent / "result" / PARENT_DIR_NAME / SAVE_DIR_NAME)
# ssh调用远程 borad_image_framework_tmp.py 进行拍摄图片雷达点云数据采集角点ROI数据生成
start_time = time.time()
command = "export LD_LIBRARY_PATH=/root/app/ss928_codec/mpp/out/lib:/root/app/detect-gui/vendors/image-framework/linux_arm64:/root/app/detect-gui/vendors/image-framework/linux_arm64/lib:/root/app/detect-gui/vendors/image-framework/linux_arm64/lib/npu:/root/app/detect-gui/vendors/image-framework/linux_arm64/lib/svp_npu:$LD_LIBRARY_PATH \n" + \
"cd /root/app/detect-gui/ \n" + \
f"/root/miniconda3/bin/python borad_image_framework_tmp.py --exp={exp} --count={cloud_count}\n"
logger.debug(f"ssh_execute_command 命令:{command}")
ssh_execute_command(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
command=command,
)
end_time = time.time() # 记录结束时间
execution_time = end_time - start_time # 计算执行时间
logger.debug(f"borad_image_framework_tmp.py 程序执行时间:{execution_time}")
time.sleep(1) # 等待操作系统保存数据完毕
logger.debug("开始保存文件到本地")
start_time2 = time.time()
local_path = Path(__file__).parent / "result" / PARENT_DIR_NAME / SAVE_DIR_NAME
logger.debug(f"本地文件保存路径为:{local_path}")
scp_get_multi_file(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
remote_path=[
"/root/app/detect-gui/output.jpg",
"/root/app/detect-gui/output.ply",
"/root/app/detect-gui/roi_conners.txt",
],
local_path=local_path
)
end_time2 = time.time() # 记录结束时间
execution_time2 = end_time2 - start_time2
logger.debug("文件到本地结束")
logger.debug(f"scp_get_file获取文件到本地 程序执行时间:{execution_time2}")
logger.debug(f"===================开处理结束============================")
def cap_wide():
logger.debug(f"===================广角开始处理============================")
# 先删除旧数据
logger.debug("删除旧数据")
ssh_execute_command(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
command="cd /root/app/detect-gui/ \n " +
"rm wide_image_processed.png \n" +
"rm wide_image.png \n" +
"rm wide_image_roi.json \n"
)
logger.debug("删除旧数据完成")
start_time = time.time()
command = "export LD_LIBRARY_PATH=/root/app/ss928_codec/mpp/out/lib:/root/app/detect-gui/vendors/image-framework/linux_arm64:/root/app/detect-gui/vendors/image-framework/linux_arm64/lib:/root/app/detect-gui/vendors/image-framework/linux_arm64/lib/npu:/root/app/detect-gui/vendors/image-framework/linux_arm64/lib/svp_npu:$LD_LIBRARY_PATH \n" + \
"cd /root/app/detect-gui/ \n" + \
f"/root/miniconda3/bin/python cap_wide_camera.py \n"
logger.debug(f"ssh_execute_command 命令:{command}")
ssh_execute_command(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
command=command,
)
end_time = time.time() # 记录结束时间
execution_time = end_time - start_time # 计算执行时间
logger.debug(f"cap_wide_camera.py 程序执行时间:{execution_time}")
time.sleep(1) # 等待操作系统保存数据完毕
logger.debug("开始保存文件到本地")
start_time2 = time.time()
local_path = Path(__file__).parent / "result" / PARENT_DIR_NAME
logger.debug(f"本地文件保存路径为:{local_path}")
scp_get_multi_file(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
remote_path=[
"/root/app/detect-gui/wide_image_processed.png",
"/root/app/detect-gui/wide_image.png",
"/root/app/detect-gui/wide_image_roi.json",
],
local_path=local_path
)
end_time2 = time.time() # 记录结束时间
execution_time2 = end_time2 - start_time2
logger.debug("文件到本地结束")
logger.debug(f"scp_get_file获取文件到本地 程序执行时间:{execution_time2}")
logger.debug(f"===================广角开处理结束============================")
if __name__ == '__main__':
# 如果路径不存在则创建
if not os.path.exists(Path(__file__).parent / "result" / PARENT_DIR_NAME):
os.makedirs(Path(__file__).parent / "result" / PARENT_DIR_NAME)
# 设置日志保存路径
set_logger_file_handler(Path(__file__).parent / "result" / PARENT_DIR_NAME)
# 加载驱动
ssh_execute_command(
host=HOST,
port=PORT,
username=USERNAME,
password=PASSWORD,
command="/opt/HuarayTech/MVviewer/module/loadAllDrv.sh \n"
)
if (TEST_CLOUD):
for cloud_count in CLOUD_COUNTS:
logger.debug("开始采集")
start_time = time.time() # 记录开始时间
cap(cloud_count=cloud_count)
end_time = time.time() # 记录结束时间
elapsed_time = end_time - start_time # 计算总时间
logger.success(f"采集完毕=========== 耗时: {elapsed_time:.2f}")
if (TEST_EXP):
for exp in EXPS:
logger.debug("开始采集")
start_time = time.time() # 记录开始时间
cap(exp=exp)
end_time = time.time() # 记录结束时间
elapsed_time = end_time - start_time # 计算总时间
logger.success(f"采集完毕=========== 耗时: {elapsed_time:.2f}")
cap_wide()

92
clog.py Normal file
View File

@ -0,0 +1,92 @@
import logging
import sys
from fileinput import filename
from colorlog import ColoredFormatter
# 创建一个 logger
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)
# 创建一个控制台处理器
console_handler = logging.StreamHandler()
# 定义 SUCCESS 级别的数值 (INFO=20, WARNING=30所以 SUCCESS 可以设为 25)
SUCCESS = 25
logging.addLevelName(SUCCESS, "SUCCESS")
# 定义一个 success 方法
def success(self, message, *args, **kwargs):
if self.isEnabledFor(SUCCESS):
self._log(SUCCESS, message, args, **kwargs)
# 绑定到 Logger 类上
logging.Logger.success = success
# 创建带颜色的格式化器(用于控制台输出)
console_formatter = ColoredFormatter(
"%(log_color)s%(asctime)s - %(filename)s:%(lineno)d - [%(levelname)s]:%(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
reset=True,
log_colors={
'SUCCESS': 'green', # 这里定义 SUCCESS 级别的颜色
'DEBUG': 'cyan',
'INFO': 'white',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'red,bg_black',
},
secondary_log_colors={
'message': {
'SUCCESS': 'green', # 这里定义 SUCCESS 级别的消息颜色
'DEBUG': 'cyan',
'INFO': 'white',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'red,bg_black',
}
},
style='%'
)
# 创建普通格式的格式化器(用于日志文件)
file_formatter = logging.Formatter(
"%(asctime)s - %(filename)s:%(lineno)d - %(levelname)s:%(name)s:%(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
# 设置格式化器
console_handler.setFormatter(console_formatter)
# 将处理器添加到 logger
logger.addHandler(console_handler)
def set_logger_file_handler(p):
# 创建一个文件处理器,保存日志到本地文件
file_handler = logging.FileHandler(f'{p}/run.log', encoding='utf-8')
file_handler.setFormatter(file_formatter)
logger.addHandler(file_handler)
# 重定向 stdout 和 stderr 到日志系统
class LoggerWriter:
def __init__(self, level):
self.level = level
def write(self, message):
if message.strip(): # 过滤掉空行
self.level(message.strip()) # 去掉首尾空白字符
def flush(self):
pass
sys.stdout = LoggerWriter(logger.info)
sys.stderr = LoggerWriter(logger.error)
# 测试日志
# logger.success("This is a debug message")
# logger.debug("This is a debug message")
# logger.info("This is an info message")
# logger.warning("This is a warning message")
# logger.error("This is an error message")
# logger.critical("This is a critical message")

48
config.ini Normal file
View File

@ -0,0 +1,48 @@
[2D]
w = 9344
h = 7000
fx = 11550.4192
fy = 11546.8773
cx = 4672.28001
cy = 3499.29103
k1 = -0.0198130409
k2 = 0.0446498961
p1 = 0.000332909840
p2 = -0.000424586368
k3 = 0.371045956
yolo_label = 0
yolo_prob = 0.601
yolo_modol_path = ./best_ep23_small_lab.om
save_image = true
roi_y_offset = 20
edge_min_line_len = 400
edge_max_line_gap = 120
edge_min_angle_th = 33
kk = 0.0
[3D]
r = 1.572895519320505
p = -1.5570521101629837
y = 0.024731696602587224
tx = 0.109253
ty = 0.0710213
tz = 0.0175978
dminx = -2.5
dmaxx = 2.5
dminy = -2.5
dmaxy = 2.5
dminz = 0.0
dmaxz = 3.6
kk = 0.0
cloud_need_points_size = 600000
save_cload = true
[sys]
fake = false
camera_cap_fake = true
lidar_cap_fake = true
npu_fake = true
conners_detect_fake = false
fake_image_fpath = ./result/test_1/ep_100000_count_600000/output.jpg
fake_lidar_fpath = ./result/test_1/ep_100000_count_600000/output.ply

271
detect.py Normal file
View File

@ -0,0 +1,271 @@
import os
import shutil
import sys
import threading
import time
from ctypes import *
import logging
from logging import makeLogRecord
from clog import logger
import cv2
import numpy as np
from imgProcess import detectionResProcessing
from util import change_config_ini
image_framework_sdk = None
data_callback = None
SYS_OK = 0
bStop = False
# 全局 msg 缓存
g_msg_cache = []
# 全局 frame 缓存
g_frame_cache = []
# 运行模式
RUNNING_MODE_NONE = -1 # 停止状态
RUNNING_MODE_LOCATION = 0 # 广角相机运行模式
RUNNING_MODE_DETECTION = 1 # 高清检测运行模式
g_running_mode = RUNNING_MODE_NONE # 默认是广角相机运行模式
TO_CLIENT_NOTIFY_BASE = 1000
# emit的结构体
MSG_ONLY_RECORD = -1
MSG_LOCATION_RECORD = 0
MSG_DETECTION_RECORD = 1
# 获取消息
def _get_msg_info(code) -> str:
global MSG_LIST
for msg in MSG_LIST:
for key, value in msg.items():
if code == key:
return value.encode("utf-8")
return "未知错误".encode("utf-8")
class Msg:
def __init__(self, msg_type, record, im2D):
self.msg_type = msg_type # 0刷新广角图片 1刷新高清 -1不刷新图片纯消息
self.record = record
self.im2D = im2D
class _SubRoiData_(Structure):
_fields_ = [
('mPparentId', c_long),
('mId', c_long),
('mInfo', c_char * 256),
('isGood', c_bool),
('vpOffset', c_float * 2),
('mRoiPoints', c_float * 8), # 4 * 2
('mInnerConners', c_float * 8), # 4 * 2
('mInnerConners3D', c_float * 12), # 4 * 3
('edges', c_float * 4),
('center', c_float * 2),
('cloud_size', c_int),
('mVc2D', POINTER(c_float)),
('mVc3D', POINTER(c_float)),
('H', c_float * 9),
]
SubRoiData = _SubRoiData_
class _CallbackInfo_(Structure):
_fields_ = [
('code', c_int),
('errorInfo', c_char * 256),
('bGetData', c_bool),
('mId', c_long),
('mInfo', c_char * 256),
('mImPath', c_char * 256),
('mIm2D3DPtr', c_char * 256),
('roi_size', c_int),
('subRois', SubRoiData * 16),
]
CallbackInfo = _CallbackInfo_
# 回调函数类型定义
CallbackType = CFUNCTYPE(None, POINTER(CallbackInfo))
def _copy_record(record):
new_record = CallbackInfo()
new_record.code = record.code
new_record.errorInfo = record.errorInfo
new_record.bGetData = record.bGetData
new_record.roi_size = record.roi_size
for i in range(record.roi_size):
if i > 15: # 超过16个ROI返回
break
subRois = record.subRois[i]
newSubRois = new_record.subRois[i]
for j in range(8):
newSubRois.mRoiPoints[j] = subRois.mRoiPoints[j]
newSubRois.mInnerConners[j] = subRois.mInnerConners[j]
for j in range(12):
newSubRois.mInnerConners3D[j] = subRois.mInnerConners3D[j]
return new_record
def init_callback():
global data_callback, bStop
def _callback(data):
print("_callback回调执行")
global g_msg_cache, g_frame_cache, g_running_mode, bStop
record = CallbackInfo(code=SYS_OK, errorInfo=b"", bGetData=False)
frame = None
ret = SYS_OK
msg = None
# 获取数据
data_type = CallbackInfo
data_ptr = cast(data, POINTER(data_type))
ckinfoCache = data_ptr.contents
record = _copy_record(ckinfoCache)
print(str(g_running_mode) + " : " + str(record.code) + " : " + bytes.decode(record.errorInfo))
# 当定位模式下,接收到【定位完成】消息
if g_running_mode == RUNNING_MODE_LOCATION and record.code == (6 + TO_CLIENT_NOTIFY_BASE):
if len(g_frame_cache) == 0:
print("当前没有广角数据")
return
frame = g_frame_cache.pop() # 从图像缓存中去除图像
g_frame_cache = [] # 清空缓存,避免无限增长
msg = Msg(MSG_LOCATION_RECORD, _copy_record(record), frame)
# 当检测模式下,接收到【拍照完成】消息
elif record.code == (8 + TO_CLIENT_NOTIFY_BASE):
bStop = True
time.sleep(1)
elif record.code == (12 + TO_CLIENT_NOTIFY_BASE):
msg = Msg(MSG_DETECTION_RECORD, _copy_record(record), None)
detectionResProcessing(msg,data_img_path,data_detect_res_save_path)
bStop = True
time.sleep(1)
# # frame = np.zeros((7000, 9344, 3), np.uint8)
# # # frame.zeros(9344, 7000, cv2.CV_8UC3)
# # # src_frame_ptr = c_char_p(frame.data.tobytes())
# # mv = memoryview(frame.data)
# # buffer_pointer = cast(mv.obj.ctypes.data, c_void_p)
# # ret = image_framework_sdk.LibapiGetHQImage(
# # buffer_pointer, frame.shape[1], frame.shape[0], 3, c_char_p(b"PythonProcessing"))
# if ret != SYS_OK:
# print("ret != SYS_OK:" + str(ret))
# record = CallbackInfo(code=ret, errorInfo=_get_msg_info(ret), bGetData=False)
# msg = Msg(MSG_DETECTION_RECORD, record, None)
# g_msg_cache.append(msg)
# # emit msg
# return
# msg = Msg(MSG_DETECTION_RECORD, _copy_record(record), frame)
# elif g_running_mode == RUNNING_MODE_LOCATION:
# msg = Msg(MSG_LOCATION_RECORD, _copy_record(record), None)
# elif g_running_mode == RUNNING_MODE_DETECTION:
# msg = Msg(MSG_DETECTION_RECORD, _copy_record(record), None)
# else:
# print("未知回调")
# return
data_callback = CallbackType(_callback)
def init_image_framework_sdk():
global image_framework_sdk
try:
# 加载C++库
current_file_dir = os.path.dirname(os.path.abspath(__file__))
image_framework_sdk = CDLL(os.path.join(current_file_dir, f'./image_framework.dll'))
print("Load Image framework sdk success")
except Exception as e:
print(f"Load Image framework sdk failed: {str(e)}")
def adjust():
global image_framework_sdk
record = CallbackInfo(code=SYS_OK, errorInfo=b"", bGetData=False)
ret = image_framework_sdk.LibapiStartDetection()
if ret != SYS_OK:
print(f"image_framework_sdk.LibapiStartDetection():执行失败 :{ret}")
return record
def check():
print("check====================")
global image_framework_sdk
record = CallbackInfo(code=SYS_OK, errorInfo=b"", bGetData=False)
ret = image_framework_sdk.LibapiContinuetDetection("{}")
if ret != SYS_OK:
print("image_framework_sdk.LibapiContinuetDetection执行失败")
return record
def start():
global bStop
# 开始检测
logger.debug("开始adjust")
adjust()
while not bStop:
logger.debug("adjust等待回调")
time.sleep(1)
logger.debug("开始check")
check()
bStop = False
while not bStop:
logger.debug("check等待回调")
time.sleep(1)
if __name__ == '__main__':
# 加载驱动
init_image_framework_sdk()
if image_framework_sdk is None:
raise RuntimeError("Image framework SDK未正确加载!")
# 设置回调函数
init_callback()
ret = image_framework_sdk.LibapiInit(1, "", data_callback)
if ret != 0:
raise RuntimeError(f"设置回调函数始设置失败, 错误码: {ret}")
dataPath = "./result/hy_1" # 数据路径
data_img_path = None # 检测的图片路径
data_detect_res_save_path = None # 检测结果的保存路径
# 遍历目录
for root, dirs, files in os.walk(dataPath):
for dir in dirs:
logger.debug(f"开始处理子目录:{dir}")
data_detect_res_save_path = os.path.join(root, dir)
# 目录下的所有文件路径
for file in os.listdir(os.path.join(root, dir)):
file_path = os.path.join(root, dir, file)
# 将反斜杠替换为正斜杠
file_path = file_path.replace('\\', '/')
logger.debug(f"文件路径:{file_path}")
# 如果是jpg图片
if file.endswith("output.jpg"):
# 将文件路径修改到ini配置中
data_img_path = file_path
change_config_ini("sys", "fake_image_fpath", file_path)
if file.endswith(".ply"):
# 将文件路径修改到ini配置中
change_config_ini("sys", "fake_lidar_fpath", file_path)
if file.endswith(".txt"):
# txt roi坐标复制到更目录曹总懒得修改c代码只能从根目录读取。
shutil.copy(file_path, os.path.join("./", file))
logger.info(f"roi坐标文件已复制到更目录")
time.sleep(1)
# ...
# 开始检测
bStop = False
logger.debug("开始检测")
start()
exit()

80
draw_ymj.py Normal file
View File

@ -0,0 +1,80 @@
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
def col(char):
return ord(char) - ord('A') + 0
# 读取Excel文件指定表格路径
file_path = '预埋件位置.xlsx'
# 使用pandas读取Excel
df = pd.read_excel(file_path, sheet_name='测量结果') # 根据你的Excel表格来设置sheet_name
# 打印列名
print("DataFrame 列名:", df.columns)
# 创建一个图形和坐标轴
fig, ax = plt.subplots()
# 初始化边界变量
x_min, x_max = float('inf'), float('-inf')
y_min, y_max = float('inf'), float('-inf')
x_max_original = 0
for index, row in df.iloc[2:30].iterrows():
original_x = row[col('K')] - row[col('D')] / 2
if(original_x > x_max_original):
x_max_original = original_x
for index, row in df.iloc[2:30].iterrows():
# 打印B列和C列的值
print(f"{index+2} -> A列-编号: {row[col('A')]}, D列-测量宽度: {row[col('D')]}, E列-测量高度: {row[col('E')]}K列-测量中心x: {row[col('K')]}, L列-测量中心y: {row[col('L')]}")
# 转换x坐标
x_original = row[col('K')]
x = x_max_original - x_original - row[col('D')] / 2
y = row[col('L')] - row[col('E')] / 2
# 更新边界
x_min = min(x_min, x)
x_max = max(x_max, x + row[col('D')])
y_min = min(y_min, y)
y_max = max(y_max, y + row[col('E')])
# 绘制矩形
rect = Rectangle((x, y), row[col('D')], row[col('E')], linewidth=1, edgecolor='r', facecolor='none')
ax.add_patch(rect)
# 在矩形中心绘制编号A列
ax.text(
x + row[col('D')] / 2, y + row[col('E')] / 2, str(row[col('A')]),
ha='center', va='center',
fontsize=12, color='blue' # 编号字体大小为12颜色为蓝色
)
# 在矩形上边绘制宽度D列
ax.text(
x + row[col('D')] / 2, y + row[col('E')], str(row[col('D')]),
ha='center', va='bottom',
fontsize=6, color='green' # 宽度字体大小为10颜色为绿色
)
# 在矩形右边绘制高度E列
ax.text(
x + row[col('D')], y + row[col('E')] / 2, str(row[col('E')]),
ha='left', va='center',
fontsize=6, color='red' # 高度字体大小为10颜色为红色
)
# 设置坐标轴的范围外扩100左右
ax.set_xlim(x_min, x_max ) # 留出一些边距
ax.set_ylim(y_min, y_max ) # 留出一些边距
# 设置坐标轴的比例
ax.set_aspect('equal')
# 显示图形
plt.show()

60
environment.yaml Normal file
View File

@ -0,0 +1,60 @@
name: ymj_test
channels:
- defaults
- https://repo.anaconda.com/pkgs/main
- https://repo.anaconda.com/pkgs/r
- https://repo.anaconda.com/pkgs/msys2
dependencies:
- ca-certificates=2024.12.31=haa95532_0
- openssl=3.0.15=h827c3e9_0
- pip=25.0=py39haa95532_0
- python=3.9.20=h8205438_1
- setuptools=75.8.0=py39haa95532_0
- sqlite=3.45.3=h2bbff1b_0
- vc=14.42=haa95532_4
- vs2015_runtime=14.42.34433=he0abc0d_4
- wheel=0.45.1=py39haa95532_0
- pip:
- bcrypt==4.2.1
- cffi==1.17.1
- colorama==0.4.6
- colorlog==6.9.0
- contourpy==1.3.0
- cryptography==44.0.1
- cycler==0.12.1
- et-xmlfile==2.0.0
- fonttools==4.56.0
- imageio==2.37.0
- importlib-resources==6.5.2
- joblib==1.4.2
- kiwisolver==1.4.7
- lazy-loader==0.4
- markdown-it-py==3.0.0
- matplotlib==3.9.4
- mdurl==0.1.2
- networkx==3.2.1
- numpy==2.0.2
- opencv-python==4.11.0.86
- openpyxl==3.1.5
- packaging==24.2
- pandas==2.2.3
- paramiko==3.5.1
- pillow==11.1.0
- pycparser==2.22
- pygments==2.19.1
- pynacl==1.5.0
- pyparsing==3.2.1
- python-dateutil==2.9.0.post0
- pytz==2025.1
- rich==13.9.4
- scikit-image==0.24.0
- scikit-learn==1.6.1
- scipy==1.13.1
- scp==0.15.0
- six==1.17.0
- threadpoolctl==3.5.0
- tifffile==2024.8.30
- typing-extensions==4.12.2
- tzdata==2025.1
- zipp==3.21.0
prefix: C:\Users\leon\miniconda3\envs\ymj_test

115
excel_point_to_bm_json_.py Normal file
View File

@ -0,0 +1,115 @@
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
def col(char):
return ord(char) - ord('A') + 0
# 读取Excel文件指定表格路径
file_path = '预埋件位置.xlsx'
# 使用pandas读取Excel
df = pd.read_excel(file_path, sheet_name='测量结果') # 根据你的Excel表格来设置sheet_name
# 打印列名
print("DataFrame 列名:", df.columns)
# 创建一个图形和坐标轴
fig, ax = plt.subplots()
# 初始化边界变量
x_min, x_max = float('inf'), float('-inf')
y_min, y_max = float('inf'), float('-inf')
x_max_original = 0
for index, row in df.iloc[2:30].iterrows():
original_x = row[col('K')] - row[col('D')] / 2
if(original_x > x_max_original):
x_max_original = original_x
bm_struct_array = []
for index, row in df.iloc[2:30].iterrows():
# 打印B列和C列的值
print(f"{index+2} -> A列-编号: {row[col('A')]}, D列-测量宽度: {row[col('D')]}, E列-测量高度: {row[col('E')]}K列-测量中心x: {row[col('K')]}, L列-测量中心y: {row[col('L')]}")
# 转换x坐标
x_original = row[col('K')]
x = x_max_original - x_original - row[col('D')] / 2
y = row[col('L')] - row[col('E')] / 2
# 转换中心点坐标
center_x = x_max_original - x_original
center_y = row[col('L')]
# [{
# "code": "PT001",
# "type": "250x1450",
# "x": "905",
# "y": "0",
# "center": "0.350",
# "w": "1450",
# "h": "250",
# "angle": "90\""
# },
bm_struct_array.append({
"code": str(row[col('A')]),
"type": f"{str(row[col('E')])}x{str(row[col('D')])}",# w x h
"x": str(center_x),
"y": 0,
"center": str(center_y),
"w": str(row[col('D')]),
"h": str(row[col('E')]),
"angle" : ""
})
# 画出中心点
ax.scatter(center_x, center_y, color='red', marker='o', s=10)
# 更新边界
x_min = min(x_min, x)
x_max = max(x_max, x + row[col('D')])
y_min = min(y_min, y)
y_max = max(y_max, y + row[col('E')])
# 绘制矩形
rect = Rectangle((x, y), row[col('D')], row[col('E')], linewidth=1, edgecolor='r', facecolor='none')
ax.add_patch(rect)
# 在矩形中心绘制编号A列
ax.text(
center_x+60, center_y, str(row[col('A')]),
ha='center', va='center',
fontsize=8, color='blue' # 编号字体大小为12颜色为蓝色
)
# 在矩形上边绘制宽度D列
ax.text(
x + row[col('D')] / 2, y + row[col('E')], str(row[col('D')]),
ha='center', va='bottom',
fontsize=6, color='green' # 宽度字体大小为10颜色为绿色
)
# 在矩形右边绘制高度E列
ax.text(
x + row[col('D')], y + row[col('E')] / 2, str(row[col('E')]),
ha='left', va='center',
fontsize=6, color='red' # 高度字体大小为10颜色为红色
)
# 设置坐标轴的范围外扩100左右
ax.set_xlim(x_min, x_max ) # 留出一些边距
ax.set_ylim(y_min, y_max ) # 留出一些边距
# 设置坐标轴的比例
ax.set_aspect('equal')
# 显示图形
plt.show()
# 保存bm_struct_array 为json到本地
import json
with open('bm_struct_array.json', 'w') as f:
json.dump(bm_struct_array, f)

BIN
image_framework.dll Normal file

Binary file not shown.

233
imgProcess.py Normal file
View File

@ -0,0 +1,233 @@
# -- coding: utf-8 --
from ctypes import *
import numpy as np
from numpy.ctypeslib import as_array
import cv2
from clog import logger
TO_CLIENT_NOTIFY_BASE = 1000
def process(msg):
record = msg.record
if msg.msg_type == 0 and record.code == (6 + TO_CLIENT_NOTIFY_BASE):
return doLocationProcessing(msg)
elif msg.msg_type == 1 and (
record.code == (2 + TO_CLIENT_NOTIFY_BASE) or record.code == (8 + TO_CLIENT_NOTIFY_BASE) or record.code == (
12 + TO_CLIENT_NOTIFY_BASE)):
return doDetectionProcessing(msg)
else:
pass
return msg
def _darw_rect(im):
cv2.rectangle(im, (130, 135), (430, 375), (0, 255, 0), 5)
# 处理图像
def doLocationProcessing(msg):
if msg is None:
return msg
im = msg.im2D
record = msg.record
ptsRoiPoints = None
ptsInnerConners = None
ptsInnerConners3D = None
if record.roi_size > 16:
return msg
for i in range(record.roi_size):
roi = record.subRois[i]
# if not roi.isGood: continue
roiPoints = roi.mRoiPoints
innerConners = roi.mInnerConners
innerConners3D = roi.mInnerConners3D
ptsRoiPoints = np.array([
[roiPoints[0], roiPoints[1]],
[roiPoints[2], roiPoints[3]],
[roiPoints[4], roiPoints[5]],
[roiPoints[6], roiPoints[7]]], dtype=np.int32)
# ptsInnerConners = np.array([
# [innerConners[0],innerConners[1]],
# [innerConners[2],innerConners[3]],
# [innerConners[4],innerConners[5]],s
# [innerConners[6],innerConners[7]]], dtype=np.int32)
# ptsInnerConners3D = np.array([
# [innerConners3D[0],innerConners3D[1],innerConners3D[2]],
# [innerConners3D[3],innerConners3D[4],innerConners3D[5]],
# [innerConners3D[6],innerConners3D[7],innerConners3D[8]],
# [innerConners3D[9],innerConners3D[10],innerConners3D[11]]])
cv2.polylines(im, [ptsRoiPoints], True, (255, 0, 0), 2)
# cv2.polylines(im, [ptsInnerConners], True, (255,0,0) , 2)
_darw_rect(im)
return msg
def doDetectionProcessing(msg):
if msg is None:
return msg
if msg.im2D is not None:
im = cv2.resize(msg.im2D, (int(msg.im2D.shape[1] / 16), int(msg.im2D.shape[0] / 16)))
record = msg.record
ptsRoiPoints = None
ptsInnerConners = None
ptsInnerConners3D = None
ptsRoiPointslist = []
ptsInnerConnerslist = []
ptsInnerConners3Dlist = []
if record.roi_size > 16:
return msg
for i in range(record.roi_size):
roi = record.subRois[i]
if not roi.isGood: continue
roiPoints = roi.mRoiPoints
innerConners = roi.mInnerConners
innerConners3D = roi.mInnerConners3D
ptsRoiPoints = np.array([
[roiPoints[0], roiPoints[1]],
[roiPoints[2], roiPoints[3]],
[roiPoints[4], roiPoints[5]],
[roiPoints[6], roiPoints[7]]], dtype=np.int32)
ptsInnerConners = np.array([
[innerConners[0], innerConners[1]],
[innerConners[2], innerConners[3]],
[innerConners[4], innerConners[5]],
[innerConners[6], innerConners[7]]], dtype=np.int32)
ptsInnerConners3D = np.array([
[innerConners3D[0], innerConners3D[1], innerConners3D[2]],
[innerConners3D[3], innerConners3D[4], innerConners3D[5]],
[innerConners3D[6], innerConners3D[7], innerConners3D[8]],
[innerConners3D[9], innerConners3D[10], innerConners3D[11]]])
print(ptsInnerConners3D)
for i in range(4):
ptsRoiPoints[i][0] = int(ptsRoiPoints[i][0] / 16)
ptsRoiPoints[i][1] = int(ptsRoiPoints[i][1] / 16)
ptsInnerConners[i][0] = int(ptsInnerConners[i][0] / 16)
ptsInnerConners[i][1] = int(ptsInnerConners[i][1] / 16)
ptsRoiPointslist.append(ptsRoiPoints)
ptsInnerConnerslist.append(ptsInnerConners)
ptsInnerConners3Dlist.append(ptsInnerConners3D)
cv2.polylines(im, ptsRoiPointslist, True, (0, 255, 0), 1)
cv2.polylines(im, ptsInnerConnerslist, True, (0, 255, 255), 1)
cv2.imwrite("result.png", im)
print("================== cv2.imwrite success =================")
if record.code == 12 + TO_CLIENT_NOTIFY_BASE:
for j in range(record.roi_size):
roi = record.subRois[j]
if not roi.isGood: continue
ptsInnerConners = ptsInnerConnerslist[j]
ptsInnerConners3D = ptsInnerConners3Dlist[j]
if len(ptsInnerConners) == 4:
for i in range(4):
p3d = ptsInnerConners3D[i]
p3d_next = ptsInnerConners3D[(i + 1) % 4]
p2d = ptsInnerConners[i]
p2d_next = ptsInnerConners[(i + 1) % 4]
edge = np.sqrt(pow((p3d[0] - p3d_next[0]), 2)
+ pow((p3d[1] - p3d_next[1]), 2)
+ pow((p3d[2] - p3d_next[2]), 2))
cv2.putText(im, str(edge)[:6], \
(int((ptsInnerConners[0][0] + ptsInnerConners[(0 + 1) % 4][0]) / 2), \
int((ptsInnerConners[0][1] + ptsInnerConners[(0 + 1) % 4][1]) / 2 + i * 20)), \
cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255, 0, 0), 2)
print("================== draw =================")
msg.im2D = im
cv2.imshow("HQImage", im)
# cv2.waitKey(1)
return msg
# detect结果处理
def detectionResProcessing(msg,data_img_path,data_detect_res_save_path):
# im = cv2.resize(msg.im2D, (int(msg.im2D.shape[1] / 16), int(msg.im2D.shape[0] / 16)))
# Read the image from the local directory
im = cv2.imread(data_img_path)
# Resize the image
im = cv2.resize(im, (int(im.shape[1] / 16), int(im.shape[0] / 16)))
record = msg.record
ptsRoiPoints = None
ptsInnerConners = None
ptsInnerConners3D = None
ptsRoiPointslist = []
ptsInnerConnerslist = []
ptsInnerConners3Dlist = []
logger.debug(f"record.roi_size{record.roi_size}")
if record.roi_size > 16:
logger.warn(f"roi_size大于:{record.roi_size}个,请检查!")
for i in range(record.roi_size):
roi = record.subRois[i]
logger.debug(f"roi====={roi.isGood}")
# if not roi.isGood: continue
roiPoints = roi.mRoiPoints
innerConners = roi.mInnerConners
innerConners3D = roi.mInnerConners3D
ptsRoiPoints = np.array([
[roiPoints[0], roiPoints[1]],
[roiPoints[2], roiPoints[3]],
[roiPoints[4], roiPoints[5]],
[roiPoints[6], roiPoints[7]]], dtype=np.int32)
ptsInnerConners = np.array([
[innerConners[0], innerConners[1]],
[innerConners[2], innerConners[3]],
[innerConners[4], innerConners[5]],
[innerConners[6], innerConners[7]]], dtype=np.int32)
ptsInnerConners3D = np.array([
[innerConners3D[0], innerConners3D[1], innerConners3D[2]],
[innerConners3D[3], innerConners3D[4], innerConners3D[5]],
[innerConners3D[6], innerConners3D[7], innerConners3D[8]],
[innerConners3D[9], innerConners3D[10], innerConners3D[11]]])
print(ptsInnerConners3D)
for i in range(4):
ptsRoiPoints[i][0] = int(ptsRoiPoints[i][0] / 16)
ptsRoiPoints[i][1] = int(ptsRoiPoints[i][1] / 16)
ptsInnerConners[i][0] = int(ptsInnerConners[i][0] / 16)
ptsInnerConners[i][1] = int(ptsInnerConners[i][1] / 16)
ptsRoiPointslist.append(ptsRoiPoints)
ptsInnerConnerslist.append(ptsInnerConners)
ptsInnerConners3Dlist.append(ptsInnerConners3D)
# 打印三个list
# for i in range(len(ptsRoiPointslist)):
# logger.debug("ptsRoiPointslist:", ptsRoiPointslist[i])
# logger.debug(("ptsInnerConnerslist:", ptsInnerConnerslist[i]))
# logger.debug(("ptsInnerConners3Dlist:", ptsInnerConners3Dlist[i]))
cv2.polylines(im, ptsRoiPointslist, True, (0, 255, 0), 1)
cv2.polylines(im, ptsInnerConnerslist, True, (0, 255, 255), 1)
cv2.imwrite(f"{data_detect_res_save_path}/result.jpg", im)
logger.success("================== cv2.imwrite result.jpg success =================")
if record.code == 12 + TO_CLIENT_NOTIFY_BASE:
for j in range(record.roi_size):
roi = record.subRois[j]
# if not roi.isGood: continue
ptsInnerConners = ptsInnerConnerslist[j]
ptsInnerConners3D = ptsInnerConners3Dlist[j]
if len(ptsInnerConners) == 4:
for i in range(4):
p3d = ptsInnerConners3D[i]
p3d_next = ptsInnerConners3D[(i + 1) % 4]
p2d = ptsInnerConners[i]
p2d_next = ptsInnerConners[(i + 1) % 4]
edge = np.sqrt(pow((p3d[0] - p3d_next[0]), 2)
+ pow((p3d[1] - p3d_next[1]), 2)
+ pow((p3d[2] - p3d_next[2]), 2))
cv2.putText(im, str(edge)[:6], \
(int((ptsInnerConners[0][0] + ptsInnerConners[(0 + 1) % 4][0]) / 2), \
int((ptsInnerConners[0][1] + ptsInnerConners[(0 + 1) % 4][1]) / 2 + i * 20)), \
cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255, 0, 0), 2)
cv2.imwrite(f"{data_detect_res_save_path}/result2.jpg", im)
logger.success("================== cv2.imwrite result2.jpg success =================")

BIN
myplot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
myplot_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
myplot_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Binary file not shown.

BIN
opencv_world420d.dll Normal file

Binary file not shown.

27
points.txt Normal file
View File

@ -0,0 +1,27 @@
[(4366.0, 226.0), (5816.0, 226.0), (5816.0, 476.0), (4366.0, 476.0)]
[(4963.0, 604.0), (5263.0, 604.0), (5263.0, 904.0), (4963.0, 904.0)]
[(4147.5, 804.0), (4647.5, 804.0), (4647.5, 1305.0), (4147.5, 1305.0)]
[(4995.0, 1024.0), (5643.0, 1024.0), (5643.0, 1274.0), (4995.0, 1274.0)]
[(4574.0, 1418.0), (4824.0, 1418.0), (4824.0, 1668.0), (4574.0, 1668.0)]
[(4131.0, 1626.0), (4380.0, 1626.0), (4380.0, 1875.0), (4131.0, 1875.0)]
[(5287.0, 1755.0), (5686.0, 1755.0), (5686.0, 2155.0), (5287.0, 2155.0)]
[(4742.0, 2009.0), (5044.0, 2009.0), (5044.0, 2309.0), (4742.0, 2309.0)]
[(4140.0, 2007.0), (4442.0, 2007.0), (4442.0, 2307.0), (4140.0, 2307.0)]
[(2373.5, 221.0), (3820.5, 221.0), (3820.5, 469.0), (2373.5, 469.0)]
[(2940.0, 598.0), (3237.0, 598.0), (3237.0, 896.0), (2940.0, 896.0)]
[(2146.5, 791.0), (2645.5, 791.0), (2645.5, 1290.0), (2146.5, 1290.0)]
[(2968.5, 1024.0), (3616.5, 1024.0), (3616.5, 1269.0), (2968.5, 1269.0)]
[(2574.0, 1427.0), (2821.0, 1427.0), (2821.0, 1674.0), (2574.0, 1674.0)]
[(2165.0, 1634.0), (2412.0, 1634.0), (2412.0, 1880.0), (2165.0, 1880.0)]
[(3291.5, 1756.0), (3683.5, 1756.0), (3683.5, 2154.0), (3291.5, 2154.0)]
[(2746.0, 1997.0), (3039.0, 1997.0), (3039.0, 2297.0), (2746.0, 2297.0)]
[(2137.0, 1995.0), (2434.0, 1995.0), (2434.0, 2293.0), (2137.0, 2293.0)]
[(372.0, 222.0), (1819.0, 222.0), (1819.0, 467.0), (372.0, 467.0)]
[(962.0, 596.0), (1262.0, 596.0), (1262.0, 891.0), (962.0, 891.0)]
[(142.0, 781.0), (637.0, 781.0), (637.0, 1279.0), (142.0, 1279.0)]
[(986.0, 1028.0), (1634.0, 1028.0), (1634.0, 1273.0), (986.0, 1273.0)]
[(616.5, 1419.0), (862.5, 1419.0), (862.5, 1664.0), (616.5, 1664.0)]
[(172.0, 1613.0), (417.0, 1613.0), (417.0, 1858.0), (172.0, 1858.0)]
[(1294.5, 1756.0), (1686.5, 1756.0), (1686.5, 2154.0), (1294.5, 2154.0)]
[(746.5, 1993.0), (1042.5, 1993.0), (1042.5, 2291.0), (746.5, 2291.0)]
[(148.0, 1998.0), (443.0, 1998.0), (443.0, 2295.0), (148.0, 2295.0)]

7
readme.md Normal file
View File

@ -0,0 +1,7 @@
```pycon
self.image_framework = ImageFramework()
self.image_framework.signals.on_image_detect_result.connect(
lambda data: self.image_result(data))
self.image_framework.configure()
self.image_framework.start()
```

24
roi_conners.txt Normal file
View File

@ -0,0 +1,24 @@
1131
2007
5900
2007
5900
5376
1131
5376
2004
2958
3142
2958
3142
3948
2004
3948
3887
2919
4839
2919
4839
3902
3887
3902

28
util.py Normal file
View File

@ -0,0 +1,28 @@
import configparser
from clog import logger
"""
修改配置文件中的指定参数
参数:
s (str): 配置文件中的节(section)名称
o (str): 配置文件中的选项(option)名称
v (str): 要设置的新值
返回值:
"""
def change_config_ini(s, o, v):
# 读取配置文件
config = configparser.ConfigParser()
config.read("config.ini", encoding="utf-8") # 解决可能的编码问题
# 修改参数
config.set(s, o, v)
# 将修改后的配置写回文件
with open("config.ini", "w", encoding="utf-8") as configfile:
config.write(configfile)
logger.info(f"{s}.{o} 参数已更新为 {v}")

BIN
预埋件位置.xlsx Normal file

Binary file not shown.