二、页面布局

一、界面

我做的界面大概思路:点击 上传图片,显示待检验的照片
点击 U-net模型检测 会使用已经训练好的U-net模型进行预测
点击 OpenCV统计 会将预测结果进行轮廓检测,并统计所有轮廓的面积
处理结果 这个groupBox中进行显示

大致界面如下:
在这里插入图片描述
详细界面布局如下:
在这里插入图片描述

二、关联PyCharm

将已经设置好的UI界面保存为yy.ui
将该文件放到自己的项目中,例如我放到的位置如下:
在这里插入图片描述
创建一个测试文件my_UI.py,在同级目录下

三、代码块讲解

1,初始化

其中:
self.ui = QUiLoader().load('yy.ui'),指定Qt页面的路径,因为我这个是同一级目录故之间导入即可yy.ui
这行代码的意思为:将yy.ui这个UI创建一个名为ui的对象
self.output_size = 480,规定图像的大小
其他的为加载U-net网络模型

    def __init__(self):# 从文件中加载UI定义# 从 UI 定义中动态 创建一个相应的窗口对象# 注意:里面的控件对象也成为窗口对象的属性了# 比如 self.ui.button , self.ui.textEditself.ui = QUiLoader().load('yy.ui')  # 这里的参数为ui的路径,对这个ui文件创建对象ui"""对某个控件进行操作会产生一个signal,常通过slot来进行处理signalslot就是通过clicked.connect来绑定某个函数,这个函数用于处理signal"""self.output_size = 480# 加载网络,图片单通道,分类为1。net = UNet(n_channels=1, n_classes=1)# 将网络拷贝到deivce中net.to(device=device)# 加载模型参数net.load_state_dict(torch.load('G:/PyCharm/workspace/my_test/yy_unet/best_model1.pth', map_location=device))  # todo 模型位置# 测试模式net.eval()self.model = net

2,处理signal,绑定slot函数

为每一个button绑定对应的处理函数,其中pushButton、pushButton_2、pushButton_3yy.ui页面中的button对象,ui中必须有这些名称的button才行
pushButton:打开文件,获取预测图片路径
pushButton_2:通过U-net网络模型预测
pushButton_3:通过OpenCV获取轮廓个数以及面积(像素)

    def window_init(self):self.ui.pushButton.clicked.connect(self.file)self.ui.pushButton_2.clicked.connect(self.unet)self.ui.pushButton_3.clicked.connect(self.opencv)

3,file函数讲解

点击pushButton即可选择图片,通过file函数进行处理
image_file 存放照片的路径
后面为例存放处理的图片,通过os.path.basename(image_file)单独抽取了图片的名称,方面后续存储照片命名
self.ui.label_5.setPixmap(image_file),通过label_5进行展示照片,也就是选择照片,然后展示一下

# 打开图片def file(self):print("已点击file")FileDialog = QFileDialog(self.ui.pushButton)# 设置可以打开任何文件FileDialog.setFileMode(QFileDialog.AnyFile)# 文件过滤Filter = "(*.jpg,*.png,*.jpeg,*.bmp,*.gif)|*.jgp;*.png;*.jpeg;*.bmp;*.gif|All files(*.*)|*.*"image_file, _ = FileDialog.getOpenFileName(self.ui.pushButton, 'open file', './','Image files (*.jpg *.gif *.png *.jpeg)')  # 选择目录,返回选中的路径 'Image files (*.jpg *.gif *.png *.jpeg)'# 判断是否正确打开文件if not image_file:QMessageBox.warning(self.ui.pushButton, "警告", "文件错误或打开文件失败!", QMessageBox.Yes)returnprint("读入文件成功")print(image_file)self.image_file = image_fileself.base_image = os.path.basename(image_file)print(self.image_file)print(self.base_image)# 设置标签的图片self.ui.label_5.setPixmap(image_file)self.ui.label_5.setScaledContents(True)  # 让图片自适应 label 大小

