linux桌面小程序开发日记-5(pyqt5+yolov5)

Linux小程序开发日记-5

哈喽,大家好,好久不见,咱今天,又开始我的小程序开发啦。

然后这几天呢,我开始记录开发这个小程序的视频啦,欢迎大家来康康。

视频链接

linux桌面小程序开发日记-2

最后一篇博客地址:https://blog.csdn.net/Liuchengzhizhi/article/details/123692365

B站视频:https://www.bilibili.com/video/BV1rZ4y1B7t8?share_source=copy_web

源码:https://gitee.com/wx_b915676bb6/yolo-pyqt.git

记得上一次咱们可以将识别的数据显示在旁边的表格中,但是呢还有很多内容没有加上去。所以这一次,咱把这个GUI没有完善的内容咱把他们完善好

今天的任务:

  • 将加载UI界面的,单独放在一个python文件内
  • 对识别的内容,进行一个排序,能够统计标签的个数
  • 对这些识别的标签,进行表格的匹配,显示价格
  • 进行一个计价

第一步:重新优化UI代码

这里呢,我单独的将ui代码,放在了我的food_ui文件里面

在这里插入图片描述

代码如下:

# @Author: Cjuicy 
# @Date: 2022-03-21 16:07:16 
# @Last Modified by:   Cjuicys 
# # @Last Modified time: 2022-03-21 16:07:16  */

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *



class Ui_MainWindow(object):
    '''程序界面布局'''
    def set_ui(self):
        self.__layout_main = QtWidgets.QGridLayout()           #总布局
        self.__layout_fun_button1 = QtWidgets.QHBoxLayout()      #按键布局1
        self.__layout_fun_button2 = QtWidgets.QHBoxLayout()      #按键布局2
        self.__layout_data_show = QtWidgets.QVBoxLayout()       #数据(视频)显示布局
        self.__layout_list_show  = QtWidgets.QVBoxLayout()          #表格布局

        self.button_confirm = QtWidgets.QPushButton('确认') #建立用于打开摄像头的按键
        self.button_settle_accounts = QtWidgets.QPushButton('结账') #建立结账的按钮
        self.list_show =  QtWidgets.QTableWidget(6,3)                          #建立表格
        self.label_account = QtWidgets.QLabel("总价:")                          #建立label

        '''set butten size '''
        self.button_confirm.setMinimumHeight(50)                #设置按键大小
        self.button_settle_accounts.setMinimumHeight(50)
        self.label_account.setMinimumHeight(50)
        

        # self.button_close.move(10,100)                      #移动按键  这句话去掉好像也没关系
        '''设置标签的格式'''
        font = QtGui.QFont()
        font.setPixelSize(18)
        self.label_account.setFont(font)

        '''设置表格'''
        self.list_show.setHorizontalHeaderLabels(["名称","数量","单价"])
        self.list_show.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)# adaptive size
        self.list_show.setEditTriggers(QAbstractItemView.EditTrigger(False))    #将表格的内容设为不可编辑
        '''信息显示'''
        self.label_show_camera = QtWidgets.QLabel()   #定义显示视频的Label
        self.label_show_camera.setFixedSize(641,481)    #给显示视频的Label设置大小为641x481
        '''把按键加入到按键布局中'''
        self.__layout_fun_button1.addWidget(self.button_confirm) #把重新确认的按键放到按键布局中
        # self.__layout_fun_button1.addWidget(self.button_close)       #把退出程序的按键放到按键布局中
        self.__layout_fun_button2.addWidget(self.button_settle_accounts) #把结账的按键放到按键布局中
        '''把表格加入到表格布局中'''
        self.__layout_list_show.addWidget(self.list_show)           #将表格添加到表格布局中
        self.__layout_list_show.addWidget(self.label_account) #将总价label添加到表格布局中


        '''把某些控件加入到总布局中'''
        self.__layout_main.addLayout(self.__layout_list_show,0,0)            #将表格布局添加到总布局中
        self.__layout_main.addLayout(self.__layout_fun_button1,1,1)      #把按键布局加入到总布局中
        self.__layout_main.addLayout(self.__layout_fun_button2,1,0)      #把按键布局加入到总布局中
        self.__layout_main.addWidget(self.label_show_camera,0,1)        #把用于显示视频的Label加入到总布局中
        
        # '''总布局布置好后就可以把总布局作为参数传入下面函数'''
        # self.setLayout(self.__layout_main) #到这步才会显示所有控件
        # 返回所有的页面布局
        return self.__layout_main
 

第二步 读取csv文件

我把他放在了price_utils.py里面

在这里插入图片描述

代码如下

