OpenVINO教程(五):实现YOLOv11+OpenVINO实时视频目标检测

news2025/4/24 22:51:20

目录

  • 实现讲解
  • 效果展示
  • 完整代码

本文作为上篇博客的延续,在之前实现了图片推理的基础上,进一步介绍如何进行视频推理。

实现讲解

首先,我们需要对之前的 predict_and_show_image 函数进行拆分,将图像显示与推理器(predictor)的初始化解耦。这样做的目的是在进行视频推理前,能够先完成推理器的初始化、模型配置的设置,以及模型与 OpenVINO 优化模型的绑定,从而确保推理过程能够充分利用 OpenVINO 提供的高性能推理引擎。

以下是修改后的代码示例:

def initialize_predictor(det_model: YOLO, compiled_model: ov.CompiledModel, conf=0.25, batch=1, save=False, mode="predict"):
    """
    初始化 det_model 的 predictor,如果尚未初始化,并设置 OpenVINO 编译好的模型。
    
    参数:
        det_model: 模型对象,包含 predictor, model, overrides 等属性。
        compiled_model: OpenVINO 编译好的模型对象。
        conf: 置信度阈值,默认 0.25。
        batch: 批处理大小,默认 1。
        save: 是否保存结果,默认 False。
        mode: 推理模式,默认 "predict"。
    """
    if det_model.predictor is None:
        config = {"conf": conf, "batch": batch, "save": save, "mode": mode}
        args = {**det_model.overrides, **config}
        det_model.predictor = det_model._smart_load("predictor")(
            overrides=args,
            _callbacks=det_model.callbacks
        )
        det_model.predictor.setup_model(model=det_model.model)

    det_model.predictor.model.ov_compiled_model = compiled_model


def predict_and_show_image(det_model: YOLO, compiled_model: ov.CompiledModel):
    """
    使用模型对图像进行目标检测,并通过 Tkinter GUI 显示检测结果
    """
    results = det_model(IMAGE_PATH)
    result_img = Image.fromarray(results[0].plot()[:, :, ::-1])

    root = tk.Tk()
    root.title("YOLOv11 (OpenVINO INT8) Detection Result")
    tk_img = ImageTk.PhotoImage(result_img)
    label = tk.Label(root, image=tk_img)
    label.pack()
    root.mainloop()

接下来,我们需要实现一个函数,用于结合 YOLO 和 OpenVINO 实现对视频的实时目标检测。该函数支持从视频文件或摄像头读取图像帧,并在完成推理处理后,实时显示检测结果、推理耗时和帧率(FPS)。此外,检测结果还可以保存为带有边框标注和帧率信息的视频文件,同时支持将检测信息(如类别、时间戳等)记录为日志文件,便于后续分析。

以下是具体的实现代码:

