当前位置: 首页 > news >正文

基于Tensorflow+SDD+Python人脸口罩识别系统(深度学习)含全部工程源码及模型+视频演示+图片数据集

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
    • Python 环境
    • Anaconda 环境搭建
  • 模块实现
    • 1. 数据预处理
    • 2. 模型构建及算法实现
    • 3. 模型生成
  • 系统测试
    • 1. 训练准确率
    • 2. 运行结果
  • 工程源代码下载
  • 其它资料下载

在这里插入图片描述

前言

在当今全球范围内,新冠疫情对我们的生活方式带来了巨大的改变。在公共场所,佩戴口罩成为了常态,以保护我们自己和他人的健康安全。然而,这也给人脸识别技术带来了新的挑战。如何准确地辨别佩戴口罩的人成为了一个重要的问题。

本文介绍的一种基于Tensorflow、SDD和Python的人脸口罩识别系统,结合了深度学习技术和计算机视觉算法,能够高效地检测人脸并准确地判断是否佩戴口罩。通过使用这个系统,我们可以更好地管理公共场所的出入口,确保员工、顾客和访客的健康安全。

当然,您可以在文末下载本系统的全部工程源码(包括Web demo)进行个人二次开发。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述

运行环境

本部分包括 Python 环境和Anaconda 环境。

Python 环境

需要 Python 3.5 及以上配置,在 Windows 环境下推荐下载 Anaconda 完成 Python 所需的配置,下载地址:https://www.anaconda.com/,也可以下载虚拟机在 Linux 环境下运行代码。

Anaconda 环境搭建

打开 Anaconda Prompt,输入清华仓库镜像。

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config –set show_channel_urls yes

创建 Python3.5 的环境,名称为 TensorFlow:

conda create -n tensorflow python=3.5

有需要确认的地方,都输入 y。
在 Anaconda Prompt 中激活 TensorFlow 环境:

activate tensorflow

安装 CPU 版本的 TensorFlow:

pip install –upgrade --ignore-installed tensorflow

安装完毕。

模块实现

本项目包括 3 个模块:数据预处理、模型构建及算法实现、模型生成,下面分别给出各模块的功能介绍及相关代码。

1. 数据预处理

WIDER Face 和 MAFA 这两个数据集包含了大量的人脸及人脸佩戴口罩的图片,但只使用WIDER Face 数据集,所含其他遮挡脸部的图片较少(如用手挡住脸部),会出现识别偏差的情况。因此,从 WIDER Face 数据集中选取 3894 张图片、MAFA 数据集中选取 4064张图片,包含戴口罩、不戴口罩、用其他物体遮挡面部共 8000 张图片进行训练。
数据集下载链接:https://pan.baidu.com/s/1nsQf_Py5YyKm87-8HiyJeQ 提取码:eyfz

2. 模型构建及算法实现

数据加载进模型之后,需要定义模型结构,并进行算法实现。

1. 定义模型结构

定义的架构共 28 个卷积层,其中有 8 个主干层,即特征提取层;20 个定位和分类层。每个卷积层的通道数是 32、64、128 三种,为了能够更好地运行在终端设备上,模型设计的较小,共 101.5 万个参数,输入为 260*260 大小的图片。

2. 算法实现
基于 SSD 检测模型推理,实现以下三步:生成全部的 anchor、网络输出值根据全部的anchors 解码、NMS(非极大值抑制)即可,即以下三个函数:

function anchorGenerator()function decodeBBox()function nonMaxSuppression()

训练目标检测模型,最重要的是合理设置 anchor 的大小和宽高比。所谓 anchor 是指在图像上预设好的不同大小,不同长宽比的参照框。假设一个 256*256 大小的图片,经过 64、128 和 256 倍下采样,会产生 4X4、2X2、1X1 大小的特征图,每个点上都设置三个不同大小的 anchor。在实际的 SSD 模型中,300X300 的输入下,anchor 数量也特别多,在38X38、19X19、10X10、5X5、3X3、1X1 的六个特征图上,每个点分别设置 4、6、6、6、6、4 个不同大小和长宽比的 anchor,一共有 38X38X4+ 19X19X6+ 10X10X6+ 5X5X6+3X3X4+ 1X1X4= 8732个 anchor。借助卷积神经网络,可直接输出每个 anchor 是否包含(与物体有较大重叠,也就是 IoU 较大)物体,以及被检测物体相对本 anchor 的中心点偏移、长宽比例。

