RTSP流图片采样助手(yolov5)

news2024/11/30 4:55:05

在监控和视频分析领域,实时采样视频流中的图像数据是十分重要的。本文将介绍一个基于Python和Tkinter构建的RTSP流图片采样助手的设计与实现,旨在简化RTSP流的采样过程,并支持根据用户定义的特殊标签进行筛选。

项目概述

该项目的主要功能包括:

  • 从多个RTSP流中实时采样图像。
  • 根据用户定义的特殊标签筛选并保存图像。
  • 提供友好的图形用户界面(GUI)以便于用户操作。

技术栈

  • Python: 主要编程语言。
  • OpenCV: 用于视频流处理和图像处理。
  • Tkinter: 用于创建图形用户界面。
  • PyTorch: 用于加载和使用深度学习模型进行目标检测。
  • Subprocess: 用于ping测试IP地址的连通性。

关键功能实现

1、GUI设计

使用Tkinter创建用户界面,用户可以输入多个IP地址、密码、特殊标签和取样间隔时间。以下是创建GUI的代码片段:

root = tk.Tk()
root.title("RTSP流图片取样助手")

tk.Label(root, text="IP地址(每行一个):").pack()
ip_entry = scrolledtext.ScrolledText(root, height=15, width=50)
ip_entry.pack()

tk.Label(root, text="密码(每行一个):").pack()
password_entry = scrolledtext.ScrolledText(root, height=15, width=50)
password_entry.pack()

tk.Label(root, text="特殊标签(以逗号分隔):").pack()
special_items_entry = tk.Entry(root, width=50)
special_items_entry.pack()
special_items_entry.insert(0, "person")

tk.Label(root, text="取样间隔时间(秒):").pack()
interval_entry = tk.Entry(root, width=10)
interval_entry.pack()
interval_entry.insert(0, "5")

model_var = StringVar(root)
model_var.set("未选择模型")
model_button = Button(root, text="选择模型", command=select_model)
model_button.pack()

status_text = tk.Text(root, height=10, width=50)
status_text.pack()

start_button = Button(root, text="开始采样", command=lambda: start_detection_thread(stop_event, status_text))
start_button.pack()

stop_button = Button(root, text="停止采样", command=lambda: stop_detection(stop_event))
stop_button.pack()

root.mainloop()

2、视频流处理

通过OpenCV打开RTSP流并读取视频帧。以下是处理视频流的代码片段:

cap = cv2.VideoCapture(rtsp_url)
if not cap.isOpened():
    print(f"Error: Could not open video stream {rtsp_url}")
    return

while not stop_event.is_set():
    ret, frame = cap.read()
    if not ret:
        print("Error: Failed to read frame from the video stream.")
        break

3、目标检测

集成深度学习模型进行目标检测。在每一帧中,我们使用模型识别物体并绘制边框。以下是模型推理的代码:

if model is not None:
    boxes = detect(imgsz, conf_thres, iou_thres, model, infer_frame, stride, device)
    save_frame = False

    for box in boxes:
        if float(box[4]) > conf_thres:
            x1, y1, x2, y2, label_id = int(box[0]), int(box[1]), int(box[2]), int(box[3]), int(box[5])
            label = _names[int(label_id)]
            plot_one_box(x1, y1, x2, y2, plot_frame, conf_or_proportion=conf_thres, label_cls_id=label, line_thickness=3, color=globalColors[int(label_id)])
            if label in special_items:
                save_frame = True

4.、图像保存逻辑

根据用户输入的特殊标签筛选图像并保存。以下是相关代码:

current_time = time.time()
if (model is None or save_frame) and (current_time - last_save_time) >= sample_interval:
    frame_filename = os.path.join(ip_folder, f"detected_{int(current_time)}.jpg")
    cv2.imwrite(frame_filename, infer_frame)
    print(f"Saved frame: {frame_filename}")
    last_save_time = current_time

5.、多线程处理

为了能够同时处理多个RTSP流,我们使用线程来管理每个流的采样。这样可以确保主线程始终响应用户的操作。以下是创建线程的示例代码:

threads = []
for index, (ip, password) in enumerate(zip(ip_list, password_list)):
    rtsp_url = rtsp_base_url.format("admin", password, ip)
    thread = threading.Thread(target=start, args=(rtsp_url, index, imgsz, conf_thres, iou_thres, model, device, half, stride, special_items, _names, globalColors, save_special_items_name, stop_event, status_text, sample_interval, ip))
    thread.start()
    threads.append(thread)

for thread in threads:
    thread.join()

6、 停止采样

用户可以点击“停止采样”按钮来中断正在进行的采样操作。以下是实现该功能的代码:

def stop_detection(stop_event):
    stop_event.set()
    start_detection_thread.running = False

运行示例

运行程序后,用户需要在GUI中输入以下信息:

  • IP地址: 监控摄像头的RTSP流地址(每行一个)。
  • 密码: 对应的RTSP流密码(每行一个)。
  • 特殊标签: 用户希望采样的物体标签(以逗号分隔)。
  • 取样间隔时间: 图像采样的时间间隔(单位:秒)。
  • 点击“开始采样”后,程序将开始处理指定的RTSP流并根据设置保存图像。如果需要停止采样,只需点击“停止采样”按钮。

源码

1、主程序

import subprocess
from tools import *  # 确保你有 tools.py 文件,包含所需的函数
import cv2
import os
import torch
import random
import time
import tkinter as tk
from tkinter import scrolledtext, messagebox, StringVar, Button, filedialog
import threading
import warnings

warnings.filterwarnings("ignore")


def ping_ip(ip):
    """Ping an IP address and return True if it is reachable, else False."""
    try:
        output = subprocess.check_output(['ping', '-n', '1', ip], stderr=subprocess.STDOUT, universal_newlines=True)
        return True
    except subprocess.CalledProcessError:
        return False


