基于深度学习CNN算法的花卉分类识别系统01--带数据集-pyqt5UI界面-全套源码

文章目录

  • 基于深度学习算法的花卉分类识别系统
  • 一、项目摘要
  • 二、项目运行效果
  • 三、项目文件介绍
  • 四、项目环境配置
    • 1、项目环境库
    • 2、环境配置视频教程
  • 五、项目系统架构
  • 六、项目构建流程
    • 1、数据集
    • 2、算法网络Mobilenet
    • 3、网络模型训练
    • 4、训练好的模型预测
    • 5、UI界面设计-pyqt5
    • 6、项目相关评价指标
  • 七、项目论文报告
  • 八、版权说明及获取方式
    • 1、项目获取方式
    • 2、项目版权说明及定制服务

各位同学大家好,本次给大家分享的项目为:

基于深度学习算法的花卉分类识别系统

一、项目摘要

花卉识别是计算机视觉中的一个重要应用,在园艺、农业和植物保护等领域具有广泛的潜在价值。本文的基于深度学习的花卉识别系统,采用MobileNet模型结合PyTorch框架实现数据集由网络采集的16类花卉图像组成,共计15740张,其中训练集和验证集按8:2的比例划分。为了提高模型的泛化能力,本文对数据进行了多种增强操作,包括随机裁剪、水平翻转及标准化处理

在训练过程中,采用AdamW优化器和交叉熵损失函数,并设置了合适的学习率及超参数,通过100个Epoch进行模型训练和验证。实验结果显示,验证集的最高准确率达到了93%,平均分类准确率为98%。为了用户体验,本文还基于PyQt5设计了用户交互界面,使用户能够便捷地上传图像并查看花卉识别结果以及相关植物信息。

二、项目运行效果

运行效果视频:
https://www.bilibili.com/video/BV1hE22YgEvk

运行效果截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、项目文件介绍

在这里插入图片描述在这里插入图片描述

四、项目环境配置

1、项目环境库

python=3.8 pytorch pyqt5 opencv matplotlib 等

2、环境配置视频教程

1)anaconda下载安装教程
2)pycharm下载安装教程
3)项目环境库安装步骤教程
在这里插入图片描述

五、项目系统架构

在这里插入图片描述
花卉识别系统的整体架构分为四个主要模块:

1. 数据输入模块:负责接收用户输入的花卉图像。

2. 图像预处理模块:对输入的图像进行标准化处理,包括调整图像大小、归一化等,以确保与训练模型的输入要求一致。

3. 深度学习模型模块:通过预训练的MobileNet模型对预处理后的图像进行识别和分类,输出花卉的种类标签。

4. 用户交互模块:通过PyQt5构建图形用户界面,使用户能够便捷地上传图像,查看识别结果,并获得相应的花卉信息。

系统的整体工作流程如下:首先,用户通过用户界面选择要识别的花卉图片,随后系统对图像进行预处理,接着将处理后的图像输入到深度学习模型中进行分类,最后在用户界面上显示识别结果及花卉相关的简介。

六、项目构建流程

1、数据集

数据集文件夹:all_data

在这里插入图片描述
在这里插入图片描述

概述:

本文使用的数据集由16类不同花卉的图像组成,总计15740张

在这里插入图片描述

数据集格式及命令统一代码:to_rgb.py
(对数据集中的图像统一成rgb格式并进行统一规范命名)

在这里插入图片描述

2、算法网络Mobilenet

概述:
Mobilenet是专为移动设备和嵌入式系统设计的轻量化卷积神经网络。其主要特点在于采用了深度可分离卷积(Depthwise Separable Convolution)来减少计算量和参数数量,从而在资源受限的环境下实现高效的图像分类和识别。
在这里插入图片描述

算法代码为:models文件夹下的mobilenet.py

在这里插入图片描述

