news 2026/9/3 18:44:57

基于PCA的人脸识别系统MATLAB实现教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于PCA的人脸识别系统MATLAB实现教程

很多做图像处理课程设计、毕业设计或论文复现的同学,都会选“基于 PCA 的人脸识别系统”这个题目。题目听起来不复杂,但真正动手实现时,不少人会遇到样本矩阵太大、特征值计算特别慢、识别率上不去、代码东拼西凑跑不通之类的问题。这篇文章把我整理的一套完整 MATLAB 实现整理成教程,从 PCA 原理讲到数据集准备、训练识别全流程、GUI 演示和常见报错排查,希望帮你把这条链路彻底走通。

整套源码结构清晰,函数边界明确,训练、测试、评估、GUI 各模块可以独立调用,适合课程设计、毕业设计二次开发,也方便改写成论文中的实验模块。

1. 背景与核心概念

1.1 人脸识别要解决什么问题

人脸识别的核心任务可以概括成一句话:给一张人脸图像,判断这个人是谁。最朴素的想法是把两张图像逐像素比较,像素相近就认为是同一个人。但这种方式在实际场景中基本不可用,原因有两点:

  • 图像像素维度太高。一张 112×92 的灰度图展开后是一个 10304 维向量,直接比较距离不仅计算量大,而且很多维度对识别没有贡献。
  • 原始像素对光照、表情、遮挡、角度非常敏感。两张同一个人的照片因为光照不同,像素差异可能比不同人之间的差异还大。

所以,人脸识别系统的关键不在于“怎么比”,而在于“比什么”。我们需要从高维图像中提取一组低维、稳定、有区分度的特征,再基于这些特征做分类。PCA 主成分分析就是最经典的特征提取方法之一。

1.2 PCA 主成分分析是什么

PCA 的全称是 Principal Component Analysis,中文叫主成分分析。它是一种无监督的线性降维方法,核心思想是寻找一组正交方向,使得样本数据在这组方向上的方差最大。

用人脸识别的语言来说:给定一批人脸图像,PCA 能找到一组“基图像”,把每张人脸表示成这组基图像的线性组合。由于只保留方差最大的前 k 个方向,人脸图像就被压缩成了 k 维特征向量,这个过程既降低了维度,又保留了数据中最有区分度的信息。

这组基图像展开后看起来像一张张模糊的人脸,所以被称为特征脸(Eigenface)。基于特征脸做人脸识别的方法,就是经典的特征脸方法。

1.3 特征脸方法的地位与适用范围

特征脸方法由 Turk 和 Pentland 在 20 世纪 90 年代提出,是传统人脸识别领域最有影响力的方法之一。虽然现在工业界的人脸识别基本被深度学习方案取代,但 PCA 人脸识别系统仍然是很多课程设计、毕业设计和算法入门教程的高频题目,原因在于:

  • 原理清晰,数学基础不复杂,适合讲解和答辩。
  • 算法实现量适中,用 MATLAB 可以很快跑通。
  • 训练过程可视化效果好,平均脸、特征脸可以直接展示。
  • 便于后续扩展,可以替换分类器,也可以对比 LDA、LBP-HOG 等方法的识别效果。

学习这套系统,不只是在做一个题目,更是理解“降维”和“特征提取”这两个机器学习核心概念的绝佳入口。

2. 系统设计与整体流程

2.1 系统功能拆分

一个完整的 PCA 人脸识别系统,可以拆成四个模块:

模块功能对应文件
数据读取模块遍历人脸库目录,读取图片并预处理load_orl_dataset.m、preprocess_image.m
训练模块计算平均脸、特征脸,保存投影模型pca_train_face.m
识别模块将测试图片投影到特征空间,最近邻分类face_recognize.m
演示与评估模块主脚本、识别率实验、GUI 演示demo_face_recognition.m、evaluate_k.m、pca_face_gui.m

这种拆分方式的好处是后续修改很方便。比如想把最近邻分类器换成 SVM,只需要改识别模块;想增加直方图均衡化预处理,只需要改 preprocess_image 函数。

2.2 训练阶段流程