# 
# @Author: Cjuicy 
# @Date: 2022-03-21 20:25:16 
# @Last Modified by:   Cjuicys 
# @Last Modified time: 2022-03-21 20:25:16 
# 
'''
存放价钱的读函数
'''
import csv

from pip import main


# 读取csv文件获得价钱信息
def get_price_info():
    price_info = {}
    with open('priceInfo.csv', 'r') as csvfile: # 此目录即是当前项目根目录
        spamreader = csv.reader(csvfile)
        # 逐行遍历csv文件,按照字典存储用户名与密码
        for row in spamreader:
            price_info[row[0]] = row[1]
    return price_info

第三步 修改我的主文件

修改主文件,将我想要的内容显示在表格上,同时进行一个乘法计算

主文件:
在这里插入图片描述

关键代码如下

  #这是初始化函数里面的
  self.ui = Ui_MainWindow()
  self.price_info = price_utils.get_price_info()      # 初始化 获取表格价钱信息(应为量少,可以这么做,安全等其他因素,应该走数据库)
  layout_main = self.ui.set_ui()                       #初始化页面布局,并获取所有的页面布局


 #这里是处理标签的函数,并将它显示在GUI 表格上
    def set_labels(self ,labels ):
        self.ui.list_show.clearContents()       #对表格先进行一个清空
        labels = pd.value_counts(labels)        #对标签数组进行重复个数统计

        total_price = 0
        
        if len(labels.index.values) != 0:
            for i in range(len(labels.index.values)):
                label_num = str(labels.values[i])             #获取对应标签的个数
                self.ui.list_show.setItem(i,0,QTableWidgetItem(labels.index.values[i]))     #添加对应标签名字
                self.ui.list_show.setItem(i,1,QTableWidgetItem(label_num))                #添加对应标签个数
                
                # 判断字典内是否有该key,有添加对应价钱数据,没有则选择默认值(99元)
                if labels.index.values[i] in self.price_info :
                    label_price = str(self.price_info[labels.index.values[i]])
                    self.ui.list_show.setItem(i,2,QTableWidgetItem(label_price))
                    # 计算总价
                    total_price = total_price + (float(label_price) * int(label_num))
                else :
                    self.ui.list_show.setItem(i,2,QTableWidgetItem("99"))
                    # 计算总价
                    total_price = total_price + (float(99) * int(label_num))
        
        account = "总价: "+ str(total_price)
        self.ui.label_account.setText(account)

所有代码如下

# 
# @Author: Cjuicy 
# @Date: 2022-03-21 16:00:23 
# @Last Modified by:   Cjuicys 
# @Last Modified time: 2022-03-21 16:00:23 
# 


from cProfile import label
import sys
from unittest import result
import cv2
import time
import argparse
import random
import torch
import numpy as np
import pandas as pd
import torch.backends.cudnn as cudnn

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from utils.torch_utils import select_device
from models.experimental import attempt_load
from utils.general import check_img_size, non_max_suppression, scale_coords
from utils.datasets import letterbox
from utils.plots import plot_one_box2
from utils.torch_utils import select_device, load_classifier, time_synchronized

from ui.food_ui import Ui_MainWindow # 导入detect_ui的界面
from utils import price_utils


