嵌入式知识点总结 Linux驱动 (六)-linux驱动模型 字符 块 网络驱动 总线驱动 framebuffer汇总

ops/2025/1/31 16:43:45/

针对于嵌入式软件杂乱的知识点总结起来,提供给读者学习复习对下述内容的强化。

目录

1.字符设备 块设备 网络设备的区别并分别举例?

2.LCD驱动模型

3.总线驱动模型

4.输入子系统模型

5.总线模型匹配规则

6.framebuffer机制?


1.字符设备 块设备 网络设备的区别并分别举例?

特点:字符设备以字节为单位进行输入和输出。每个字节都是独立的,设备无法寻址或读取特定的块;块设备以块为单位进行输入和输出。块是设备中数据的固定大小的块,可以寻址和读取访间方式:字符设备通常是顺序访问;块设备支持随机访问实例:键盘、鼠标、串口设备;SSD(固态硬盘)USB 存储设备。

1.字符设备

字符设备指能够像字节流串行顺序依次进行访问的设备,对它的读写是以字节为单位。字符设备的上层没有磁盘文件系统,所以字符设备的file_operations成员函数就直接由字符设备驱动提供(一般字符设备都会实现相应的fops集),因此file_operations 也就成为了字符设备驱动的核心。

特点:

一个字节一个字节读写的设备

读取数据需要按照先后数据(顺序读取)

每个字符设备在/dev目录下对应一个设备文件,linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备。

常见的字符设备有鼠标、键盘、串口、控制台等

上层应用如何调用底层驱动:

1)应用层的程序open(“/dev/xxx”,mode,flags)打开设备文件,进入内核中,即虚拟文件系统中。

2)VFS层的设备文件有对应的struct inode,其中包含该设备对应的设备号,设备类型,返回的设备的结构体。

3)在驱动层中,根据设备类型和设备号就可以找到对应的设备驱动的结构体,用i_cdev保存。该结构体中有很重要的一个操作函数接口file_operations。

4)在打开设备文件时,会分配一个struct file,将操作函数接口的地址保存在该结构体中。

5)VFS层 向应用层返回一个fd,fd是和struct file相对应,这样,应用层可以通过fd调用操作函数,即通过驱动层调用硬件设备。

ps:可以讲字符设备和块设备归为一类,它们都是可以顺序/随机地进行读取和存储的单元,二者驱动主要在于块设备需要具体的burst实现,对访问也有一定的边界要求。其他的没有什么不同。 网络设备是特殊设备的驱动,它负责接收和发送帧数据,可能是物理帧,也可能是ip数据包,这些特性都有网络驱动决定。它并不存在于/dev下面,所以与一般的设备不同。网络设备是一个net_device结构,并通过register_netdev注册到系统里,最后通过ifconfig -a的命令就能看到。 不论是什么设备,设备级的数据传输都是基本类似的,内核里的数据表示只是一部分,更重要的是总线的访问,例如串行spi,i2c,并行dma等。

2.块设备

块设备以数据块的形式存放数据,如NAND Flash以页为单位存储数据,并采用mount方式挂载块设备

块设备必须能够随机存取(random access),字符设备则没有这个要求。

块设备除了给内核提供和字符设备一样的接口外,还提供了专门面向块设备的接口块设备的接口必须支持挂装文件系统,通过此接口,块设备能够容纳文件系统,因此应用程序一般通过文件系统来访问块设备上的内容,而不是直接和设备打交道。

对于块设备而言,上层ext2,jiffs2,fat等文件系统会 实现针对VFS的file_opertations成员函数,所以设备驱动层将看不到file_opeations的存在。磁盘文件系统和设备驱动会将对磁盘上文件的访问转换成对磁盘上柱面和扇区的访问。

特点:

数据以固定长度进行传输,比如512K

从设备的任意位置(可跳)读取,但实际上,块设备会读一定长度的内容,而只返回用户要求访问的内容,所以随机访问实际上还是读了全部内容。

块设备包括硬盘、磁盘、U盘和SD卡等

每个块设备在/dev目录下对应一个设备文件,linux用户程序可以通过设备文件(或称设备节点)来使用驱动程序操作块设备。

块设备可以容纳文件系统,所以一般都通过文件系统来访问,而不是/dev设备节点。

