main.py(二)

这段代码首先检查配置文件中是否设置了保存 CSV 文件的选项(SAVE_CSVTrue),如果是,则执行以下操作:

  1. 定义了一个列表 header,包含了 CSV 文件的列名。在这个例子中,列名包括了 car_center_xcar_center_yxyz,这些可能是表示车辆中心坐标和位置的数据。

  2. 使用 open() 函数创建了一个名为 data.csv 的 CSV 文件,并以写入模式打开它。参数 newline='' 表示不使用额外的换行符,而是由 csv 模块来管理换行。

  3. 使用 csv.DictWriter() 函数创建了一个 writer 对象,该对象用于将字典数据写入 CSV 文件。参数 chart 是之前创建的 CSV 文件对象,header 是 CSV 文件的列名。

  4. 使用 writer.writeheader() 方法写入了 CSV 文件的头部,即列名。这样可以确保在写入数据之前,文件中已经有了正确的列名。

if main_cfg['ctrl']['SAVE_CSV']:header = ['car_center_x', 'car_center_y', 'x', 'y', 'z']chart = open("data.csv", "w", newline='')writer = csv.DictWriter(chart, header)writer.writeheader()

这段代码定义了一个名为 push_button_clicked_quit 的函数,用于处理当某个按钮被点击时触发的事件。函数的作用是设置全局变量 exit_signalLoop,使得程序退出主循环并退出程序。

具体来说:

  • global exit_signal, Loop:这行代码声明了函数中将要使用的两个全局变量 exit_signalLoop
  • exit_signal = True:将 exit_signal 设置为 True,表示程序应该退出。
  • print('exit'):打印消息提示程序即将退出。
  • Loop = False:将 Loop 设置为 False,以停止主循环的执行,从而退出程序。
def push_button_clicked_quit():global exit_signal, Loopexit_signal = Trueprint('exit')Loop = False

这段代码定义了一个名为 main() 的函数,用于程序的主逻辑。函数内部涉及到一系列变量的定义和初始化,以及根据配置文件中的设置选择相应的操作模式。

具体来说:

  • global targets:声明了函数内部将要使用的全局变量 targets
  • camera_left = camera_right = None:初始化左右摄像头对象为 None
  • image_left = image_right = None:初始化左右图像对象为 None
  • ret_p = ret_q = None:初始化一些其他变量为 None
  • coex_matcher = None:初始化匹配模型对象为 None
  • model_car = None:初始化车辆模型对象为 None
  • monitor = None:初始化监视器对象为 None
  • main_scene = None:初始化主场景对象为 None
  • timeout_draw_zone = False:初始化一个标志变量为 False,用于标记是否超时。

接下来是根据配置文件中的模式选择相应的操作:

  • 如果模式为 'video',则调用 bc.get_video_loader() 函数加载视频数据。
  • 如果模式为 'camera',则调用 bc.get_camera() 函数加载摄像头数据。

最后,初始化一个 CoExMatcher 对象,用于匹配图像特征。

def main():global targetscamera_left = camera_right = Noneimage_left = image_right = Noneret_p = ret_q = Nonecoex_matcher = Nonemodel_car = Nonemonitor = Nonemain_scene = Nonetimeout_draw_zone = Falseif main_cfg['ctrl']['MODE'] == 'video':camera_left, camera_right, fps, size = bc.get_video_loader(main_cfg['video']['bin_video_left'],main_cfg['video']['bin_video_right'])elif main_cfg['ctrl']['MODE'] == 'camera':print("\nLoading binocular camera")camera_left, camera_right, ret_p, ret_q = bc.get_camera(bin_cam_cfg)print("Done")print("\nLoading matching model")coex_matcher = CoExMatcher(bin_cam_cfg)print("Done\n")
  1. 创建了一个名为 left_cam_cfg 的字典,用于存储左侧摄像头的内参和畸变系数。这些参数从 bin_cam_cfg 中获取。

  2. 创建了一个 CameraPoseSolver 类的实例 camera_pose_solver,用于解算相机姿态。这个实例根据己方颜色(ALLY_COLOR)和左侧摄像头的配置参数进行初始化。

  3. 如果配置文件中设置了使用锚定点(ANCHORTrue),则执行以下操作:

    • 创建了一个名为 anchor 的锚定点对象。
    • 使用 camera_leftcamera_right 读取图像数据(如果模式为 'video')或者获取摄像头帧数据(如果模式为 'camera')。
    • 如果读取到的图像为空,则继续循环读取直到成功读取到图像。
    • 对左侧图像进行手动设置锚定点的操作,然后使用锚定点初始化相机姿态解算器。
    • 循环结束后退出循环。
  4. 如果未设置使用锚定点,则暂时注释掉了使用常量初始化相机姿态解算器的部分。