4,unet函数讲解

点击pushButton_2即可运行到unet函数进行处理
model = self.model,加载模型

# 开始检测def unet(self):print("U-net...")model = self.model # 加载模型output_size = self.output_size # 规定输入图片的大小img = cv2.imread(self.image_file)# 读取file函数所打开的图片origin_shape = img.shape# print(origin_shape)# 转为灰度图img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)img = cv2.resize(img, (512, 512))# 转为batch为1,通道为1,大小为512*512的数组img = img.reshape(1, 1, img.shape[0], img.shape[1])# 转为tensorimg_tensor = torch.from_numpy(img)# 将tensor拷贝到device中,只用cpu就是拷贝到cpu中,用cuda就是拷贝到cuda中。img_tensor = img_tensor.to(device=device, dtype=torch.float32)# 预测pred = self.model(img_tensor)# 提取结果pred = np.array(pred.data.cpu()[0])[0]# 处理结果pred[pred >= 0.5] = 255pred[pred < 0.5] = 0# 保存图片cv2.imwrite("E:/change_picture/{}".format(self.base_image), pred)# 将预测的结果进行保存# 将预测的图片通过label_6进行展示self.ui.label_6.setPixmap("E:/change_picture/{}".format(self.base_image))self.ui.label_6.setScaledContents(True)

5,opencv函数讲解

该函数的作用是在unet预测的结果之上,将已经识别出来的起毛起球绘制轮廓并且统计个数以及每个起毛起球的面积(像素)

    def opencv(self):print("start")print(self.base_image)print("E:/change_picture/{}".format(self.base_image))img = cv2.imread("E:/change_picture/{}".format(self.base_image))#cv2.imshow('img', img)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换为灰度图ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)  # 二值化  # 对图像进行二值处理,小于127为0,大于127为255contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)draw_img = img.copy()  # 注意一定要copy要不然会对原图进行改变!!!res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)  # -1表示显示所有轮廓,(0,0,225)BGR表示红色,2为轮廓粗细#cv2.imshow('-1 is All', res)cv2.imwrite("E:/change_picture/result/{}".format(self.base_image), res)  # 保存照片# cv2.waitKey(0)# cv2.destroyAllWindows()self.ui.label_7.setPixmap("E:/change_picture/result/{}".format(self.base_image))self.ui.label_7.setScaledContents(True)self.ui.plainTextEdit.clear()n = len(contours)  # 轮廓数量print(n)coutoursImg = []  # 创建绘制轮廓列表sum_all = 0for i in range(n):temp = np.zeros(draw_img.shape, np.uint8)  # 把图像转换为矩阵coutoursImg.append(temp)  # 向列表追加矩阵信息# 绘制轮廓:drawContours()"""绘制轮廓:drawContours()1、img2:等待绘制轮廓的图像2、coutours:要绘制的轮廓(与findContours()函数输出的coutours参数一致《list类型即:列表类型》)3、contourIdx:要绘制一条轮廓还是全部轮廓:如果参数是一个整数或者0表示绘制对应索引号的轮廓[如果是-1表示绘制全部轮廓]4、color:绘制颜色,用B,G,R格式表示5、thickness:表示绘制时的画笔粗细,如果为-1表示用实心绘制6、lineType:表示绘制线轮廓时的线形7、hierarchy:所输出的层次信息8、maxLevel:控制轮廓层次的深度(如果是0表示绘制地0层轮廓)9、offset:偏移参数使轮廓偏移一定位置用[ x , y ]坐标表示"""if cv2.contourArea(contours[i]) >= 0:#对轮廓面积进行筛选,要是太小的话就可以忽略不计sum_all = sum_all + cv2.contourArea(contours[i])print("第" + str(i + 1) + "个毛球的面积是:" + str(cv2.contourArea(contours[i])) + "个像素点")self.ui.plainTextEdit.appendPlainText("第" + str(i + 1) + "个毛球的面积是:" + str(cv2.contourArea(contours[i])) + "个像素点")#cv2.imshow("chulihou", draw_img)# 键盘输入检测,参数为显示时长,如果参数为0就是键盘按下退出显示cv2.waitKey()# 关闭所有窗口cv2.destroyAllWindows()self.ui.label_8.setText(str(len(contours)))self.ui.label_9.setText(str(sum_all))self.ui.label_10.setText("1级")