正点原子IMX6u文档中有提到,可以去看看!

大家如果仔细观察的话就会发现有些硬盘或者 NAND Flash 就会标明擦除次数(flash 的特性,写之前要先擦除),比如擦除 100000 次等。因此,为了提高块 设备寿命引入了缓冲区,数据先写入到缓冲区中,等满足一定条件后再一次性写入到真正的物 理存储设备中,这样就减少了对块设备的擦除次数,提高了块设备寿命

都知道字符驱动设备的核心主要在于file_opeations而块设备驱动模型框架主要是block_device_operations

块设备也有操作集,但是file_opeations中是涉及到read、write这些操作的,涉及文件IO内容嘛,但是块设备不一样,众所周知我们都知道他是挂载类型的,那如何从物理块中读写数据?通过request_queue,request和bio

请求队列,请求,遍历请求之类的,点到为止,具体可以去看正点原子文档即可。

3.网络设备

虽然在Linux系统存在一句话叫一切皆文件,无论是各种文本文件还是具体的硬件设备(硬件由设备文件来实现相应)。但是网络设备在Linux内核中却是唯一不体现一切皆设备思想的驱动架构,因为网络设备使用套接字来实现网数据的接受和发送。

网络设备驱动不同于字符设备和块设备,不在/dev下以文件节点代表,而是通过单独的网络接口来代表。

特点:

网络接口没有像字符设备和块设备一样的设备号和/dev设备节点,只有接口名,如eth0,eth1

通过socket操作,而不是open read write

核心在于net_device_ops

设备类型访问方式主要特点典型示例设备文件路径
字符设备按字节访问无缓冲,顺序访问,直接与硬件交互串口(UART)、I2C、SPI、键盘、鼠标/dev/ttyS0 (串口)、/dev/input/mouse0 (鼠标)
块设备按块(通常 512B 或 4KB)访问缓冲读写,随机访问,有块缓存机制硬盘(SATA、SSD)、SD 卡、U 盘/dev/sda (硬盘)、/dev/mmcblk0 (SD 卡)
网络设备按数据包(帧)访问基于协议栈通信,使用套接字接口以太网网卡(eth0)、WLAN、LoRa/sys/class/net/eth0 (以太网)

2.LCD驱动模型

在嵌入式 Linux 或 RTOS 系统中,LCD(液晶显示屏)驱动一般采用 帧缓冲(Framebuffer) 模型,或直接使用 SPI、I2C、MIPI、RGB 并行 接口进行数据传输。
不同 LCD 屏幕的驱动方式不同,主要有以下几种:

  • 字符型 LCD(如 1602、2004 LCD) —— I2C / SPI / GPIO 控制
  • 图形 LCD(如 ST7735、ILI9341) —— SPI / 并行总线控制
  • TFT LCD(如 RGB888、MIPI DSI 屏幕) —— 并行 RGB / MIPI DSI / HDMI

Linux LCD 设备树示例

如果你的 LCD 采用 SPI 接口(如 ST7735、ILI9341),需要在设备树 dts 中定义:

&spi0 {st7735: lcd@0 {compatible = "sitronix,st7735";reg = <0>;  // SPI 片选 0spi-max-frequency = <50000000>;dc-gpios = <&gpio3 12 0>;  // 数据/命令引脚reset-gpios = <&gpio3 11 0>;  // 复位引脚backlight = <&backlight>;};
};

这个设备树配置告诉内核:

  • 使用 SPI0 进行通信
  • 指定 GPIO 控制 DC、复位引脚
  • 设置 SPI 频率

2. LCD 驱动代码示例(Linux Framebuffer 方式)

下面是一个 基本的 Framebuffer 驱动,适用于 并行接口 LCD

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/fb.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/io.h>#define LCD_WIDTH   320
#define LCD_HEIGHT  240struct fb_info *lcd_info;
static u32 *lcd_buffer;/* 打开 LCD */
static int lcd_open(struct fb_info *info, int user)
{printk(KERN_INFO "LCD Opened\n");return 0;
}/* 释放 LCD */
static int lcd_release(struct fb_info *info, int user)
{printk(KERN_INFO "LCD Released\n");return 0;
}/* 写入 Framebuffer */
static ssize_t lcd_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos)
{if (copy_from_user(lcd_buffer, buf, count))return -EFAULT;return count;
}/* LCD 操作结构 */
static struct fb_ops lcd_ops = {.owner   = THIS_MODULE,.fb_open = lcd_open,.fb_release = lcd_release,.fb_write = lcd_write,
};/* 初始化 LCD */
static int __init lcd_init(void)
{lcd_info = framebuffer_alloc(sizeof(u32) * LCD_WIDTH * LCD_HEIGHT, NULL);if (!lcd_info)return -ENOMEM;lcd_buffer = (u32 *)lcd_info->screen_base;lcd_info->var.xres = LCD_WIDTH;lcd_info->var.yres = LCD_HEIGHT;lcd_info->fix.line_length = LCD_WIDTH * 4;lcd_info->fbops = &lcd_ops;if (register_framebuffer(lcd_info) < 0) {framebuffer_release(lcd_info);return -EINVAL;}printk(KERN_INFO "LCD Driver Initialized\n");return 0;
}/* 卸载 LCD */
static void __exit lcd_exit(void)
{unregister_framebuffer(lcd_info);framebuffer_release(lcd_info);printk(KERN_INFO "LCD Driver Removed\n");
}module_init(lcd_init);
module_exit(lcd_exit);
MODULE_LICENSE("GPL");

驱动说明

注册 Framebuffer

提供 openwrite 等接口

用户空间可以通过 /dev/fb0 写入像素数据

数据最终存储到 lcd_buffer,并映射到物理 LCD

#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main()
{int fd = open("/dev/fb0", O_RDWR);if (fd < 0) return -1;char buffer[320 * 240 * 4];  // 320x240 RGBAmemset(buffer, 0xFF, sizeof(buffer));  // 填充白色write(fd, buffer, sizeof(buffer));close(fd);return 0;
}

3.总线驱动模型

在 Linux 内核中,设备驱动模型由 三大子系统 组成:

  1. 总线(Bus) —— 负责管理 设备(Device)驱动(Driver) 之间的匹配与通信。
  2. 设备(Device) —— 具体的硬件设备,如 SPI 设备、I2C 设备、USB 设备等。
  3. 驱动(Driver) —— 负责控制 设备,提供接口供应用程序访问。
结构体作用
struct bus_type定义总线
struct device代表总线上的设备
struct device_driver代表驱动
struct bus_type {const char *name;            // 总线名称struct device *dev_root;     // 总线根设备struct list_head devices;    // 设备链表struct list_head drivers;    // 驱动链表int (*match)(struct device *dev, struct device_driver *drv);  // 设备与驱动匹配规则
};

bus_type 负责管理 设备和驱动的匹配(match)

device 代表 硬件设备

device_driver 代表 驱动

4.输入子系统模型

Linux 输入子系统(Input Subsystem)用于处理各种 输入设备(如 键盘、鼠标、触摸屏、遥控器、加速度计等)。它为驱动程序提供统一的 事件传递机制,避免用户态程序直接操作底层硬件。

输入子系统的主要职责:

接收硬件输入事件

标准化输入设备的数据格式

通过 /dev/input/eventX 设备文件向用户空间提供统一接口

结构体作用
struct input_dev代表输入设备(Input Device),负责上报输入事件
struct input_handler事件处理器(Event Handler),处理不同类型的事件
struct input_event具体输入事件(如按键按下/松开、坐标变化)
struct input_device_id设备和处理器的匹配表
struct input_dev {const char *name;             // 设备名称struct input_id id;           // 设备 ID(厂商、产品、版本)unsigned long evbit[EV_MAX];  // 支持的事件类型unsigned long keybit[KEY_MAX];// 支持的按键unsigned long relbit[REL_MAX];// 支持的相对事件(鼠标)unsigned long absbit[ABS_MAX];// 支持的绝对事件(触摸屏)void (*event)(struct input_dev *, unsigned int, unsigned int, int);
};
  • evbit[] 设备支持的 输入事件(如按键 EV_KEY、鼠标移动 EV_REL)。
  • keybit[] 设备支持的 具体按键(如 KEY_AKEY_ENTER)。
  • relbit[] 设备支持的 相对坐标(鼠标的 REL_XREL_Y)。
  • absbit[] 设备支持的 绝对坐标(触摸屏的 ABS_XABS_Y)。