综上所述,这段代码的主要作用是根据配置文件的设置,初始化左侧摄像头的配置参数,并根据情况使用锚定点初始化相机姿态解算器。

left_cam_cfg = dict()left_cam_cfg['intrinsic'] = bin_cam_cfg['calib']['intrinsic1']left_cam_cfg['distortion'] = bin_cam_cfg['calib']['distortion1']camera_pose_solver = cc.CameraPoseSolver(ALLY_COLOR, left_cam_cfg)if main_cfg['ctrl']['ANCHOR']:anchor = Anchor()while True:  # this while is for case where no img gotif main_cfg['ctrl']['MODE'] == 'video':ret, image_left = camera_left.read()ret, image_right = camera_right.read()elif main_cfg['ctrl']['MODE'] == 'camera':image_left = bc.get_frame(camera_left, 'left_camera', ret_p)image_right = bc.get_frame(camera_right, 'right_camera', ret_q)if image_left is None or image_right is None:continueset_by_hand(image_left, anchor)camera_pose_solver.init_by_anchor(anchor)breakelse:# camera_pose_solver.init_by_constant()pass
  1. 如果配置文件中设置了检测(DETECTTrue),则执行以下操作:

    • 打印消息提示正在加载车辆模型。
    • 使用 YOLO 模型加载车辆模型,模型权重文件路径从配置文件中获取。
    • 打印消息提示加载完成。
  2. 如果配置文件中设置了使用图形用户界面(GUI),则执行以下操作:

    • 打印消息提示正在准备 GUI。
    • 设置 GUI 的缩放属性以支持高 DPI 缩放。
    • 创建一个 QApplication 对象。
    • 创建一个 QMainWindow 对象,并设置其界面为通过 gui.Ui_Monitor() 创建的界面。
    • 将退出按钮的点击事件连接到 push_button_clicked_quit 函数。
    • 创建一个 QGraphicsScene 对象作为主场景。
    • 将主场景设置到 GUI 界面中的视图中,并显示出来。
    • 打印消息提示 GUI 准备完成。
    • 如果存在超时的绘制区域,则向调试消息框添加一条消息。
  3. 最后,初始化了一些计数器和时间变量。

        if main_cfg['ctrl']['DETECT']:print('Loading Car Model')model_car = YOLO(main_cfg['weights']['yolov8'])print('Done\n')if main_cfg['ctrl']['GUI']:print('preparing gui')QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)app = QApplication(sys.argv)MainWindow = QMainWindow()monitor = gui.Ui_Monitor()monitor.setupUi(MainWindow)monitor.pushButton_quit.clicked.connect(push_button_clicked_quit)main_scene = QGraphicsScene()monitor.main_frame_view.setScene(main_scene)monitor.main_frame_view.show()MainWindow.show()print('done')if timeout_draw_zone:monitor.debug_msg.append('zone initialize: timeout, using saved one\n')cnt = 0start = 0.last = time.time()
  4. 使用全局变量 Loop 来控制程序的运行,只有当 LoopTrue 时,程序才会继续执行主循环。这个变量通常在其他地方被设置为 False,从而触发程序退出。

  5. 如果按下键盘上的 'q' 键,那么 Loop 被设置为 False,程序将退出主循环。

  6. 根据配置文件中的模式选择相应的操作:

    • 如果模式为 'video',则从左右摄像头读取图像数据。
    • 如果模式为 'camera',则从左右摄像头获取图像帧数据。
  7. 对于获取的左右图像数据,进行了一系列处理:

    • 如果开启了录制视频的选项,则将左右原始图像写入相应的视频文件中。
    • 调用 coex_matcher.inference() 对左右图像进行立体匹配,获取深度信息和视差图。
    • 对视差图进行颜色映射,并写入深度视频文件中。
    • 如果开启了棋盘格检测的选项,则检测图像中的棋盘格角点,并在图像中标注对应的三维坐标信息。
  8. 最后,根据配置文件中的设置,显示处理后的图像或者关闭窗口。

    global Loopwhile Loop:if cv2.waitKey(1) == ord('q'):Loop = Falseif main_cfg['ctrl']['MODE'] == 'video':ret, image_left = camera_left.read()ret, image_right = camera_right.read()elif main_cfg['ctrl']['MODE'] == 'camera':image_left = bc.get_frame(camera_left, 'left_camera', ret_p)image_right = bc.get_frame(camera_right, 'right_camera', ret_q)if image_right is not None and image_left is not None:if main_cfg['ctrl']['RECORDING']:left_video.write(image_left)right_video.write(image_right)re_left, point_cloud, disp_np = coex_matcher.inference(image_left, image_right)if main_cfg['ctrl']['RECORDING']:disp_video.write(disp_np)cv2.imshow('raw_disp', disp_np)disp_np = cv2.applyColorMap(2 * disp_np, cv2.COLORMAP_MAGMA)if main_cfg['ctrl']['RECORDING']:depth_video.write(disp_np)if main_cfg['ctrl']['CHESSBOARD']:pattern_size = (8, 6)corners, image_with_corners = find_chessboard_corners(re_left, pattern_size)# print(corners)if corners is not None:cv2.putText(image_with_corners,'[ ' + str(round(point_cloud[int(corners[0][0][1])][int(corners[0][0][0])][0], 2)) + ', '+ str(round(point_cloud[int(corners[0][0][1])][int(corners[0][0][0])][1], 2)) + ', '+ str(round(point_cloud[int(corners[0][0][1])][int(corners[0][0][0])][2], 2)) + ']',(int(corners[0][0][0]), int(corners[0][0][1])),fontFace=cv2.FONT_HERSHEY_SIMPLEX,fontScale=0.7,color=(255, 255, 255),thickness=1,lineType=cv2.LINE_AA)cv2.imshow('xyz', image_with_corners)

