毕业设计:水果检测系统

目录

前言

一、项目介绍

1.1 背景与目的

1.2 模型介绍

1.3 项目效果

二、项目准备

2.1 编程软件

2.2 配置环境

2.3 数据集

三、项目开展

3.1 项目介绍

3.2 初始化数据集

3.3 模型训练

3.4 单张图片测试

3.5 批量图片预测

3.6 视频预测

四、pyqt5界面

4.1 加载模型

4.2 定义(UI)界面

4.3 构建程序

4.4 启动项目

五、总结

5.1 模型收获

5.2 学习收获

5.3 拓展


前言

本项目旨在开发一个基于深度学习的水果识别系统,利用计算机视觉技术识别常见水果,如猕猴桃、柠檬、石榴、菠萝和西瓜。水果的自动识别在农业生产、市场销售和物流管理等领域具有重要意义。本系统采用了经典的VGG-16模型作为基础架构,通过预训练的模型权重和重新训练的分类器来提高识别准确性。

一、项目介绍

1.1 背景与目的

该水果检测系统应运而生,主要是为了应对现代农业和零售业中水果分类工作的低效率和误差问题。通过利用最新的图像识别技术,该系统能自动识别多种水果,显著提升分类的速度与准确性。此外,系统还支持数据的实时收集和分析,有助于优化供应链管理和库存控制,提升整体运营效率。开发此系统的目的在于实现水果检测的自动化和精确化,同时提供易于操作的用户界面,确保非技术用户也能轻松使用,且设计具备良好的可扩展性,以便适应未来技术的发展和更广泛的应用需求。

1.2 模型介绍

VGG-16由16层卷积层和全连接层组成,因此得名“VGG-16”。这些卷积层中大部分都使用了3x3的卷积核,步幅为1,同时使用了较小的池化核(2x2池化核,步幅为2),以保持特征图的大小和信息的完整性。

  

1.3 项目效果

PyQt5 提供了丰富的工具和功能,能够帮助开发者创建现代化、交互式和高效的图形用户界面,适用于各种应用场景,从简单的工具到复杂的数据可视化应用都能得心应手。

上传一张图片进行检测:

预测结果为:pomegranate,结果正确,下面请跟着我的步骤来

二、项目准备

2.1 编程软件

提前下载好PyCharm和Anaconda(或者Miniconda)如果有需要:

Anaconda:

Download Anaconda Distribution | Anacondaicon-default.png?t=N7T8https://www.anaconda.com/download/PyCharm:

https://www.jetbrains.com/zh-cn/pycharm/icon-default.png?t=N7T8https://www.jetbrains.com/zh-cn/pycharm/

2.2 配置环境

每个项目可能需要的包版本不一样,这里建议创建一个新的conda的虚拟环境来进行

下面进行一个简单的演示(Windows下推荐使用Anaconda Prompt或命令行,Linux/macOS下使用终端)

1.使用以下命令创建一个新的Conda虚拟环境,并指定环境名称(例如,env_name是你想要的环境名称)

conda create --name env_name

2.如果需要特定版本的Python,可以指定Python版本号

conda create --name env_name python=3.8

3.激活虚拟环境

Windows

conda activate env_name

Linux/macOS

source activate env_name

这样虚拟环境就创建好了,创建好虚拟环境之后可以直接使用 requirements.txt 文件快速下载里面所需要的包。

2.3 数据集

我使用到同济子豪兄的水果识别数据集,该数据集包含了81种水果:水果数据集

或者前往Kaggle平台:一个数据科学竞赛平台,提供大量公开的数据集供下载和使用。

其中每种水果种类的图片都非常丰富,数据多样,对模型的泛化能力有很好的帮助。同时,还有一段视频作为待会测试的视频数据,该视频包含包含了五种水果,分别是猕猴桃,柠檬,西瓜,菠萝以及石榴, 所以为了简化任务,我单独抽出以上五种水果的数据集做了一个简单的小数据集,opencv不接受中文名,所以我这里使用英文,如下图:

三、项目开展

3.1 项目介绍

我们项目要用到VGG16模型,和pyqt5界面,可以提前下载好。

这些就是整个项目所需要用的东西,下面我将开始讲解代码。

3.2 初始化数据集

这段代码的主要功能是创建一个自定义的数据集类,以便在训练深度学习模型时能够方便地加载和处理图像数据。用于图像分类的PyTorch数据集加载器的实现。具体来说,它定义了一个名为SeedlingData的类,用于加载和处理图像数据集。