def run_video_inference(det_model, source=0, flip=True, width=None,
                        save_video=True, save_log=True,
                        output_dir="results"):
    """
    使用 OpenVINO 和 YOLO 模型对视频进行目标检测推理并可视化。

    参数:
        det_model:YOLO 推理模型,支持 __call__(image) 方式调用
        source:视频源,可以是文件路径或摄像头索引, 0 表示默认摄像头
        flip:是否镜像翻转视频(镜像)
        width:设置画面宽度(自动等比例缩放), None 表示保持原尺寸
        save_video: 是否保存检测后的视频(MP4)
        save_log: 是否记录检测日志
        output_dir: 输出文件目录
    """
    cap = cv2.VideoCapture(source)
    if not cap.isOpened():
        print(f"无法打开视频源: {source}")
        return

    Path(output_dir).mkdir(parents=True, exist_ok=True)

    # 视频保存设置(保存为 MP4)
    out_writer = None
    output_path = str(Path(output_dir) / "output_yolo.mp4")
    fourcc = cv2.VideoWriter_fourcc(*"mp4v")

    # 日志文件准备
    log_file = open(Path(output_dir) / "detection_log.txt", "w") if save_log else None

    cv2.namedWindow("YOLO OpenVINO Detection", cv2.WINDOW_GUI_NORMAL | cv2.WINDOW_AUTOSIZE)
    processing_times = collections.deque()

    try:
        while True:
            ret, frame = cap.read()
            if not ret:
                print("视频读取失败或结束。")
                break

            # 检测窗口是否关闭
            if cv2.getWindowProperty("YOLO OpenVINO Detection", cv2.WND_PROP_VISIBLE) < 1:
                print("窗口已关闭,退出推理。")
                break

            # 镜像翻转(常用于摄像头)
            if flip:
                frame = cv2.flip(frame, 1)

            # 等比例缩放画面到指定宽度
            if width:
                scale = width / max(frame.shape)
                frame = cv2.resize(frame, None, fx=scale, fy=scale, interpolation=cv2.INTER_AREA)

            input_image = np.array(frame)

            # 计时推理开始
            start_time = time.time()
            results = det_model(input_image, verbose=False)
            stop_time = time.time()

            # 保存日志
            if log_file:
                for result in results:
                    for box in result.boxes:
                        cls_id = int(box.cls)
                        conf = float(box.conf)
                        log_file.write(f"time: {stop_time:.3f}, class_id: {cls_id}, confidence: {conf:.2f}\n")


            # 绘制检测结果
            frame = results[0].plot()

            # 推理时间统计,用于计算平均推理时间和 FPS
            processing_times.append(stop_time - start_time)
            if len(processing_times) > 200:
                processing_times.popleft()

            avg_time = np.mean(processing_times) * 1000
            fps = 1000 / avg_time

            # 显示推理时间和 FPS
            _, f_width = frame.shape[:2]
            cv2.putText(
                frame,
                f"Inference: {avg_time:.1f}ms ({fps:.1f} FPS)",
                (20, 40),
                cv2.FONT_HERSHEY_COMPLEX,
                f_width / 1000,
                (0, 0, 255),
                1,
                cv2.LINE_AA
            )

          # 初始化 MP4 写入器
            if save_video and out_writer is None:
                height, width_out = frame.shape[:2]
                out_writer = cv2.VideoWriter(output_path, fourcc, 25.0, (width_out, height))

            if save_video and out_writer:
                out_writer.write(frame)

            cv2.imshow("YOLO OpenVINO Detection", frame)
            # ESC 键退出
            if cv2.waitKey(1) == 27:
                print("按下 ESC 键,退出。")
                break

    except KeyboardInterrupt:
        print("用户中断。")
    except RuntimeError as e:
        print("运行错误:", e)
    finally:
        cap.release()
        cv2.destroyAllWindows()
        if out_writer:
            out_writer.release()
        if log_file:
            log_file.close()
        print(f"检测视频保存至: {output_path}")
        if save_log:
            print(f"检测日志保存至: {Path(output_dir) / 'detection_log.txt'}")

最后就是调用这个函数的部分了,下面是具体的示例代码:

    # 5. 初始化 predictor
    initialize_predictor(det_model, compiled_int8_model)

    # 6. 执行视频推理
    run_video_inference(
    det_model=det_model,          # 模型对象
    source="./1.mp4",             # 视频路径或摄像头编号
    flip=False,                    # 是否镜像
    width=1280,                   # 画面宽度
    save_video=True,              # 是否保存 MP4 视频
    save_log=True,                # 是否保存检测日志
    output_dir="./results"        # 输出目录
    )

效果展示

video

完整代码

from pathlib import Path
from zipfile import ZipFile
from typing import Dict

import urllib.request
import tkinter as tk
from PIL import Image, ImageTk

from ultralytics import YOLO
from ultralytics.utils import DEFAULT_CFG
from ultralytics.cfg import get_cfg
from ultralytics.data.converter import coco80_to_coco91_class
from ultralytics.data.utils import check_det_dataset

import openvino as ov
import nncf
import cv2
import numpy as np
import collections
import time


# ----------------------------- #
# 全局配置和路径定义
# ----------------------------- #

