YOLOv5+pyqt5+摄像头在特定条件下进行目标检测并采集原始数据

项目介绍

项目地址

GitHub - biabu0/Yolov5_D435i: 通过YOLOV5与pyqt5实现一个使用D435i深度摄像头采集特定需求与场景下的深度数据的小程序

通过YOLOV5对指定的区域进行检测,当检测到目标进入特定区域时,开始保存数据,摄像头采用D435i深度相机,用于采集深度数据集。

  1. 指定需要屏蔽的检测区域,即使目标进入该区域也无法进行有效的检测,应用于特定场景的检测。
  2. 只有目标在检测区域内,才进行数据的采集与保存,避免一直采集数据,目标离开检测区域则停止保存数据,避免在数据采集过程中存在大量的无效数据,节约数据清洗时间,节省磁盘容量。
  3. 按照时间存储数据。
  4. 使用pyqt5设计可视化界面,将UI界面与逻辑代码分离。

项目演示视频

演示视频

环境配置

按照requements.txt文件配置yolov5环境,安装pyqt5和pyrealsense2。

核心代码解析

detect_logical.py:负责加载模型,并初始化模型参数;选择遮蔽区域以及需要保存的数据文件地址;加载D435深度相机数据流,将数据送入检测,检测到特定目标返回数据保存的标志位进行数据存储。
main_logic.py:主界面,可以进行注册账号与登录账号。
ui/ori_ui:ui源文件,可以通过使用QTdesigner对UI界面进行修改,修改后使用**pyuic5 main.ui > ui_main.py**,(注意最好使用绝对路径,不然可能出现问题)转换成py文件。
utlis/id_utlis.py与userInfo.csv:用于写入账户信息。

遮蔽区域选择

通过鼠标左键获取需要屏蔽的区域的四个角的位置,保存到一个全局变量中,用于后序检测的时候生成指定区域的掩码,从而屏蔽特定区域。

python 复制代码
    def mouse_callback(self, event, x, y, flags, param):

        if event == cv2.EVENT_LBUTTONDOWN:
            # 将位置标准化(可选,根据需求决定是否需要)
            normalized_x = x / self.frame_shape[1]
            normalized_y = y / self.frame_shape[0]

            # 将位置添加到二维数组中
            self.mouse_positions.append([normalized_x, normalized_y])
        return ;
    def select_mask(self):
        self.mouse_positions = []

        self.pipeline.start(self.config)
        frames = self.pipeline.wait_for_frames()
        img_color = frames.get_color_frame()


        # 检查摄像头是否成功打开
        if img_color is None:
            print("Error: Could not open video device.")
            exit()

        img_color = np.asanyarray(img_color.get_data())
        self.frame_shape = img_color.shape[:2]
        # 创建一个窗口
        cv2.namedWindow('Camera Image')
        # 设置鼠标回调函数
        cv2.setMouseCallback('Camera Image', self.mouse_callback)
        while True:
            # 显示图像
            cv2.imshow('Camera Image', img_color)
            #等待按键,如果按下'q'键,退出循环
            if cv2.waitKey(0) & 0xFF == ord('q'):
                break
        # 释放D435i对象
        self.pipeline.stop()  # 停止RealSense管道

        # 销毁创建的窗口
        print("mouse_positions", self.mouse_positions)
        QtWidgets.QMessageBox.information(self, u"Notice", u"遮掩区域选择成功", buttons=QtWidgets.QMessageBox.Ok,
                                      defaultButton=QtWidgets.QMessageBox.Ok)

选择数据保存地址

直接将寻找的路径保存到全局变量中,后序需要保存地址的时候加载进去。

python 复制代码
    def open_file(self):

        self.openfile_name_dataset = QFileDialog.getExistingDirectory(self, '选择数据集目录')
        if not self.openfile_name_dataset:
            QtWidgets.QMessageBox.warning(self, u"Warning", u"打开文件地址失败", buttons=QtWidgets.QMessageBox.Ok,
                                          defaultButton=QtWidgets.QMessageBox.Ok)
        else:
            QtWidgets.QMessageBox.information(self, u"Notice", u"数据集路径为:" + str(self.openfile_name_dataset), buttons=QtWidgets.QMessageBox.Ok,
                                              defaultButton=QtWidgets.QMessageBox.Ok)

采集数据

当检测到目标存在时,需要进行数据保存,调用该函数。从D435i中获取帧作为参数。将深度帧与彩色帧对齐,获取深度图与彩色图。按照时间格式创建数据保存的文件夹,可以选择保存四种数据格:color:彩色图;depth:原始深度图npy格式;depthjpg与可视化后的彩色图。