"""mobilenet in pytorch[1] Andrew G. Howard, Menglong Zhu, Bo Chen, Dmitry Kalenichenko, Weijun Wang, Tobias Weyand, Marco Andreetto, Hartwig AdamMobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applicationshttps://arxiv.org/abs/1704.04861
"""import torch
import torch.nn as nnclass DepthSeperabelConv2d(nn.Module):def __init__(self, input_channels, output_channels, kernel_size, **kwargs):super().__init__()self.depthwise = nn.Sequential(nn.Conv2d(input_channels,input_channels,kernel_size,groups=input_channels,**kwargs),nn.BatchNorm2d(input_channels),nn.ReLU(inplace=True))self.pointwise = nn.Sequential(nn.Conv2d(input_channels, output_channels, 1),nn.BatchNorm2d(output_channels),nn.ReLU(inplace=True))def forward(self, x):x = self.depthwise(x)x = self.pointwise(x)return xclass BasicConv2d(nn.Module):def __init__(self, input_channels, output_channels, kernel_size, **kwargs):super().__init__()self.conv = nn.Conv2d(input_channels, output_channels, kernel_size, **kwargs)self.bn = nn.BatchNorm2d(output_channels)self.relu = nn.ReLU(inplace=True)def forward(self, x):x = self.conv(x)x = self.bn(x)x = self.relu(x)return xclass MobileNet(nn.Module):def __init__(self, width_multiplier=1, class_num=16):super().__init__()alpha = width_multiplierself.stem = nn.Sequential(BasicConv2d(3, int(32 * alpha), 3, padding=1, bias=False),DepthSeperabelConv2d(int(32 * alpha),int(64 * alpha),3,padding=1,bias=False))#downsampleself.conv1 = nn.Sequential(DepthSeperabelConv2d(int(64 * alpha),int(128 * alpha),3,stride=2,padding=1,bias=False),DepthSeperabelConv2d(int(128 * alpha),int(128 * alpha),3,padding=1,bias=False))#downsampleself.conv2 = nn.Sequential(DepthSeperabelConv2d(int(128 * alpha),int(256 * alpha),3,stride=2,padding=1,bias=False),DepthSeperabelConv2d(int(256 * alpha),int(256 * alpha),3,padding=1,bias=False))#downsampleself.conv3 = nn.Sequential(DepthSeperabelConv2d(int(256 * alpha),int(512 * alpha),3,stride=2,padding=1,bias=False),DepthSeperabelConv2d(int(512 * alpha),int(512 * alpha),3,padding=1,bias=False),DepthSeperabelConv2d(int(512 * alpha),int(512 * alpha),3,padding=1,bias=False),DepthSeperabelConv2d(int(512 * alpha),int(512 * alpha),3,padding=1,bias=False),DepthSeperabelConv2d(int(512 * alpha),int(512 * alpha),3,padding=1,bias=False),DepthSeperabelConv2d(int(512 * alpha),int(512 * alpha),3,padding=1,bias=False))#downsampleself.conv4 = nn.Sequential(DepthSeperabelConv2d(int(512 * alpha),int(1024 * alpha),3,stride=2,padding=1,bias=False),DepthSeperabelConv2d(int(1024 * alpha),int(1024 * alpha),3,padding=1,bias=False))self.fc = nn.Linear(int(1024 * alpha), class_num)self.avg = nn.AdaptiveAvgPool2d(1)def forward(self, x):x = self.stem(x)x = self.conv1(x)x = self.conv2(x)x = self.conv3(x)x = self.conv4(x)x = self.avg(x)x = x.view(x.size(0), -1)x = self.fc(x)return xdef mobilenet(alpha=1, class_num=16):return MobileNet(alpha, class_num)

3、网络模型训练

训练代码为:train.py

  • 图像尺寸:输入图像大小设置为224×224,以适应MobileNet网络的输入层要求。

  • 批量大小(Batch-size):设置为16,既可以保证模型能够充分学习数据特征,又能在有限的计算资源下保持较高的训练效率。

  • 学习率(Learning Rate):初始学习率设为0.0001,并使用AdamW优化器,该优化器在保持学习率稳定的同时,能够通过权重衰减减少模型过拟合的风险。

  • 损失函数:采用交叉熵损失函数(CrossEntropyLoss),适合多类别分类任务。

  • Epoch设置:训练总共进行100个Epoch,以确保模型能够充分学习到数据特征,并利用早停策略保存最优模型。

在这里插入图片描述