def start(rtsp_url, idx, imgsz, conf_thres, iou_thres, model, device, half, stride, special_items, _names, globalColors, save_special_items_name, stop_event, status_text, sample_interval, ip_address):
    if not ping_ip(ip_address):
        messagebox.showerror("Error", f"无法连接到 IP 地址: {ip_address}")
        return

    cap = cv2.VideoCapture(rtsp_url)
    if not cap.isOpened():
        print(f"Error: Could not open video stream {rtsp_url}")
        return

    status_text.insert(tk.END, f"正在采样视频流: {rtsp_url}_{idx}\n")
    last_save_time = time.time()
    ip_folder = os.path.join(save_special_items_name, f'{ip_address}_{str(idx)}')
    os.makedirs(ip_folder, exist_ok=True)

    while not stop_event.is_set():
        ret, frame = cap.read()
        if not ret:
            print("Error: Failed to read frame from the video stream.")
            break

        infer_frame = frame.copy()
        plot_frame = frame.copy()

        if model is not None:
            boxes = detect(imgsz, conf_thres, iou_thres, model, infer_frame, stride, device)
            save_frame = False

            for box in boxes:
                if float(box[4]) > conf_thres:
                    x1, y1, x2, y2, label_id = int(box[0]), int(box[1]), int(box[2]), int(box[3]), int(box[5])
                    label = _names[int(label_id)]
                    plot_one_box(x1, y1, x2, y2, plot_frame, conf_or_proportion=conf_thres, label_cls_id=label, line_thickness=3, color=globalColors[int(label_id)])
                    if label in special_items:
                        save_frame = True

        current_time = time.time()
        if (model is None or save_frame) and (current_time - last_save_time) >= sample_interval:
            frame_filename = os.path.join(ip_folder, f"detected_{int(current_time)}.jpg")
            cv2.imwrite(frame_filename, infer_frame)
            print(f"Saved frame: {frame_filename}")
            last_save_time = current_time

        cv2.imshow(f'Detection - {rtsp_url}_{idx}', plot_frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()
    status_text.insert(tk.END, f"视频流 {rtsp_url}_{idx} 已停止采样。\n")


def run_detection(ip_list, password_list, special_items, model_path, stop_event, status_text, sample_interval):
    rtsp_base_url = "rtsp://{}:{}@{}:554/Streaming/Channels/101"
    conf_thres = 0.25
    iou_thres = 0.5
    imgsz = 640
    save_special_items_name = "special_items_datasets"

    device = select_device("0" if torch.cuda.is_available() else "cpu")
    half = device.type != 'cpu'
    model = None
    if model_path:
        model = torch.load(model_path, map_location=device)['model'].float()
        model.to(device).eval()
        if half:
            model.half()

    if not os.path.exists(save_special_items_name):
        os.makedirs(save_special_items_name)

    img = torch.zeros((1, 3, imgsz, imgsz), device=device)
    if model is not None:
        _ = model(img.half() if half else img) if device.type != 'cpu' else None
        _names = model.module.names if hasattr(model, 'module') else model.names
        globalColors = [[random.randint(0, 255) for _ in range(3)] for _ in _names]
        stride = max(int(model.stride.max()), 32)
    else:
        _names = []
        globalColors = []
        stride = 32

    threads = []
    for index, (ip, password) in enumerate(zip(ip_list, password_list)):
        rtsp_url = rtsp_base_url.format("admin", password, ip)
        thread = threading.Thread(target=start, args=(rtsp_url, index, imgsz, conf_thres, iou_thres, model, device, half, stride, special_items, _names, globalColors, save_special_items_name, stop_event, status_text, sample_interval, ip))
        thread.start()
        threads.append(thread)

    for thread in threads:
        thread.join()
    start_detection_thread.running = False


def start_detection_thread(stop_event, status_text):
    if hasattr(start_detection_thread, 'running') and start_detection_thread.running:
        messagebox.showwarning("Warning", "Detection is already running.")
        return

    stop_event.clear()  # 重置 stop_event
    start_detection_thread.running = True
    status_text.delete(1.0, tk.END)
    status_text.insert(tk.END, "开始采样...\n")

    ip_list = ip_entry.get("1.0", tk.END).strip().split("\n")
    password_list = password_entry.get("1.0", tk.END).strip().split("\n")
    special_items = special_items_entry.get().strip().split(",")
    model_path = model_var.get() if model_var.get() != "未选择模型" else None
    sample_interval = int(interval_entry.get())

    if len(ip_list) != len(password_list):
        messagebox.showerror("Error", "IP addresses and passwords must match.")
        start_detection_thread.running = False
        return

    detection_thread = threading.Thread(target=run_detection, args=(ip_list, password_list, special_items, model_path, stop_event, status_text, sample_interval))
    detection_thread.start()

    status_text.insert(tk.END, "采样正在进行中...\n")


def stop_detection(stop_event):
    stop_event.set()
    start_detection_thread.running = False


def select_model():
    model_path = filedialog.askopenfilename(title="选择模型文件", filetypes=[("PyTorch Model", "*.pt")])
    if model_path:
        model_var.set(model_path)


if __name__ == '__main__':
    # Tkinter GUI
    root = tk.Tk()
    root.title("RTSP流图片取样助手")

    tk.Label(root, text="IP地址(每行一个):").pack()
    ip_entry = scrolledtext.ScrolledText(root, height=15, width=50)
    ip_entry.pack()

    tk.Label(root, text="密码(每行一个):").pack()
    password_entry = scrolledtext.ScrolledText(root, height=15, width=50)
    password_entry.pack()

    tk.Label(root, text="特殊标签(以逗号分隔):").pack()
    special_items_entry = tk.Entry(root, width=50)
    special_items_entry.pack()
    special_items_entry.insert(0, "person")

    tk.Label(root, text="取样间隔时间(秒):").pack()
    interval_entry = tk.Entry(root, width=10)
    interval_entry.pack()
    interval_entry.insert(0, "5")

    model_var = StringVar(root)
    model_var.set("未选择模型")
    model_button = Button(root, text="选择模型", command=select_model)
    model_button.pack()

    stop_event = threading.Event()

    status_text = tk.Text(root, height=10, width=50)
    status_text.pack()

    start_button = Button(root, text="开始采样", command=lambda: start_detection_thread(stop_event, status_text))
    start_button.pack()

    stop_button = Button(root, text="停止采样", command=lambda: stop_detection(stop_event))
    stop_button.pack()

    root.mainloop()

2、工具程序

# !/usr/bin/python3
# -*- coding:utf-8 -*-
# cython: language_level=3
import os.path
import random
import shutil
import time
from pathlib import Path
import cv2
import numpy as np
import torch
from tqdm import tqdm
from utils.augmentations import letterbox
from utils.general import non_max_suppression, scale_boxes
from utils.torch_utils import select_device
NUM_THREADS = min(8, max(1, os.cpu_count() - 1))  # number of YOLO multiprocessing threads




def img_transpose(img0, img_size, stride):
    assert img0 is not None, 'Image Not Found '
    img = letterbox(img0, img_size, stride=stride)[0]
    img = img[:, :, ::-1].transpose(2, 0, 1)
    img = np.ascontiguousarray(img)
    return img


def calculate_box_area(x1, y1, x2, y2):
    return (x2 - x1) * (y2 - y1)


def detect(img_size, conf_thres, iou_thres, model, img0, stride, device):
    imgsz = img_size
    img = img_transpose(img0, imgsz, stride)
    img = torch.from_numpy(img).to(device)  # 移动到与模型相同的设备
    img = img.float()  # 确保是全精度
    img /= 255.0

    if img.ndimension() == 3:
        img = img.unsqueeze(0)

    pred = model(img, augment=False)[0]
    pred = non_max_suppression(pred, conf_thres, iou_thres, classes=None, agnostic=False)

    for i, det in enumerate(pred):
        if det is not None and len(det):
            det[:, :4] = scale_boxes(img.shape[2:], det[:, :4], img0.shape).round()
    return det


def plot_one_box(x1, y1, x2, y2, img, conf_or_proportion=None, label_cls_id=None, line_thickness=None, color=None):
    tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1
    c1, c2 = (x1, y1), (x2, y2)
    cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)

    if label_cls_id:
        full_label = str(label_cls_id) + (f'_{conf_or_proportion}' if conf_or_proportion is not None else '')
        tf = max(tl - 1, 1)  # font thickness
        t_size = cv2.getTextSize(full_label, 0, fontScale=tl / 3, thickness=tf)[0]

        # Compute the size of the label background based on the full label text size
        c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
        cv2.rectangle(img, c1, (c2[0], c1[1] - t_size[1] - 3), color, -1, cv2.LINE_AA)

        # Draw label text above the rectangle background
        bottom_left_corner_of_text = (c1[0], c1[1] - 2)
        cv2.putText(img, full_label, bottom_left_corner_of_text, 0, tl / 3, [225, 255, 255], thickness=tf,
                    lineType=cv2.LINE_AA)