MODEL_VARIANTS = ["yolo11n", "yolo11s", "yolo11m", "yolo11l", "yolo11x"]
MODEL_NAME = MODEL_VARIANTS[0]  # 默认使用最轻量的 yolo11n 模型
PT_MODEL_PATH = f"{MODEL_NAME}.pt"
IR_MODEL_DIR = Path(f"{MODEL_NAME}_openvino_model")
IR_MODEL_PATH = IR_MODEL_DIR / f"{MODEL_NAME}.xml"
INT8_MODEL_PATH = Path(f"{MODEL_NAME}_openvino_int8_model/{MODEL_NAME}.xml")

IMAGE_PATH = Path("./coco_bike.jpg")
OUT_DIR = Path("./")

# COCO 数据集资源路径
DATA_URL = "http://images.cocodataset.org/zips/val2017.zip"
LABELS_URL = "https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017labels-segments.zip"
CFG_URL = "https://raw.githubusercontent.com/ultralytics/ultralytics/v8.1.0/ultralytics/cfg/datasets/coco.yaml"
DATA_PATH = OUT_DIR / "val2017.zip"
LABELS_PATH = OUT_DIR / "coco2017labels-segments.zip"
CFG_PATH = OUT_DIR / "coco.yaml"

# ----------------------------- #
# 工具函数模块
# ----------------------------- #

def download_file_if_needed(url: str, filename: str, dest_dir: Path) -> Path:
    """
    下载文件(若文件已存在则跳过)
    """
    dest_dir.mkdir(parents=True, exist_ok=True)
    file_path = dest_dir / filename
    if not file_path.exists():
        print(f"Downloading: {filename}")
        urllib.request.urlretrieve(url, file_path)
    else:
        print(f"File already exists: {file_path}")
    return file_path

def prepare_test_image():
    """
    确保测试图片存在,如无则从官方地址下载
    """
    if not IMAGE_PATH.exists():
        download_file_if_needed(
            "https://storage.openvinotoolkit.org/repositories/openvino_notebooks/data/data/image/coco_bike.jpg",
            IMAGE_PATH.name, IMAGE_PATH.parent
        )

def load_or_export_openvino_model() -> ov.CompiledModel:
    """
    加载或导出 YOLOv11 OpenVINO IR 模型,并编译为 CPU 运行时模型
    """
    model = YOLO(PT_MODEL_PATH).to("cpu")
    if not IR_MODEL_PATH.exists():
        model.export(format="openvino", dynamic=True, half=True)
    core = ov.Core()
    ir_model = core.read_model(IR_MODEL_PATH)
    return core.compile_model(ir_model, "CPU")

def build_ultralytics_model() -> YOLO:
    """
    创建 Ultralytics 的 YOLO 模型接口,用于调用预测器
    """
    return YOLO(IR_MODEL_DIR, task="detect")

def prepare_dataset() -> 'tuple[nncf.Dataset, object]':
    """
    下载并解压 COCO 数据集,构造验证器和 NNCF 所需数据集格式
    """
    if not (OUT_DIR / "coco/labels").exists():
        download_file_if_needed(DATA_URL, DATA_PATH.name, DATA_PATH.parent)
        download_file_if_needed(LABELS_URL, LABELS_PATH.name, LABELS_PATH.parent)
        download_file_if_needed(CFG_URL, CFG_PATH.name, CFG_PATH.parent)

        with ZipFile(LABELS_PATH, "r") as z:
            z.extractall(OUT_DIR)
        with ZipFile(DATA_PATH, "r") as z:
            z.extractall(OUT_DIR / "coco/images")

    args = get_cfg(cfg=DEFAULT_CFG)
    args.data = str(CFG_PATH)

   # 用 ultralytics 的 validator 构建 dataset
    det_model = build_ultralytics_model();
    validator_cls = det_model.task_map[det_model.task]["validator"]
    validator = validator_cls(args=args)

    validator.data = check_det_dataset(args.data)
    validator.stride = 32
    dataloader = validator.get_dataloader(OUT_DIR / "coco", 1)
    validator.class_map = coco80_to_coco91_class()
    validator.names = YOLO(PT_MODEL_PATH).to("cpu").model.names
    validator.nc = 80


    def transform_fn(data: Dict):
        return validator.preprocess(data)['img'].numpy()

    return nncf.Dataset(dataloader, transform_fn), validator