import os
import argparseimport torch
import torch.optim as optim
import matplotlib.pyplot as plt
from torch.utils.tensorboard import SummaryWriter
from torchvision import transformsfrom my_dataset import MyDataSet
from models.mobilenet import mobilenet as create_model
from utils import read_split_data, train_one_epoch, evaluatedef draw(train, val, ca):plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.rcParams['axes.unicode_minus'] = Falseplt.cla() # 清空之前绘图数据plt.title('精确度曲线图' if ca == "acc" else '损失值曲线图')plt.plot(train, label='train_{}'.format(ca))plt.plot(val, label='val_{}'.format(ca))plt.legend()plt.grid()plt.savefig('精确度曲线图' if ca == "acc" else '损失值曲线图')# plt.show()def main(args):device = torch.device(args.device if torch.cuda.is_available() else "cpu")if os.path.exists("./weights") is False:os.makedirs("./weights")tb_writer = SummaryWriter()train_images_path, train_images_label, val_images_path, val_images_label = read_split_data(args.data_path)img_size = 224data_transform = {"train": transforms.Compose([transforms.RandomResizedCrop(img_size),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),"val": transforms.Compose([transforms.Resize(int(img_size * 1.143)),transforms.CenterCrop(img_size),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])}# 实例化训练数据集train_dataset = MyDataSet(images_path=train_images_path,images_class=train_images_label,transform=data_transform["train"])# 实例化验证数据集val_dataset = MyDataSet(images_path=val_images_path,images_class=val_images_label,transform=data_transform["val"])batch_size = args.batch_sizenw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8])  # number of workersprint('Using {} dataloader workers every process'.format(nw))train_loader = torch.utils.data.DataLoader(train_dataset,batch_size=batch_size,shuffle=True,pin_memory=True,num_workers=nw,collate_fn=train_dataset.collate_fn)val_loader = torch.utils.data.DataLoader(val_dataset,batch_size=batch_size,shuffle=False,pin_memory=True,num_workers=nw,collate_fn=val_dataset.collate_fn)model = create_model(class_num=16).to(device)if args.weights != "":assert os.path.exists(args.weights), "weights file: '{}' not exist.".format(args.weights)model.load_state_dict(torch.load(args.weights, map_location=device))if args.freeze_layers:for name, para in model.named_parameters():# 除head外,其他权重全部冻结if "head" not in name:para.requires_grad_(False)else:print("training {}".format(name))pg = [p for p in model.parameters() if p.requires_grad]optimizer = optim.AdamW(pg, lr=args.lr, weight_decay=5E-2)for epoch in range(args.epochs):# traintrain_loss, train_acc = train_one_epoch(model=model,optimizer=optimizer,data_loader=train_loader,device=device,epoch=epoch)# validateval_loss, val_acc = evaluate(model=model,data_loader=val_loader,device=device,epoch=epoch)train_acc_list.append(train_acc)train_loss_list.append(train_loss)val_acc_list.append(val_acc)val_loss_list.append(val_loss)tags = ["train_loss", "train_acc", "val_loss", "val_acc", "learning_rate"]tb_writer.add_scalar(tags[0], train_loss, epoch)tb_writer.add_scalar(tags[1], train_acc, epoch)tb_writer.add_scalar(tags[2], val_loss, epoch)tb_writer.add_scalar(tags[3], val_acc, epoch)tb_writer.add_scalar(tags[4], optimizer.param_groups[0]["lr"], epoch)if val_loss == min(val_loss_list):print('save-best-epoch:{}'.format(epoch))with open('loss.txt', 'w') as fb:fb.write(str(train_loss) + ',' + str(train_acc) + ',' + str(val_loss) + ',' + str(val_acc))torch.save(model.state_dict(), "./weights/flower-best-epoch.pth")if __name__ == '__main__':parser = argparse.ArgumentParser()parser.add_argument('--num_classes', type=int, default=16)parser.add_argument('--epochs', type=int, default=100)parser.add_argument('--batch-size', type=int, default=16)parser.add_argument('--lr', type=float, default=0.0001)# 数据集所在根目录parser.add_argument('--data-path', type=str,default="all_data")# 预训练权重路径,如果不想载入就设置为空字符parser.add_argument('--weights', type=str, default='',help='initial weights path')# 是否冻结权重parser.add_argument('--freeze-layers', type=bool, default=False)parser.add_argument('--device', default='cuda:0', help='device id (i.e. 0 or 0,1 or cpu)')opt = parser.parse_args()train_loss_list = []train_acc_list = []val_loss_list = []val_acc_list = []main(opt)draw(train_acc_list, val_acc_list, 'acc')draw(train_loss_list, val_loss_list, 'loss')