# 导入必要的包
import os
from PIL import Image
from torch.utils import data
from torchvision import transforms as T
from sklearn.model_selection import train_test_split
import torch.optim as optim
import torch
import torch.nn as nn
import torch.utils.data
import torchvision.transforms as transforms
from torch.autograd import Variable
from torchvision.models import vgg16, VGG16_Weights
import matplotlib.pyplot as plt

# 更新标签字典,包括'pineapple'和'Watermelon'两个类别
Labels = {'Kiwifruit': 0, 'lemon': 1, 'pomegranate': 2, 'pineapple': 3, 'Watermelon': 4}

class SeedlingData(data.Dataset):
    def __init__(self, root, transforms=None, train=True, test=False):
        self.test = test
        self.transforms = transforms
        if self.test:
            self.imgs = [os.path.join(root, img) for img in os.listdir(root)]
        else:
            imgs_labels = [os.path.join(root, img) for img in os.listdir(root)]
            imgs = []
            for imglable in imgs_labels:
                for imgname in os.listdir(imglable):
                    imgpath = os.path.join(imglable, imgname)
                    imgs.append(imgpath)
            trainval_files, val_files = train_test_split(imgs, test_size=0.3, random_state=42)
            self.imgs = trainval_files if train else val_files

    def __getitem__(self, index):
        img_path = self.imgs[index]
        if self.test:
            label = -1
        else:
            # 使用 os.path 模块处理路径,获取类别标签
            labelname = os.path.basename(os.path.dirname(img_path))
            label = Labels[labelname]
        data = Image.open(img_path).convert('RGB')
        data = self.transforms(data)
        return data, label

    def __len__(self):
        return len(self.imgs)

3.3 模型训练

选择了VGG-16模型作为基础,通过替换全连接层实现了对新类别的适应性训练。训练过程中,我们使用了交叉熵损失函数来优化模型,采用Adam优化器进行参数更新。训练过程中动态调整学习率,以确保模型在训练中保持稳定且有效的学习状态。

# 设置全局参数
modellr = 1e-4
BATCH_SIZE = 32
EPOCHS = 10
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 数据预处理
transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])

dataset_train = SeedlingData('data', transforms=transform, train=True)
dataset_val = SeedlingData('data', transforms=transform, train=False)

train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset_val, batch_size=BATCH_SIZE, shuffle=False)

# 更新模型初始化以使用'weights'参数
model_ft = vgg16(weights=VGG16_Weights.IMAGENET1K_V1)
num_ftrs = model_ft.classifier[6].in_features
model_ft.classifier[6] = nn.Linear(num_ftrs, len(Labels))
model_ft = model_ft.to(DEVICE)

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model_ft.parameters(), lr=modellr)

