FFMPEG+SDL简单视频播放器——人脸检测
前言
最近突发奇想,给播放器加上一个人脸检测的功能(事情似乎朝着奇怪的方向发展了,谁家的播放器会需要去检测人脸啊!),主要的目的是为了学习opencv,尝试将ffmpeg和opencv融合在一起使用。这里着重展示opencv用于人脸检测部分的代码,播放器其余部分可以参考《FFMPEG+SDL简单视频播放器——视频播放》和《FFMPEG+SDL简单视频播放器——视频快进》
实现
人脸检测
在之前写的播放器中,视频帧的格式为YUV420。在opencv处理图片前需要进行格式转化,将图片格式从YUV420转化成BGR。如果不进行格式转化,图片被opencv处理后的部分会出现颜色无法正常显示的问题
cv::cvtColor(yuvimg, img, COLOR_YUV2BGR_I420);
在检测到人脸后,用红框将人脸框起来
if (faces.size() > 0)
{
for (size_t i = 0; i < faces.size(); i++)
{
rectangle(img, faces[i], Scalar(0, 0, 255), 3, 8, 0);
}
}
在opencv对图片处理完成后,将处理后的图片进行返回。这里用到了haarcascade_frontalface_alt2.xml文件,需要提前下载,或者从opecv的编译目录下复制过来。
完整的人脸检测函数如下
cv::Mat detect_face(Mat yuvimg, int64_t times)
{
cv::Mat img;
// 转换YUV图像为BGR图像
cv::cvtColor(yuvimg, img, COLOR_YUV2BGR_I420);
CascadeClassifier cascade;
const string path = "./haarcascade_frontalface_alt2.xml";
// 尝试加载人脸检测器模型
if (!cascade.load(path))
{
// 如果加载失败,返回原始YUV图像
return yuvimg;
}
vector<cv::Rect> faces(0);
// 使用人脸检测器检测人脸
cascade.detectMultiScale(img, faces, 1.1, 2, 0, Size(30, 30));
// 如果检测到人脸
if (faces.size() > 0)
{
// 在图像上绘制检测到的人脸的红色框
for (size_t i = 0; i < faces.size(); i++)
{
rectangle(img, faces[i], Scalar(0, 0, 255), 3, 8, 0);
}
}
else
{
// 如果未检测到人脸,返回原始YUV图像
return yuvimg;
}
// 返回处理后的YUV图像
cv::cvtColor(img, yuvimg, COLOR_BGR2YUV_I420);
return img;
}
视频播放
定义一个Mat,用于接收视频帧
cv::Mat frameMat;
在对AVFrame的格式进行转换后,将图像数据传递给Mat
sws_scale(img_convert_ctx, (const unsigned char *const *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
int64_t pts = packet->pts;
frameMat = cv::Mat(pCodecCtx->height * 3 / 2, pCodecCtx->width, CV_8UC1, pFrameYUV->data[0]);
调用detect_face函数对视频帧进行人脸检测,得到经过处理后的视频帧
frameMat = detect_face(frameMat, pts);
将视频帧传递给SDL,通过SDL进行播放
SDL_UpdateTexture(sdlTexture, NULL, frameMat.data, frameMat.step);
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect_1);
SDL_RenderPresent(sdlRenderer);
需要注意的地方是在ffmpeg,opencv和sdl之间进行图像数据的传递时,三者之间的图像数据格式。必要时需要进行图像格式转换,确保图像数据被正确的处理,否则会出现视频无法正常播放或者视频颜色无法正常显示的问题。
播放器的最新完整源码:https://github.com/canaconZion/streaming-practice/tree/main/opencv
在windows端编译opencv过程稍微有点繁琐,有空我会写一篇关于在windows端编译opencv源码的blog,帮大家避避坑
Makefile
INC_DIR = ./include
BIN_DIR = ./bin
SRC = face_detect_player.cpp
LIB = -lavutil -lavformat -lavcodec -lavutil -lswscale -lswresample \
-lSDL2 -llibopencv_core480 -llibopencv_imgcodecs480 -lopencv_highgui480 \
-lopencv_objdetect480 -lopencv_imgproc480
TARGET = detectPlayer
BIN_TARGET = $(BIN_DIR)/$(TARGET)
CC = g++
$(BIN_TARGET):$(SRC)
$(CC) $(SRC) -o $(BIN_TARGET) \
-I$(INC_DIR) \
$(LIB)
clean:
rm $(BIN_TARGET).exe
视频播放效果

FFMPEG+SDL简单视频播放器——人脸检测的更多相关文章
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (採用SDL2.0)
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 基于<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)>的一些个人总结
最近因为项目接近收尾阶段,所以变的没有之前那么忙了,所以最近重新拿起了之前的一些FFMPEG和SDL的相关流媒体播放器的例子在看. 同时自己也用FFMPEG2.01,SDL2.01结合MFC以及网上罗 ...
- 用JavaCV改写“100行代码实现最简单的基于FFMPEG+SDL的视频播放器 ”
FFMPEG的文档少,JavaCV的文档就更少了.从网上找到这篇100行代码实现最简单的基于FFMPEG+SDL的视频播放器.地址是http://blog.csdn.net/leixiaohua102 ...
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)【转】
转自:http://blog.csdn.net/leixiaohua1020/article/details/8652605 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] ...
- 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 音视频处理之FFmpeg+SDL+MFC视频播放器20180411
一.FFmpeg+SDL+MFC视频播放器 1.MFC知识 1).创建MFC工程的方法 打开VC++ 文件->新建->项目->MFC应用程序 应用程序类型->基于对话框 取消勾 ...
- 【转】100行代码实现最简单的基于FFMPEG+SDL的视频播放器
FFMPEG工程浩大,可以参考的书籍又不是很多,因此很多刚学习FFMPEG的人常常感觉到无从下手.我刚接触FFMPEG的时候也感觉不知从何学起. 因此我把自己做项目过程中实现的一个非常简单的视频播放器 ...
- FFMPEG+SDL实现视频播放器
一. 前言 基于学习ffmpeg和sdl,写一个视频播放器是个不错的练手项目. 视频播放器的原理很多人的博客都有讲过,这里出于自己总结的目的,还是会做一些概况. 二. 视频播放器基本原理 2.1 解封 ...
- FFMPEG学习----使用SDL构建视频播放器
#include <stdio.h> #include <string.h> extern "C" { #include "libavcodec/ ...
随机推荐
- sFlow-RT监控设备教程
1.前言 sflow-rt网站国内无法访问,这里使用蓝奏云下载 2.下载源码 https://lvpeiming.lanzoup.com/imRxy10was0h密码:5rxk 3.开启sFlow-R ...
- 如何使用libswscale库将YUV420P格式的图像序列转换为RGB24格式输出?
一.视频格式转换初始化 将视频中的图像帧按照一定比例缩放或指定宽高进行放大和缩小是视频编辑中最为常见的操作之一,这里我们将1920x1080的yuv图像序列转换成640x480的rgb图像序列,并输出 ...
- CF961E Tufurama题解
我们维护一个存储下标数据的树状数组,先将 \(1\sim n\) 插入树状数组. 用 \(a\) 表示原数组,\(b\) 表示按照 \(a_i\) 排序后的数组. 我们从 \(1\) 开始统计,直到 ...
- AcWing 4490. 染色题解
题目描述 样例 输入: 6 1 2 2 1 5 2 1 1 1 1 1 输出 3 算法描述 思路 我们以样例为例讲讲思路. 如何确保dfs能顺利便利呢,我们可以使用链式前向星来存图(树) C++代码 ...
- 【Shell】字符串
单引号和双引号 shell 字符串可以用单引号 '',也可以用双引号 "",也可以不用引号. 单引号的特点 单引号里不识别变量 单引号里不能出现单独的单引号(使用转义符也不行),但 ...
- 解读 --- yield 关键字
引言 yield关键字是 C# 中的一种语言特性,用于在枚举器中简化迭代器的实现.它使得开发人员可以通过定义自己的迭代器来简化代码,而不必手动实现 IEnumerable 和 IEnumerator ...
- PREDIV与PLLMUL配置应用笔记
下图为CH32V305/307和CH32F205/207时钟树框图,在此,以CH32V307VCT6芯片,外置25MHz晶振为例,简述图中PREDIV与PLLMUL的配置方法,最终实现144MHz系统 ...
- == 与 equals 的区别?
一. 介绍: Java中的 "==" 是一个运算符,是用于比较两个对象地址值或基本数据类型之间的值是否相等.它的来源可以追溯到C语言,以及受C语言影响的许多其他编程语言. Jav ...
- 用 Rust 生成 Ant-Design Table Columns
经常开发表格,是不是已经被手写Ant-Design Table的Columns整烦了? 尤其是ToB项目,表格经常动不动就几十列.每次照着后端给的接口文档一个个配置,太头疼了,主要是有时还会粘错就尴尬 ...
- python 打包模块:nuitka
该模块可以将python编译成C++级的可执行文件,是解决python图形化界面启动慢的神器. 1.环境配置 配置c/c++编译器:MinGW64 ,最低使用8.1版本,该资源自行下载. 百度网盘链接 ...