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

人脸真假检测:SVM 与 ResNet18 的实战对比

  在人工智能蓬勃发展的当下,人脸相关技术广泛应用于安防、金融、娱乐等诸多领域。然而,随着人脸合成技术的日益成熟,人脸真假检测成为保障这些应用安全的关键环节。本文将深入探讨基于支持向量机(SVM)结合局部二值模式(LBP)特征,以及基于 ResNet18 神经网络的人脸真假检测方法,并通过 Python 代码实战进行详细分析与对比。

一、技术原理

(一)SVM 与 LBP 特征

  LBP 特征提取:LBP 是一种用于描述图像局部纹理特征的算子。其基本原理是对图像每个像素点,以其为中心,设定邻域像素点个数(如本文中的 8 个邻域点)和半径(本文为 1)。将邻域像素点的灰度值与中心像素点灰度值进行比较,大于等于中心像素点灰度值的邻域点记为 1,小于则记为 0,这些二进制值按顺时针或逆时针顺序排列形成一个二进制码,该码就是中心像素点的 LBP 值。对整幅图像计算 LBP 值后,通过统计不同 LBP 值出现的频率(即直方图),得到图像的 LBP 特征。这种特征对光照变化具有一定的鲁棒性,能有效捕捉图像的纹理细节 。

  SVM 模型:支持向量机是一种二分类模型,旨在寻找一个最优分类超平面,使得不同类别的样本点尽可能地远离该超平面。在本文中,采用径向基函数(RBF)作为核函数,它能够将低维空间中的数据映射到高维空间,从而更好地处理非线性分类问题。利用提取的 LBP 特征训练 SVM 模型,实现对人脸真假的分类预测。

(二)ResNet18 神经网络

  ResNet18 架构:ResNet(残差网络)是深度学习领域的经典网络结构,通过引入残差块解决了深度神经网络训练过程中的梯度消失和梯度爆炸问题,使得网络可以训练得更深。ResNet18 包含 18 层卷积层和全连接层,能够自动学习图像的高级特征。

  模型修改与训练:在本文中,对预训练的 ResNet18 模型进行了修改,将最后一层全连接层的输出特征数量调整为 1,并添加了 Sigmoid 激活函数,使其输出为 0 到 1 之间的概率值,用于二分类任务(判断人脸真假)。训练过程中,使用交叉熵损失函数(BCELoss)衡量预测结果与真实标签之间的差异,通过 Adam 优化器调整模型参数,逐步降低损失,提高模型的准确性。

二、代码实现

(一)环境设置与库导入

  首先,需要导入一系列必要的库,包括用于图像处理的 OpenCV、NumPy、scikit - image,用于深度学习的 PyTorch 及其相关工具,以及用于数据处理和评估的 scikit - learn 等:

import os
import cv2
import numpy as np
from skimage.feature import local_binary_pattern
import torch
from torch import nn
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, models
from PIL import Image
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, classification_report
import matplotlib.pyplot as plt
import random

 

(二)SVM 模型实现 

  LBP 特征提取函数extract_lbp_features函数负责读取图像并提取其 LBP 特征。首先将图像转换为灰度图,调整大小为指定尺寸,计算 LBP 值并生成直方图,最后对直方图进行归一化处理:

def extract_lbp_features(image_path, target_size=(64, 64)):try:image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)if image is None:return Noneimage = cv2.resize(image, target_size)lbp = local_binary_pattern(image, 8, 1, method='uniform')(hist, _) = np.histogram(lbp.ravel(), bins=np.arange(0, 10), range=(0, 10))hist = hist.astype("float")hist /= (hist.sum() + 1e-7)return histexcept:return None

 

  数据加载函数load_svm_data函数从指定的真假人脸图像文件夹中读取图像,提取 LBP 特征,并为每个样本标记对应的标签(0 表示假脸,1 表示真脸):

def load_svm_data(fake_dir, real_dir):X, y = [], []for img_name in os.listdir(fake_dir):img_path = os.path.join(fake_dir, img_name)features = extract_lbp_features(img_path)if features is not None:X.append(features)y.append(0)for img_name in os.listdir(real_dir):img_path = os.path.join(real_dir, img_name)features = extract_lbp_features(img_path)if features is not None:X.append(features)y.append(1)return np.array(X), np.array(y)

 

  模型训练与评估函数train_svm函数加载训练数据和测试数据,训练 SVM 模型,并对模型进行评估,输出准确率和分类报告:

def train_svm():X_train, y_train = load_svm_data("training_fake", "training_real")X_test, y_test = load_svm_data("testing_fake", "testing_real")svm = SVC(kernel='rbf', random_state=42)svm.fit(X_train, y_train)y_pred = svm.predict(X_test)accuracy = accuracy_score(y_test, y_pred)print("\n支持向量机模型评估结果:")print("准确率:", accuracy)print(classification_report(y_test, y_pred))return accuracy

 

(三)ResNet18 模型实现 

  自定义数据集类FaceDataset类继承自Dataset,用于加载真假人脸图像数据。在初始化时,将图像路径和对应的标签存储起来,并支持数据增强操作(如随机水平翻转):

class FaceDataset(Dataset):def __init__(self, fake_dir, real_dir, transform=None):self.image_paths = []self.labels = []for img_name in os.listdir(fake_dir):self.image_paths.append(os.path.join(fake_dir, img_name))self.labels.append(0)for img_name in os.listdir(real_dir):self.image_paths.append(os.path.join(real_dir, img_name))self.labels.append(1)self.transform = transformdef __len__(self):return len(self.image_paths)def __getitem__(self, idx):try:image = Image.open(self.image_paths[idx]).convert("RGB")label = self.labels[idx]if self.transform:image = self.transform(image)return image, labelexcept:return None

 

  ResNet18 模型定义与修改get_resnet18函数获取预训练的 ResNet18 模型,并修改其最后一层全连接层和添加 Sigmoid 激活函数:

def get_resnet18():model = models.resnet18(pretrained=True)num_ftrs = model.fc.in_featuresmodel.fc = nn.Linear(num_ftrs, 1)model = nn.Sequential(model, nn.Sigmoid())return model

 

  训练与评估函数train_resnet18函数对数据进行预处理,创建数据集和数据加载器,初始化模型、损失函数和优化器,进行模型训练和测试评估,并绘制训练过程中的损失和准确率曲线:

def train_resnet18():transform = transforms.Compose([transforms.Resize((224, 224)),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])def create_dataset(fake_dir, real_dir, transform):dataset = FaceDataset(fake_dir, real_dir, transform)valid_indices = [i for i in range(len(dataset)) if dataset[i] is not None]return torch.utils.data.Subset(dataset, valid_indices)train_dataset = create_dataset("training_fake", "training_real", transform)test_dataset = create_dataset("testing_fake", "testing_real", transform)train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=4)device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model = get_resnet18().to(device)criterion = nn.BCELoss()optimizer = torch.optim.Adam(model.parameters(), lr=0.001)losses = []accuracies = []model.train()for epoch in range(10):running_loss = 0.0for images, labels in train_loader:images, labels = images.to(device), labels.float().to(device).unsqueeze(1)optimizer.zero_grad()outputs = model(images)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()epoch_loss = running_loss / len(train_loader)losses.append(epoch_loss)print(f"Epoch {epoch + 1}/10, Loss: {epoch_loss:.4f}")model.eval()correct, total = 0, 0test_images = []test_labels = []test_predictions = []with torch.no_grad():for images, labels in test_loader:test_images.extend(images.cpu().numpy())test_labels.extend(labels.cpu().numpy())images, labels = images.to(device), labels.float().to(device).unsqueeze(1)outputs = model(images)predicted = (outputs > 0.5).float()total += labels.size(0)correct += (predicted == labels).sum().item()test_predictions.extend(predicted.cpu().numpy())accuracy = correct / totalprint("\nResNet18模型评估结果:")print(f"准确率: {accuracy:.4f}")plt.figure(figsize=(12, 5))plt.subplot(1, 2, 1)plt.plot(losses, label='Training Loss')plt.xlabel('Epoch')plt.ylabel('Loss')plt.legend()plt.subplot(1, 2, 2)plt.plot(accuracies, label='Training Accuracy')plt.xlabel('Epoch')plt.ylabel('Accuracy')plt.legend()plt.show()return accuracy, test_images, test_labels, test_predictions

 

  可视化随机五张识别结果visualize_random_five函数从测试数据中随机选取五张图像,展示其真实标签和预测结果:

def visualize_random_five(test_images, test_labels, test_predictions):indices = random.sample(range(len(test_images)), 5)plt.figure(figsize=(15, 7))for i, idx in enumerate(indices):img = np.transpose(test_images[idx], (1, 2, 0))img = (img - np.min(img)) / (np.max(img) - np.min(img))label = 'Real' if test_labels[idx] == 1 else 'Fake'prediction = 'Real' if test_predictions[idx] == 1 else 'Fake'plt.subplot(1, 5, i + 1)plt.imshow(img)plt.title(f'Label: {label}\nPred: {prediction}')plt.axis('off')plt.show()

 

(四)主程序入口 

  在主程序中,依次训练 SVM 模型和 ResNet18 模型,比较两个模型的准确率并进行可视化,同时可视化 ResNet18 模型随机五张测试图像的识别结果:

if __name__ == "__main__":print("正在训练支持向量机模型...")svm_accuracy = train_svm()print("\n正在训练ResNet18模型...")resnet_accuracy, test_images, test_labels, test_predictions = train_resnet18()models = ['SVM', 'ResNet18']accuracies = [svm_accuracy, resnet_accuracy]plt.bar(models, accuracies)plt.xlabel('Models')plt.ylabel('Accuracy')plt.title('Model Accuracy Comparison')for i, v in enumerate(accuracies):plt.text(i, v, str(round(v, 4)), ha='center')plt.show()visualize_random_five(test_images, test_labels, test_predictions)

 

三、实验结果与分析 

 

 

 

 

 

  从训练过程输出的日志来看,ResNet18 模型在 10 个训练轮次(Epoch)中,损失(Loss)不断下降,从 Epoch 1 的 0.7298 逐步降低到 Epoch 10 的 0.2930 ,这表明模型在训练过程中不断学习,对训练数据的拟合能力逐渐增强。最终在测试集上得到的准确率为 0.6176 。

  对比 SVM 模型与 ResNet18 模型的准确率柱状图,SVM 模型的准确率为 0.5392,而 ResNet18 模型的准确率为 0.6176,ResNet18 模型的准确率相对更高。这是因为 ResNet18 作为深度神经网络,具备强大的自动特征提取能力,能够从大量图像数据中学习到更复杂、更具区分性的特征表示,从而在分类任务中表现更优。而 SVM 虽然在处理一些简单特征和小规模数据时表现良好,但在面对人脸真假检测这种复杂的图像分类任务时,其特征表示能力相对有限,导致准确率略低。

  观察 ResNet18 模型训练损失曲线,其呈现出持续下降的趋势,说明模型在训练过程中能够有效优化,不断调整参数以降低损失。但从下降的速率和幅度来看,在前期下降较快,后期下降逐渐变缓,这可能意味着模型在后期逐渐接近收敛状态,进一步提升的难度增大。同时,由于未给出测试集上的损失或准确率随 Epoch 的变化情况,暂时无法确定是否存在过拟合现象。不过仅从当前训练损失持续下降且测试准确率有所提升来看,模型在一定程度上能够泛化到测试数据,但后续仍需进一步分析验证。

  从这五张随机选取的测试图像可视化结果来看,模型在部分样本上预测准确,但也存在误判情况。其中,第一张、第二张和第四张图像真实标签为 “Real”,模型预测也为 “Real” ,说明对于这类图像,模型能够较好地提取特征并做出正确判断。第五张图像真实标签为 “Fake”,模型预测也为 “Fake”,表明模型在识别这类假脸图像时具备一定能力。

  然而,第三张图像真实标签为 “Fake”,但模型却预测为 “Real” ,出现了误判。这可能是由于该假脸图像具有一些与真脸相似的特征,或者其合成技术较为特殊,导致模型提取的特征不足以准确区分真假。通过对这类误判样本的深入分析,我们可以针对性地改进模型。比如,进一步挖掘该图像中模型未能有效捕捉的特征差异,调整模型结构或训练策略,以增强模型对这类特殊样本的识别能力。这也再次强调了在实际应用中,不能仅依赖模型的准确率指标,还需关注模型在具体样本上的预测表现,通过对误判样本的研究来不断优化模型性能。