这段代码实现了以下功能:

  1. 跳过开始的前 20 帧以便更准确地记录时间。在第 20 帧之后开始记录时间,计算帧率。
  2. 使用 OpenCV 在深度图像上绘制帧率信息。
  3. 如果配置文件中启用了目标检测(DETECT为True),则执行以下操作:
    • 对左侧摄像头的图像进行目标检测,获取目标检测结果。
    • 更新目标列表中的目标信息,并根据相机坐标解算出场地坐标。
    • 如果启用了调试模式(debug为True),则在左侧图像上标注目标的相机坐标。
    • 将目标信息发送给串口。
    • 如果启用了 GUI 模式,则在监视器上显示发送的消息。
  4. 如果未启用目标检测,则显示左侧摄像头的图像。
# skip starting frames for more accurate time recordif cnt == 20:start = time.time()if cnt > 20:now = time.time()fps = (cnt - 10) / (now - start)cv2.putText(disp_np,"fps: " + "%.2f" % fps,(4, 40),fontFace=cv2.FONT_HERSHEY_SIMPLEX,fontScale=0.9,color=(255, 255, 255),thickness=2,lineType=cv2.LINE_AA)cv2.imshow('disp', disp_np)if main_cfg['ctrl']['DETECT']:dst_img = np.copy(re_left)result = model_car.predict(dst_img, show=True)boxes = result[0].boxes.data.cpu()boxes = boxes.numpy()print(boxes)targets.update(boxes)for target in targets.targets:if target.conf > 0:cam_coord = [[point_cloud[int(target.center_yx[0])][int(target.center_yx[1])][0]],[point_cloud[int(target.center_yx[0])][int(target.center_yx[1])][1]],[point_cloud[int(target.center_yx[0])][int(target.center_yx[1])][2]]]field_coord = camera_pose_solver.get_field_coord(cam_coord)target.x = field_coord[0]target.y = field_coord[1]if main_cfg['debug']:msg = str(cam_coord)cv2.putText(re_left,msg,(int(target.center_yx[1]), int(target.center_yx[0])),cv2.FONT_HERSHEY_PLAIN,1.0,(0, 0, 255),thickness=1)if main_cfg['debug']:cv2.imshow('dist', re_left)for car in targets.targets:if car.conf > 0:now = time.time()# 距离上一次发送时间小于0.1s:sleepif now - last < 0.1:time.sleep(0.1 - (now - last))messager.send_enemy_location(ser, car.get_id(), car.x / 1000,car.y / 1000)  # mm to mif main_cfg['ctrl']['GUI']:monitor.debug_msg.append('at [' + str(now) + '] send: ' + str(car.get_id()) + ' ' +str(car.x / 1000) + ' ' + str(car.y / 1000) + '\n')last = time.time()else:cv2.imshow('re_left', re_left)