在训练的时候,也就是给每张图片物体的 Bounding Box,相对于 anchor 进行编码,如果物体 Bounding Box 与某个 anchor 的 IoU 较大,例如,大于 0.5 认为是正样本,否则是负样本。

对于检测网络,有的实现,是用没有归一化的坐标,例如,anchor 设置为(30, 42)尺度大小,但是,有的算法实现,是将坐标和物体框的宽高比,除以图片的宽和高。如果图片都是正方形的,那归一化后宽高比没有变化,如果是 1080P 分辨率的摄像头,那么长宽比是16:9。本来就小的宽度,再除以 1920,而高度除以 1080,会导致归一化后的人脸高度是宽度的 2 倍左右。归一化处理即:

BBOX_NORMALIZE = True

根据数据的分布,将五个定位层的 anchor 的宽高比统一设置为 1,0.62, 0.42。(转换为高宽比,也就是约 1,1.6:1,2.4:1)。

3. 代码实现

# -*- coding:utf-8 -*-
import cv2
import time
import argparseimport numpy as np
from PIL import Image
from keras.models import model_from_json
from utils.anchor_generator import generate_anchors
from utils.anchor_decode import decode_bbox
from utils.nms import single_class_non_max_suppression
from load_model.tensorflow_loader import load_tf_model, tf_inference# 载入模型
sess, graph = load_tf_model('models/face_mask_detection.pb')
# anchor configuration
#特征图大小
feature_map_sizes = [[33, 33], [17, 17], [9, 9], [5, 5], [3, 3]]
#anchor大小
anchor_sizes = [[0.04, 0.056], [0.08, 0.11], [0.16, 0.22], [0.32, 0.45], [0.64, 0.72]]
#anchor宽高比
anchor_ratios = [[1, 0.62, 0.42]] * 5# generate anchors
anchors = generate_anchors(feature_map_sizes, anchor_sizes, anchor_ratios)# 用于推断,批大小为 1,模型输出形状为 [1,N,4],因此将锚点的 dim 扩展为 [1,anchor_num,4]
anchors_exp = np.expand_dims(anchors, axis=0)id2class = {0: 'Mask', 1: 'NoMask'}# 用训练好的模型做预测
def inference(image,conf_thresh=0.5,iou_thresh=0.4,target_shape=(160, 160),draw_result=True,show_result=True):'''  检测推理的主要功能# :param image:3D numpy 图片数组#  :param conf_thresh:分类概率的最小阈值。#  :param iou_thresh:网管的 IOU 门限#  :param target_shape:模型输入大小。#  :param draw_result:是否将边框拖入图像。#  :param show_result:是否显示图像。'''output_info = []height, width, _ = image.shape#获取初始图像的长宽image_resized = cv2.resize(image, target_shape)#改变图像尺寸image_np = image_resized / 255.0  # 归一化到0~1image_exp = np.expand_dims(image_np, axis=0) #扩展图片维度y_bboxes_output, y_cls_output = tf_inference(sess, graph, image_exp)#构建图,返回包含预测结果的框和颜色# 删除批次维度,因为用于推断批次始终是1。y_bboxes = decode_bbox(anchors_exp, y_bboxes_output)[0]y_cls = y_cls_output[0]# 为了加快速度,执行单类 NMS,而不是多类 NMS。即戴口罩人脸和不戴口罩人脸两个类别一起做NMSbbox_max_scores = np.max(y_cls, axis=1)bbox_max_score_classes = np.argmax(y_cls, axis=1)# keep_idx 是 nms 之后的活动边界框。keep_idxs = single_class_non_max_suppression(y_bboxes,bbox_max_scores,conf_thresh=conf_thresh,iou_thresh=iou_thresh,)for idx in keep_idxs:conf = float(bbox_max_scores[idx])class_id = bbox_max_score_classes[idx]bbox = y_bboxes[idx]# 裁剪坐标,避免该值超出图像边界。xmin = max(0, int(bbox[0] * width))ymin = max(0, int(bbox[1] * height))xmax = min(int(bbox[2] * width), width)ymax = min(int(bbox[3] * height), height)

