一步一步学OAK之十一:实现在RGB相机上进行对象跟踪

目录

    • Setup 1: 创建文件
    • Setup 2: 安装依赖
    • Setup 3: 导入需要的包
    • Setup 4:定义和加载模型相关的路径和标签
    • Setup 5: 创建pipeline
    • Setup 6: 创建节点
    • Setup 7: 设置属性
      • 设置相机属性
      • 设置神经网络节点属性
      • 设置物体跟踪对象属性
    • Setup 8: 建立链接
    • Setup 9: 连接设备并启动管道
    • Setup 10: 创建与DepthAI设备通信的输出队列
    • Setup 11: 主循环
      • 从输出队列中获取图像帧数据和目标跟踪结果
      • 计算帧率FPS(frames per second)
      • 获取图像帧的颜色、OpenCV格式的图像帧数据以及目标跟踪的数据
      • 在图像帧上绘制目标跟踪的结果
      • 在窗口中显示图像帧,并在帧上绘制神经网络的帧率信息
    • Setup 12:运行程序

这里我们用到了mobilenet-ssd_openvino_2021.4_6shave.blob模型文件,需要下载并存储到本地文件夹,不会下载的小伙伴可以看我前面的博客,里面有介绍,这里直接使用,不介绍下载过程了。

Setup 1: 创建文件

  • 创建新建13-object-tracker-on-rgb文件夹
  • 用vscode打开该文件夹
  • 新建一个main.py 文件

Setup 2: 安装依赖

安装依赖前需要先创建和激活虚拟环境,我这里已经创建了虚拟环境OAKenv,在终端中输入cd…退回到OAKenv的根目录,输入 OAKenv\Scripts\activate激活虚拟环境

安装pip依赖项:

pip install numpy opencv-python depthai blobconverter --user

Setup 3: 导入需要的包

在main.py中导入项目需要的包

from pathlib import Path
import cv2
import depthai as dai
import numpy as np
import time
import argparse

pathlib用于处理文件路径,sys用于系统相关的操作,cv2是OpenCV库用于图像处理,depthai是depthai库用于深度计算和AI推理。time用于处理时间,argparse用于处理命令行参数。

time库:用于处理和操作时间相关的功能和操作。提供了许多用于测量时间、获取当前时间、等待或延迟执行的函数。可用于计时、性能测试、调度任务等场景。例如,time.time()可以获取当前的时间戳,time.sleep()可以使程序休眠指定时间。

argparse库:用于解析命令行参数以及生成用户友好的命令行界面。

  • 允许定义程序所需的命令行参数,并自动解析和验证这些参数。
  • 可以处理位置参数、可选参数、布尔标志等多种参数类型。
  • 使用argparse可以实现灵活的命令行接口,使得程序可以方便地从命令行中获得输入。
  • 例如,可以使用argparse.ArgumentParser创建一个解析器对象,定义参数后调用parse_args()方法解析命令行参数。

Setup 4:定义和加载模型相关的路径和标签