这段代码检查了配置文件中是否启用了 GUI 模式。如果启用了 GUI 模式,则执行以下操作:

  1. 使用 cv2.resize() 函数将左侧摄像头的图像 re_left 缩放到指定的大小(720x360像素)。
  2. 使用 QImage() 函数将 OpenCV 图像转换为 Qt 的图像格式 QImage
  3. 在每次循环开始之前,通过 main_scene.clear() 清空上一次循环中残留的图像。
  4. 使用 QPixmap.fromImage()QImage 转换为 QPixmap
  5. 使用 main_scene.addPixmap()QPixmap 添加到主场景中。
            if main_cfg['ctrl']['GUI']:resized = cv2.resize(re_left, (720, 360))frame = QImage(resized, 720, 360, 720 * 3, QImage.Format_BGR888)main_scene.clear()  # 先清空上次的残留pixel_map = QPixmap.fromImage(frame)main_scene.addPixmap(pixel_map)
  1. 将计数器 cnt 自增一,用于记录循环的次数。

  2. 输出 - end of loop -----------------------------------------------------------------------------,作为循环结束的标志。

  3. 如果配置文件中的模式为 'camera',则关闭摄像头。

  4. 关闭所有 OpenCV 窗口,释放图像资源。

  5. 如果配置文件中设置了录制视频的选项,则将配置文件复制到视频文件夹中,并释放视频写入对象。

  6. 如果配置文件中设置了保存 CSV 文件的选项,则关闭 CSV 文件。

  7. 输出 'release!',表示所有资源已经释放。

  8. 最后,检查是否处于主程序的入口,如果是,则调用 main() 函数开始执行程序的主逻辑。

这段代码用于完成程序的收尾工作,包括关闭摄像头、释放资源、保存文件等操作,并最终执行程序的主逻辑。

cnt += 1'- end of loop -----------------------------------------------------------------------------'if main_cfg['ctrl']['MODE'] == 'camera':bc.camera_close(camera_left, 'camera_left')bc.camera_close(camera_right, 'camera_right')cv2.destroyAllWindows()if main_cfg['ctrl']['RECORDING']:os.system('copy bin_cam_config.yaml ' + video_folder[2:] + '/cfg/bin_cam_config.yaml')os.system('copy main_config.yaml ' + video_folder[2:] + '/cfg/main_config.yaml')left_video.release()right_video.release()disp_video.release()depth_video.release()if main_cfg['ctrl']['SAVE_CSV']:chart.close()print('release!')if __name__ == '__main__':main()

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/774481.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入理解nginx mp4流媒体模块[上]