6,主函数

调用上面所定义的beyondyanyu类即可

if __name__=="__main__":app = QApplication([])gui = beyondyanyu()  #初始化gui.window_init()gui.ui.show() #将窗口控件显示在屏幕上app.exit(app.exec_())# 进行死循环展示

四、完整代码

import shutil
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import torch
from model.unet_model import UNet
import numpy as np
from PySide2.QtWidgets import QApplication, QMessageBox,QFileDialog,QMainWindow
from PySide2.QtUiTools import QUiLoader
import cv2
import os# 窗口主类
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')class beyondyanyu():def __init__(self):# 从文件中加载UI定义# 从 UI 定义中动态 创建一个相应的窗口对象# 注意:里面的控件对象也成为窗口对象的属性了# 比如 self.ui.button , self.ui.textEditself.ui = QUiLoader().load('yy.ui')  # 这里的参数为ui的路径,对这个ui文件创建对象ui"""对某个控件进行操作会产生一个signal,常通过slot来进行处理signalslot就是通过clicked.connect来绑定某个函数,这个函数用于处理signal"""self.output_size = 480# 加载网络,图片单通道,分类为1。net = UNet(n_channels=1, n_classes=1)# 将网络拷贝到deivce中net.to(device=device)# 加载模型参数net.load_state_dict(torch.load('G:/PyCharm/workspace/my_test/yy_unet/best_model1.pth', map_location=device))  # todo 模型位置# 测试模式net.eval()self.model = netdef window_init(self):self.ui.pushButton.clicked.connect(self.file)self.ui.pushButton_2.clicked.connect(self.unet)self.ui.pushButton_3.clicked.connect(self.opencv)# 打开图片def file(self):print("已点击file")FileDialog = QFileDialog(self.ui.pushButton)# 设置可以打开任何文件FileDialog.setFileMode(QFileDialog.AnyFile)# 文件过滤Filter = "(*.jpg,*.png,*.jpeg,*.bmp,*.gif)|*.jgp;*.png;*.jpeg;*.bmp;*.gif|All files(*.*)|*.*"image_file, _ = FileDialog.getOpenFileName(self.ui.pushButton, 'open file', './','Image files (*.jpg *.gif *.png *.jpeg)')  # 选择目录,返回选中的路径 'Image files (*.jpg *.gif *.png *.jpeg)'# 判断是否正确打开文件if not image_file:QMessageBox.warning(self.ui.pushButton, "警告", "文件错误或打开文件失败!", QMessageBox.Yes)returnprint("读入文件成功")print(image_file)  # 'C:\\', 默认C盘打开self.image_file = image_fileself.base_image = os.path.basename(image_file)print(self.image_file)print(self.base_image)# 设置标签的图片self.ui.label_5.setPixmap(image_file)  #输入为图片路径,比如当前文件内的logo.png图片# self.label.setFixedSize(600, 400)  # 设置显示固定尺寸,可以根据图片的像素长宽来设置self.ui.label_5.setScaledContents(True)  # 让图片自适应 label 大小# 开始检测def unet(self):print("U-net...")model = self.modeloutput_size = self.output_sizeimg = cv2.imread(self.image_file)origin_shape = img.shape# print(origin_shape)# 转为灰度图img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)img = cv2.resize(img, (512, 512))# 转为batch为1,通道为1,大小为512*512的数组img = img.reshape(1, 1, img.shape[0], img.shape[1])# 转为tensorimg_tensor = torch.from_numpy(img)# 将tensor拷贝到device中,只用cpu就是拷贝到cpu中,用cuda就是拷贝到cuda中。img_tensor = img_tensor.to(device=device, dtype=torch.float32)# 预测pred = self.model(img_tensor)# 提取结果pred = np.array(pred.data.cpu()[0])[0]# 处理结果pred[pred >= 0.5] = 255pred[pred < 0.5] = 0# 保存图片#im0 = cv2.resize(pred, self.origin_shape)cv2.imwrite("E:/change_picture/{}".format(self.base_image), pred)# 目前的情况来看,应该只是ubuntu下会出问题,但是在windows下是完整的,所以继续#self.right_img.setPixmap(QPixmap("images/tmp/single_result.jpg"))self.ui.label_6.setPixmap("E:/change_picture/{}".format(self.base_image))self.ui.label_6.setScaledContents(True)def opencv(self):print("start")print(self.base_image)print("E:/change_picture/{}".format(self.base_image))img = cv2.imread("E:/change_picture/{}".format(self.base_image))#cv2.imshow('img', img)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换为灰度图ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)  # 二值化  # 对图像进行二值处理,小于127为0,大于127为255contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)draw_img = img.copy()  # 注意一定要copy要不然会对原图进行改变!!!res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)  # -1表示显示所有轮廓,(0,0,225)BGR表示红色,2为轮廓粗细#cv2.imshow('-1 is All', res)cv2.imwrite("E:/change_picture/result/{}".format(self.base_image), res)  # 保存照片# cv2.waitKey(0)# cv2.destroyAllWindows()self.ui.label_7.setPixmap("E:/change_picture/result/{}".format(self.base_image))self.ui.label_7.setScaledContents(True)self.ui.plainTextEdit.clear()n = len(contours)  # 轮廓数量print(n)coutoursImg = []  # 创建绘制轮廓列表sum_all = 0for i in range(n):temp = np.zeros(draw_img.shape, np.uint8)  # 把图像转换为矩阵coutoursImg.append(temp)  # 向列表追加矩阵信息# 绘制轮廓:drawContours()"""绘制轮廓:drawContours()1、img2:等待绘制轮廓的图像2、coutours:要绘制的轮廓(与findContours()函数输出的coutours参数一致《list类型即:列表类型》)3、contourIdx:要绘制一条轮廓还是全部轮廓:如果参数是一个整数或者0表示绘制对应索引号的轮廓[如果是-1表示绘制全部轮廓]4、color:绘制颜色,用B,G,R格式表示5、thickness:表示绘制时的画笔粗细,如果为-1表示用实心绘制6、lineType:表示绘制线轮廓时的线形7、hierarchy:所输出的层次信息8、maxLevel:控制轮廓层次的深度(如果是0表示绘制地0层轮廓)9、offset:偏移参数使轮廓偏移一定位置用[ x , y ]坐标表示"""if cv2.contourArea(contours[i]) >= 0:sum_all = sum_all + cv2.contourArea(contours[i])print("第" + str(i + 1) + "个毛球的面积是:" + str(cv2.contourArea(contours[i])) + "个像素点")self.ui.plainTextEdit.appendPlainText("第" + str(i + 1) + "个毛球的面积是:" + str(cv2.contourArea(contours[i])) + "个像素点")#cv2.imshow("chulihou", draw_img)# 键盘输入检测,参数为显示时长,如果参数为0就是键盘按下退出显示cv2.waitKey()# 关闭所有窗口cv2.destroyAllWindows()self.ui.label_8.setText(str(len(contours)))self.ui.label_9.setText(str(sum_all))self.ui.label_10.setText("1级")# # 设置标签的图片# self.ui.label_2.setPixmap(self.image_file)  ##输入为图片路径,比如当前文件内的logo.png图片# # self.label.setFixedSize(600, 400)  # 设置显示固定尺寸,可以根据图片的像素长宽来设置# self.ui.label_2.setScaledContents(True)  # 让图片自适应 label 大小if __name__=="__main__":app = QApplication([])gui = beyondyanyu()  #初始化gui.window_init()gui.ui.show() #将窗口控件显示在屏幕上app.exit(app.exec_())