def quantize_model(original_model: ov.Model, quant_dataset: nncf.Dataset) -> ov.Model:
    """
    使用 NNCF 对 OpenVINO 模型进行混合精度量化(混合 INT8/F32)
    """
    ignored_scope = nncf.IgnoredScope(
        subgraphs=[
            nncf.Subgraph(
                inputs=[f"__module.model.{22 if 'v8' in MODEL_NAME else 23}/aten::cat/Concat",
                        f"__module.model.{22 if 'v8' in MODEL_NAME else 23}/aten::cat/Concat_1",
                        f"__module.model.{22 if 'v8' in MODEL_NAME else 23}/aten::cat/Concat_2"],
                outputs=[f"__module.model.{22 if 'v8' in MODEL_NAME else 23}/aten::cat/Concat_7"]
            )
        ]
    )

    quant_model = nncf.quantize(
        original_model,
        quant_dataset,
        preset=nncf.QuantizationPreset.MIXED,
        ignored_scope=ignored_scope
    )
    ov.save_model(quant_model, str(INT8_MODEL_PATH))
    print(f"Quantized model saved to: {INT8_MODEL_PATH}")
    return quant_model

def initialize_predictor(det_model: YOLO, compiled_model: ov.CompiledModel, conf=0.25, batch=1, save=False, mode="predict"):
    """
    初始化 det_model 的 predictor,如果尚未初始化,并设置 OpenVINO 编译好的模型。
    
    参数:
        det_model: 模型对象,包含 predictor, model, overrides 等属性。
        compiled_model: OpenVINO 编译好的模型对象。
        conf: 置信度阈值,默认 0.25。
        batch: 批处理大小,默认 1。
        save: 是否保存结果,默认 False。
        mode: 推理模式,默认 "predict"。
    """
    if det_model.predictor is None:
        config = {"conf": conf, "batch": batch, "save": save, "mode": mode}
        args = {**det_model.overrides, **config}
        det_model.predictor = det_model._smart_load("predictor")(
            overrides=args,
            _callbacks=det_model.callbacks
        )
        det_model.predictor.setup_model(model=det_model.model)

    det_model.predictor.model.ov_compiled_model = compiled_model


def predict_and_show_image(det_model: YOLO, compiled_model: ov.CompiledModel):
    """
    使用模型对图像进行目标检测,并通过 Tkinter GUI 显示检测结果
    """
    results = det_model(IMAGE_PATH)
    result_img = Image.fromarray(results[0].plot()[:, :, ::-1])

    root = tk.Tk()
    root.title("YOLOv11 (OpenVINO INT8) Detection Result")
    tk_img = ImageTk.PhotoImage(result_img)
    label = tk.Label(root, image=tk_img)
    label.pack()
    root.mainloop()