训练阶段的目标是得到一组特征脸和一个投影模型,流程如下:

  1. 读取训练集中所有人脸图像。
  2. 每张图像灰度化、缩放到统一尺寸。
  3. 将每张图像按列拉直成一个列向量。
  4. 计算所有训练样本的平均脸。
  5. 每个样本减去平均脸,得到中心化矩阵。
  6. 求解协方差矩阵的特征向量,取前 k 个构成特征脸空间。
  7. 将所有训练样本投影到特征脸空间,得到训练投影系数。
  8. 保存平均脸、特征脸、训练投影系数和标签。

2.3 识别阶段流程

识别阶段是对一张未知人脸判断身份,流程如下:

  1. 读取测试图片,执行与训练阶段相同的预处理。
  2. 拉直成列向量。
  3. 减去训练集的平均脸。
  4. 投影到特征脸空间,得到 k 维特征向量。
  5. 与训练集中每个样本的投影系数做距离比较。
  6. 距离最小的训练样本对应的标签,就是识别结果。

2.4 为什么必须区分训练集和测试集

这里有一个很容易被忽略但非常重要的点:测试图片不能参与 PCA 模型训练。

PCA 计算协方差矩阵和特征脸时,只需要使用训练集。如果测试图片也参与了特征脸空间的计算,相当于模型已经提前“见过”了测试数据,识别率会虚高,这在论文和课程设计中叫作数据泄漏。所以本文所有实验都严格把每个人的人脸图片分成两部分,前 5 张用于训练,后 5 张用于测试。

3. 环境准备与数据集说明

3.1 运行环境

本文示例以 MATLAB R2020a 为参考环境,更低版本也能运行,核心代码只使用了 MATLAB 基础功能和图像处理工具箱。

需要提前确认以下几点:

  • 已安装 MATLAB,建议 R2018a 及以上版本。
  • 已安装 Image Processing Toolbox,因为代码用到了 rgb2gray、imresize、imshow 等函数。
  • 如果没有安装图像处理工具箱,灰度化、缩放等步骤需要自己实现,建议直接安装对应工具箱,省时省力。
  • 电脑内存建议 8GB 以上,ORL 人脸库的规模不算大,一般不会遇到内存问题。

3.2 人脸库准备

本文使用 ORL 人脸库,这是人脸识别领域非常经典的公开数据集,由剑桥大学 AT&T 实验室发布。ORL 人脸库包含 40 个人,每人 10 张图像,图像尺寸为 112×92,格式是 PGM 灰度图。图像包含表情、光照、姿态和面部细节的变化,非常适合做人脸识别算法的对比实验。

将 ORL 人脸库下载后放到项目目录中,目录结构如下:

ORL/ ├── 1/ │ ├── 1.pgm │ ├── 2.pgm │ ├── ... │ └── 10.pgm ├── 2/ │ ├── 1.pgm │ ├── 2.pgm │ ├── ... │ └── 10.pgm ├── ... └── 40/ ├── 1.pgm ├── 2.pgm ├── ... └── 10.pgm

这里用子目录编号作为人的身份标签,1.pgm 到 10.pgm 是同一个人的 10 张照片。如果你的数据集不是这个结构,需要对应修改数据读取函数。

3.3 项目目录结构

完整项目建议按下面的结构组织:

PCARecognition/ ├── ORL/ % 人脸库 ├── preprocess_image.m % 图像预处理函数 ├── load_orl_dataset.m % 数据读取函数 ├── pca_train_face.m % PCA 训练函数 ├── face_recognize.m % 识别函数 ├── demo_face_recognition.m % 主演示脚本 ├── evaluate_k.m % 不同 k 值识别率实验 └── pca_face_gui.m % GUI 演示

所有 .m 文件放在同一个目录下,MATLAB 运行时把当前文件夹切换到该目录即可。

4. 核心算法原理详解

4.1 样本矩阵的构造

假设训练集中有 N 张人脸图像,每张图像宽 w、高 h,灰度化后像素总数为 d = w × h。对 ORL 人脸库来说,d = 112 × 92 = 10304,N = 40 × 5 = 200。

把每张图像按列优先拉直成一个 d 维列向量,然后将 N 个列向量拼成一个 d × N 的样本矩阵 X。每一列就是一张人脸图像,每一行对应一个像素位置。

这里需要注意,d 通常远大于 N。例如 d = 10304,N = 200,这就是典型的高维小样本问题。直接处理 d × d 矩阵会非常耗时,所以后面会使用小矩阵技巧。