python 复制代码
    def save_dataset(self, frames):


        align_to = rs.stream.color
        align = rs.align(align_to)  # 对齐

        aligned_frames = align.process(frames)
        aligned_depth_frame = aligned_frames.get_depth_frame()
        color_frame = aligned_frames.get_color_frame()
        depth_image = np.asanyarray(aligned_depth_frame.get_data())
        depth_data = np.asanyarray(aligned_depth_frame.get_data(), dtype="uint16")
        color_image = np.asanyarray(color_frame.get_data())


        t1 = time.strftime("%Y_%m_%d_%H_%M", time.localtime())
        if not self.openfile_name_dataset:
            QtWidgets.QMessageBox.warning(self, u"Warning", u"请先选择数据集地址", buttons=QtWidgets.QMessageBox.Ok,
                                          defaultButton=QtWidgets.QMessageBox.Ok)
            return

        save_path = os.path.join(self.openfile_name_dataset, "outfile", t1)
        os.makedirs(save_path, exist_ok=True)
        os.makedirs(os.path.join(save_path, "color"), exist_ok=True)
        os.makedirs(os.path.join(save_path, "depth"), exist_ok=True)
        os.makedirs(os.path.join(save_path, "depthjpg"), exist_ok=True)
        os.makedirs(os.path.join(save_path, "depth_mapped_image"), exist_ok=True)
        saved_count = int(time.time() * 1000) #毫秒级的时间戳


        depth_mapped_image = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.03), cv2.COLORMAP_JET)

        # 彩色图片保存为png格式
        cv2.imwrite(save_path + "/color/" + "{}".format(saved_count) + '.jpg', color_image)
        # -----------深度图保存信息----------------#
        # 深度信息由采集到的float16直接保存为npy格式
        np.save(os.path.join(save_path, "depth", "{}".format(saved_count)), depth_data)  #
        # 黑白图
        # 使用jpg格式保存的图片,图像采集错误还能肉眼发现
        cv2.imwrite(save_path + "/depthjpg/" + "{}.jpg".format(saved_count), depth_image)

        # 渲染的图片
        cv2.imwrite(save_path + "/depth_mapped_image/"+"{}.jpg".format(saved_count), depth_mapped_image)
        return True

目标检测信息

根据选择掩码阶段选择的四个坐标位置生成mask应用到图像上,达到遮蔽区域检测的目的。实现mask后查看掩码具体位置,然后进入检测逻辑,返回检测信息以及数据保存位。

python 复制代码
    def detect(self, name_list, img):

        #(1, 3, 480, 640) [[[145 146 143], [148 149 146
        # ]]]
        showimg = img

        hl1 = self.mouse_positions[0][1]  # 监测区域高度距离图片顶部比例
        wl1 = self.mouse_positions[0][0]  # 监测区域高度距离图片左部比例
        hl2 = self.mouse_positions[1][1]  # 监测区域高度距离图片顶部比例
        wl2 = self.mouse_positions[1][0]  # 监测区域高度距离图片左部比例
        hl3 = self.mouse_positions[3][1]  # 监测区域高度距离图片顶部比例
        wl3 = self.mouse_positions[3][0]  # 监测区域高度距离图片左部比例
        hl4 = self.mouse_positions[2][1]  # 监测区域高度距离图片顶部比例
        wl4 = self.mouse_positions[2][0]  # 监测区域高度距离图片左部比例
        mask = np.zeros([img.shape[0], img.shape[1]], dtype=np.uint8)
        pts = np.array([[int(img.shape[1] * wl1), int(img.shape[0] * hl1)],  # pts1
                            [int(img.shape[1] * wl2), int(img.shape[0] * hl2)],  # pts2
                            [int(img.shape[1] * wl3), int(img.shape[0] * hl3)],  # pts3
                            [int(img.shape[1] * wl4), int(img.shape[0] * hl4)]], np.int32)
        cv2.fillPoly(mask, [pts], (255, 255, 255))
        mask = 255 - mask

        # 应用mask:将mask为0的部分设置为黑色(0,0,0)
        img = cv2.add(img, np.zeros(np.shape(img), dtype=np.uint8), mask=mask)
        # 2========================================================================================
        if not self.border:
        # 只显示一次
            # 定义框的颜色和线宽
            border_color = (255, 0, 0)  # 红色
            border_thickness = 2
            cv2.polylines(img, [pts], True, border_color, border_thickness)
            self.border = True
        # 显示结果
            cv2.imshow('Image with Mask and Border', img)
            cv2.waitKey(0)
            cv2.destroyAllWindows()

        # 2========================================================================================


        with torch.no_grad():

            img = letterbox(img, new_shape=self.opt.img_size)[0]
            # Convert
            img = img[:, :, ::-1].transpose(2, 0, 1)  # BGR to RGB, to 3x416x416
            img = np.ascontiguousarray(img)
            img = torch.from_numpy(img).to(self.device)
            img = img.half() if self.half else img.float()  # uint8 to fp16/32
            img /= 255.0  # 0 - 255 to 0.0 - 1.0
            if img.ndimension() == 3:
                img = img.unsqueeze(0)
            # Inference
            # 1==============================================================================================================


                # 1========================================================================================
            pred = self.model(img, augment=self.opt.augment)[0]
            # Apply NMS
            pred = non_max_suppression(pred, self.opt.conf_thres, self.opt.iou_thres, classes=self.opt.classes,
                                       agnostic=self.opt.agnostic_nms)
            info_show = ""
            info_show_target = ""
            # Process detections
            self.info_show_int = 1
            for i, det in enumerate(pred):
                if det is not None and len(det):
                    # 3=====================================================================================
                    condition = (det[:, 5] == 0.0) & (det[:, 4] > 0.6)
                    if condition.any():
                        #print("有人员进入监测区域")
                        info_show_target = "有人员进入检测区域"
                        self.info_show_int = 0
                    else:

                        info_show_target = "无人员进入检测区域"
                        self.info_show_int = 1

                    # 3================================================================================================================================================================
                    # Rescale boxes from img_size to im0 size
                    det[:, :4] = scale_coords(img.shape[2:], det[:, :4], showimg.shape).round()
                    for *xyxy, conf, cls in reversed(det):
                        label = '%s %.2f' % (self.names[int(cls)], conf)
                        name_list.append(self.names[int(cls)])
                        single_info = plot_one_box2(xyxy, showimg, label=label, color=self.colors[int(cls)], line_thickness=2)
                        # print(single_info)
                        info_show = info_show + single_info + "\n"
        return info_show_target, self.info_show_int