def run_video_inference(det_model, source=0, flip=True, width=None,
                        save_video=True, save_log=True,
                        output_dir="results"):
    """
    使用 OpenVINO 和 YOLO 模型对视频进行目标检测推理并可视化。

    参数:
        det_model:YOLO 推理模型,支持 __call__(image) 方式调用
        source:视频源,可以是文件路径或摄像头索引, 0 表示默认摄像头
        flip:是否镜像翻转视频(镜像)
        width:设置画面宽度(自动等比例缩放), None 表示保持原尺寸
        save_video: 是否保存检测后的视频(MP4)
        save_log: 是否记录检测日志
        output_dir: 输出文件目录
    """
    cap = cv2.VideoCapture(source)
    if not cap.isOpened():
        print(f"无法打开视频源: {source}")
        return

    Path(output_dir).mkdir(parents=True, exist_ok=True)

    # 视频保存设置(保存为 MP4)
    out_writer = None
    output_path = str(Path(output_dir) / "output_yolo.mp4")
    fourcc = cv2.VideoWriter_fourcc(*"mp4v")

    # 日志文件准备
    log_file = open(Path(output_dir) / "detection_log.txt", "w") if save_log else None

    cv2.namedWindow("YOLO OpenVINO Detection", cv2.WINDOW_GUI_NORMAL | cv2.WINDOW_AUTOSIZE)
    processing_times = collections.deque()

    try:
        while True:
            ret, frame = cap.read()
            if not ret:
                print("视频读取失败或结束。")
                break

            # 检测窗口是否关闭
            if cv2.getWindowProperty("YOLO OpenVINO Detection", cv2.WND_PROP_VISIBLE) < 1:
                print("窗口已关闭,退出推理。")
                break

            # 镜像翻转(常用于摄像头)
            if flip:
                frame = cv2.flip(frame, 1)

            # 等比例缩放画面到指定宽度
            if width:
                scale = width / max(frame.shape)
                frame = cv2.resize(frame, None, fx=scale, fy=scale, interpolation=cv2.INTER_AREA)

            input_image = np.array(frame)

            # 计时推理开始
            start_time = time.time()
            results = det_model(input_image, verbose=False)
            stop_time = time.time()

            # 保存日志
            if log_file:
                for result in results:
                    for box in result.boxes:
                        cls_id = int(box.cls)
                        conf = float(box.conf)
                        log_file.write(f"time: {stop_time:.3f}, class_id: {cls_id}, confidence: {conf:.2f}\n")


            # 绘制检测结果
            frame = results[0].plot()

            # 推理时间统计,用于计算平均推理时间和 FPS
            processing_times.append(stop_time - start_time)
            if len(processing_times) > 200:
                processing_times.popleft()

            avg_time = np.mean(processing_times) * 1000
            fps = 1000 / avg_time

            # 显示推理时间和 FPS
            _, f_width = frame.shape[:2]
            cv2.putText(
                frame,
                f"Inference: {avg_time:.1f}ms ({fps:.1f} FPS)",
                (20, 40),
                cv2.FONT_HERSHEY_COMPLEX,
                f_width / 1000,
                (0, 0, 255),
                1,
                cv2.LINE_AA
            )

          # 初始化 MP4 写入器
            if save_video and out_writer is None:
                height, width_out = frame.shape[:2]
                out_writer = cv2.VideoWriter(output_path, fourcc, 25.0, (width_out, height))

            if save_video and out_writer:
                out_writer.write(frame)

            cv2.imshow("YOLO OpenVINO Detection", frame)
            # ESC 键退出
            if cv2.waitKey(1) == 27:
                print("按下 ESC 键,退出。")
                break

    except KeyboardInterrupt:
        print("用户中断。")
    except RuntimeError as e:
        print("运行错误:", e)
    finally:
        cap.release()
        cv2.destroyAllWindows()
        if out_writer:
            out_writer.release()
        if log_file:
            log_file.close()
        print(f"检测视频保存至: {output_path}")
        if save_log:
            print(f"检测日志保存至: {Path(output_dir) / 'detection_log.txt'}")

# ----------------------------- #
# 主执行流程
# ----------------------------- #
def main():
    # 1. 准备测试图像(如无则下载)
    prepare_test_image()

    # 2. 加载或导出 OpenVINO IR 模型,并编译运行(用于量化或预测)
    compiled_fp_model = load_or_export_openvino_model()

    # 3. 构造 Ultralytics YOLO 接口,用于推理/验证
    det_model = build_ultralytics_model()

    # 4. 若 INT8 模型已存在,则直接加载;否则进行量化生成
    core = ov.Core()
    if INT8_MODEL_PATH.exists():
        quantized_model = core.read_model(INT8_MODEL_PATH)
        compiled_int8_model = core.compile_model(quantized_model, "CPU")
    else:
        quant_dataset, _ = prepare_dataset()
        quantized_model = quantize_model(core.read_model(IR_MODEL_PATH), quant_dataset)
        compiled_int8_model = core.compile_model(quantized_model, "CPU")

    # 5. 初始化 predictor
    initialize_predictor(det_model, compiled_int8_model)

    # 6. 执行视频推理
    run_video_inference(
    det_model=det_model,          # 模型对象
    source="./1.mp4",             # 视频路径或摄像头编号
    flip=False,                    # 是否镜像
    width=1280,                   # 画面宽度
    save_video=True,              # 是否保存 MP4 视频
    save_log=True,                # 是否保存检测日志
    output_dir="./results"        # 输出目录
    )