3. 模型生成

该应用主要有两部分,一是对图片中的人脸进行识别;二是对视频中出现的人脸进行识别。

1. 调用训练好的模型

sess, graph = load_tf_model('models\face_mask_detection.pb') #载入模型

2. 图片处理

1)anchor 设定完成后,进行识别
2)解码及非极大值抑制

		if draw_result:if class_id == 0:color = (0, 255, 0)#戴口罩显示绿框else:color = (255, 0, 0) #没戴口罩显示红框cv2.rectangle(image, (xmin, ymin), (xmax, ymax), color, 2)#图像,左上角坐标,右下角坐标 ,颜色,粗细cv2.putText(image, "%s: %.2f" % (id2class[class_id], conf), (xmin + 2, ymin - 2),cv2.FONT_HERSHEY_SIMPLEX, 0.8, color)#图片,添加的文字,左上角坐标,字体,字体大小,颜色output_info.append([class_id, conf, xmin, ymin, xmax, ymax])if show_result:Image.fromarray(image).show()return output_info

3. 视频处理

#视频检测
def run_on_video(video_path, output_video_name, conf_thresh):cap = cv2.VideoCapture(video_path) #读取本地视频height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)#计算视频的高width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)#计算视频的宽fps = cap.get(cv2.CAP_PROP_FPS)#得到视频的帧率fourcc = cv2.VideoWriter_fourcc(*'XVID')#XVID是MPEG-4编码类型,文件名后缀为.avi# writer = cv2.VideoWriter(output_video_name, fourcc, int(fps), (int(width), int(height)))total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)#获取视频总帧数if not cap.isOpened():#视频打开失败raise ValueError("Video open failed.")returnstatus = Trueidx = 0while status:start_stamp = time.time()#返回当前时间的时间戳status, img_raw = cap.read()#第一个参数ret 为True 或者False,代表有没有读取到图片# #第二个参数frame表示截取到一帧的图片img_raw = cv2.cvtColor(img_raw, cv2.COLOR_BGR2RGB)#色彩空间BGR转为RGBread_frame_stamp = time.time()if (status):inference(img_raw,conf_thresh,iou_thresh=0.5,target_shape=(260, 260),draw_result=True,show_result=False)#调用推断cv2.imshow('image', img_raw[:, :, ::-1])cv2.waitKey(1)inference_stamp = time.time()# writer.write(img_raw)write_frame_stamp = time.time()idx += 1#循环直到识别到口罩,然后输出帧数和时间.print("%d of %d" % (idx, total_frames))print("read_frame:%f, infer time:%f, write time:%f" % (read_frame_stamp - start_stamp,inference_stamp - read_frame_stamp,write_frame_stamp - inference_stamp))# writer.release()

系统测试

本部分包括模型训练准确率及模型测试效果。

1. 训练准确率

戴口罩的人脸识别准确率接近 92%,可识别绝大部分戴口罩的人脸,如图所示。

在这里插入图片描述

2. 运行结果

1. 在命令行中运行

# 跟命令行有关的
if __name__ == "__main__":# 跟命令行有关的parser = argparse.ArgumentParser(description="Face Mask Detection") # 创建解析器parser.add_argument('--img-mode', type=int, default=1, help='set 1 to run on image, 0 to run on video.')#这里设置为 1:检测图片;还是设置为 0:视频文件(实时图像数据)检测parser.add_argument('--img-path', type=str, help='path to your image.')parser.add_argument('--video-path', type=str, default='0', help='path to your video, `0` means to use camera.')# parser.add_argument('--hdf5', type=str, help='keras hdf5 file')args = parser.parse_args()# 把parser中设置的所有"add_argument"给返回到args子类实例当中, 那么parser中增加的属性内容都会在args实例中,使用即可。if args.img_mode:imgPath = args.img_path#图片路径img = cv2.imread(imgPath)#读取图片img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)#转换色彩空间(R,G,B换个位置)inference(img, show_result=True, target_shape=(260, 260))else:video_path = args.video_path#视频路径if args.video_path == '0':video_path = 0run_on_video(video_path, '', conf_thresh=0.5)