五、效果图展示

在这里插入图片描述

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

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

相关文章

GNU工具以及GCC对C语言程序的处理流程

GCC是一族工具的集合&#xff0c;包含预处理器、编译器、汇编器、链接器。 对于默认的文件名&#xff0c;GCC可以自动选择工具自动完成文件处理过程。 从C语言的源程序道可执行文件&#xff0c;实质上是依靠GCC调用一系列工具完成的。 GCC默认处理的文件 文件类型扩展名文件说…

请不要对我说“你要马上把这个小问题修改好”

“我需要”&#xff0c;“小问题”&#xff0c;“立刻”。你激怒我了。你的每个词都激怒我了。这种情绪很难翻译成英语表达&#xff0c;但在荷兰&#xff0c;有些人就是用这种方式要求你。翻译成英语&#xff0c;这有点像“你要几分钟内把这个东西修改好”。大家都知道的这样的…

c#异常处理_C#中的异常处理

c#异常处理What an exception is? 有什么例外&#xff1f; An exception is a runtime error; that means an abnormal situation which is created at run time and the program doesn’t execute successfully. Due to the exceptions, our program gets crash. 异常是运行…

(转)走进AngularJs(六) 服务

原文地址&#xff1a;http://www.cnblogs.com/lvdabao/p/3464015.html 今天学习了一下ng的service机制&#xff0c;作为ng的基本知识之一&#xff0c;有必要做一个了解&#xff0c;在此做个笔记记录一下。 一、认识服务&#xff08;service&#xff09; 服务这个概念其实并不陌…

