根据视频生成可以头尾衔接的循环视频

最近手头有一个视频,基本上是一个部分重复循环的,我想把循环的一段提取出来造成动态壁纸,但怎奈何不会用 pr,只能用 ffmpeg 配合 pillow 搞了……

实现的关键在于找到可以首位相接的两帧画面,这就要求两个画面有极高的相似度。判断画面相似度首先需要对图像进行量化,一般有两种方案,一种是提取特征向量,一种是计算哈希。考虑到我手头视频的特征,我选择了比较简单的哈希。

开始之前,需要安装必要的包以及 ffmpeg,执行

pip install ffmpeg-python Pillow numpy imagehash

!Notice 简略起见,以下代码不重要部分折叠,具体实现参照文末链接

首先需要把视频分离成帧,存入数组:

def extract_frames(input_video) -> Generator[np.ndarray, None, None]:
    # 一个生成器,生成每一帧的数据存入 numpy 数组
    ...

图像的哈希算法有多种,比如均值哈希(aHash)、感知哈希(pHash)以及差异哈希(dHash),各有优劣,但选择哪一种对接下来的算法影响不大,我这里以 pHash 为例。以上图像哈希算法在 imagehash 中均有提供,由于本篇主要讨论循环视频生成,哈希算法的具体原理就不研究了(肯定不是因为我不会)。

def generate_hashes(input_video: str) -> Generator[int, None, None]:
    for frame in extract_frames(input_video):
        # 将 numpy 数组转换为 PIL 图像
        pil_image: ImageHash = Image.fromarray(frame)

        # 生成 pHash 值
        phash_value = int(str(phash(pil_image)), 16)

        yield phash_value

图像哈希越相似,图像就越相似。两个哈希值的相似度可以用汉明距离表示,汉明距离表两个二进制数差异的位数,可以通过异或和中 math 的个数计算。

def hamming_distance(hash1: int, hash2: int) -> int:
    return bin(hash1 ^ hash2).count('1')

接下来遍历每一帧的哈希找到距离最近的两帧即可。遍历过程如果有确定起始或结束帧可以直接遍历,复杂度 math;如果没有固定起始帧,根据汉明权重(也就是与 math 的汉明距离)排序后遍历即可,复杂度 math

最后完整代码在github gist

ffmpeg·video·python
15 views
Comments
登录后评论
Sign In
·

Don’t miss this opportunity to optimize your operations

Hello,

The social engineering landscape is changing rapidly. To stay competitive, you need reliable and innovative partners.

The Pro Corner offers you the tools and expertise to stand out.

Contact us today for a free consultation and learn how we can help you.