if __name__ == "__main__":
    main()

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

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

相关文章

CentOS的安装以及网络配置

CentOS的下载 在学习docker之前&#xff0c;我们需要知道的就是docker是运行在Linux内核之上的&#xff0c;所以我们需要Linux环境的操作系统&#xff0c;当然了你也可以选择安装ubuntu等操作系统&#xff0c;如果你不想在本机安装的话还可以考虑买阿里或者华为的云服务器&…

「Java EE开发指南」用MyEclipse开发EJB 3无状态会话Bean(二)

本教程介绍在MyEclipse中开发EJB 3无状态会话bean&#xff0c;由于JPA实体和EJB 3实体非常相似&#xff0c;因此本教程不涉及EJB 3实体Bean的开发。在本教程中&#xff0c;您将学习如何&#xff1a; 创建EJB 3项目创建无状态会话bean部署并测试bean 在上文中&#xff08;点击…

深度学习在DOM解析中的应用:自动识别页面关键内容区块

摘要 本文介绍了如何在爬取东方财富吧&#xff08;https://www.eastmoney.com&#xff09;财经新闻时&#xff0c;利用深度学习模型对 DOM 树中的内容区块进行自动识别和过滤&#xff0c;并将新闻标题、时间、正文等关键信息分类存储。文章聚焦爬虫整体性能瓶颈&#xff0c;通…

PyQt6实例_pyqtgraph多曲线显示工具_代码分享

目录 概述 效果 代码 返回结果对象 字符型横坐标 通用折线图工具 工具主界面 使用举例 概述 1 分析数据遇到需要一个股票多个指标对比或一个指标多个股票对比&#xff0c;涉及到同轴多条曲线的显示&#xff0c;所以开发了本工具。 2 多曲线显示部分可以当通用工具使…

Linux网络编程 多线程Web服务器:HTTP协议与TCP并发实战

问题解答 TCP是如何防止SYN洪流攻击的&#xff1f; 方式有很多种&#xff0c;我仅举例部分&#xff1a; 1、调整内核参数 我们知道SYN洪流攻击的原理就是发送一系列无法完成三次握手的特殊信号&#xff0c;导致正常的能够完成三次握手的信号因为 连接队列空间不足&#xff…

Qt 下载的地址集合

Qt 下载离线安装包 download.qt.io/archive/qt/5.14/5.14.2/ Qt 6 安装下载在线安装包 Index of /qt/official_releases/online_installers/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror

ubuntu下gcc/g++安装及不同版本切换

1. 查看当前gcc版本 $ gcc --version# 查看当前系统中已安装版本 $ ls /usr/bin/gcc*2. 安装新版本gcc $ sudo apt-get update# 这里以版本12为依据&#xff08;也可以通过源码方式安装&#xff0c;请自行Google&#xff01;&#xff09; $ sudo apt-get install -y gcc-12 g…

FPGA入门学习Day1——设计一个DDS信号发生器

目录 一、DDS简介 &#xff08;一&#xff09;基本原理 &#xff08;二&#xff09;主要优势 &#xff08;三&#xff09;与传统技术的对比 二、FPGA存储器 &#xff08;一&#xff09;ROM波形存储器 &#xff08;二&#xff09;RAM随机存取存储器 &#xff08;三&…

微信小程序拖拽排序有效果图