Linux驱动程序框架以及概述

目录驱动程序三种基本类型&#xff08;组成&#xff09;设备驱动程序功能驱动程序的内核模块机制&#xff08;开发模式&#xff09;驱动程序框架三个主要部分1、字符设备驱动程序框架2、块设备驱动程序框架2、网络设备驱动程序框架驱动程序三种基本类型&#xff08;组成&#x…

curl 使用整理(转载)

我一向以为&#xff0c;curl只是一个编程用的函数库。 最近才发现&#xff0c;这个命令本身&#xff0c;就是一个无比有用的网站开发工具&#xff0c;请看我整理的它的用法。 curl网站开发指南 阮一峰 整理 curl是一种命令行工具&#xff0c;作用是发出网络请求&#xff0c;然…

Linux内核逻辑结构

linux内核从逻辑上可以分为5个部分&#xff1a; 1、进程调度 进程调度控制进程对CPU的访问。当需要选择下一个进程运行时&#xff0c;由调度程序选择最值得运行的程序。可运行进程实际上是仅等待CPU资源的进程&#xff0c;如果某个进程在等待其他资源&#xff0c;则该进程是不可…

对批量文件重命名

一、 文件夹下存放各种不同名称的同类型文件 F:\test 二、重命名格式从a0开始&#xff0c;数字依次递增&#xff0c;a0,a1,a2,a3… import ospathr"F:\test"#要修改文件的路径 namer"a"#命名从什么开始 num0#默认从0开始&#xff0c;即a0,a1,a2...... …

替换Quartus 自带编辑器 (转COM张)

正文 此处以Quartus II 11.1和Notepad v5.9.6.2为例。 1. 使用QII自动调用Notepad来打开HDL、sdc、txt等文件&#xff1b;并且可以在报错的时候&#xff0c;Notepad可以直接高亮所报错的行&#xff08;此模式下&#xff0c;Notepad最大化后效果最佳&#xff09;。 方法&#xf…

四、采集和制作数据集

一、采集数据 安装labelme&#xff1a;pip install labelme 打开labelme&#xff1a;labelme 将收集好的照片(320320&#xff0c;png格式)存放到一个文件夹中&#xff0c;例如我的是F:\test&#xff0c;再此文件夹下再创建个文件夹label用于存放标签文件 使用labelme打开数据…