视频帧操作逻辑

打开D435i,获取彩色图,要将彩色图copy一份再送入detect检测逻辑,不然会导致最后保存的数据还有检测的目标框。

python 复制代码
   def show_video_frame(self):
        frames = self.pipeline.wait_for_frames()

        color_frame = frames.get_color_frame()
        #在此处就获取帧,后面获取帧会导致获取color含有检测框
        # depth_frame = frames.get_depth_frame()
        if not color_frame:
            self.finish_detect()
            return
        color_image = np.asanyarray(color_frame.get_data())
        color_image_detect = color_image.copy()
        info_show, info_show_int = self.detect([], color_image_detect)  # 检测结果写入到原始img上

        #print(info_show)
        if info_show_int == 0:
            #print("---开始处理保存数据程序---")
            flag = self.save_dataset(frames)
            if flag:
                #print("数据保存成功")
                info_show += " 数据保存成功"
        elif info_show_int == 1:
            #print("---停止保存数据程序---")
            info_show += " 停止保存数据"

        # 显示检测信息和图像
        self.ui.textBrowser.setText(info_show)
        show = cv2.resize(color_image_detect, (640, 480))
        self.result = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)
        showImage = QtGui.QImage(self.result.data, self.result.shape[1], self.result.shape[0],
                                 QtGui.QImage.Format_RGB888)
        self.ui.label.setPixmap(QtGui.QPixmap.fromImage(showImage))
        self.ui.label.setScaledContents(True)

参考

项目UI主要参考使用PyQt5为YoloV5添加界面(一)_pyqt pyvista-CSDN博客

YOLOv5区域入侵检测【附完整代码以及视频演示】_yolov5入侵检测-CSDN博客

pyqt5学习:Python Qt 简介 - 白月黑羽

相关推荐
goomind3 小时前
YOLOv8实战bdd100k自动驾驶目标识别
人工智能·深度学习·yolo·计算机视觉·目标跟踪·自动驾驶·bdd100k
博雅智信3 小时前
人工智能-自动驾驶领域
人工智能·python·深度学习·yolo·机器学习·计算机视觉·自动驾驶
风采臣*⁂6 小时前
完成cuda-gpu安装成功(new_env) D:\Miniconda3\envs\new_env>conda clean --all
yolo
代码小狗Codog20 小时前
WIDER FACE数据集转YOLO格式
人工智能·yolo·目标跟踪
Coovally AI模型快速验证1 天前
YOLO系列发展历程:从YOLOv1到YOLO11,目标检测技术的革新与突破
人工智能·yolo·目标检测·机器学习·计算机视觉
goomind2 天前
YOLOv8实战道路裂缝缺陷识别
人工智能·yolo·目标检测·计算机视觉·pyqt5·裂缝检测·裂缝识别
lanbo_ai2 天前
基于yolov8的SAR影像目标检测系统,支持图像、视频和摄像实时检测【pytorch框架、python源码】
pytorch·python·yolo
千码君20162 天前
PyQt5:一个逗号引发的闪退血案
python·excel·pyqt5·tuple·闪退
阿_旭3 天前
【实战教程】使用YOLO和EasyOCR实现视频车牌检测与识别【附源码】
深度学习·yolo·车牌识别·easyocr
数学人学c语言3 天前
yolov11剪枝、蒸馏、加注意力
人工智能·yolo·剪枝