#include <linux/module.h>
#include <linux/input.h>
#include <linux/timer.h>static struct input_dev *virtual_key_dev;
static struct timer_list key_timer;static void key_timer_func(struct timer_list *t)
{static int key_value = 0;key_value = !key_value; // 模拟按键按下/松开input_report_key(virtual_key_dev, KEY_A, key_value);input_sync(virtual_key_dev); // 同步事件mod_timer(&key_timer, jiffies + HZ); // 1 秒后触发
}static int __init virtual_key_init(void)
{virtual_key_dev = input_allocate_device(); // 分配 input_devif (!virtual_key_dev) {pr_err("Failed to allocate input device\n");return -ENOMEM;}virtual_key_dev->name = "Virtual Key Device";virtual_key_dev->evbit[0] = BIT_MASK(EV_KEY); // 设备支持按键virtual_key_dev->keybit[BIT_WORD(KEY_A)] |= BIT_MASK(KEY_A); // 设备支持 A 键if (input_register_device(virtual_key_dev)) {pr_err("Failed to register input device\n");input_free_device(virtual_key_dev);return -EINVAL;}timer_setup(&key_timer, key_timer_func, 0);mod_timer(&key_timer, jiffies + HZ); // 1 秒后触发pr_info("Virtual Key Device Registered\n");return 0;
}static void __exit virtual_key_exit(void)
{del_timer(&key_timer);input_unregister_device(virtual_key_dev);pr_info("Virtual Key Device Unregistered\n");
}module_init(virtual_key_init);
module_exit(virtual_key_exit);
MODULE_LICENSE("GPL");
input_dev代表输入设备
input_event代表输入事件(按键、触摸、鼠标等)
input_handler处理输入事件
input_report_key()上报按键事件
input_register_device()注册输入设备
input_unregister_device()注销输入设备

5.总线模型匹配规则

总线,设备,驱动。匹配规则就是当有一个新的设备挂起时,总线被唤醒,match函数被调用,用device名字去跟本总线下的所有驱动名字去比较。相反就是用驱动的名字去device链表中和所有device的名字比较。如果匹配上,才会调用驱动中的probe函数,否则不调用。至于先后顺序,鉴于个人理解,不会有影响,不管谁先谁后,bus都会完成匹配工作。谈谈对Linux设备驱动模型的认识:设备驱动模型的出现主要有三个好处,设备与驱动分离,驱动可移植性增强:设备驱动抽象结构以总线结构表示看起来更加清晰明了,谁是属于哪一条bus的:最后,就是大家最熟悉的热插拔了,设备与驱动分离很好的奠定了热插拔机制。

在 Linux 设备驱动模型(Device Model)中,总线(Bus)用于连接 设备(Device)驱动(Driver),并提供匹配、管理和电源控制等功能。

Linux 设备驱动采用 "设备-驱动-总线" 三层架构:

  • 设备(Device):硬件设备,如 I2C 设备、SPI 设备、USB 设备等。
  • 驱动(Driver):控制设备的代码,实现设备的初始化、数据传输等。
  • 总线(Bus):管理设备和驱动程序,并负责匹配它们。
struct bus_type {const char *name;   // 总线名称int (*match)(struct device *dev, struct device_driver *drv);int (*probe)(struct device *dev);int (*remove)(struct device *dev);
};

适用于 ARM、嵌入式设备(I2C、SPI、GPIO),匹配规则:

  • compatible 属性匹配 of_match_table
  • 设备树 compatible 字符串必须与驱动匹配
