使用图像匹配查找视频文件位置

使用图像匹配查找视频文件位置

什么是最好的工具/方法,可以自动从视频文件中找出一个位置,使该帧与给定的图像大致匹配*?

基本上,命令如下:“找到[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

您可以使用md5framemd5复用器如果图像和帧完全相同。 例子:

  1. 获取目标图像的 MD5 值:

    $ ffmpeg -i frame.jpg -f md5 - 2>&1 | grep MD5
    MD5=b7fb5124a65108ebb067129d9d81ed57
    
  2. 在视频中查找精确的图像帧:

    $ 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

相关内容