运行方法如下:

  • 如果您要运行图片,需要:
python tensorflow_infer.py --img-path /path/to/your/img

如果您要在视频上运行,需要:

python tensorflow_infer.py --img-mode 0 --video-path /path/to/video 

如果要打开本地摄像头, video_path 填写 0 就可以:

python tensorflow_infer.py --img-mode 0 --video-path 0

2. 运行结果

照片测试结果如图所示:

在这里插入图片描述

工程源代码下载

详见本人博客资源下载页

其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

相关文章:

基于Tensorflow+SDD+Python人脸口罩识别系统(深度学习)含全部工程源码及模型+视频演示+图片数据集

目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境Anaconda 环境搭建 模块实现1. 数据预处理2. 模型构建及算法实现3. 模型生成 系统测试1. 训练准确率2. 运行结果 工程源代码下载其它资料下载 前言 在当今全球范围内,新冠疫情对我们的生活方式带来了…...

abc200 D 鸽巢原理

题意:https://www.luogu.com.cn/problem/AT_abc200_d 思路:对于一个序列最多有多少个模数,其实就是子序列个数,所以当子序列个数超过200是那么答案一定存在,那么我们就可以直接枚举了,所以我们直接枚举前八…...

QT day1 (图形界面设计)

要求&#xff1a; 功能函数模块 #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow) {qDebug("%s","hello world");//qDebug() << &qu…...

JS逆向系列之猿人学爬虫第9题-动态cookie2

文章目录 目标参数流程分析js代码Python调用测试目标 https://match.yuanrenxue.cn/match/9参数流程分析 二次请求cookie携带m 第一次请求响应内容格式化之后是这样的: < body > < script src = "/static/match/safety/match9/udc.js" > <...

Java ~ Reference ~ FinalizerHistogram【总结】

前言 文章 相关系列&#xff1a;《Java ~ Reference【目录】》&#xff08;持续更新&#xff09;相关系列&#xff1a;《Java ~ Reference ~ FinalizerHistogram【源码】》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;相关系列&#xff1a;《Java ~ Referenc…...

【MySQL】一文带你了解SQL

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集&#xff01; &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指…...

python基础学习3【NumPy矩阵与通用函数【矩阵相乘+平方+广播机制+转置】+ save、load、sort、repeat、unique、鸢尾花1】

NumPy矩阵与通用函数 a np.mat([[1,2],[3,4]])#生成矩阵b np.matrix([[1,7],[6,4]])np.bmat("a b") 矩阵的运算 矩阵特有属性&#xff1a; 属性 说明 T自身转置H共轭转置I逆矩阵A自身数据的二维数据视图 例如&#xff1a; np.matrix(a).T 矩阵相乘&#xff1a;…...

【Spring学习之更简单的读取和存储Bean对象】教会你使用五大类注解和方法注解去存储 Bean 对象

前言&#xff1a; &#x1f49e;&#x1f49e;今天我们依然是学习Spring&#xff0c;这里我们会更加了解Spring的知识&#xff0c;知道Spring是怎么更加简单的读取和存储Bean对象的。也会让大家对Spring更加了解。 &#x1f49f;&#x1f49f;前路漫漫&#xff0c;希望大家坚持…...

微客云原生淘宝客APP小程序系统如何定制

淘宝是中国最大的电商网站&#xff0c;而淘宝的火热&#xff0c;也兴起了一个全新的行业&#xff0c;淘宝客。就是帮助淘宝商家推广商品的一种职业。目前淘宝每年有百分之10的销售业绩都是通过淘宝客贡献的&#xff0c;所以说淘宝客的市场越来越大。但是淘宝客要推广自己的产品…...

QT CTK插件开发(六) 多对一插件

