教你在Linux中从视频流截取图片帧(ffmpeg)

说明: 使用到的 依赖包 1. ffmpegsudo apt update sudo apt-get install ffmpeg2. imagemagick (选装)(检测图像边缘信息推断清晰度,如果是简单截取但个图像帧= 用不到 =)sudo apt-get install imagemagick备注: 指令及相关参数说明
核心指令: (作用: 执行 ffmpeg 命令提取帧,每10帧选择一帧, 一共提取5张)
示例:
ffmpeg -i https://cdn.pixabay.com/video/2023/10/22/186115-877653483_large.mp4 -vf select= not(mod(n,10)) -frames:v 5 -q:v 1 output_%03d.jpg
指令说明:
这条
ffmpeg命令从视频流中提取帧并保存为图片,具体的参数含义如下:
ffmpeg:调用ffmpeg命令。-i https://cdn.pixabay.com/video/2023/10/22/186115-877653483_large.mp4:指定输入文件,视频源为给定的网络视频 URL。
-vf:表示使用视频滤镜。"select='not(mod(n,10))'"
:视频帧选择器,这里
mod(n,10)
表示每 10 帧提取一次帧。
n
是当前帧的编号,
mod(n,10)
计算帧编号除以 10 的余数,
not(mod(n,10))
选择那些编号是 10 的倍数的帧。
换句话说,这条命令每 10 帧提取一个帧。
只提取 5 帧图片。
-q:v设置视频帧的质量,范围为 1 到 31,值越小质量越高,1是最高质量。
输出文件名模板。%03d是一个占位符,表示文件名中包含 3 位数字(例如output_001.jpg,output_002.jpg),这样可以保存多个帧。
从视频中每隔 10 帧提取一个帧,总共提取 5 帧,保存为高质量的 JPEG 图片文件,文件名为
output_001.jpg,output_002.jpg, 以此类推。
指令执行完可见当前文件夹中文件:
具体的命令可根据需求情况进行修改, 到这里文章的标题功能就已经实现了.
下面是加餐环节
需求: 提取视频中的图片帧, 并从多张中选取最清晰的一张照片
注: 其中的文件路径需要改为自己所存在的路径
这里准备了三个脚本文件如下:
extract_frames.sh 提取视频帧输出指定张数据照片并存到指定位置 并执行 detect_sharpness.sh 脚本(已注释掉, 需要的话自行打开)detect_sharpness.sh 从多张照片中选择最清晰的一张 并将其余的照片删除, 且保留最清晰一张并重命名create_directory.sh 判断文件夹是否存在, 不存在则创建, 存在则不处理提取视频帧输出指定张数据照片并存到指定位置 并执行
detect_sharpness.sh脚本注: 执行该脚本需要指定 视频路径
示例:
/data/hikuser/handler_video_to_picture/extract_frames.sh https://cdn.pixabay.com/video/2023/10/22/186115-877653483_large.mp4
#!/bin/bash# 删除指定目录下已有的图片rm -f /data/hikuser/handler_video_to_picture/output*.jpg# 检查是否提供了视频流 URL 参数if [ "$#" -ne 1 ]; then echo "Usage: ${0##*/} video_stream_url " exit 1fi# 视频流 URLVIDEO_URL="$1"# 检查输出目录是否存在if [ ! -d "/data/hikuser/handler_video_to_picture" ]; then echo "Directory /data/hikuser/handler_video_to_picture does not exist." exit 1fi# 执行 ffmpeg 命令提取帧,每10帧选择一帧, 一共提取5张if ! ffmpeg -i "$VIDEO_URL" -vf "select='not(mod(n,10))'" -frames:v 5 -q:v 1 /data/hikuser/handler_video_to_picture/output_%03d.jpg; then echo "ffmpeg command failed." exit 1fi# 执行检测图片清晰度的脚本# if [ -f /data/hikuser/handler_video_to_picture/detect_sharpness.sh ]; then# /bin/bash /data/hikuser/handler_video_to_picture/detect_sharpness.sh# else# echo "detect_sharpness.sh script not found!"# exit 1# fi
从多张照片中选择像素最高的一张 并将其余的照片删除, 并将最新的一张重命名
#!/bin/bash# 初始化最大边缘值和最清晰的图片变量max_edge_value=0sharpest_image=""# 进入图片所在目录cd /data/hikuser/handler_video_to_picture || exit 1# 遍历每张图片并计算边缘值for img in output_*.jpg; do # 计算图片的边缘检测值 edge_value=$(convert "$img" -edge 1 -format "%[mean]" info:) echo "$img 边缘检测值: $edge_value" # 比较边缘值,保留最大值对应的图片 if (( $(echo "$edge_value $max_edge_value" | bc -l) )); then max_edge_value=$edge_value sharpest_image=$img fidone# 输出最清晰的图片echo "最清晰的图片是: $sharpest_image"# 删除其他图片for img in output_*.jpg; do if [ "$img" != "$sharpest_image" ]; then rm "$img" fidone# 将最清晰的图片重命名为 output.jpgmv "$sharpest_image" /data/hikuser/handler_video_to_picture/output.jpgecho "已删除其他图片,保留最清晰的图片: $sharpest_image"
脚本执行效果示例:
所以截取的图片大小因为数据源是一个静态视频, 当然如果采集帧率过快时也会出现这样的情况, 注意空值
判断文件夹是否存在存在则创建不存在则不处理
#!/bin/bash# 检查是否提供了文件夹名称参数if [ "$#" -ne 1 ]; then echo "Usage: ${0##*/} directory_name " exit 1fi# 文件夹名称DIR_NAME="$1"# 检查文件夹是否存在if [ -d "$DIR_NAME" ]; then echo "Directory '$DIR_NAME' already exists."else # 创建文件夹 mkdir -p "$DIR_NAME" if [ $? -eq 0 ]; then echo "Directory '$DIR_NAME' has been created." else echo "Failed to create directory '$DIR_NAME'." exit 1 fifi
教你在Linux中从视频流截取图片帧(ffmpeg)