3、代码依赖

将以上两个代码放在yolov5-7.0的根目录运行即可

4、程序打包(参考我的博客《使用 PyInstaller 打包 Python 应用程序时解决 FileNotFoundError 的问题》)

spec代码:

# -*- mode: python ; coding: utf-8 -*-


block_cipher = None


a = Analysis(['pic.py'],
             pathex=['C:\\Users\\linds\\anaconda3\\envs\\py36\\Lib\\site-packages\\torch\\lib'],
             binaries=[
             (r'.\utils\general.pyc', r'.\utils' ),
             (r'C:\\Users\\linds\\anaconda3\\envs\\py36\\Lib\\site-packages\\torch\\lib\\*', 'torch\\lib'),
             (r'C:\\Users\\linds\\anaconda3\\envs\\py36\\Lib\\site-packages\\torchvision\\*.dll', 'torchvision')

    ],
             datas=[(r'utils/general.py', 'utils'), ('utils/general.pyc', 'utils')],
             hiddenimports=['torch', 'torchvision', 'PIL'],  # 添加隐藏导入
             hookspath=[],
             hooksconfig={},
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)



for d in a.datas:
	if 'cp36-win_amd64.pyd' in d[0]:
		a.datas.remove(d)
		break

for d in a.datas:
	if 'cp36-win_amd64.pyd' in d[0]:
		a.datas.remove(d)
		break


pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)

exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,  
          [],
          name='pic',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True,
          disable_windowed_traceback=False,
          target_arch=None,
          codesign_identity=None,
          entitlements_file=None )

5、软件截图

在这里插入图片描述

总结

本项目展示了如何使用Python、OpenCV和Tkinter构建一个功能强大的RTSP流图片采样助手。该工具可用于监控、视频分析和机器学习等多个领域,能够帮助用户实时采样并保存感兴趣的图像数据。

通过这个项目,您可以更好地理解视频流处理、目标检测以及多线程编程的基本概念。希望这个项目能为您提供灵感,欢迎随时反馈与交流!

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

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

相关文章

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于AGCN-LSTM模型的海上风电场功率概率预测 》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

时序数据库 TDengine 支持集成开源的物联网平台 ThingsBoard

Thingsboard 中“设备配置”和“设备”的关系是一对多的关系,通过设备配置为每个设备设置不同的配置,每个设备都会有一个与其关联的设备配置文件。等等,这不就是TDengine 中超级表的概念: 超级表是一种特殊的表结构,用…

分布式ID多种生成方式

分布式ID 雪花算法(时间戳41机器编号10自增序列号10) 作用:希望ID按照时间进行有序生成 原理: 即一台带有编号的服务器在毫秒级时间戳内生成带有自增序号的ID,这个ID保证了自增性和唯一性 雪花算法根据结构的生成ID个数的上线时…

密码学原理

1.1 加密算法 Tags: 1、加密算法分类 2、对称算法 <原理、特征、算法> 3、非对称算法 <原理、特征、算法> 4、对称算法vs非对称算法 <结合体> 1、加密算法概述&#xff1a; 用于对用户数据进行加密&#xff0c;常用算法有DES、3DES、AES、RSA、DH算法。 根据…

循序渐进丨在 MogDB 数据库中实现 Oracle ASH能力

我们都知道&#xff0c;当 Oracle 数据库出现性能故障后&#xff0c;一般会在线上实时诊断数据库性能问题&#xff0c;特别是资源突然打高的场景&#xff0c;这个时候用到ASH的数据&#xff0c;就能很大程度上准确定位问题所在。 Oracle ASH 在 Oracle 数据库中&#xff0c;实…

E-R网络

一、ER网络的基本性质 ER网络的生成方式 定义&#xff1a;一个随机图是由N个节点构成并且每对节点之间的连接概率为p G(N,L)模型&#xff1a; 一个随机图由N个节点构成&#xff0c;并且有L条连边随机放置在L对节点之间&#xff08;不出现重边与自环&#xff09; G(N,p)模型…

利用移动式三维扫描技术创建考古文物的彩色纹理网格【上海沪敖3D】

文章来源于蔡司工业质量解决方案&#xff0c;作者蔡司工业质量 在考古环境中&#xff0c;三维扫描技术应用广泛&#xff0c;如存档、保存、复制和分享&#xff08;包括实体和虚拟形式&#xff09;。 文中&#xff0c;通过真实的扫描案例&#xff0c;您将了解到三维光学解决方案…

微信小程序绘制轨迹

1、map | uni-app官网 根据官网描述&#xff1a;通过从数据库获取POI数据&#xff0c;并通过 uni-id-common 内的路线规划API&#xff0c;计算路线、距离、时间。 2、 <map style"width:100%;height:96%;" id"myMap" :scale"scale" :longi…

打包使用pythn编写的maya插件,使用pyeal打包

1.安装python,注意版本一定要和maya上面的python解释器版本一致 2.安装pyeal使用pycharm或者maya自带的python解释器mayapy.exe 3.如果有别的库&#xff0c;下载安装到你需要的文件夹中&#xff1a; 使用mayapy: "D:\AnZhuangBao\maya2022\2022\maya2022AZ\Maya2022\bin\m…