4.2 中心化与协方差矩阵

PCA 的第一步是中心化。计算所有训练样本的平均列向量:

meanFace = (1/N) * sum(X, 2)

然后将每一列减去平均脸,得到中心化矩阵:

A = X - meanFace

协方差矩阵为 C = A * A' / N,它是一个 d × d 的矩阵。特征值 λ 表示对应特征向量方向上方差的大小,也就是该方向保留的信息量。

可以按特征值从大到小排序,取前 k 个特征向量构成特征脸空间 U,维度为 d × k。这样每张人脸图像 x 就可以投影成 k 维向量:

y = U' * (x - meanFace)

这个 y 就是人脸的低维特征。

4.3 小矩阵技巧:解决维度灾难

直接计算 d × d 矩阵 A * A' 的特征分解,在像素维度很大时基本不可行。好在有一个经典的数学技巧可以绕开这个问题。

考虑小矩阵 L = A' * A,它是 N × N 的矩阵。假设 v 是 L 的特征向量,对应特征值为 λ,那么:

A' * A * v = λ * v

两边同时左乘 A:

A * A' * A * v = λ * A * v

也就是说,(A * A') * (A * v) = λ * (A * v)。

这说明 A * v 就是原协方差矩阵 A * A' 的特征向量,对应特征值也是 λ。

于是,我们不需要计算 d × d 的大矩阵,只需要计算 N × N 的小矩阵 L 的特征分解,然后用 A * v 还原出特征脸向量。这一步是 PCA 人脸识别系统能够在小样本情况下高效运行的关键。

在 MATLAB 中,可以把 L = A' * A 的特征向量记为 V,然后 eigenfaces = A * V,再对每一列做归一化即可。

4.4 特征脸的物理意义

特征脸本质上是训练集中人脸图像在方差最大方向上的“线性组合”。把特征脸向量 reshape 成图像尺寸后,会看到一些模糊的人脸轮廓,也就是平均脸基础上的主要变化模式。

第一张特征脸通常对应光照变化,后面的特征脸对应不同人脸结构的变化。保留的特征脸数量 k 决定了人脸特征空间的表达能力。k 太小,信息不足;k 太大,会引入噪声,而且计算量增加。一般通过识别率实验来选择合适的 k 值。

4.5 最近邻分类

人脸图像投影到特征空间后,识别问题就变成了一个低维空间中的最近邻问题。常用距离度量是欧氏距离:

distance = ||y_test - y_train_i||_2

遍历训练集中所有样本,找到最小距离对应的标签作为识别结果。

也可以用余弦相似度代替欧氏距离,两种方式各有优劣,欧氏距离实现简单,余弦相似度对光照变化更鲁棒一些。本文核心代码使用欧氏距离,识别函数中可以很方便地切换。

5. 系统源码实现

下面开始写完整源码。先给出所有函数文件,再给主脚本。每个函数都加了注释,方便按模块理解。

5.1 图像预处理函数 preprocess_image.m

这个函数负责读取一张图片,并完成灰度化、缩放到统一尺寸、拉直成列向量三个步骤。

function imgVec = preprocess_image(imgPath, targetSize) % 图像预处理函数 % 输入: % imgPath - 图像文件路径 % targetSize - [rows, cols],目标缩放尺寸 % 输出: % imgVec - d x 1 的列向量,取值范围 [0, 1] img = imread(imgPath); % 如果是彩色图,转成灰度图 if size(img, 3) == 3 img = rgb2gray(img); end % 缩放到统一尺寸 img = imresize(img, targetSize); % 转成 double 并归一化到 [0, 1] img = double(img) / 255; % 按列优先拉直成列向量 imgVec = img(:); end

这里把图像统一缩放到 112×92,是因为 ORL 原始图像就是 112×92。如果你使用自己的人脸库,目标尺寸可以根据实际情况调整,但训练集和测试集必须使用相同尺寸。

5.2 数据读取函数 load_orl_dataset.m

这个函数遍历 ORL 人脸库目录,读取每个人前 trainCount 张图片作为训练数据。

function [images, labels] = load_orl_dataset(rootFolder, trainCount, imgSize) % 读取 ORL 人脸数据集的训练部分 % 输入: % rootFolder - 人脸库根目录 % trainCount - 每个人取前 trainCount 张作为训练样本 % imgSize - 统一缩放尺寸 [rows, cols] % 输出: % images - d x N 的样本矩阵,每列是一张人脸向量 % labels - 1 x N 的标签向量 subDirs = dir(rootFolder); subDirs = subDirs([subDirs.isdir]); subDirs = subDirs(~ismember({subDirs.name}, {'.', '..'})); images = []; labels = []; for i = 1:length(subDirs) personLabel = i; for idx = 1:trainCount imgPath = fullfile(rootFolder, subDirs(i).name, [num2str(idx), '.pgm']); if ~exist(imgPath, 'file') warning('文件不存在,跳过: %s', imgPath); continue; end imgVec = preprocess_image(imgPath, imgSize); images = [images, imgVec]; %#ok<AGROW> labels = [labels, personLabel]; %#ok<AGROW> end end end

注意这里直接将子目录的顺序编号作为人的标签,也就是第 1 个子目录对应标签 1。这样写的好处是不依赖子目录名称是不是纯数字,通用性更强。

5.3 PCA 训练函数 pca_train_face.m

这是整个系统的核心函数,完成平均脸计算、中心化、小矩阵特征分解、特征脸提取和训练样本投影。

function model = pca_train_face(images, labels, k) % PCA 人脸识别训练函数 % 输入: % images - d x N 的样本矩阵,每列是一张拉直后的人脸向量 % labels - 1 x N 的标签向量 % k - 保留的特征脸数量 % 输出: % model - 结构体,包含平均脸、特征脸、训练投影和标签 numSamples = size(images, 2); if k > numSamples k = numSamples; warning('k 大于训练样本数,已自动调整为 %d', k); end % 1. 计算平均脸 meanFace = mean(images, 2); % 2. 中心化 centered = images - meanFace; % 3. 小矩阵特征分解:L = A' * A,尺寸为 N x N L = centered' * centered; [V, D] = eig(L); eigenvalue = diag(D); % 特征值从大到小排序 [~, sortIdx] = sort(eigenvalue, 'descend'); V = V(:, sortIdx); % 4. 还原到原空间:A * v 是 A * A' 的特征向量 eigenfaces = centered * V; % 5. 特征向量归一化 for i = 1:size(eigenfaces, 2) normVal = norm(eigenfaces(:, i)); if normVal > 1e-10 eigenfaces(:, i) = eigenfaces(:, i) / normVal; end end % 6. 取前 k 个特征脸 eigenfaces = eigenfaces(:, 1:k); % 7. 训练样本投影 trainProj = eigenfaces' * centered; % 8. 封装模型 model = struct(); model.meanFace = meanFace; model.eigenfaces = eigenfaces; model.trainProj = trainProj; model.labels = labels; model.k = k; model.trainImages = images; end

几个实现细节需要说明:

  • eig 求出的特征值不保证按大小排列,所以必须手动排序。
  • 小矩阵 L = centered' * centered 的特征向量是 N 维的,左乘 centered 后还原为 d 维特征向量。
  • 归一化可以避免特征向量的尺度不一致影响距离计算。
  • model.trainImages 字段是为了在 GUI 中展示最相似的训练人脸,如果内存紧张可以删除这个字段。

5.4 识别函数 face_recognize.m

识别函数输入一张测试图片的列向量和训练好的模型,输出预测标签、最相似样本索引和最小距离。

function [predictLabel, predictIdx, distance] = face_recognize(testVec, model) % 人脸识别函数,基于最近邻分类 % 输入: % testVec - d x 1 的测试图像列向量 % model - pca_train_face 训练得到的模型 % 输出: % predictLabel - 预测的标签 % predictIdx - 训练集中最相似样本的索引 % distance - 最近邻欧氏距离 % 1. 减去平均脸 testCentered = testVec - model.meanFace; % 2. 投影到特征脸空间 testProj = model.eigenfaces' * testCentered; % 3. 计算与所有训练样本的欧氏距离 diff = model.trainProj - testProj; distances = sum(diff .^ 2, 1); % 4. 取最小距离对应的样本 [distance, predictIdx] = min(distances); predictLabel = model.labels(predictIdx); end

如果要改用余弦相似度,可以把第 3 步改成计算向量夹角的余弦值,然后取最大值对应的样本。这个函数保持接口不变,替换内部的相似度计算即可。

5.5 主脚本 demo_face_recognition.m

主脚本串联整个流程,加载数据、训练模型、显示平均脸和特征脸、测试识别率。

%% PCA 人脸识别系统 - 主脚本 clear; close all; clc; %% 参数设置 rootFolder = 'ORL'; trainCount = 5; % 每个人取前 5 张训练 imgSize = [112, 92]; % 图像统一缩放尺寸 k = 30; % 特征脸数量 %% 读取训练集 [images, labels] = load_orl_dataset(rootFolder, trainCount, imgSize); fprintf('训练样本数: %d\n', size(images, 2)); %% PCA 训练 tic; model = pca_train_face(images, labels, k); trainTime = toc; fprintf('PCA 训练耗时: %.4f 秒\n', trainTime); %% 显示平均脸和前 9 个特征脸 figure('Name', '平均脸与特征脸'); subplot(2, 5, 1); imshow(mat2gray(reshape(model.meanFace, imgSize))); title('平均脸'); for i = 1:9 subplot(2, 5, i + 1); imshow(mat2gray(reshape(model.eigenfaces(:, i), imgSize))); title(['特征脸 ', num2str(i)]); end %% 读取测试集:每个人剩余 5 张 testImages = []; testLabels = []; subDirs = dir(rootFolder); subDirs = subDirs([subDirs.isdir]); subDirs = subDirs(~ismember({subDirs.name}, {'.', '..'})); for i = 1:length(subDirs) for idx = (trainCount + 1):10 imgPath = fullfile(rootFolder, subDirs(i).name, [num2str(idx), '.pgm']); if ~exist(imgPath, 'file') continue; end imgVec = preprocess_image(imgPath, imgSize); testImages = [testImages, imgVec]; %#ok<AGROW> testLabels = [testLabels, i]; %#ok<AGROW> end end %% 测试并统计识别率 correctCount = 0; totalCount = size(testImages, 2); for i = 1:totalCount [predLabel, ~, ~] = face_recognize(testImages(:, i), model); if predLabel == testLabels(i) correctCount = correctCount + 1; end end accuracy = correctCount / totalCount * 100; fprintf('测试样本数: %d, 识别正确: %d, 识别率: %.2f%%\n', ... totalCount, correctCount, accuracy);

运行这个脚本,会先输出训练样本数和训练耗时,然后弹出一个显示平均脸和特征脸的窗口,最后在命令行输出测试识别率。

5.6 不同 k 值识别率实验 evaluate_k.m

PCA 特征脸数量 k 对识别率影响很大,这个脚本批量测试多个 k 值,帮助你选择合适参数。

%% 不同 k 值对识别率的影响 clear; close all; clc; rootFolder = 'ORL'; imgSize = [112, 92]; trainCount = 5; %% 加载训练集 [images, labels] = load_orl_dataset(rootFolder, trainCount, imgSize); %% 加载测试集 testImages = []; testLabels = []; subDirs = dir(rootFolder); subDirs = subDirs([subDirs.isdir]); subDirs = subDirs(~ismember({subDirs.name}, {'.', '..'})); for i = 1:length(subDirs) for idx = (trainCount + 1):10 imgPath = fullfile(rootFolder, subDirs(i).name, [num2str(idx), '.pgm']); if ~exist(imgPath, 'file') continue; end testImages = [testImages, preprocess_image(imgPath, imgSize)]; %#ok<AGROW> testLabels = [testLabels, i]; %#ok<AGROW> end end %% 测试不同 k 值 ks = [5, 10, 20, 30, 50, 80]; fprintf('k\t识别率\n'); for k = ks model = pca_train_face(images, labels, k); correct = 0; for t = 1:size(testImages, 2) pred = face_recognize(testImages(:, t), model); if pred == testLabels(t) correct = correct + 1; end end acc = correct / size(testImages, 2) * 100; fprintf('%d\t%.2f%%\n', k, acc); end

运行后会输出类似下面格式的结果:

k 识别率 5 70.50% 10 86.00% 20 90.50% 30 91.00% 50 89.50% 80 88.50%

需要说明的是,具体数字会因数据集划分方式、是否使用随机划分而不同,但整体规律是一致的:随着 k 增大,识别率先上升,达到峰值后缓慢下降。这是因为 k 太小会丢失有效信息,k 太大会引入噪声维度。

5.7 GUI 演示 pca_face_gui.m

最后提供一个简单的 GUI,方便交互式选择测试图片并查看识别结果。

function pca_face_gui(model, imgSize) % PCA 人脸识别系统 GUI 演示 % 输入: % model - pca_train_face 训练得到的模型 % imgSize - 图像尺寸 [rows, cols] fig = figure('Name', 'PCA 人脸识别系统', 'NumberTitle', 'off', ... 'Position', [300 200 850 550], 'MenuBar', 'none'); ax1 = axes('Parent', fig, 'Units', 'pixels', 'Position', [60 120 320 360]); ax2 = axes('Parent', fig, 'Units', 'pixels', 'Position', [470 120 320 360]); uicontrol('Style', 'pushbutton', 'String', '选择测试图片', ... 'Position', [120 50 120 35], 'Callback', @selectImage); uicontrol('Style', 'pushbutton', 'String', '开始识别', ... 'Position', [280 50 120 35], 'Callback', @recognizeImage); infoLabel = uicontrol('Style', 'text', ... 'String', '请选择一张人脸图片', ... 'Position', [60 490 500 30], 'FontSize', 12); testImgPath = '';
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 18:42:15

从U-Net源码到实践:深度学习遥感图像道路提取全流程解析

简介&#xff1a;本资源是一套面向遥感图像处理方向的高分课程设计项目&#xff0c;专为计算机、地理信息或人工智能相关专业本科生打造&#xff0c;聚焦遥感影像中道路目标的自动识别与提取任务&#xff0c;可直接用于课程设计、期末大作业及毕业设计。压缩包共52个文件&#…

作者头像 李华
网站建设 2026/9/3 18:42:02

基于倒向随机微分方程的图像去噪与重建:从数学理论到深度学习实践

简介&#xff1a;本资源是一套基于倒向随机微分方程&#xff08;BSDE&#xff09;实现图像去噪与重建的完整算法实践包&#xff0c;面向图像处理、计算数学及计算机视觉方向的中高级学习者与研究者&#xff0c;解决传统滤波方法易模糊边缘、丢失纹理等关键问题。压缩包共10个文…

作者头像 李华
网站建设 2026/9/3 18:36:30

ffmpeg画面墙检测黑帧:告别抽帧漏检,一行命令快速扫查全片

交付视频之前做质量检查&#xff0c;最怕的不是画面全面崩溃&#xff0c;而是那种“抽查正常、全片有问题”的隐蔽故障。之前帮客户处理一批视频素材&#xff0c;临时抽了三帧检查&#xff0c;画面、色彩、字幕都正常&#xff0c;就直接进入合成环节。等把整条视频的关键帧拼成…

作者头像 李华
网站建设 2026/9/3 18:30:28

微信小程序步数排行榜开发实战:从登录、解密到榜单避坑

简介&#xff1a;压缩包内提供了一款基于微信小程序的步数计数与排名应用werun的完整源码&#xff0c;适合具备JavaScript基础的开发者作为微信小程序实战入门项目。源码通过调用微信运动开放接口获取用户每日步数&#xff0c;并利用数组排序、页面渲染等机制实现数据统计和排行…

作者头像 李华
网站建设 2026/9/3 18:30:07

工业级焊缝缺陷检测系统:YOLOv8闭环落地实践

简介&#xff1a;本资源是一套面向计算机、人工智能、自动化等专业在校学生与初学者的化工管道焊缝缺陷检测实战项目&#xff0c;基于YOLOv8实现端到端目标检测&#xff0c;解决工业质检中焊缝裂纹、气孔、未熔合等典型缺陷的自动识别问题&#xff0c;适用于毕业设计、课程设计…

作者头像 李华
网站建设 2026/9/3 18:28:39

Android端RTSP/RTMP视频播放实践:IjkPlayer集成与调优指南

简介&#xff1a;面向需要处理实时流媒体播放的Android开发者&#xff0c;这套可运行Demo集成IjkPlayer&#xff0c;用于播放RTSP/RTMP视频流&#xff0c;适合在视频监控、直播推拉流等场景中快速起步。压缩包共147个文件&#xff0c;大小13.68MB&#xff0c;包含aar库、so动态…

作者头像 李华