目录 1. 引言2. 配置3. 源码分析3.1 配置指令3.1.1 mp43.1.2 mp4_buffer_size3.1.3 mp4_max_buffer_size3.1.4 mp4_start_key_frame 3.2 MP4的请求处理过程3.2.1 预处理3.2.2 找到并打开本地mp4文件3.2.3 解析请求参数3.2.4 MP4文件的处理 1. 引言 在当今数字化时代&#xff0c…

YOLOv9改进策略:卷积魔改 | DCNv2升级版本,助力检测

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a;在DCN的基础上&#xff0c;增加了2个创新点&#xff0c;分别是调制模块和使用多个调制后的DCN模块&#xff0c;从形成了DCN的升级版本——DCNv2 &#x1f4a1;&#x1f4a1;&#x1f4a1;如何使用&#xff1a…

红岩思维导图的制作软件,分享4款热门的!

红岩思维导图的制作软件&#xff0c;分享4款热门的&#xff01; 在当今信息爆炸的时代&#xff0c;思维导图作为一种有效的知识整理和思维拓展工具&#xff0c;受到了广大用户的青睐。红岩思维导图以其独特的风格和实用性&#xff0c;成为了许多人学习和工作中的得力助手。那么…

JavaScript中的行为委托和面向类的区别?

先复习一些原型链的知识&#xff1a; [[Prototype]] 机制是一种存在于一个对象上的内部链接&#xff0c;它指向一个其他对象。 在JavaScript中&#xff0c;每个对象都有一个原型对象&#xff08;prototype&#xff09;&#xff0c;当访问对象的属性或方法时&#xff0c;如果对象…

【SpringSecurity】基础入门

目录 权限管理什么是权限管理认证授权权限管理解决方案Shiro开发者自定义Spring Security Spring Security特性Spring、Spring Boot 和 Spring Security 三者的关系整体架构1.认证AuthenticationManagerAuthenticationSecurityContextHolder 2.授权AccessDecisionManagerAccess…

作为数据分析师,如何能把AI工具和数据分析工作更好的结合?

在当今信息爆炸的时代&#xff0c;数据已经成为企业、研究机构乃至个人决策的重要依据。然而&#xff0c;如何高效地处理、分析和解读这些数据&#xff0c;从而提炼出有价值的信息&#xff0c;却成为了一个亟待解决的问题。 幸运的是&#xff0c;随着人工智能技术的飞速发展&a…

刷好题,固基础-2

7-5 运动会 T公司的员工层级关系可以表示成一棵树&#xff0c;员工X是员工Y的直接领导&#xff0c;则在树中X是Y的父结点。公司拟组织一场运动会&#xff0c;但为了避免尴尬&#xff0c;每个员工都不想与自己的直接领导一起参赛。假定每个员工都对应一个权重&#xff08;领导的…

二叉树|450.删除二叉搜索树中的节点