class Ui_Logic_Window(QtWidgets.QWidget):
    def __init__(self,parent=None):
        super().__init__(parent) #父类的构造函数
 
        self.timer_video = QtCore.QTimer() #定义定时器,用于控制显示视频的帧率
        self.cap = cv2.VideoCapture()       #视频流
        
        self.ui = Ui_MainWindow()
        self.price_info = price_utils.get_price_info()      # 初始化 获取表格价钱信息(应为量少,可以这么做,安全等其他因素,应该走数据库)

        layout_main = self.ui.set_ui()                       #初始化页面布局,并获取所有的页面布局

        '''将总布局作为参数传入下面函数'''
        self.setLayout(layout_main) #到这步才会显示所有控件

        self.slot_init()                    #初始化槽函数


        self.num_stop = 1 # 暂停与播放辅助信号,note:通过奇偶来控制暂停与播放
        self.output_folder = 'output/'
        self.vid_writer = None

        # 权重初始文件名
        #模型路径
        self.openfile_name_model = "./weights/yolov5s.pt"
        self.model_init()
        # 打开摄像头
        self.button_camera_open()

    
 
    '''初始化所有槽函数'''
    def slot_init(self):
        
        self.ui.button_confirm.clicked.connect(self.button_video_stop)    #若该按键被点击,则调用button_confirm()
        self.timer_video.timeout.connect(self.show_video_frame) # 定时器超时,将槽绑定至show_video_frame
    
    # ========================================================


    # 加载相关参数,并初始化模型
    def model_init(self):
        # 模型相关参数配置
        parser = argparse.ArgumentParser()
        parser.add_argument('--weights', nargs='+', type=str, default='weights/yolov5s6.pt', help='model.pt path(s)')
        parser.add_argument('--source', type=str, default='data/images', 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='0', 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)
        # 默认使用opt中的设置(权重等)来对模型进行初始化
        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

        # 若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
        #  Second-stage classifier
        classify = False
        if classify:
            modelc = load_classifier(name='resnet101', n=2)  # initialize
            modelc.load_state_dict(torch.load('weights/resnet101.pt', map_location=self.device)['model']).to(self.device).eval()

        # 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)




    # 目标检测
    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 = ""

            # 定义标签变量名
            label_names = ""

            # Process detections
            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)])
                        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"

                        # 新添加的标签信息,提交给pyqt5 处理
                        label_names = label_names+","+self.names[int(cls)]
            # 转化为数组    
            label_names = label_names.split(",")
            # 去掉空值
            label_names = [i for i in label_names if(len(str(i))!=0)]

        return  info_show , label_names

    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 button_camera_open(self):
        

        print("Open camera to detect")
        # 设置使用的摄像头序号,系统自带为0
        camera_num = 0
        # 打开摄像头
        self.cap = cv2.VideoCapture(camera_num)
        # 判断摄像头是否处于打开状态
        bool_open =self.cap.open(camera_num)
        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.timer_video.start(30)

    # 定义视频帧显示操作
    def show_video_frame(self):
        name_list = []
        flag, img = self.cap.read()
        if img is not None:
            info_show , label_names = self.detect(name_list, img) # 检测结果写入到原始img上
            self.vid_writer.write(img) # 检测结果写入视频
            print(info_show)

            # print(label_names)
            self.set_labels(label_names)
            # 检测信息显示在界面
            # self.ui.textBrowser.setText(info_show)
            

            show = cv2.resize(img, (640, 480)) # 直接将原始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.ui.label.setPixmap(QtGui.QPixmap.fromImage(showImage))
            self.ui.label_show_camera.setPixmap(QtGui.QPixmap.fromImage(showImage))  #往显示视频的Label里 显示QImage
            # self.ui.label.setScaledContents(True)  # 设置图像自适应界面大小

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


    # 暂停与继续检测
    def button_video_stop(self):
        self.timer_video.blockSignals(False)
        # 暂停检测
        # 若QTimer已经触发,且激活
        if self.timer_video.isActive() == True and self.num_stop%2 == 1:
            self.ui.button_confirm.setText(u'重新确认') # 当前状态为暂停状态
            self.num_stop = self.num_stop + 1 # 调整标记信号为偶数
            self.timer_video.blockSignals(True)
            # 启动结账按钮
            self.ui.button_settle_accounts.setDisabled(False)
        # 继续检测
        else:
            self.num_stop = self.num_stop + 1
            self.ui.button_confirm.setText(u'确认')
            self.ui.button_settle_accounts.setDisabled(False)


# 处理label集的函数
    def set_labels(self ,labels ):
        self.ui.list_show.clearContents()       #对表格先进行一个清空
        labels = pd.value_counts(labels)        #对标签数组进行重复个数统计

        total_price = 0
        
        if len(labels.index.values) != 0:
            for i in range(len(labels.index.values)):
                label_num = str(labels.values[i])             #获取对应标签的个数
                self.ui.list_show.setItem(i,0,QTableWidgetItem(labels.index.values[i]))     #添加对应标签名字
                self.ui.list_show.setItem(i,1,QTableWidgetItem(label_num))                #添加对应标签个数
                
                # 判断字典内是否有该key,有添加对应价钱数据,没有则选择默认值(99元)
                if labels.index.values[i] in self.price_info :
                    label_price = str(self.price_info[labels.index.values[i]])
                    self.ui.list_show.setItem(i,2,QTableWidgetItem(label_price))
                    # 计算总价
                    total_price = total_price + (float(label_price) * int(label_num))
                else :
                    self.ui.list_show.setItem(i,2,QTableWidgetItem("99"))
                    # 计算总价
                    total_price = total_price + (float(99) * int(label_num))
        
        account = "总价: "+ str(total_price)
        self.ui.label_account.setText(account)



       

if __name__ == '__main__':
    app =  QtWidgets.QApplication(sys.argv)
    current_ui =Ui_Logic_Window()                 #实例化Ui_MainWindow
    current_ui.show()                               #调用ui的show()以显示。同样show()是源于父类QtWidgets.QWidget的
    # current_ui = UI_Logic_Window()
    # current_ui.show()
    sys.exit(app.exec_())


最后

附上一张咱运行后的截图

在这里插入图片描述

最后的最后,谢谢叼着骨头的猫,都是在他的项目上,咱修改出来的代码

叼着骨头的猫yyds!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值