效果图 .wxml <view class"container" style"--w:{{w}}px;" wx:if"{{location.length}}"><view class"container-item" wx:for"{{list}}" wx:key"index" data-index"{{index}}"style"--…

WT2000T专业录音芯片:破解普通录音设备信息留存、合规安全与远程协作三大难题

在快节奏的现代商业环境中&#xff0c;会议是企业决策、创意碰撞和战略部署的核心场景。然而&#xff0c;传统会议记录方式常面临效率低、信息遗漏、回溯困难等痛点。如何确保会议内容被精准记录并高效利用&#xff1f;会议室专用录音芯片应运而生&#xff0c;以智能化、高保真…

【Python 学习笔记】 pip指令使用

系列文章目录 pip指令使用 文章目录 系列文章目录前言安装配置使用pip 管理Python包修改pip下载源 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 当前文章记录的是我在学习过程的一些笔记和思考&#xff0c;可能存在有误解的地方&#xff0c;仅供大家…

C# 文件读取

文件读取是指使用 C# 程序从计算机文件系统中获取文件内容的过程。将存储在磁盘上的文件内容加载到内存中&#xff0c;供程序处理。主要类型有&#xff1a;文本文件读取&#xff08;如 .txt, .csv, .json, .xml&#xff09;&#xff1b;二进制文件读取&#xff08;如 .jpg, .pn…

leetcode125.验证回文串

class Solution {public boolean isPalindrome(String s) {s s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();for(int i0,js.length()-1;i<j;i,j--){if(s.charAt(i)!s.charAt(j))return false;}return true;} }

【Android面试八股文】Android系统架构【一】

Android系统架构图 1.1 安卓系统启动 1.设备加电后执行第一段代码&#xff1a;Bootloader 系统引导分三种模式&#xff1a;fastboot&#xff0c;recovery&#xff0c;normal&#xff1a; fastboot模式&#xff1a;用于工厂模式的刷机。在关机状态下&#xff0c;按返回开机 键进…

【数据可视化-21】水质安全数据可视化:探索化学物质与水质安全的关联

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

【prometheus+Grafana篇】从零开始:Linux 7.6 上二进制安装 Prometheus、Grafana 和 Node Exporter

&#x1f4ab;《博主主页》&#xff1a;奈斯DB-CSDN博客 &#x1f525;《擅长领域》&#xff1a;擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控&#xff1b;并对SQLserver、NoSQL(MongoDB)有了解 &#x1f496;如果觉得文章对你有所帮…

STM32(M4)入门:GPIO与位带操作(价值 3w + 的嵌入式开发指南)

一&#xff1a;GPIO 1.1 了解时钟树&#xff08;必懂的硬件基础&#xff09; 在 STM32 开发中&#xff0c;时钟系统是一切外设工作的 “心脏”。理解时钟树的工作原理&#xff0c;是正确配置 GPIO、UART 等外设的核心前提。 1.1.1 为什么必须开启外设时钟&#xff1f; 1. 计…

Linux419 三次握手四次挥手抓包 wireshark

还是Notfound 没连接 可能我在/home 准备配置静态IP vim ctrlr 撤销 u撤销 配置成功 准备关闭防火墙 准备配置 YUM源 df -h 未看到sr0文件 准备排查 准备挂载 还是没连接 计划重启 有了 不重启了 挂载准备 修改配置文件准备 准备清理缓存 ok 重新修改配…

CSS-跟随图片变化的背景色

CSS-跟随图片变化的背景色 获取图片的主要颜色并用于背景渐变需要安装依赖 colorthief获取图片的主要颜色. 并丢给背景注意 getPalette并不是个异步方法 import styles from ./styles.less; import React, { useState } from react; import Colortheif from colorthief;cons…

解决Docker 配置 daemon.json文件后无法生效

vim /etc/docker/daemon.json 在daemon中配置一下dns {"registry-mirrors": ["https://docker.m.daocloud.io","https://hub-mirror.c.163.com","https://dockerproxy.com","https://docker.mirrors.ustc.edu.cn","ht…