【问题标题】:How to pair screenshots with videos?如何将屏幕截图与视频配对?
【发布时间】:2018-06-08 12:04:21
【问题描述】:

我有包含短视频的文件夹和包含图片的文件夹。大多数图像是其中一个视频的截图,但它们可能并不完全相同(不同的大小、噪声、由于压缩导致的细节丢失等)。我的目标是将每张图片与从中获取的视频进行匹配。到目前为止,我使用 OpenCV 库加载一个视频并计算每个视频帧和每个图像之间的 SSIM 分数。我存储每张图像的最高 SSIM 分数。然后我会获取 SSIM 得分最高的图像,将其与视频相关联,然后再次为第二个视频运行该函数。

这是我的代码:

import cv2
import numpy as np
from skimage.measure import compare_ssim
import sqlite3   

#screenshots - list that contains dict(id=screenshot id, image=jpeg image data)
#video_file - str - path to video file
def generate_matches(screenshots, video_file):
    for screenshot in screenshots:
            screenshot["cv_img"] = cv2.imdecode(np.fromstring(screenshot["image"], np.uint8), 0)
            screenshot["best_match"] = dict(score=0, frame=0)
            screenshot.pop('image', None) #remove jpg data from RAM

    vidcap = cv2.VideoCapture(video_file)
    success,image = vidcap.read()
    count = 1
    while success:
            image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            for screenshot in screenshots:
                    c_image = cv2.resize(image, screenshot["cv_img"].shape[1::-1])
                    score = compare_ssim(screenshot["cv_img"], c_image, full=False)
                    if score > screenshot["best_match"]["score"]:
                            screenshot["best_match"] = dict(score=score,frame=count)
            count += 1
            success,image = vidcap.read()

            if count % 500 == 0:
                    print("Frame {}".format(count))

    print("Last Frame {}".format(count))
    for screenshot in screenshots:
            c.execute("INSERT INTO matches(screenshot_id, file, match, frame) VALUE (?,?,?,?)",
                      (screenshot["id"], video_file, screenshot["best_match"]["score"], screenshot["best_match"]["frame"]))

generate_matches(list_of_screenshots, "video1.mp4")
generate_matches(list_of_screenshots, "video2.mp4")
...

这个算法似乎很好 - 可以将视频与图像关联起来,但它很慢,即使我会使用更多线程。有没有办法让它更快?也许不同的算法或视频和图像的一些预处理?我会很高兴有任何想法!

【问题讨论】:

  • 与其在每个屏幕截图中调整每个视频的每一帧的大小,不如调整屏幕截图的大小以匹配视频的大小不是更有意义吗?
  • @DanMašek 也许,我会试试。屏幕截图的分辨率低于视频帧,所以我认为使用较小的分辨率会使 SSIM 的计算速度更快。
  • 为什么不使用任何感知散列(例如 img -> 128 位),然后使用高效的 kd-trees / ball-trees 或类似的进行搜索/查找?
  • @DanMašek 我使用列表中的 10 个屏幕截图对其进行了测试,调整每一帧的大小比将屏幕截图调整为视频分辨率快约 5 倍。 (屏幕截图分辨率 - 224x450,视频分辨率 - 720x1280)
  • @sascha 哇,我不知道这些哈希值存在,我真的很喜欢它的工作方式。我会测试它tommorov,看看它是否能给我带来好的结果。 OpenCV 的 pHash 适合这个任务吗?

标签: python opencv image-processing video video-processing


【解决方案1】:

根据sascha的建议,我计算了视频中所有帧的dhashes(source)和所有屏幕主机的dhashes,并使用汉明距离(source)进行了比较。

def dhash(image, hashSize=16): #hashSize=16 worked best for me
    # resize the input image, adding a single column (width) so we
    # can compute the horizontal gradient
    resized = cv2.resize(image, (hashSize + 1, hashSize))

    # compute the (relative) horizontal gradient between adjacent
    # column pixels
    diff = resized[:, 1:] > resized[:, :-1]

    # convert the difference image to a hash
    return sum([2 ** i for (i, v) in enumerate(diff.flatten()) if v])

def hamming(a, b):
        return bin(a^b).count('1')

此解决方案快速且足够精确,可以满足我的需求。如果我使用different hashing function(例如 OpenCV 的 pHash),结果很可能会得到改善,但我在 OpenCV python 中找不到它们。

【讨论】:

    猜你喜欢
    • 2018-09-28
    • 2013-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-26
    • 1970-01-01
    相关资源
    最近更新 更多