i2c_device: my_i2c@50 {compatible = "mycompany,my_i2c_device";reg = <0x50>;
};
static const struct of_device_id my_i2c_of_match[] = {{ .compatible = "mycompany,my_i2c_device" },{ }
};
MODULE_DEVICE_TABLE(of, my_i2c_of_match);static struct i2c_driver my_i2c_driver = {.driver = {.name = "my_i2c",.of_match_table = my_i2c_of_match,  // 设备树匹配表},.probe = my_i2c_probe,
};

适用于 I2C、SPI、PCI、USB 设备,匹配规则:

  • 设备驱动注册时提供 设备 ID 表
  • 设备注册时 ID 需要匹配驱动中的 ID
static const struct i2c_device_id my_i2c_id[] = {{ "my_i2c_device", 0 },{ }
};
MODULE_DEVICE_TABLE(i2c, my_i2c_id);static struct i2c_driver my_i2c_driver = {.driver = {.name = "my_i2c",},.id_table = my_i2c_id,  // ID 匹配表.probe = my_i2c_probe,
};

I2C 设备注册 

struct i2c_board_info my_i2c_info = {I2C_BOARD_INFO("my_i2c_device", 0x50),
};
i2c_new_device(adapter, &my_i2c_info);
  • I2C_BOARD_INFO("my_i2c_device", 0x50) 设备名称 = my_i2c_id
  • i2c_register_driver() 遍历 ID 表 匹配成功后调用 probe()
设备类型匹配方式
设备树设备(I2C、SPI、GPIO)of_match_table (compatible 匹配)
I2C、SPI 设备i2c_device_id / spi_device_id
PCI 设备pci_device_id (Vendor ID + Device ID)
USB 设备usb_device_id (Vendor ID + Product ID)
ACPI 设备acpi_device_id
平台设备platform_device.name 匹配 platform_driver.name

Linux 总线模型使用 match() 进行设备和驱动的匹配,每种总线(I2C、PCI、USB)有不同的匹配方式。

I2C/SPI 设备常用 of_match_table(设备树匹配)或 id_table(ID 表匹配)。

USB/PCI 设备基于 Vendor ID + Product ID 进行匹配。

平台设备匹配 platform_device.nameplatform_driver.name

6.framebuffer机制?

Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。用户可以将Framebuffer看成是显示内存的一个映像,通过mmap将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。用户不必关心物理内存、换贡机制等等具体细节,这些都是由Framebuffer设备驱动来完成的。通过mmap调用把显卡的物理内存空间映射到用户空间来进行操作。

ramebuffer(帧缓冲) 是 Linux 内核提供的一个 通用图形显示接口,用于驱动 LCD、OLED、HDMI 显示屏。
它允许用户空间进程直接向 内存中的缓冲区 写入像素数据,内核驱动程序会将这些数据映射到物理屏幕上。

Linux 下的 Framebuffer 设备通常在 /dev/fbX 目录下,比如:

/dev/fb0  # 第一个 Framebuffer 设备
/dev/fb1  # 第二个 Framebuffer 设备

用户可以通过 open()write()mmap() 直接访问 Framebuffer,完成屏幕显示。

如果你的 LCD 采用 SPI 接口,需要在设备树 dts 中配置:

&spi0 {ili9341: lcd@0 {compatible = "sitronix,ili9341";reg = <0>;  // 片选 0spi-max-frequency = <50000000>;dc-gpios = <&gpio3 12 0>;  // DC 数据/命令引脚reset-gpios = <&gpio3 11 0>;  // 复位引脚};
};

这告诉内核:

  • 使用 SPI0 设备
  • 指定 GPIO 控制 DC、复位引脚
  • 设置 SPI 频率

完整的 Framebuffer 驱动(适用于并行 RGB LCD)

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/fb.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/io.h>#define LCD_WIDTH   320
#define LCD_HEIGHT  240struct fb_info *lcd_info;
static u32 *lcd_buffer;/* 打开 LCD */
static int lcd_open(struct fb_info *info, int user)
{printk(KERN_INFO "LCD Opened\n");return 0;
}/* 释放 LCD */
static int lcd_release(struct fb_info *info, int user)
{printk(KERN_INFO "LCD Released\n");return 0;
}/* 写入 Framebuffer */
static ssize_t lcd_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos)
{if (copy_from_user(lcd_buffer, buf, count))return -EFAULT;return count;
}/* LCD 操作结构 */
static struct fb_ops lcd_ops = {.owner   = THIS_MODULE,.fb_open = lcd_open,.fb_release = lcd_release,.fb_write = lcd_write,
};/* 初始化 LCD */
static int __init lcd_init(void)
{lcd_info = framebuffer_alloc(sizeof(u32) * LCD_WIDTH * LCD_HEIGHT, NULL);if (!lcd_info)return -ENOMEM;lcd_buffer = (u32 *)lcd_info->screen_base;lcd_info->var.xres = LCD_WIDTH;lcd_info->var.yres = LCD_HEIGHT;lcd_info->fix.line_length = LCD_WIDTH * 4;lcd_info->fbops = &lcd_ops;if (register_framebuffer(lcd_info) < 0) {framebuffer_release(lcd_info);return -EINVAL;}printk(KERN_INFO "LCD Driver Initialized\n");return 0;
}/* 卸载 LCD */
static void __exit lcd_exit(void)
{unregister_framebuffer(lcd_info);framebuffer_release(lcd_info);printk(KERN_INFO "LCD Driver Removed\n");
}module_init(lcd_init);
module_exit(lcd_exit);
MODULE_LICENSE("GPL");
LCD 类型推荐驱动方式
RGB 并行 LCDFramebuffer (/dev/fb0)
SPI LCD (如 ILI9341)SPI 驱动 + Framebuffer
MIPI DSI LCDDRM/KMS

http://www.ppmy.cn/ops/154525.html

相关文章

mysql_use_result的概念和使用案例

mysql_use_result 是 MySQL C API 中的一个函数&#xff0c;它用于检索一个结果集&#xff0c;并且不同于 mysql_store_result&#xff0c;它不会立即将整个结果集读入客户端。相反&#xff0c;它会初始化一个结果集&#xff0c;客户端随后可以通过调用 mysql_fetch_row 来逐行…

蓝桥与力扣刷题(160 相交链表)

题目&#xff1a;给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; ​编辑 题目数据 保证 整个链式结构中不存在环。 注意&a…

openRv1126 AI算法部署实战之——ONNX模型部署实战

在RV1126开发板上部署ONNX算法&#xff0c;实时目标检测RTSP传输。视频演示地址 rv1126 yolov5 实时目标检测 rtsp传输_哔哩哔哩_bilibili 一、准备工作 1.从官网下载YOLOv5-v7.0工程&#xff08;YOLOv5的第7个版本&#xff09; 手动在线下载&#xff1a; Releases ultraly…

2025美赛美国大学生数学建模竞赛A题完整思路分析论文(43页)(含模型、可运行代码和运行结果)

2025美国大学生数学建模竞赛A题完整思路分析论文 目录 摘要 一、问题重述 二、 问题分析 三、模型假设 四、 模型建立与求解 4.1问题1 4.1.1问题1思路分析 4.1.2问题1模型建立 4.1.3问题1样例代码&#xff08;仅供参考&#xff09; 4.1.4问题1样例代码运行结果&…

130周四复盘(162)研究神作

1.设计相关 今天没有进行大思想的学习&#xff0c; 而思考的比较细节&#xff0c; 分析了某神作的核心机制的内外逻辑&#xff0c;总结优点&#xff0c;以及一些过时的缺点&#xff0c; b4这款神作就像一座高峰&#xff0c;难以企及&#xff0c;但魂牵梦萦。如果未来有朝一…

【Block总结】SCSA,探索空间与通道注意力之间的协同效应|即插即用

论文信息 该论文于2025年1月27日发布&#xff0c;探讨了空间注意力和通道注意力的协同作用&#xff0c;提出了一种新的空间与通道协同注意力模块&#xff08;SCSA&#xff09;。该模块由可共享多语义空间注意力&#xff08;SMSA&#xff09;和渐进通道自注意力&#xff08;PCS…

Python 函数魔法书:基础、范例、避坑、测验与项目实战

Python 函数魔法书&#xff1a;基础、范例、避坑、测验与项目实战 内容简介 本系列文章是为 Python3 学习者精心设计的一套全面、实用的学习指南&#xff0c;旨在帮助读者从基础入门到项目实战&#xff0c;全面提升编程能力。文章结构由 5 个版块组成&#xff0c;内容层层递进…

【计算机视觉】目标跟踪应用

一、简介 目标跟踪是指根据目标物体在视频当前帧图像中的位置&#xff0c;估计其在下一帧图像中的位置。视频帧由t到t1的检测&#xff0c;虽然也可以使用目标检测获取&#xff0c;但实际应用中往往是不可行的&#xff0c;原因如下&#xff1a; 目标跟踪的目的是根据目标在当前…