开始训练

在all_data中准备好数据集,并设置好超参数后,即可开始运行train.py

成功运行效果展示

1)会生成dataset.png数据集分布柱状图

2)pycharm下方实时显示相关训练日志

在这里插入图片描述

等待所有epoch训练完成后代码会自动停止,并在weights文件夹下生成训练好的模型pth文件,并生成准确率和损失值曲线图。

在这里插入图片描述

在这里插入图片描述

4、训练好的模型预测

无界面预测代码为:predict.py

在这里插入图片描述

import os
import jsonimport torch
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as pltfrom models.mobilenet import mobilenet  as create_modeldef main(img_path):import osos.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")img_size = 224data_transform = transforms.Compose([transforms.Resize(int(img_size * 1.143)),transforms.CenterCrop(img_size),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])assert os.path.exists(img_path), "file: '{}' dose not exist.".format(img_path)img = Image.open(img_path)plt.imshow(img)# [N, C, H, W]img = data_transform(img)# expand batch dimensionimg = torch.unsqueeze(img, dim=0)# read class_indictjson_path = './class_indices.json'assert os.path.exists(json_path), "file: '{}' dose not exist.".format(json_path)json_file = open(json_path, "r")class_indict = json.load(json_file)# create model  创建模型网络model = create_model(class_num=len(os.listdir('all_data'))).to(device)# load model weights  加载模型model_weight_path = "weights/flower-best-epoch.pth"model.load_state_dict(torch.load(model_weight_path, map_location=device))model.eval()#调用模型进行检测with torch.no_grad():# predict classoutput = torch.squeeze(model(img.to(device))).cpu()predict = torch.softmax(output, dim=0)predict_cla = torch.argmax(predict).numpy()for i in range(len(predict)):print("class: {:10}   prob: {:.3}".format(class_indict[str(i)],predict[i].numpy()))# 返回检测结果和准确率res = class_indict[str(list(predict.numpy()).index(max(predict.numpy())))]num= "%.2f" % (max(predict.numpy()) * 100) + "%"print(res,num)return res,numif __name__ == '__main__':img_path = r"all_data\向日葵\2.png"main(img_path)

使用方法
1)设置好训练好的模型权重路径
2)设置好要预测的图像的路径
直接右键运行即可,成功运行后会在pycharm下方生成预测结果数据

在这里插入图片描述

5、UI界面设计-pyqt5

两款UI样式界面,自由选择

样式1纯色背景界面,可自由更改界面背景颜色

在这里插入图片描述

样式2:背景图像界面

在这里插入图片描述

对应代码文件
1)ui.py 和 ui2.py
用于设置界面中控件的属性样式和显示的文本内容,可自行修改界面背景色及界面文本内容

在这里插入图片描述
在这里插入图片描述

2)主界面.py 和 主界面2.py
用于设置界面中的相关按钮及动态的交互功能

在这里插入图片描述

3)inf.py 相关介绍及展示信息文本,可自行修改介绍信息

在这里插入图片描述

6、项目相关评价指标

1、准确率曲线图(训练后自动生成)
在这里插入图片描述

2、损失值曲线图(训练后自动生成)
在这里插入图片描述

3、混淆矩阵图
在这里插入图片描述

生成方式:训练完模型后,运行confusion_matrix.py文件,设置好使用的模型权重文件后,直接右键运行即可,等待模型进行预测生成

在这里插入图片描述

以上为本项目完整的构建实现流程步骤,更加详细的项目讲解视频如下
https://www.bilibili.com/video/BV1Kt22YPEb2
(对程序使用,项目中各个文件作用,算法网络结构,所有程序代码等进行的细致讲解,时长1小时)

七、项目论文报告

本项目有配套的论文报告(1w字左右),部分截图如下

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