CTK在软件的开发过程中可以很好的降低复杂性、使用 CTK Plugin Framework 提供统一的框架来进行开发增加了复用性 将同一功能打包可以提供多个应用程序使用避免重复性工作、可以进行版本控制提供了良好的版本更新迭代需求、并且支持动态热拔插 动态更新、开发更加简单快捷 方便…...

【Spring Boot整合MyBatis教程】

Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。通过这种方式&#xff0c;Spring Boot致力于在蓬勃发展的快速应用开发…...

ThinkPHP3.2.3通过局域网手机访问项目

折腾一上午&#xff0c; 试了nginx&#xff0c; 试了修改Apache的httpd.conf 试了关闭代理 试了手动配置网络 试了关闭防火墙 试了添加防火墙入站出站规则 问了五个ChatGPT 都没解决。 记录一下 wampserver3.0.4 Apache2.4.18 PHP 5.6.19 MySQL 5.7.11 所有服务启…...

2306C++虚继承

构 B{无序映<串,串>列;整 大小0;空 f(){大小;} }; //虚继承其实不错,但是占位置,占空间.构 C:虚 公 B{空 g(){} };构 D:虚 公 C{空 h(){} }; 构 S{}; 构 T{}; //元<类 T>构 E:虚 公 D{}; 构 E:虚 公 D{};空 主(){//E<S>e;e.f();打印(e.大小);//E<T>m;m…...

使用oracle遇到问题笔记

一、oracle还原到不同版本的oracle数据库报错和解决办法 产生&#xff1a;执行imp导入dmp备份文件时报错 错误内容&#xff1a;导入失败提示&#xff1a;“不是有效的导出文件, 标头验证失败”解决方法 解决办法&#xff1a;http://t.csdn.cn/pJyhc...

我和老刘又被搞惨了

前两天在调试PHY的时候遇到了一堆问题&#xff0c;老刘都不耐其烦的搞定了&#xff0c;这次我们开始调试音频部分&#xff0c;音频部分很简单&#xff0c;无非就是录音&#xff0c;要是能把录音的音频拿到了&#xff0c;那就万事大吉了。老刘也是信心满满&#xff0c;老刘对我说…...

DDD--基本概念

最近项目组一直在推DDD领域驱动设计&#xff0c;现就一些个人理解分享如下。 DDD&#xff08;领域驱动设计&#xff09;是一种软件开发方法论&#xff0c;旨在解决复杂业务场景下的软件设计与开发问题。以下是DDD的基本概念&#xff1a; 领域&#xff08;Domain&#xff09;&…...

chatgpt赋能python:Python多行注释

Python 多行注释 在 Python 中&#xff0c;我们经常需要写注释来解释代码或者用于调试。Python 的注释分为单行注释和多行注释&#xff0c;本文主要介绍 Python 中如何多行注释。 单行注释 在 Python 中&#xff0c;单行注释以符号 # 开头&#xff0c;可以写在代码的任何位置…...

JSP详细基础教学

目录 前言 环境设置 创建JSP文件 编写基本的JSP代码 部署和运行JSP页面 基础语法 前言 JSP&#xff08;JavaServer Pages&#xff09;是一种用于开发动态网页的Java技术。它允许将Java代码嵌入HTML页面中&#xff0c;以便在服务器端生成动态内容。在本次教程中&#xff…...

mysql修改登录用户的密码

文章目录 mysql5.7即mysql7.0 的修改方式mysql5.8即mysql8.0的修改方式如果修改完密码&#xff0c;发现旧密码和新密码都登录不进来怎么办&#xff1f;发现设置密码老报错 mysql5.7即mysql7.0 的修改方式 1.如果是使用docker里装的mysql 首先使用 [rootlocalhost /]# docker p…...

SNAT和DNAT

SNAT和DNAT 一、SNAT的策略及应用&#xff1a; 1.SNAT&#xff1a; &#xff08;1&#xff09;定义&#xff1a;又称源地址转换。源地址转换是内网地址向外访问时&#xff0c;发起访问的内网ip地址转换为指定的ip地址&#xff08;可指定具体的服务以及相应的端口或端口范围&…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...