labelMap = ["background", "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow",
            "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]

nnPathDefault = str((Path(__file__).parent / Path('../models/mobilenet-ssd_openvino_2021.4_6shave.blob')).resolve().absolute())
parser = argparse.ArgumentParser()
parser.add_argument('nnPath', nargs='?', help="Path to mobilenet detection network blob", default=nnPathDefault)
parser.add_argument('-ff', '--full_frame', action="store_true", help="Perform tracking on full RGB frame", default=False)

args = parser.parse_args()

fullFrameTracking = args.full_frame

这段代码使用argparse库解析命令行参数,并根据解析的结果设置对应的变量值。

  1. 定义labelMap为一个字符串列表,包含了针对图像分类任务的类别标签。每个元素代表一个类别,按照索引与模型预测结果相对应。

  2. 定义nnPathDefault字符串,指定了模型文件的路径,默认为mobilenet-ssd_openvino_2021.4_6shave.blob文件的路径。

  3. parser = argparse.ArgumentParser()创建一个参数解析器对象。

  4. parser.add_argument('nnPath', nargs='?', help="Path to mobilenet detection network blob", default=nnPathDefault)定义一个位置参数nnPath,该参数用于指定模型文件的路径,默认值为nnPathDefault

  5. parser.add_argument('-ff', '--full_frame', action="store_true", help="Perform tracking on full RGB frame", default=False)用于开启全帧追踪。该参数可以通过命令行中的-ff--full_frame标志进行设置,默认值为False

  6. args = parser.parse_args()执行解析命令行参数的操作,并将解析结果保存在args对象中。

  7. fullFrameTracking = args.full_frame根据解析的结果获取可选参数full_frame的值,并将其赋值给fullFrameTracking变量。

Setup 5: 创建pipeline

pipeline = dai.Pipeline()

Setup 6: 创建节点

camRgb = pipeline.createColorCamera()
detectionNetwork = pipeline.createMobileNetDetectionNetwork()
objectTracker = pipeline.createObjectTracker()

xlinkOut = pipeline.createXLinkOut()
trackerOut = pipeline.createXLinkOut()

xlinkOut.setStreamName("preview")
trackerOut.setStreamName("tracklets")

分别创建ColorCamera节点、MobileNetDetectionNetwork节点、ObjectTracker节点和两个XLinkOut节点,并设置两个XLinkOut节点的节点名称

Setup 7: 设置属性

设置相机属性

camRgb.setPreviewSize(300, 300)
camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
camRgb.setInterleaved(False)
camRgb.setColorOrder(dai.ColorCameraProperties.ColorOrder.BGR)
camRgb.setFps(40)

使用dai.ColorCamera对象的方法来设置相机的预览大小、分辨率、颜色顺序和帧率等参数。

  • camRgb.setInterleaved(False)设置相机捕获图像时是否使用交织模式。如果设置为False,则图像数据将以分离的方式进行捕获,更容易处理和获取分离的通道数据。

  • camRgb.setColorOrder(dai.ColorCameraProperties.ColorOrder.BGR)设置相机捕获图像的颜色顺序为BGR。这意味着相机捕获的图像中,颜色通道的排列顺序是蓝、绿、红。

  • camRgb.setFps(40)设置相机的帧率为40帧/秒。帧率表示相机每秒传输的图像帧数,高帧率可以获得更连续、流畅的图像。

设置神经网络节点属性

detectionNetwork.setBlobPath(args.nnPath)
detectionNetwork.setConfidenceThreshold(0.5)
detectionNetwork.input.setBlocking(False)

使用setBlobPathsetConfidenceThresholdinput.setBlocking方法来配置detectionNetwork对象的设置模型文件路径、置信度阈值和输入通道的阻塞模式。

  • detectionNetwork.setBlobPath(args.nnPath)使用args.nnPath的值来设置detectionNetwork的模型文件路径。args.nnPath是在命令行中通过nnPath参数指定的模型文件路径。
  • detectionNetwork.setConfidenceThreshold(0.5)将置信度阈值设置为0.5。这个阈值决定了模型对目标检测结果的信任程度。只有置信度高于该阈值的检测结果才会被认定为有效结果。
  • detectionNetwork.input.setBlocking(False)将输入通道的阻塞模式设置为非阻塞模式。当设置为非阻塞模式时,输入通道可以在没有新数据时立即返回,而不需要等待新数据到达。

设置物体跟踪对象属性

objectTracker.setDetectionLabelsToTrack([5])   
objectTracker.setTrackerType(dai.TrackerType.ZERO_TERM_COLOR_HISTOGRAM) 
objectTracker.setTrackerIdAssignmentPolicy(dai.TrackerIdAssignmentPolicy.SMALLEST_ID)
  • objectTracker.setDetectionLabelsToTrack([5]) 将要跟踪的目标类别设置为只有瓶子(类别标签为5)。这意味着只有检测到瓶子目标时,才会进行跟踪。

  • objectTracker.setTrackerType(dai.TrackerType.ZERO_TERM_COLOR_HISTOGRAM) 设置跟踪器的类型为“零阶跟踪器”(ZERO_TERM_COLOR_HISTOGRAM)。这种类型的跟踪器使用颜色直方图来描述目标,并根据颜色信息进行跟踪。

  • objectTracker.setTrackerIdAssignmentPolicy(dai.TrackerIdAssignmentPolicy.SMALLEST_ID) 设置当新目标开始跟踪时,选择最小的ID作为跟踪器的ID。这意味着在跟踪过程中,较早被检测到的目标将具有较小的ID值。

Setup 8: 建立链接

camRgb.preview.link(detectionNetwork.input)
objectTracker.passthroughTrackerFrame.link(xlinkOut.input)

if fullFrameTracking:
    camRgb.video.link(objectTracker.inputTrackerFrame)
else:
    detectionNetwork.passthrough.link(objectTracker.inputTrackerFrame)

detectionNetwork.passthrough.link(objectTracker.inputDetectionFrame)
detectionNetwork.out.link(objectTracker.inputDetections)
objectTracker.out.link(trackerOut.input)

连接不同的节点以建立数据流。

  • camRgb.preview.link(detectionNetwork.input)将相机的预览输出连接到目标检测网络的输入,将实时图像流输入到目标检测网络中进行处理。

  • objectTracker.passthroughTrackerFrame.link(xlinkOut.input)将目标跟踪器的跟踪帧经过数据流连接发送到xlink输出端口,以便在外部查看和分析跟踪结果。

  • 如果fullFrameTrackingTrue,则执行camRgb.video.link(objectTracker.inputTrackerFrame)将相机的视频输出连接到目标跟踪器的跟踪帧输入。这意味着完整的帧将用于目标跟踪,而不是仅使用目标检测网络的结果。

  • 如果fullFrameTrackingFalse,则执行detectionNetwork.passthrough.link(objectTracker.inputTrackerFrame)将目标检测网络的传递输出连接到目标跟踪器的跟踪帧输入。这意味着只使用目标检测网络的结果作为跟踪器的输入。

  • detectionNetwork.passthrough.link(objectTracker.inputDetectionFrame)将目标检测网络的传递输出连接到目标跟踪器的检测帧输入。这样,目标检测网络的结果将作为目标跟踪器检测帧的输入,用于跟踪目标。

  • detectionNetwork.out.link(objectTracker.inputDetections)将目标检测网络的输出连接到目标跟踪器的检测输入。这样,目标检测网络检测到的目标将成为目标跟踪器的输入。

  • objectTracker.out.link(trackerOut.input)将目标跟踪器的输出连接到trackerOut对象的输入,以便将跟踪结果输出到其他模块或设备中。

Setup 9: 连接设备并启动管道

with dai.Device(pipeline) as device:

Setup 10: 创建与DepthAI设备通信的输出队列

    preview = device.getOutputQueue("preview", 4, False)
    tracklets = device.getOutputQueue("tracklets", 4, False)
    
    startTime = time.monotonic()
    counter = 0
    fps = 0
    frame = None

创建输出队列,以便从设备获取处理后的结果。

  • device.getOutputQueue("preview", 4, False) 创建一个名为 “preview” 的输出队列。这个队列最多可以存储4个元素,且不是自动清空。通常,“preview” 输出队列用于获取相机的预览图像数据。

  • device.getOutputQueue("tracklets", 4, False) 创建一个名为 “tracklets” 的输出队列。这个队列最多可以存储4个元素,且不是自动清空。通常,“tracklets” 输出队列用于获取目标跟踪的结果,如目标的位置、边界框等信息。

  • startTime = time.monotonic() 用于获取当前的绝对时间,作为计时器的起始时间。time.monotonic() 函数返回的是一个不受系统时间调整影响的单调递增的值。

Setup 11: 主循环

    while True:

从输出队列中获取图像帧数据和目标跟踪结果

        imgFrame = preview.get()
        track = tracklets.get()
  • imgFrame = preview.get() 用于从名为 “preview” 的输出队列中获取图像帧数据。preview.get() 函数会从队列中获取最新的元素并将其返回给 imgFrame 变量。

  • track = tracklets.get() 用于从名为 “tracklets” 的输出队列中获取目标跟踪结果。tracklets.get() 函数会从队列中获取最新的元素并将其返回给 track 变量。

计算帧率FPS(frames per second)

        counter+=1
        current_time = time.monotonic()
        if (current_time - startTime) > 1 :
            fps = counter / (current_time - startTime)
            counter = 0
            startTime = current_time
  • counter += 1 用于增加计数器的值,表示接收到了一帧新的图像数据。

  • current_time = time.monotonic() 用于获取当前的绝对时间。

  • 通过 (current_time - startTime) > 1 条件判断,在过去的一秒钟内是否已经计算过帧率。如果是,则执行以下操作:

  1. fps = counter / (current_time - startTime) 计算帧率,即每秒接收到的图像帧数。
  2. counter = 0 将计数器重置为0,准备重新计数下一秒的图像帧数。
  3. startTime = current_time 更新起始时间为当前时间,重新开始计时。

通过这些操作,可以在每秒钟结束时计算得到最新的帧率,并在需要时使用该值。

获取图像帧的颜色、OpenCV格式的图像帧数据以及目标跟踪的数据

        color = (255, 0, 0)
        frame = imgFrame.getCvFrame()
        trackletsData = track.tracklets
  • color = (255, 0, 0) 定义一个颜色变量,表示RGB颜色值为红色。

  • frame = imgFrame.getCvFrame()imgFrame 对象中获取OpenCV格式的图像帧数据getCvFrame() 函数是一个用于从 imgFrame 对象中提取图像帧数据的方法。

  • trackletsData = track.tracklets 获取目标跟踪数据。track 是一个对象或类,其中包含目标跟踪的相关方法和数据。这里通过 track.tracklets 访问了目标跟踪数据,可能是获取目标物体的位置、速度等信息。根据实际情况,trackletsData 可能包含一个列表或其他数据结构,存储跟踪目标的相关数据。

在图像帧上绘制目标跟踪的结果

        for t in trackletsData:
            roi = t.roi.denormalize(frame.shape[1], frame.shape[0])
            x1 = int(roi.topLeft().x)
            y1 = int(roi.topLeft().y)
            x2 = int(roi.bottomRight().x)
            y2 = int(roi.bottomRight().y)

            try:
                label = labelMap[t.label]
            except:
                label = t.label

            cv2.putText(frame, str(label), (x1 + 10, y1 + 20), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
            cv2.putText(frame, f"ID: {[t.id]}", (x1 + 10, y1 + 35), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
            cv2.putText(frame, t.status.name, (x1 + 10, y1 + 50), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
            cv2.rectangle(frame, (x1, y1), (x2, y2), color, cv2.FONT_HERSHEY_SIMPLEX)
  • 通过 for t in trackletsData 循环遍历目标跟踪数据列表中的每一个跟踪目标。

  • 通过 t.roi.denormalize(frame.shape[1], frame.shape[0]) 将目标的相对坐标转换为绝对坐标,并赋值给 roiroi 是一个矩形区域对象,表示目标在图像中的位置。

  • 通过 roi 对象获取目标矩形的四个角的坐标值,并分别赋值给 x1y1x2y2 变量。这些坐标用于确定目标矩形框的位置和大小。

  • 通过 labelMap[t.label] 尝试从 labelMap 字典中获取目标的标签值,并将其赋值给 label 变量。如果在 labelMap 中没有找到对应的标签,就将 t.label 的值直接赋给 label

  • 使用 cv2.putText() 在图像帧上绘制目标的标签、ID和状态信息。cv2.putText() 函数用于在图像上绘制文本,可以指定文本内容、位置、字体、字体大小、颜色等参数。

  • 使用 cv2.rectangle() 在图像帧上绘制目标矩形框,以及使用定义的 color 绘制框的颜色。

在窗口中显示图像帧,并在帧上绘制神经网络的帧率信息

        cv2.putText(frame, "NN fps: {:.2f}".format(fps), (2, frame.shape[0] - 4), cv2.FONT_HERSHEY_TRIPLEX, 0.4, color)

        cv2.imshow("tracker", frame)

        if cv2.waitKey(1) == ord('q'):
            break

这段代码用于在窗口中显示图像帧,并在帧上绘制神经网络的帧率信息。

  • 通过 cv2.putText() 在图像帧上绘制 NN fps: {:.2f} 格式化字符串,用来显示神经网络的帧率信息。字符串中的 {:.2f} 是一个占位符,用来显示一个浮点数,保留两位小数。format(fps) 中的 fps 是一个变量,表示神经网络的帧率。(2, frame.shape[0] - 4) 表示文本的位置,坐标为 (2, frame.shape[0] - 4),即文本在图像帧左上角的位置。cv2.FONT_HERSHEY_TRIPLEX 表示使用的字体类型,0.4 表示字体的大小,color 表示文本的颜色。

  • 通过 cv2.imshow() 将图像帧显示在名为 “tracker” 的窗口中。

  • 通过 cv2.waitKey(1) 检测键盘输入。如果按下的键是 ‘q’ (对应的 ASCII 值是 ord(‘q’)),则跳出循环,终止显示图像帧的操作。

Setup 12:运行程序

在终端中输入如下指令运行程序

python main.py

运行看下效果,可以看到相机能实时追踪杯子的位置
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

有哪些免费好用的Python IDE(集成开发环境)?

工欲善其事,必先利其器。Python的学习过程少不了集成开发编辑环境(IDE)。这些Python IDE会提供插件、工具等帮助开发者加快使用Python开发的速度,提高效率。这里收集了一些对开发者非常有帮助的Python IDE(来自hittp://doc.okbase.net/havoc/archive/242…

苹果正在研发具备智能家居显示功能的外接显示器,具备低功耗模式

据彭博社记者 Mark Gurman 在他最新一期的 Power On 时事通讯中报道,苹果公司正致力于研发一款新的 Mac 外接显示器,具备智能家居设备显示器的低功耗模式功能。 根据了解,这款显示器将集成iOS设备芯片,与Studio Display不同的是&a…

【Spring】基于注解方式存取JavaBean:Spring有几种注入方式?有什么区别?

前言 Hello,我是小黄。众所周知,Spring是一个开源的Java应用程序框架,其中包括许多通过注解实现依赖注入的功能。Spring提供了多种注入方式,可以满足不同的需求和场景。常见的注入方式包括构造函数注入、Setter方法注入和属性注入…

基于卷积神经网络的狗猫数据集分类实验

目录 一、环境配置1、anaconda安装2、配置TensorFlow、Keras 二、数据集分类1、分类源码2、训练流程 三、模型调整1、图像增强2、网络模型添加dropout层 四、使用VGG19优化提高猫狗图像分类五、总结六、参考资料 一、环境配置 1、anaconda安装 下载链接:anaconda …

Appium安装部署

目录 一、检查Java环境 二、安装android SDK 一、检查Java环境 Android SDK依赖ava环境,因此需要先安装jdk。在CMD中输入java -version 出现下图的结果,说明当前环境已安装jdk 如果提示java命令无效,请安装后进行下一步。 二、安装androi…

iOS App的上架和版本更新流程

一、前言: 作为一名iOSDeveloper,把开发出来的App上传到App Store是必要的。下面就来详细讲解一下具体流程步骤。 二、准备: 一个已付费的开发者账号(账号类型分为个人(Individual)、公司(Com…

单片机-串口通信

1.串口向电脑发送数据 1.配置串口 T1定时器,方式二8位重装 void UartInit(void) //4800bps11.0592MHz {PCON & 0x7F; //波特率不倍速SCON 0x50; //8位数据,可变波特率TMOD & 0x0F; //清除定时器1模式位TMOD | 0x20; //设定定时器1为8位自动重装方式…

【论文笔记】FASTER SEGMENT ANYTHING:TOWARDS LIGHTWEIGHT SAM FOR MOBILE APPLICATIONS

前脚fast SAM刚发完,后脚mobile SAM就发了 ,之前的论文笔记中我一直就认为fast SAM其实应该算是yolo的扩展工作,和原生的SAM架构相去甚远,而且在简介上直接就对(gong)比(ji)了FastSA…

ElasticSearch 8.0+ 版本Windows系统启动

下载地址:https://www.elastic.co/cn/downloads/past-releases/winlogbeat-8-8-1 解压\elasticsearch\elasticsearch-8.5.1 进入bin目录,启动elasticsearch.bat 问题1: warning: ignoring JAVA_HOMED:\jdk1.8.0_271; using bundled JDK J…

【FPGA】Verilog:时序电路设计 | 自循环移位寄存器 | 环形计数 | 扭环计数 | 约翰逊计数器

前言:本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载 示例:计数器 ​​ 功能特性: 采用 Xilinx Artix-7 XC7A35T芯片 配置方式:USB-JTAG/SPI Flash 高达100MHz 的内部时钟速度 存储器:2Mb…

简单认识Tomcat的部署和优化

文章目录 一、简单认识Tomcat1、简介2、构成3、Tomcat 功能组件结构4、Tomcat 请求过程: 二、Tomcat部署1.关闭防火墙,将安装 Tomcat 所需软件包传到/opt目录下2.安装JDK3.设置JDK环境变量4.测试java环境5.安装Tomcat6.启动和关闭Tomcat7.优化 tomcat 启…

【每日一题】2. 两数相加

【每日一题】2. 两数相加 2. 两数相加题目描述解题思路 2. 两数相加 题目描述 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一…

会网络爬虫能干什么?

网络爬虫是一种自动化程序,用于浏览互联网并从网页中获取数据。它可以执行以下任务: 数据采集:网络爬虫可以访问网站,并从中提取所需的数据,例如新闻文章、产品信息、用户评论等。这些数据可以用于各种目的&#xff0…

MySQL复合查询

目录 一、多表查询 二、自连接 三、子查询 3.1 单行子查询 3.2 多行子查询 3.3 多列子查询 3.4 在from子句中使用子查询 四、合并查询 一、多表查询 实际开发中往往需要将多张表关联起来进行查询,即多表查询在进行多表查询时,只需将多张表的表名…

python机器学习——机器学习相关概念 特征工程

目录 机器学习特征工程1.特征抽取2.特征处理2.1 归一化:传统精确小数据2.2 标准化:大多数情况 3.数据降维3.1特征选择3.2主成分分析PCA 案例:超市订单分析 机器学习 监督学习:输入数据有特征有标签,即有标准答案 分类&…

5.4.1 虚拟专用网VPN

5.4.1 虚拟专用网VPN 我们已经学习了因特网的路由协议(5.3.1 因特网的路由协议(一)、5.3.2 因特网的路由协议(二)基于距离向量算法的RIP协议、5.3.3 因特网的路由协议(三)OSPF协议、5.3.4 因特…

无锡斑目信息技术有限公司与无锡漫途科技有限公司签署战略伙伴合作协议!

2023年6月21日无锡斑目信息技术有限公司与无锡漫途科技有限公司签署战略伙伴合作协议。双方将在数字工厂、智慧城市等领域凭借各自的优势进行全方面的合作。 漫途传感科技总经理田吉成、无锡艾森汇智科技总经理钱小伟、无锡数字城市建设发展工业互联网事业部部长王威共同参加签…

kafka安装(包含Zookeeper 安装)

kafka 依赖于 Zookeeper 1. Zookeeper 本地模式安装 修改配置文件 解压后的目录中的 conf 路径下,将文件 zoo_sample.cfg 修改为 zoo.cfg。 mv zoo_sample.cfg zoo.cfg打开 zoo.cfg 文件,修改 dataDir 路径。 dataDir 路径 默认在 /tmp 下&#xff0…

尚硅谷微信小程序开发 仿网易云音乐App 小程序 后端接口服务器搭建

小程序学习 尚硅谷微信小程序开发 项目网易云小程序学习地址: 01-尚硅谷-小程序-课程介绍_哔哩哔哩_bilibili 视频相关的教程文档与笔记分享 链接:https://pan.baidu.com/s/1aq7ks8B3fJ1Wahge17YYUw?pwd7oqm 提取码:7oqm 配套服务器 老师…

Redis的高可用与持久化

目录 一、Redis 高可用1. 持久化2. 主从复制3. 哨兵4. 集群(cluster) 二、Redis 持久化方式1. 持久化的功能2. 持久化的方式 三、RDB 持久化1. 触发条件2.执行流程3. 启动时加载 四、AOF持久化1.开启 AOF2. 执行流程2.1 命令追加2.2 文件写入(write)和文…