八、版权说明及获取方式

1、项目获取方式

1)项目全套文件代码获取地址
项目全套代码地址:https://yuanlitui.com/a/acg
2)项目配套论文报告获取地址
项目配套报告:https://yuanlitui.com/a/ac4

2、项目版权说明及定制服务

本项目由本人 Smaller-孔 设计并开发
可提供服务如下:
1)项目功能及界面定制改进服务
如添加用户登录注册、语音播报、语音输入等系统功能,设计Web端界面,添加mysql数据库替换数据集、算法、及算法改进对比等服务
2)售后服务
获取项目后,按照配置视频进行配置,配置过程中出现问题可添加我咨询答疑,配置好后后续因产品自身代码问题无法正常使用,提供1月内免费售后(因使用者对代码或环境进行调整导致程序无法正常运行需有偿售后),项目文件中售后服务文档获取本人联系方式,提供后续售后及相关定制服务。
3)深度学习CV领域的毕设项目,项目及技术1v1辅导,开发等

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

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

相关文章

【PCIE常见面试问题-1】

PCIE常见面试问题-1 1 PCIE概述1.1 PCI为何发展开PCIE?1.2 什么是Root Complex(RC)1.3 什么是EP?1.4 什么是Swith1.5 PCIE协议如何组织通信的?1.6 简要介绍一下PCIE的分层结构,为什么需要分层?1.7 PCIE的事务类型有哪些…

解决 Docker Desktop 启动报错:Docker Desktop is unable to detect a Hypervisor

在使用 Docker Desktop 时,有时会遇到启动报错:“Docker Desktop is unable to detect a Hypervisor.” 这是由于系统的虚拟化功能未正确启用或配置导致的。本文将分步骤指导如何解决该问题。 一、检查虚拟化是否已启用 打开任务管理器 按下 Ctrl Shift…

订单日记为“惠采科技”提供全方位的进销存管理支持

感谢温州惠采科技有限责任公司选择使用订单日记! 温州惠采科技有限责任公司,成立于2024年,位于浙江省温州市,是一家以从事销售电气辅材为主的企业。 在业务不断壮大的过程中,想使用一种既能提升运营效率又能节省成本…

rust中解决DPI-1047: Cannot locate a 64-bit Oracle Client library问题

我们在使用rust-oracle crate连接oracle进行测试的过程中,会发现无法连接oracle,测试运行过程中抛出“DPI-1047: Cannot locate a 64-bit Oracle Client library”错误。该问题是由于rust-oracle需要用到oracle的动态连接库,我们通过安装orac…

东方通重置管理员密码

百度给出的回答 注意,箭头所指的密码是举例,不是自己的默认密码 自己的默认密码存储在下图位置 原文地址

spark 写入mysql 中文数据 显示?? 或者 乱码

目录 前言 Spark报错: 解决办法: 总结一下: 报错: 解决: 前言 用spark写入mysql中,查看中文数据 显示?? 或者 乱码 Spark报错: Sat Nov 23 19:15:59 CST 2024 WARN: Establishing SSL…

电子应用设计方案-20:智能电冰箱系统方案设计

智能电冰箱系统方案设计 一、系统概述 本智能电冰箱系统旨在提供更便捷、高效、智能化的食品存储和管理解决方案,通过集成多种传感器、智能控制技术和联网功能,实现对冰箱内部环境的精确监测和控制,以及与用户的互动和远程管理。 二、系统组成…

实验四:构建园区网(OSPF 动态路由)

目录 一、实验简介 二、实验目的 三、实验需求 四、实验拓扑 五、实验步骤 1、在 eNSP 中部署网络 2、设计全网 IP 地址 3、配置二层交换机 4、配置路由交换机并测试通信 5、配置路由接口地址 6、配置 OSPF 动态路由,实现全网互通 一、实验简介 使用路由…

【大数据学习 | Spark-Core】yarn-client与yarn-cluster的区别

1. yarn的提交命令 # yarn的提交命令参数 --master yarn #执行集群 --deploy-mode # 部署模式 --class #指定运行的类 --executor-memory #指定executor的内存 --executor-cores # 指定核数 --num-executors # 直接指定executor的数量 --queue # 指定队列 2. yarn-client模式…

