行人检测之搭建pyqt界面

本文介绍了如何使用yolov5训练的模型,在Qt环境中设计一个用户界面,包括控件布局、图片和视频检测功能,以及与模型参数的交互。
摘要由CSDN通过智能技术生成

 为行人检测项目添加一个可视化检测界面,利用训练的yolov5来设计一个qt界面

设计界面

打开Qt designer,自定义控件摆放位置,

摆放完控件后保存得到一个ui文件,利用Pyuic工具转变为.py文件。

新建立一个.py文件负责界面控制,使用connect,将按钮与操作对应起来。

打开图片

打开权重文件

加载相关参数,并初始化模型

这部分是将detct.py文件进行修改得到

#加载相关参数,并初始化模型
    def model_init(self):
        #11111
        parser = argparse.ArgumentParser()
        parser.add_argument('--weights', nargs='+', type=str,
                            default=r'D:\yolov5\yolov5-5.0\yolov5-5.0\runs\train\exp11\weights\best.pt',
                            help='model.pt path(s)')
        parser.add_argument('--source', type=str, default=r'D:\yolov5\yolov5-5.0\yolov5-5.0\three.jpg', help='source')  # file/folder, 0 for webcam
        parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
        parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold')
        parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS')
        parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
        parser.add_argument('--view-img', action='store_true', help='display results')
        parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
        parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
        parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
        parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
        parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
        parser.add_argument('--augment', action='store_true', help='augmented inference')
        parser.add_argument('--update', action='store_true', help='update all models')
        parser.add_argument('--project', default='runs/detect', help='save results to project/name')
        parser.add_argument('--name', default='exp', help='save results to project/name')
        parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
        self.opt = parser.parse_args()
        print(self.opt)
        #22222
        source, weights, view_img, save_txt, imgsz =self.opt.source, self.opt.weights, self.opt.view_img, self.opt.save_txt, self.opt.img_size
        #save_img = not opt.nosave and not source.endswith('.txt')  # save inference images
        # 若openfile_name_model不为空,则使用此权重进行初始化
        if self.openfile_name_model:
            weights = self.openfile_name_model
            print("Using button choose model")

        self.device = select_device(self.opt.device)
        self.half = self.device.type != 'cpu'  # half precision only supported on CUDA

        cudnn.benchmark = True
        # Load model
        self.model = attempt_load(weights, map_location=self.device)  # load FP32 model
        stride = int(self.model.stride.max())  # model stride
        self.imgsz = check_img_size(imgsz, s=stride)  # check img_size
        if self.half:
            self.model.half()  # to FP16

            # Get names and colors
            self.names = self.model.module.names if hasattr(self.model, 'module') else self.model.names
            self.colors = [[random.randint(0, 255) for _ in range(3)] for _ in self.names]
            print("model initial done")
            # 设置提示框
            QtWidgets.QMessageBox.information(self, u"Notice", u"模型加载完成", buttons=QtWidgets.QMessageBox.Ok,
                                               defaultButton=QtWidgets.QMessageBox.Ok)

#11111部分改自detect.py文件以下部分,注意要将所有的opt前加上self #22222部分改自detect.py文件以下部分,因为加入了可以选择权重文件的步骤,所以加了对openfile_name_model是否为空的判断,注意添加self.

检测

一个检测的方法,没有直接与控件链接,而是在选择是图片或视频检测时在调用

 def detect(self, name_list, img):
        '''
        :param name_list: 文件名列表
        :param img: 待检测图片
        :return: info_show:检测输出的文字信息
        '''
        showimg = img
        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
            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 = ""
            # Process detections
            num=0
            for i, det in enumerate(pred):
                if det is not None and len(det):
                    # 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)])
                        # label = f'{self.names[int(cls)]} {conf:.2f}'
                        if self.names[int(cls)]=='person':
                            label = '%s %.2f' % (self.names[int(cls)], conf)
                            name_list.append(self.names[int(cls)])
                            plot_one_box(xyxy, showimg, label=label, color=self.colors[int(cls)], line_thickness=3)
                            num+=1

        print(num)
        return  num

检测图片

    def button_image_open(self):
        print('button_image_open')
        name_list = []
        try:
            img_name, _ = QFileDialog.getOpenFileName(self, '请选择图片', '.', '图像文件(*.jpg *.jpeg *.png, *.mp4)')
        except OSError as reason:
            print('文件打开出错啦!核对路径是否正确'+ str(reason))
        else:
        # 判断图片是否为空
            if not img_name:
                QtWidgets.QMessageBox.warning(self, u"Warning", u"打开图片失败", buttons=QtWidgets.QMessageBox.Ok,
                                              defaultButton=QtWidgets.QMessageBox.Ok)
            else:
                img = cv2.imread(img_name)
                print("img_name:", img_name)

                # self.label.setPixmap(QtGui.QPixmap.fromImage(self.QtImg))
                # self.label.setScaledContents(True)
                info_show = self.detect(name_list, img)
                self.label_3.setText("检测到的人数:"+str(info_show))
                # print(info_show)
                self.label_2.setScaledContents(True)  # 需要在图片显示之前进行设置
                self.label_2.setPixmap(QPixmap(img_name))  # 运行之后QLabel就可以自适应显示图片了
                # 获取当前系统时间,作为img文件名
                now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time()))
                file_extension = img_name.split('.')[-1]
                # new_filename
                new_filename = str(now) + '.' + file_extension  # 获得文件后缀名
                # file_path = self.output_folder + 'img_output/' + new_filename
                # file_path = self.output_folder + 'img_output/'

                file_path = self.output_folder + 'img_output/' + new_filename
                print(file_path)
                cv2.imwrite(file_path, img)
                self.label_4.setText("输出结果存储到:" + file_path)

                # 检测结果显示在界面
                # self.textBrowser.setText(info_show)
                self.result = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
                self.result = cv2.resize(self.result, (640, 480), interpolation=cv2.INTER_AREA)
                self.QtImg = QtGui.QImage(self.result.data, self.result.shape[1], self.result.shape[0],
                                          QtGui.QImage.Format_RGB32)
                self.label.setPixmap(QtGui.QPixmap.fromImage(self.QtImg))
                self.label.setScaledContents(True)  # 设置图像自适应界面大小

