什么是最好的工具/方法,可以自动从视频文件中找出一个位置,使该帧与给定的图像大致匹配*?
基本上,命令如下:“找到[video.mpg]中[image.jpg]出现的位置”
最好与ffmpeg或者其他一些 Linux 命令行工具。
* - 或者可能是视频中所有帧中与图像最匹配的帧
答案1
2023 这样做的方法
ffmpeg -i "video.mp4" -r 1 -loop 1 -i image.png -an -filter_complex "blend=difference:shortest=1,blackframe=90:32" -f null -
注意这里的 90,如果设置为 100,则只会匹配相同数量,如果数字较低,则可以设置模糊搜索条件
答案2
框架文件是一个使用 ffmpeg 在视频文件中搜索图像的 bash 脚本,以及查找重复图片。
使用threshold
变量,您可以指定搜索的模糊程度。
我们成功使用该脚本删除了电视节目剧集的片头和结尾。
对于“audiodetect”,我们使用似曾相识, 有可能pyAudioAnalysis 分割可以使用。
相关伪代码....
代码中最复杂的是并行运行“提取”和“比较”,以提高速度和效率:
function framepos() {
# extract frames. run in background
# bmp format is faster than png or jpg
$ffmpeg_cmd \
$ff_args -i "$V" \
${tmp_pre}frame-%04d.bmp \
2>/dev/null &
pid=$!
# output function for findimagedupes
script_include=$(cat <<-'EOF'
VIEW () {
for f in "$@"
do
echo -n "$f"
echo -ne "\t\t\t\t"
done
echo
}
EOF
)
n2=0
while true
do
n=$(ls ${tmp_pre}frame-*.bmp 2>/dev/null | wc -l)
(( $n == 0 )) && {
kill -0 $pid 2>/dev/null || {
# extract done
echo debug found no match >&2
break
}
kill -SIGCONT $pid
sleep $step_duration
continue
}
(( $n == 1 )) && {
# only one frame extracted.
# if ffmpeg is still extracting, this file is incomplete
kill -0 $pid 2>/dev/null && {
# extract running
kill -SIGCONT $pid
sleep $step_duration
continue
}
n2=1
}
(( 1 < $n && $n <= $frames_bufsize )) && {
# frame buffer not full
# if extract is running, then wait before compare
kill -0 $pid 2>/dev/null && {
# extract running
kill -SIGCONT $pid
sleep $step_duration
continue
}
n2=$(( $n - 1 ))
}
(( $n > $frames_bufsize )) && { #echo found $n frames
# pause frame extraction to save space
# extract is faster than compare
kill -SIGSTOP $pid
n2=$(( $n - 1 ))
}
echo compare $n2 frames
break_while=false
for I_cur in "${I[@]}"
do
# we need the "real path" for findimagedupes
pattern=$(readlink -f "$I_cur")
# call findimagedupes
# to find "visually similar images"
res=$(
ls ${tmp_pre}frame-*.bmp \
| head -n $n2 \
| xargs findimagedupes -t $threshold \
-i "$script_include" "$pattern" \
| grep -a "$pattern"
)
if [ ! -z "$res" ]
then
res=$(
echo "$res" \
| sed 's/\t\t\t\t/\n/g' \
| grep -v '^$' \
| grep -v "$pattern" \
| sort \
| head -n 1 \
| sed -E 's/^.*frame-(.*?)\.bmp$/\1/'
)
# get frame time
# note: frame numbers start with 1
# frame minus one:
t=$(
echo $T1 $res $fps \
| awk '{printf "%.4f\n", $1 + ( ( $2 - 2 ) / $3 ) }'
)
# matching frame:
# | awk '{printf "%.4f\n", $1 + ( ( $2 - 1 ) / $3 ) }'
# return
echo $t
# stop extracting
kill -9 $pid 2>/dev/null
# remove all temp files
rm ${tmp_pre}frame-*.bmp
break_while=true
break
fi
done
$break_while && break
# remove processed temp files
(( $n2 > 0 )) \
&& ls ${tmp_pre}frame-*.bmp | head -n $n2 | xargs rm
done
}
答案3
您可以使用md5和framemd5复用器如果图像和帧完全相同。 例子:
获取目标图像的 MD5 值:
$ ffmpeg -i frame.jpg -f md5 - 2>&1 | grep MD5 MD5=b7fb5124a65108ebb067129d9d81ed57
在视频中查找精确的图像帧:
$ ffmpeg -i video.mov -f framemd5 - 2>&1 | grep b7fb5124a65108ebb067129d9d81ed57 0, 62, 62, 1, 1424400, b7fb5124a65108ebb067129d9d81ed57
输出数字指的是:stream_index, packet_dts, packet_pts, packet_duration, packet_size, MD5
。
但是,这可能不是你想要的。如果video.mov
是 mjpeg,那么这可以工作;例如,如果你制作一个来自 jpg 输入的视频和流复制将它们输出:
ffmpeg -pattern_type glob -i "*.jpg" -codec copy output.mkv