四、总结与展望

  本文通过代码实现并对比了 SVM 结合 LBP 特征与 ResNet18 神经网络在人脸真假检测任务中的应用。实验结果表明,ResNet18 在准确率上优于 SVM,展现出深度神经网络在图像分类任务中的强大性能。SVM 结合 LBP 特征的方法虽然计算相对简单,但在复杂图像特征提取方面存在不足,导致准确率受限。

  在实际应用中,对于计算资源有限、数据规模较小的场景,SVM 方法可作为一种轻量级的解决方案;而对于追求高准确率、数据量充足的场景,ResNet18 等深度神经网络更为合适。未来可尝试将两者结合,比如先用 SVM 进行初步筛选,再利用 ResNet18 进行精细分类,发挥各自优势,提升检测性能。

  此外,当前模型的准确率仍有提升空间。未来可从以下几方面改进:一是进一步优化模型结构,如调整 ResNet18 的层数、参数,或尝试其他更先进的神经网络架构;二是扩充数据集,引入更多不同场景、光照条件、合成技术的人脸图像,增强模型的泛化能力。

 

 

 

相关文章:

人脸真假检测:SVM 与 ResNet18 的实战对比

在人工智能蓬勃发展的当下,人脸相关技术广泛应用于安防、金融、娱乐等诸多领域。然而,随着人脸合成技术的日益成熟,人脸真假检测成为保障这些应用安全的关键环节。本文将深入探讨基于支持向量机(SVM)结合局部二值模式&…...

如何创建伪服务器,伪接口

创建伪接口一般是用于模拟真实接口的行为,以便在开发和测试过程中进行使用,以下是一些常见的创建伪接口的方法: 使用 Web 框架搭建: Python 和 Flask:Flask 是一个轻量级的 Python Web 框架。示例代码如下:…...

《AI大模型应知应会100篇》第54篇:国产大模型API对比与使用指南