读取视频

    def button_video_open(self):
        video_name, _ = QtWidgets.QFileDialog.getOpenFileName(self, "打开视频", "yolov5-5.0/", "*.mp4;;*.avi;;All Files(*)")
        flag = self.cap.open(video_name)
        if not flag:
            QtWidgets.QMessageBox.warning(self, u"Warning", u"打开视频失败", buttons=QtWidgets.QMessageBox.Ok,
                                          defaultButton=QtWidgets.QMessageBox.Ok)
        else:
            # -------------------------写入视频----------------------------------#
            fps, w, h, save_path = self.set_video_name_and_path()
            self.vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
            self.label_4.setText("输出结果存储到:" + save_path)

            self.timer_video.start(30)  # 以30ms为间隔,启动或重启定时器
            # 进行视频识别时,关闭其他按键点击功能
            self.pushButton.setDisabled(True)
            self.pushButton_2.setDisabled(True)
            self.pushButton_5.setDisabled(True)

 读取摄像头

# 打开摄像头检测
    def button_camera_open(self):
        print("Open camera to detect")
        # 设置使用的摄像头序号,系统自带为0
        camera_num = 0
        # 打开摄像头
        self.cap = cv2.VideoCapture(camera_num)
        # 判断摄像头是否处于打开状态
        bool_open = self.cap.isOpened()
        if not bool_open:
            QtWidgets.QMessageBox.warning(self, u"Warning", u"打开摄像头失败", buttons=QtWidgets.QMessageBox.Ok,
                                          defaultButton=QtWidgets.QMessageBox.Ok)
        else:
            fps, w, h, save_path = self.set_video_name_and_path()
            fps = 5  # 控制摄像头检测下的fps,Note:保存的视频,播放速度有点快,我只是粗暴的调整了FPS
            self.vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
            self.label_4.setText("输出结果存储到:" + save_path)
            self.timer_video.start(30)
            self.pushButton.setDisabled(True)
            self.pushButton_2.setDisabled(True)
            self.pushButton_5.setDisabled(True)

读取时间与视频显示操作

读取时间用于视频和摄像头检查时使用时间作为结果存储的文件名,而视频帧操作是在labe控件上显示视频,在上面的读取视频和打开摄像头操作都设置有一个定时器,而定时器一旦超时就会定时器超时,就会将槽绑定至show_video_frame

    def set_video_name_and_path(self):
        # 获取当前系统时间,作为img和video的文件名
        now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time()))
        # if vid_cap:  # video
        fps = self.cap.get(cv2.CAP_PROP_FPS)
        w = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        h = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        # 视频检测结果存储位置
        save_path = self.output_folder + 'video_output/' + now + '.mp4'
        return fps, w, h, save_path


# 定义视频帧显示操作
    def show_video_frame(self):
        name_list = []
        flag, img = self.cap.read()
        show=img
        if img is not None:
            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.label_2.setPixmap(QtGui.QPixmap.fromImage(showImage))
            self.label_2.setScaledContents(True)  # 设置图像自适应界面大小
            info_show = self.detect(name_list, img)  # 检测结果写入到原始img上
            self.label_3.setText("检测到的人数:" + str(info_show))
            self.vid_writer.write(img)  # 检测结果写入视频
            print(info_show)
            show=img
            # show = cv2.resize(img, (491,400))  # 直接将原始img上的检测结果进行显示
            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.label.setPixmap(QtGui.QPixmap.fromImage(showImage))
            self.label.setScaledContents(True)  # 设置图像自适应界面大小

        else:
            self.timer_video.stop()
            # 读写结束,释放资源
            self.cap.release()  # 释放video_capture资源
            self.vid_writer.release()  # 释放video_writer资源
            self.label.clear()
            self.label_2.clear()
            # 视频帧显示期间,禁用其他检测按键功能
            self.pushButton.setDisabled(False)
            self.pushButton_2.setDisabled(False)
            self.pushButton_5.setDisabled(False)

 参考了博主‘叼着狗骨头的猫’以及在B站的一些视频,本文章仅记录自己学习过程,防止忘得太快。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值