二、页面布局

一、界面

我做的界面大概思路:点击 上传图片,显示待检验的照片
点击 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默认处理的文件 文件类型扩展名文件说…

Professional C++读书笔记05

2012-05-20 Chapter09 1、复制构造函数浅复制时的隐患 若对象中有指针成员&#xff0c;则当对象作为形参传入时 例如void myFun(Spreadsheet s)…… Spreadsheet s1(5,3); myFun(s1);// s1与s中的指针成员指向同一块内存&#xff08;s是由s1通过复制构造函数生成的&#xff…

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

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

javascript 常量_JavaScript中的常量

javascript 常量JavaScript常数 (JavaScript Constants) Before ES15, the only way to declare variables using the var keyword. JavaScripts inbuilt feature of hoisting variables could be carried out using the var keyword. If youre unfamiliar with variables in J…

GDB与远程(交叉)GDB调试

GDB提供的功能 1、启动的程序&#xff0c;可以按照自定义的要求运行程序 2、可以让被调试的程序在指定的断点处停住(断点可以是条件表达式) 3、当程序被停住时&#xff0c;可以检查这个时候程序中发生的事 4、动态地改变程序的运行环境。 远程&#xff08;交叉&#xff09;GD…

OTR-Linux控制台打印颜色区分.

What I write, what I lost. 对于依靠打印来作debug的主要手段的, 能够区分打印中的debug信息和error信息便显得非常重要. 原文的介绍有一篇关于控制台颜色的文章http://www.ibm.com/developerworks/cn/linux/l-tip-prompt/tip01/ 有定义实现各种颜色的方式. 以此为基础, 方式挺…

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…

scala 方法重载_Scala中的方法重载

scala 方法重载Scala方法重载 (Scala method overloading) Method overloading is a method that is redefined in different ways under the same name. Method overloading is one of the methods used to implement polymorphism in Scala. 方法重载是一种使用相同名称以不…

C#网页自动登录和提交POST信息的多种方法 新人学习中

网页自动登录和提交POST信息的核心就是分析网页的源代码&#xff08;HTML&#xff09;&#xff0c;在C#中&#xff0c;可以用来提取网页HTML的组件比较多&#xff0c;常用的用WebBrowser、WebClient、HttpWebRequest这三个。 以下就分别用这三种方法来实现&#xff1a;1、WebBr…

四、采集和制作数据集

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

MTFBWU的完整形式是什么?

MTFBWU&#xff1a;愿力量与您同在 (MTFBWU: May The Force Be With You) MTFBWU is an abbreviation of “May The Force Be With You". MTFBWU是“愿力量与你同在”的缩写 。 It is an expression, which is commonly used in messaging or chatting on social media n…

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;若这张新牌的次序在…

学习Lucene笔记一:创建索引

public class HelloLucene {/*** 建立索引* param args*/public void index(){IndexWriter writer null; try {//1.创建Directory,// Directory directory new RAMDirectory();//索引是建立在内存中的Directory directory FSDirectory.open(new File("D:/Lucene/ind…