力扣题目链接 class Solution { public:TreeNode* deleteNode(TreeNode* root, int key) {if (root nullptr) return root; // 第一种情况&#xff1a;没找到删除的节点&#xff0c;遍历到空节点直接返回了if (root->val key) {// 第二种情况&#xff1a;左右孩子都为空&…

使用AI 编写一个Mybatis SQL日志解析工具

使用AI 编写一个Mybatis SQL日志解析工具 背景 尝试使用智谱清言 AI 编写一个工具&#xff0c;将Mybatis SQL日志解析为可以执行的SQL语句。 操作 准备初始代码 首先网站上找了一个有BUG的简单的实现 https://blog.csdn.net/x541211190/article/details/107410409 用提示…

【WEEK4】 【DAY5】AJAX第二部分【中文版】

2024.3.22 Friday 接上文【WEEK4】 【DAY4】AJAX第一部分【中文版】 目录 8.4.Ajax异步加载数据8.4.1.新建User.java8.4.2.在pom.xml中添加lombok、jackson支持8.4.3.更改tomcat设置8.4.4.修改AjaxController.java8.4.5.新建test2.jsp8.4.5.1.注意&#xff1a;和WEB-INF平级&…

.NET Core教程:入门与实践实例

.NET Core教程&#xff1a;入门与实践实例 在信息技术飞速发展的今天&#xff0c;掌握一门高效的编程技术成为了每个开发者不可或缺的技能。在众多编程框架中&#xff0c;.NET Core以其跨平台、高性能和易扩展的特性&#xff0c;受到了广大开发者的青睐。本文将通过实例&#…

一文解析:固定电感器结构、作用及其与扼流圈和可变电感器的差异

固定电感器是一种电子元件又称固定线圈&#xff0c;用于在电路中产生固定的电感值。电感是指导致电流变化时产生电动势的能力&#xff0c;通常用亨利&#xff08;Henry&#xff09;作为单位。固定电感器的电感值是预先确定的&#xff0c;通常以特定的数值标识&#xff0c;例如1…

免疫荧光染色

每次要将手/样品伸进细胞培养箱&#xff0c;生物培养平台D 中时&#xff0c;都要喷洒酒精消毒。 以两个样品/两个培养基为例 从细胞培养箱&#xff08;37度&#xff0c;5%CO2浓度&#xff09;取出要染色的细胞&#xff1b;放在显微镜下观察&#xff0c;观察细胞是否趴壁以及细…

【正点原子FreeRTOS学习笔记】————(10)FreeRTOS时间管理

这里写目录标题 一、延时函数介绍&#xff08;了解&#xff09;二、延时函数解析&#xff08;熟悉&#xff09;三、延时函数演示实验&#xff08;掌握&#xff09; 一、延时函数介绍&#xff08;了解&#xff09; 相对延时&#xff1a;指每次延时都是从执行函数vTaskDelay()开始…

onnxruntime 中的 Gather 算子

上一篇文章中介绍了 Division by Invariant Integers using Multiplication 的原理&#xff0c;很多框架均才用该算法优化除法运算。onnxruntime 是已知实现中最为简洁的&#xff0c;因此本文结合 onnxruntime 的 Gather 实现进行介绍。 Gather 算子是一个索引类算子&#xff0…

Python(django)之单一接口展示功能前端开发

1、代码 建立apis_manage.html 代码如下&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>测试平台</title> </head> <body role"document"> <nav c…

S7-200 SMART 选型指南及详细技术参数

S7-200 SMART 选型指南 选型指南 硬件能力 功能 CPU外形结构与电源需求计算 直流安装 交流安装 电源需求与计算 S7-200 SMART CPU模块提供5VDC和24VDC电源&#xff1a; CPU有一个内部电源&#xff0c;用于为CPU、扩展模块、信号板提供电源和满足其他24 VDC用户电源需求。请使…

数据结构二叉树计算公式

这些是关于二叉树、完全二叉树、B-树以及树的深度和高度的一些基本概念和重要性质。让我们一一解读这些性质: 二叉树的计数公式:给定 n 个节点,可以构造的不同二叉树数量是 (\frac{(2n)!}{n! \cdot (n+1)!})。这是一个来自组合数学的结果,称为 Catalan 数。这个公式非常重要…

鸿蒙HarmonyOS应用开发之使用Node-API接口进行线程安全开发

场景介绍 napi_create_threadsafe_function是Node-API接口之一&#xff0c;用于创建一个线程安全的JavaScript函数。主要用于在多个线程之间共享和调用&#xff0c;而不会出现竞争条件或死锁。例如以下场景&#xff1a; 异步计算&#xff1a;如果需要进行耗时的计算或IO操作&a…

Scala介绍与环境搭建

Scala环境搭建与介绍 一、Scala环境搭建 1、环境准备与下载 2、验证Scala 3、IDEA新建项目&#xff0c;配置Scala&#xff0c;运行Hello world 二、Scala介绍 1、Scala 简介 2、Scala 概述 一、Scala环境搭建 1、环境准备与下载 JDK1.8 Java Downloads | Oracle 下载需求版本…