WEB攻防-通用漏洞文件上传二次渲染.htaccess变异免杀

知识点: 1、文件上传-二次渲染 2、文件上传-简单免杀变异 3、文件上传-.htaccess妙用 4、文件上传-PHP语言特性 1、上传后门时,文件内容带.就不行 这时可以上传一个转换后的ip地址,ip地址对应网站包含后门代码 转换后的int会在访问的时候…

【汽车制动】汽车制动相关控制系统

目录 1.ABS (Anti-lock Brake System,防抱死制动系统) 2.EBD(Electronic Brake-force Distribution,电子制动力分配系统) 3.TCS(Traction Control System,牵引力控制系统) 4.VDC&#xff08…

Tri Mode Ethernet MAC IP核详解

本文对 Vivado 的三速 MAC IP 核(Tri Mode Ethernet MAC,TEMAC)进行介绍。 在自行实现三速以太网 MAC 控制器时,GMII/RGMII 接口可以通过 IDDR、ODDR 原语实现,然而实际使用中自己实现的模块性能不是很稳定&#xff08…

项目实战:基于Vue3实现一个小相册

相册的示例效果图 注意看注释... CSS部分&#xff1a; <style>/* 伪元素选择器&#xff0c;用于在具有clear_ele类的元素内部的末尾添加一个新的元素 */.clear_ele::after{ content: ""; /* 这个伪元素的内容属性必须有 *//* 块级元素&#xff0c;便于占据一…

HTMLCSS:比赛记分卡

效果演示 这段 HTML 和 CSS 代码创建了一个卡片式的体育比赛信息展示组件&#xff0c;用于显示篮球比赛的两个队伍名称、比赛时间、比分以及一些装饰性的视觉元素。 HTML <div class"card"><div data-status"inprogress" class"teams"…

Paper -- 3D建筑模型生成 -- GABLE: 基于高分辨率卫星影像的全国尺度精细3D建筑模型

基本信息 论文题目: GABLE: A first fine-grained 3D building model of China on a national scale from very high resolution satellite imagery 中文题目: GABLE: 基于高分辨率卫星影像的全国尺度精细3D建筑模型 作者及单位: – 多数作者来自中国科学院空间信息研究所&…

蓝桥杯嵌入式再学习(2)基础框架的构建

1&#xff1a;打开工程以后我们需要进行一些配置如图&#xff1a; 第一步&#xff1a;将core里面的对勾取消掉 勾选Microlib 优化等级选择level 0 将我们自己的文件夹添加到路径里面去 这个样子我们就基本将框架搭建好了我们然后需要编写各个底层的驱动了

矩阵/矩阵乘法/特征征/特征向量的讲解

线性代数里有很多的概念&#xff0c;很多概念是有几何意义的&#xff0c;了解了几何意义可能会更好的理解各种概念及其相互之间的关系。 矩阵&#xff1a; 矩阵是一个变换&#xff0c;一个坐标系到另一个坐标第的变换。矩阵里的各个参数&#xff0c;代表了如何进行变换。 矩阵…

Easyexcel(5-自定义列宽)

相关文章链接 Easyexcel&#xff08;1-注解使用&#xff09;Easyexcel&#xff08;2-文件读取&#xff09;Easyexcel&#xff08;3-文件导出&#xff09;Easyexcel&#xff08;4-模板文件&#xff09;Easyexcel&#xff08;5-自定义列宽&#xff09; 注解 ColumnWidth Data…

1+X应急响应(网络)文件包含漏洞:

常见网络攻击-文件包含漏洞&命令执行漏洞&#xff1a; 文件包含漏洞简介&#xff1a; 分析漏洞产生的原因&#xff1a; 四个函数&#xff1a; 产生漏洞的原因&#xff1a; 漏洞利用条件&#xff1a; 文件包含&#xff1a; 漏洞分类&#xff1a; 本地文件包含&#xff1a; …

Flutter:SlideTransition位移动画,Interval动画延迟

配置vsync&#xff0c;需要实现一下with SingleTickerProviderStateMixinclass _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{// 定义 AnimationControllerlate AnimationController _controller;overridevoid initState() {super.…