def adjust_learning_rate(optimizer, epoch):
    # 根据 epoch 调整学习率
    modellrnew = modellr * (0.1 ** (epoch // 50))
    for param_group in optimizer.param_groups:
        param_group['lr'] = modellrnew

# 定义训练过程
def train(model, device, train_loader, optimizer, epoch):
    model.train()
    sum_loss = 0
    correct = 0
    total_num = len(train_loader.dataset)

    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        output = model(data)
        loss = criterion(output, target)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        sum_loss += loss.item()
        _, pred = torch.max(output, 1)
        correct += pred.eq(target).sum().item()

        if (batch_idx + 1) % 10 == 0:
            print(
                f'训练 Epoch: {epoch} [{(batch_idx + 1) * len(data)}/{total_num} ({100. * (batch_idx + 1) / len(train_loader):.0f}%)]\t损失: {loss.item():.6f}')

    avg_loss = sum_loss / len(train_loader)
    accuracy = 100. * correct / total_num
    print(f'Epoch: {epoch}, 损失: {avg_loss:.6f}, 准确率: {accuracy:.2f}%')

# 验证过程
def val(model, device, test_loader):
    model.eval()
    test_loss = 0
    correct = 0
    total_num = len(test_loader.dataset)

    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            loss = criterion(output, target)
            test_loss += loss.item()
            _, pred = torch.max(output, 1)
            correct += pred.eq(target).sum().item()

    avg_loss = test_loss / len(test_loader)
    accuracy = 100. * correct / total_num
    print(f'\n验证集: 平均损失: {avg_loss:.4f}, 准确率: {correct}/{total_num} ({accuracy:.2f}%)\n')

# 训练模型
for epoch in range(1, EPOCHS + 1):
    adjust_learning_rate(optimizer, epoch)
    train(model_ft, DEVICE, train_loader, optimizer, epoch)
    val(model_ft, DEVICE, test_loader)

# 保存模型
torch.save(model_ft.state_dict(), 'model.pth')

代码实现了一个完整的图像分类训练和验证流程,包括数据预处理、模型定义、训练、验证和保存模型。通过每个epoch调整学习率,并在每个epoch结束时评估模型的性能,以确保模型逐渐收敛和优化。经过10轮训练后得到model.pth

3.4 单张图片测试

代码通过使用预训练的VGG16模型,对指定路径下的单张水果图像进行分类预测。它首先加载模型和模型参数,然后对图像进行必要的预处理,并利用模型进行推理以获取分类结果,最后在图像上显示预测类别。

# 加载预训练模型
model = models.vgg16(weights=models.VGG16_Weights.IMAGENET1K_V1)
num_ftrs = model.classifier[6].in_features
model.classifier[6] = nn.Linear(num_ftrs, len(classes))

# 指定模型文件路径
model_path = 'D:\\python\\fruit\\model.pth'

# 加载模型参数
model.load_state_dict(torch.load(model_path, map_location=DEVICE))

# 将模型设置为评估模式
model.eval()

# 输入图像路径
image_path = 'D:\\python\\fruit\\data\\Kiwifruit\\1.jpg'

# 检查文件是否存在
if not os.path.isfile(image_path):
    print(f"文件不存在: {image_path}")
else:
    print(f"文件存在: {image_path}")

    # 使用OpenCV加载图像
    img = cv2.imread(image_path)

    # 检查图像是否加载成功
    if img is None:
        print(f"无法加载图像: {image_path}")
    else:
        # 转换图像格式为PIL
        pil_image = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

        # 对图像进行预处理
        transformed_image = transform_test(pil_image)

        # 添加批处理维度
        transformed_image.unsqueeze_(0)

        # 将输入数据移动到设备
        transformed_image = transformed_image.to(DEVICE)

        # 进行推理
        with torch.no_grad():
            output = model(transformed_image)

        # 获取预测类别
        _, pred = torch.max(output, 1)
        predicted_class = classes[pred.item()]

        # 在图像上绘制预测结果
        cv2.putText(img, predicted_class, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        cv2.imshow('Classification Result', img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

效果图如下:

3.5 批量图片预测

这段代码通过加载预训练的VGG16模型,对指定文件夹中的多张水果图像进行批量分类预测。它实现了图像的加载、预处理、模型推理和结果输出,最后计算并展示了整体的分类准确率和执行时间。

# 加载预训练模型
model = models.vgg16(weights=models.VGG16_Weights.IMAGENET1K_V1)
num_ftrs = model.classifier[6].in_features
model.classifier[6] = nn.Linear(num_ftrs, len(classes))

# 指定模型文件路径
model_path = 'D:\\python\\fruit\\model.pth'

# 加载模型参数
try:
    model.load_state_dict(torch.load(model_path, map_location=DEVICE))
except Exception as load_e:
    print(f"无法加载模型状态字典: {str(load_e)}")
    exit()

# 将模型设置为评估模式
model.eval()

# 输入图像文件夹路径
folder_path = 'D:\\python\\fruit\\data\\Kiwifruit'  # 更改为你的图像文件夹路径

# 获取图像文件夹中的所有文件
file_list = os.listdir(folder_path)

correct = 0
total = 0
start_time = time.time()

# 获取实际类别名称
actual_class = os.path.basename(folder_path)

# 遍历图像文件列表
for file_name in file_list:
    # 构建图像文件的完整路径
    file_path = os.path.join(folder_path, file_name)

    try:
        # 使用OpenCV加载图像
        img = cv2.imread(file_path)

        # 检查图像是否加载成功
        if img is None:
            print(f"无法加载图像: {file_path}")
            continue

        # 转换成PIL图像
        pil_image = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

        # 对图像进行预处理
        transformed_image = transform_test(pil_image)

        # 添加批处理维度
        transformed_image.unsqueeze_(0)

        # 将输入数据移动到设备
        transformed_image = transformed_image.to(DEVICE)

        # 进行推理
        with torch.no_grad():
            output = model(transformed_image)

        # 获取预测类别
        _, pred = torch.max(output, 1)
        predicted_class = classes[pred.item()]

        # 打印实际类别和预测类别
        print(f"文件: {file_name}, 实际: {actual_class}, 预测: {predicted_class}")

        if actual_class == predicted_class:
            correct += 1
        total += 1

    except Exception as process_e:
        print(f"处理 {file_name} 时出错: {str(process_e)}")

# 计算准确率
accuracy = correct / total if total > 0 else 0

end_time = time.time()
total_time = end_time - start_time

print(f"准确率: {accuracy * 100:.2f}%")
print(f"执行时间: {total_time:.2f} 秒")

最终输出的预测结果:

3.6 视频预测

代码实现了利用预训练的VGG16模型对给定视频进行分类和标注。首先,通过OpenCV读取视频并获取其属性(帧率、宽度、高度),然后将每一帧转换为PIL图像格式进行预处理(调整大小、转换为张量、归一化)。接着,将处理后的图像输入模型进行推理,预测每帧的类别,并在帧上标注预测结果。最后,将标注后的帧写入新的输出视频文件,完成整个分类和标注过程。

# 加载模型架构
model = models.vgg16(weights=models.VGG16_Weights.IMAGENET1K_V1)
num_ftrs = model.classifier[6].in_features
model.classifier[6] = torch.nn.Linear(num_ftrs, len(classes))

# 指定模型文件的绝对路径
model_path = 'D:\\python\\fruit\\model.pth'

# 加载模型的状态字典
state_dict = torch.load(model_path, map_location=torch.device('cpu'))

# 将状态字典加载到模型中
model.load_state_dict(state_dict)

# 指定设备为CPU
device = torch.device('cpu')
model = model.to(device)
model.eval()

# 定义视频文件路径
video_path = 'D:\\python\\fruit\\Video\\fruit2.mp4'

# 输出目录路径
output_dir = 'D:\\python\\fruit\\output'

# 打开视频文件
video = cv2.VideoCapture(video_path)
if not video.isOpened():
    print(f"无法打开视频文件:{video_path}")
    exit()

# 获取视频属性
fps = video.get(cv2.CAP_PROP_FPS)
width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))

# 创建视频写入对象
output_path = os.path.join(output_dir, 'output5.mp4')
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
output_video = cv2.VideoWriter(output_path, fourcc, fps, (width, height))

# 检查视频写入对象是否创建成功
if not output_video.isOpened():
    print(f"无法创建视频文件:{output_path}")
    exit()

# 打印调试信息
print(f"Processing video: {video_path}")
print(f"Output video: {output_path}")
print(f"Video properties - FPS: {fps}, Width: {width}, Height: {height}")

# 处理视频中的每一帧
while video.isOpened():
    ret, frame = video.read()

    if not ret:
        break

    # 将帧转换为PIL图像
    pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))

    # 应用预处理转换
    transformed_image = transform(pil_image)
    transformed_image = transformed_image.unsqueeze(0).to(device)

    # 使用模型进行推理
    with torch.no_grad():
        output = model(transformed_image)

    # 预测类别
    _, pred = torch.max(output, 1)
    predicted_class = classes[pred.item()]

    # 在帧上绘制预测的类别
    cv2.putText(frame, predicted_class, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    # 将带有标注类别的帧写入输出视频
    output_video.write(frame)

# 释放视频对象并关闭输出视频
video.release()
output_video.release()

print("视频分类和标注完成!")

这个思路是将对视频的每一帧进行分类,并在每一帧图像上打印分类结果。最后,将分类好的图像写入输出视频文件,视频如下:

output3

四、pyqt5界面

4.1 加载模型

重新训练后的VGG16模型,更新其最后一层以适应新的分类任务(水果识别),加载预训练的参数,将模型移动到CPU上,并将其设置为评估模式,为后续的图形用户界面应用程序做准备。

# 加载重新训练后的模型
model = models.vgg16(weights=None)
num_ftrs = model.classifier[6].in_features
model.classifier[6] = nn.Linear(num_ftrs, len(classes))

# 指定模型文件路径
model_path = 'model.pth'
if not os.path.exists(model_path):
    raise FileNotFoundError(f"The model file {model_path} does not exist.")
model.load_state_dict(torch.load(model_path, map_location=DEVICE))

# 将模型移动到设备(CPU)
model.to(DEVICE)

# 将模型设置为评估模式
model.eval()

有GPU的可以使用GPU,速度会快一些,我没有所以用能使用CPU

4.2 定义(UI)界面

通过PyQt5库创建了一个简单的用户界面,用于水果识别应用。界面包括显示原始图片或视频的标签、显示识别结果的标签、显示预测类别的标签以及几个按钮用于上传图片、上传视频、开始识别、上传新图片和退出应用。

    def initUI(self):
        # 设置窗口标题和尺寸
        self.setWindowTitle('水果识别')
        self.setGeometry(100, 100, 1200, 800)

        # 设置背景图片
        palette = QPalette()
        background_image = QPixmap("background/Backdrop.jpg")
        if not background_image.isNull():
            palette.setBrush(QPalette.Background, QBrush(background_image))
        self.setPalette(palette)

        # 左侧标签用于显示原始图片或视频
        self.labelOriginal = QLabel(self)
        self.labelOriginal.setAlignment(Qt.AlignCenter)
        self.labelOriginal.setStyleSheet("border: 2px dashed black; padding: 10px; background-color: rgba(255, 255, 255, 150);")

        # 右侧标签用于显示识别结果
        self.labelResult = QLabel(self)
        self.labelResult.setAlignment(Qt.AlignCenter)
        self.labelResult.setStyleSheet("border: 2px dashed black; padding: 10px; background-color: rgba(255, 255, 255, 150);")

        # 标签用于显示预测的类别
        self.resultLabel = QLabel('预测类别: ', self)
        self.resultLabel.setAlignment(Qt.AlignCenter)
        self.resultLabel.setFont(QFont('Comic Sans MS', 12))

        # 上传图片按钮
        self.uploadButton = QPushButton('上传图片', self)
        self.uploadButton.clicked.connect(self.openImage)

        # 上传视频按钮
        self.videoButton = QPushButton('上传视频', self)
        self.videoButton.clicked.connect(self.openVideo)

        # 开始识别按钮
        self.predictButton = QPushButton('开始识别', self)
        self.predictButton.clicked.connect(self.startRecognition)
        self.predictButton.setEnabled(False)  # 初始状态下禁用

        # 上传新图片按钮
        self.newUploadButton = QPushButton('上传新图片', self)
        self.newUploadButton.clicked.connect(self.openImage)
        self.newUploadButton.setEnabled(False)  # 初始状态下禁用

        # 退出按钮
        self.exitButton = QPushButton('退出', self)
        self.exitButton.clicked.connect(self.close)

设置他的按钮,以及对应的功能,如片如下:

4.3 构建程序

这些方法共同构成了一个用于水果识别的GUI应用程序,实现了从上传图片或视频到显示预测结果的完整流程。

    def openImage(self):
        # 打开文件对话框选择图像文件
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getOpenFileName(self, "选择图像文件", "", "Images (*.png *.xpm *.jpg);;All Files (*)", options=options)
        if fileName:
            # 显示选择的图像
            self.labelOriginal.setPixmap(QPixmap(fileName).scaled(400, 400, Qt.KeepAspectRatio))
            self.resultLabel.setText('预测类别: ')
            self.currentImagePath = fileName
            self.currentVideoPath = None
            self.predictButton.setEnabled(True)  # 启用开始识别按钮

    def openVideo(self):
        # 打开文件对话框选择视频文件
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getOpenFileName(self, "选择视频文件", "", "Videos (*.mp4 *.avi);;All Files (*)", options=options)
        if fileName:
            # 设置当前视频路径并更新UI
            self.currentVideoPath = fileName
            self.currentImagePath = None
            self.resultLabel.setText('预测类别: ')
            self.labelOriginal.setText('视频加载成功')
            self.predictButton.setEnabled(True)  # 启用开始识别按钮

    def startRecognition(self):
        # 根据当前文件类型启动识别
        if self.currentImagePath:
            self.predictImage(self.currentImagePath)
        elif self.currentVideoPath:
            self.videoCap = cv2.VideoCapture(self.currentVideoPath)
            self.timer.start(30)  # 每30毫秒处理一帧
        else:
            QMessageBox.warning(self, '错误', '请先上传图片或视频')

    def processFrame(self):
        # 处理视频中的每一帧
        ret, frame = self.videoCap.read()
        if ret:
            # 将帧转换为PIL图像并进行预测
            image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
            self.predictImage(image)
            self.displayFrame(frame)
        else:
            # 视频结束时停止定时器并释放视频资源
            self.timer.stop()
            self.videoCap.release()

    def displayFrame(self, frame):
        # 在界面上显示当前帧
        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        height, width, channel = frame_rgb.shape
        bytesPerLine = 3 * width
        qImg = QImage(frame_rgb.data, width, height, bytesPerLine, QImage.Format_RGB888)
        self.labelOriginal.setPixmap(QPixmap.fromImage(qImg).scaled(400, 400, Qt.KeepAspectRatio))

    def predictImage(self, image):
        try:
            # 预测图像类别
            if isinstance(image, str):
                image = Image.open(image)
            image_tensor = transform_test(image).unsqueeze(0).to(DEVICE)
            print(f"Image tensor: {image_tensor}")  # 调试信息
            with torch.no_grad():
                outputs = model(image_tensor)
                print(f"Model outputs: {outputs}")  # 调试信息
                _, predicted = torch.max(outputs, 1)
                class_name = classes[predicted.item()]
                print(f"Predicted class: {class_name}")  # 调试信息

            self.resultLabel.setText(f'预测类别: {class_name}')
            if isinstance(image, str):
                self.labelResult.setPixmap(QPixmap(image).scaled(400, 400, Qt.KeepAspectRatio))
            else:
                # 将图像转换为QImage并显示在界面上
                image_pil = image.convert('RGB')
                image_np = np.array(image_pil)
                height, width, channel = image_np.shape
                bytesPerLine = 3 * width
                qImg = QImage(image_np.data, width, height, bytesPerLine, QImage.Format_RGB888)
                self.labelResult.setPixmap(QPixmap.fromImage(qImg).scaled(400, 400, Qt.KeepAspectRatio))
            self.predictButton.setEnabled(False)  # 禁用开始识别按钮
            self.newUploadButton.setEnabled(True)  # 启用上传新图片按钮
        except Exception as e:
            # 处理识别过程中发生的异常
            QMessageBox.critical(self, '错误', f'识别失败: {str(e)}')
            print(f"Error: {str(e)}")  # 调试信息

连接前端按钮,实现功能:

4.4 启动项目

创建一个水果识别的GUI应用程序,显示主窗口并进入Qt的事件处理循环,直到应用程序关闭。

if __name__ == '__main__':
    # 创建应用程序实例并启动主循环
    app = QApplication(sys.argv)
    ex = FruitRecognitionApp()
    ex.show()
    sys.exit(app.exec_())

效果图如下:

启动完项目之后发现界面不够好看,可以添加适当的背景图片进行美化。

添加背景图片:

进行上传图片识别测试:

点击开始识别之后,发现预测结果是成功的,下面进行测试视频。


代码逐帧进行识别检测,预测类别会根据识别结果而进行改变。

五、总结

5.1 模型收获

选择VGG-16作为水果识别系统的基础模型时,其优点在于其简单清晰的结构易于理解和实现,同时能有效捕捉复杂的图像特征,使其在大规模图像分类任务中表现出色。然而,由于其较深的网络结构导致参数量大、计算量高,适用于资源丰富的环境,并需要有效的数据增强和正则化以应对潜在的过拟合问题。

5.2 学习收获

我设计了一个基于VGG-16模型的水果识别系统,并结合PyQt5开发了直观易用的用户界面。通过调整模型的最后一层全连接层,系统能够准确识别输入图像中的五种特定水果类别。通过这次项目开发,我获得了深度学习模型应用的宝贵经验,特别是在使用VGG-16进行图像分类任务时的实际操作和调整。通过修改模型的最后一层全连接层,我学会了如何自定义模型以适应特定的分类需求,并通过数据预处理和输入格式化提高了模型的效率和准确性。在图形用户界面设计方面,结合PyQt5的使用,我不仅学习了界面元素的布局和交互设计,还深入了解了如何与后端模型集成,实现用户友好的操作体验。这次项目还锻炼了我的问题解决能力,从模型加载、数据处理到界面逻辑的调试,每一步都是对实际项目管理和实施的重要实践。

5.3 拓展

还想继续了解VGG16模型请前往:

https://www.cnblogs.com/fusheng-rextimmy/p/15452248.htmlicon-default.png?t=N7T8https://www.cnblogs.com/fusheng-rextimmy/p/15452248.html

想要继续了解pyqt5请前往:

https://maicss.gitbooks.io/pyqt5/content/hello_world.htmlicon-default.png?t=N7T8https://maicss.gitbooks.io/pyqt5/content/hello_world.html

项目到这里就结束,代码后期人多想要的话我会上传到Github平台,希望本片文章对你有所帮助。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值