第54篇:国产大模型API对比与使用指南 ——从百度文心到通义千问,一文看懂国内AI平台选型 📌 摘要 随着中国人工智能产业的快速发展,越来越多的国产大模型平台开始崭露头角。本文将系统梳理当前主流国产大模型 API(如…...

质量、重力、引力、惯性 的本质,以及虫洞

1、质量 物体,之所以,有质量源自于其微观结构。物体好比一块海绵,浸没在暗物质的海洋里。随暗物质海洋的涌动而不断移动。海绵微观结构越细密,受到暗物质海洋的裹携力就越大(好比汤勺,与漏勺对汤水的阻碍力。又好比纱窗与船帆对风的阻隔力。) 微观结构越细密,在相同表面积…...

基于ssm+mysql的快递管理系统(含LW+PPT+源码+系统演示视频+安装说明)

系统功能 管理员功能:个人中心、用户管理、订单管理、快递员管理;快递员功能:查看订单、更新快递状态;派单员功能:订单分配、订单管理;客户功能:订单查询、个人信息维护。 作者:计算…...

JVM——即时编译器的中间表达形式

中间表达形式(IR):编译器的核心抽象层 1. IR的本质与作用 在编译原理的体系中,中间表达形式(Intermediate Representation, IR)是连接编译器前端与后端的桥梁。前端负责将源代码转换为IR,而后…...

质心均匀体(引力屏蔽技术)

1、线质心体 陀螺我们都玩过,一个惯性圆盘加一个轴,旋转起来可以独脚而立。(垂直于旋转面的不平衡力,在旋转面旋转180度后,被其自身抵消,故而平衡。可抵消不平衡力的大小,取决于惯性飞轮的质量和旋转的速度)。此时,旋转的陀螺等同于一个轴线质心体(轴线上任意一点提供支…...

深度学习:AI为老年痴呆患者点亮希望之光

引言 随着全球人口老龄化进程的加速,老年痴呆症已成为严重威胁老年人健康和生活质量的公共卫生问题。据世界卫生组织统计,全球每 3 秒钟就有 1 人被诊断为痴呆,预计到 2050 年,全球痴呆患者人数将从目前的约 5000 万激增至 1.52 亿…...

JAVA实战开源项目:健身房管理系统 (Vue+SpringBoot) 附源码

本文项目编号 T 180 ,文末自助获取源码 \color{red}{T180,文末自助获取源码} T180,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...

STM32的SysTick

SysTick介绍 定义:Systick,即滴答定时器,是内核中的一个特殊定时器,用于提供系统级的定时服务。该定时器是一个24位的递减计数器,具有自动重载值寄存器的功能。当计数器到达自动重载值时,它会自动重新加载…...

【图书管理系统】深度讲解:图书列表展示的后端实现、高内聚低耦合的应用、前端代码讲解

1.约定前后端交互接口 [请求] /book/getListByPage [参数] currentPage1&pageSize10 [响应] 返回封装的result对象对应的Json数据 2. 整体逻辑 2.1 Controller的逻辑 (1)把接收的参数封装为PageRequest类,里面有属性:curren…...

Github 2025-05-10 Rust开源项目日报 Top10

根据Github Trendings的统计,今日(2025-05-10统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10TypeScript项目1Python项目1Zed: 由Atom和Tree-sitter的创建者开发的高性能多人代码编辑器 创建周期:1071 天开发语言:Rust协议类型…...

drf 使用jwt

安装jwt pip install pyJwt 添加登录url path("jwt/login",views.JwtLoginView.as_view(),namejwt-login),path("jwt/order",views.JwtOrderView.as_view(),namejwt-order), 创建视图 from django.contrib.auth import authenticateimport jwt from jw…...

养生:为健康生活添彩

养生是对生活的热爱,是为健康生活注入活力的良方。从饮食、运动到生活习惯,每一个方面都能让我们离健康更近一步。以下是一些实用的养生之道,助你开启健康生活的新旅程。 饮食养生:营养均衡,健康基石 合理的饮食是养…...

在 Vue 3 中使用 canvas-confetti 插件

🎉 在 Vue 3 中使用 canvas-confetti 插件 canvas-confetti 是一个轻量、无依赖的 JavaScript 动画库,用于在网页上展示彩带、庆祝动画。非常适合用于抽奖、支付成功、活动庆祝等场景。 本教程将指导你如何在 Vue 3 项目中集成并使用该插件。 &#x1…...

rt-thread+STM32H7移植lwip出现问题解决方法

问题一:ping不通,或有丢帧情况。 问题二:不开启优化一切正常,keil开启优化后就无法联网。 问题三:网络断断续续。 解决方法: 主要是mpu配置和drv_eth驱动的问题,我的配置如下: mpu&…...

Java Spring、Spring MVC、Spring Boot 和 Spring Cloud 的关系与区别

在 Java 开发领域,Spring、Spring MVC、Spring Boot 和 Spring Cloud 这些框架和技术名词频繁出现。对于初学者来说,理解它们之间的关系和区别可能有些困惑。本文将深入浅出地讲解这些概念,帮助你理清它们的联系与差异。 一、Spring 1.1 定义 Spring 是一个轻量级的 Java…...

服务器综合实验(实战详解)

该文章的目录部分 实验内容 实验完成步骤 虚拟机准备 配置两个虚拟机的本地仓库 虚拟机A: 虚拟机B: 配置SSH公钥互信 虚拟机A: ​编辑 虚拟机B: 提供基于bind的DNS服务 虚拟机A: 项目需求1: …...

Milvus 向量数据库详解与实践指南

一、Milvus 核心介绍 1. 什么是 Milvus? Milvus 是一款开源、高性能、可扩展的向量数据库,专门为海量向量数据的存储、索引和检索而设计。它支持近似最近邻搜索(ANN),适用于图像检索、自然语言处理(NLP&am…...

react+ts中函数组件父子通信方式

1. 父组件通过 Props 向子组件传递数据 这是最常见也是最基本的父子组件通信方式。父组件通过 props 将数据或回调函数传递给子组件。 示例代码&#xff1a; // 子组件接收来自父组件的数据 interface ChildProps {message: string; }const ChildComponent: React.FC<Chi…...

VSCode-插件:codegeex:ai coding assistant / 清华智普 AI 插件

一、官网 https://codegeex.cn/ 二、vscode 安装插件 点击安装即可&#xff0c;无需复杂操作&#xff0c;国内软件&#xff0c;无需科学上网&#xff0c;非常友好 三、智能注释 输入 // 或者 空格---后边自动出现注释信息&#xff0c;&#xff0c;按下 Tab 键&#xff0c;进…...

SlideLoss与FocalLoss在YOLOv8分类损失中的应用及性能分析

文章目录 一、引言二、YOLOv8 损失函数概述三、SlideLoss 详解&#xff08;一&#xff09;SlideLoss 的原理&#xff08;二&#xff09;SlideLoss 的代码实现 四、FocalLoss 分类损失函数详解&#xff08;一&#xff09;FocalLoss 的原理&#xff08;二&#xff09;FocalLoss 的…...

【AI智能推荐系统】第七篇:跨领域推荐系统的技术突破与应用场景

第七篇:跨领域推荐系统的技术突破与应用场景 提示语:🔥 “打破数据孤岛,实现1+1>2的推荐效果!深度解析美团、亚马逊如何用跨领域推荐技术实现业务协同,知识迁移核心技术全公开!” 目录 跨领域推荐的商业价值跨领域推荐技术体系 2.1 基于共享表征的学习2.2 迁移学习…...

ui组件二次封装(vue)

组件二次封装的意义 保证一个系统中ui风格和功能的一致性便于维护 从属性、事件、插槽、ref这几方面考虑 属性和事件的处理&#xff1a;ui组件上绑定$attrs&#xff08;v-model本质也是一个属性加一个事件&#xff0c;所以也在其列&#xff09; 在自定义组件中打印$attrs&am…...

OpenCv实战笔记(4)基于opencv实现ORB特征匹配检测

一、原理作用 ORB 原理&#xff08;Oriented FAST and Rotated BRIEF&#xff09;&#xff1a; 特征点检测&#xff1a;使用 FAST 算法检测角点&#xff08;关键点&#xff09;。 方向计算&#xff1a;为每个关键点分配主方向&#xff0c;增强旋转不变性。 特征描述&#xff1a…...

PyTorch 线性回归模型构建与神经网络基础要点解析

笔记 1 PyTorch构建线性回归模型 1.1 创建数据集 import torch from torch.utils.data import TensorDataset # 创建x和y张量数据集对象 from torch.utils.data import DataLoader # 创建数据集加载器 import torch.nn as nn # 损失函数和回归函数 from torch.optim impo…...

Android平台FFmpeg音视频开发深度指南

一、FFmpeg在Android开发中的核心价值 FFmpeg作为业界领先的多媒体处理框架&#xff0c;在Android音视频开发中扮演着至关重要的角色。它提供了&#xff1a; 跨平台支持&#xff1a;统一的API处理各种音视频格式完整功能链&#xff1a;从解码、编码到滤镜处理的全套解决方案灵…...

深入解析路由策略:从流量控制到策略实施

一、网络流量双平面解析 在路由策略的设计中&#xff0c;必须明确区分两个关键平面&#xff1a; 1. 控制层面&#xff08;Control Plane&#xff09; ​​定义​​&#xff1a;路由协议传递路由信息形成的逻辑平面&#xff08;如OSPF的LSA、RIP的Response报文&#xff09;​…...

FHE 之 面向小白的引导(Bootstrapping)

1. 引言 FHE初学者和工程师常会讨论的一个问题是&#xff1b; “什么是引导&#xff08;bootstrapping&#xff09;&#xff1f;” 从理论角度看&#xff0c;这个问题的答案很简单&#xff1a; 引导就是套用 Gentry 提出的思想——在加密状态下同态地执行解密操作&#xff…...

51单片机入门教程——AT24C02数据存储

前言 本教程基于B站江协科技课程进行个人学习整理&#xff0c;专为拥有C语言基础的零基础入门51单片机新手设计。既帮助解决因时间差导致的设备迭代调试难题&#xff0c;也助力新手快速掌握51单片机核心知识&#xff0c;实现从C语言理论到单片机实践应用的高效过渡 。 目录 …...