【华为HCIP实战课程十四】OSPF网络中LSA过滤,网络工程师

一、3类LSA过滤以及汇总 我们查看SW3的路由到达R4的lo0下一跳是R1的接口IP 10.1.15.1 我们在SW3上查看3类汇总LSA: SW3的3类汇总LSA可以看到ABR R1和R5到达R4的lo0的度量值分别为48和96,因此SW3到达R4的lo0的地址为48+1=49 和 96+1=97, 因此会显示49的cost,SW3的下一跳为R1的…

word怎么清除格式,Word一键清除所有格式教程

你是否曾在编辑Word文档时遇到过复制内容时格式混乱的情况?别担心&#xff0c;这只需要清除一下格式就可以了&#xff0c;很多朋友还不知道word怎么清除格式&#xff0c;下面小编就来给大家讲一讲word一键清除所有格式的方法教程&#xff0c;操作非常简单&#xff0c;有需要的…

使用短效IP池的优势是什么?

短效IP池作为代理IP服务中一种独特的资源管理方式&#xff0c;其应用已经在数据采集、市场分析和网络安全等多个领域中展示出强大的功能。尽管“短效”听起来似乎意味着某种限制&#xff0c;然而在某些特定的应用场景下&#xff0c;短效IP池却提供了无可比拟的优势。本文将详细…

流量PID控制(开度前馈量计算+辅助PID)

和流体流速(瞬时流量)相关的计算请参考下面文章链接: 1、PLC通过伯努利方程近似计算水箱流量 PLC通过伯努利方程近似计算水箱流量(FC)-CSDN博客文章浏览阅读1.6k次。本文介绍了如何使用PLC通过伯努利方程近似计算水箱中的液体流量,主要涉及流量计算、模型验证、梯形图编程及…

R语言机器学习算法实战系列(六)K-邻近算法 (K-Nearest Neighbors)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍教程下载数据加载R包导入数据数据预处理数据描述数据切割调节参数构建模型预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve保存模型总结系统信息介绍 K-邻…

AI创新驱动教育:科技革命下的教育转型

日前&#xff0c;2024教育装备创新大会在杭州市余杭区举行&#xff0c;会上集中展示了AI技术如何赋能教学并深入探讨了其影响。AI技术正在以前所未有的力度&#xff0c;引领教育步入智能新时代&#xff0c;成为教育改革创新的催化剂。 在国家政策的积极推动下&#xff0c;AI技…

tomcat catalina log 出现乱码(SpringMvc)

如下图所示&#xff1a; 解决方法&#xff1a; 找到tomcat的conf文件夹&#xff0c;打开logging.properties&#xff0c;把最后一个UTF-8改成GBK就可以啦 改正后&#xff1a;

基于SpringBoot+Vue+uniapp微信小程序的校园反诈骗微信小程序的详细设计和实现(源码+lw+部署文档+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

2024系统架构师---论软件维护方法及其应用

论软件维护方法及其应用 软件维护是指在软件交付使用后&#xff0c;直至软件被淘汰的整个时间范围内&#xff0c;为了改正错误或满足新的需求而修改软件的活动。在软件系统运行过程中&#xff0c;软件需要维护的原因是多种多样的。根据维护的原因不同可以将软件维护分为改正性…

C语言_指针_进阶

引言&#xff1a;在前面的c语言_指针初阶上&#xff0c;我们了解了简单的指针类型以及使用&#xff0c;下面我们将进入更深层次的指针学习&#xff0c;对指针的理解会有一个极大的提升。从此以后&#xff0c;指针将不再是难点&#xff0c;而是学习底层语言的一把利器。 本章重点…

MySQL中查询语句的执行流程

文章目录 前言流程图概述最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;今天我们一起探讨一下执行一条查询的SQL语句在MySQL内部都发生了什么&#xff0c;让你对MySQL内部的架构具备一个宏观上的了解 流程图 概述 对于查询语句的SQL的执行流程&#xff0c;主要可以分为…