VMware14.0 安装 CentOS7.2

大致流程 对于VMware14.0安装包用百度网盘下载即可。 链接&#xff1a;https://pan.baidu.com/s/1DEGa47EbI1Fup_MTXhv0xg 提取码&#xff1a;izo6 华为云CentOS7 下载划线的。其他步骤与大致流程里一样。 最后输入root 以及配置的密码即可&#xff1a;密码输入时是没有任何显…

基于visual Studio2013解决C语言竞赛题之1049抓牌排序

&#xfeff;&#xfeff;&#xfeff;&#xfeff;&#xfeff;&#xfeff;题目解决代码及点评/* 功能&#xff1a;插入排序。许多玩牌的人是以这样的方式来对他们手中的牌进行排序的&#xff1a;设手中原有3张牌已排好序&#xff0c;抓1张新牌&#xff0c;若这张新牌的次序在…

【C++进阶】C++创建文件/屏幕输出流类(将信息同时输出到文件和屏幕)

在软件的调试技术中&#xff0c;很重要的一个技术是将软件运行过程中的一些信息写入到“日志文件”中。但是同时还要将信息显示到屏幕上&#xff0c;以方便程序员实时查看这些信息。 最简单的一种办法是这样的&#xff1a; std::ofstream output("debug.log", ios::…

五、加载数据集

之前写过加载数据集的一些小笔记&#xff0c;这里详细内容就不再叙述了 详细学习可以参考该博文二、PyTorch加载数据 一、分析 因为U-net网络架构是输入1通道&#xff0c;大小为(572,572)的灰度图&#xff0c;图片大小无所谓&#xff0c;我的思路是将三通道的图像使用OpenCV进…

CDMA的完整形式是什么?

CDMA&#xff1a;码分多址 (CDMA: Code Division Multiple Access) CDMA is an abbreviation of Code Division Multiple Access. Code Division Multiple Access is a digital cellular technology and displays a network of multiple accesses. The various radio communica…

DSP关于存储器读写、IO读写时序图的注意点

这里的存储器图不涉及插入等待周期。 IO设备的图可以自行减去插入等待周期&#xff0c;然后观察。 存储器读读写 存储器写写读 I/O设备读写操作

oem模式是什么_OEM的完整形式是什么?

oem模式是什么OEM&#xff1a;原始设备制造商 (OEM: Original Equipment Manufacturer) OEM is an abbreviation of "Original Equipment Manufacturer". Its meaning has changed over time. In former times, it alluded to a corporation that manufactures produ…

妈了个巴卡

配置文件修改&#xff1a; 一、打开PC端微信&#xff0c;打开咩了个咩小程序&#xff0c;点进入第一关&#xff0c;之后再关掉小程序 二、PC端微信设置里面&#xff0c;找到管理文件&#xff0c;打开文件夹 三、Applet下按修改日期找到a9结尾的文件 四、接着进入\usr\gamecac…

【C++进阶】利用重载二元运算符改进平面向量类Vec2D

先前回顾 在【C进阶】 遵循TDD原则&#xff0c;实现平面向量类(Vec2D)中我们初步实现了Vec2D内容&#xff0c;现在做出一定的改进&#xff1a; 实现Vec2D的一半二元算数运算符重载 1、 - (两个Vec2D对象运算以及1个Vec2D对象与一个double数运算) 2、*(点乘和数乘) 同时将之前…

简单的群体测试方案C++代码(Group testing against Covid-19)

原理参考链接 https://www.econstor.eu/handle/10419/221811 http://www.magigen.com/h-nd-348.html 文章原理回顾 文章比较了两种估计人群中病毒流行率的方法&#xff1a; 1、个体测试&#xff0c;即对12000人的样本进行病毒测试&#xff0c;并采用标准二项测试得出95%的置…