2017-12-27 51 views
1

Ich habe einen Ordner mit kurzen Videos und Ordner mit Bildern. Die meisten Bilder sind Szenenbilder von einem der Videos, aber sie sind vielleicht nicht genau gleich (unterschiedliche Größe, Rauschen, Verlust von Details wegen Komprimierung usw.). Mein Ziel ist es, jedes Bild mit dem Video zu vergleichen, aus dem es stammt. Bisher verwende ich die OpenCV-Bibliothek, um ein Video zu laden und den SSIM-Score zwischen jedem Videoframe und jedem Bild zu berechnen. Ich speichere den höchsten SSIM-Wert jedes Bildes. Dann würde ich das Bild mit der höchsten SSIM-Punktzahl aufnehmen, es mit dem Video verknüpfen und die Funktion für das zweite Video erneut ausführen.Schneller Weg, um Screenshots mit Videos zu paaren

Hier ist mein Code:

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") 
... 

Dieser Algorithmus scheint gut genug zu sein, um Videos mit Bildern zu verknüpfen, aber es ist ziemlich langsam, auch wenn ich mehrere Threads verwenden würde. Gibt es eine Möglichkeit, es schneller zu machen? Vielleicht ein anderer Algorithmus oder eine Vorverarbeitung von Videos und Bildern? Ich werde mich für irgendwelche Ideen freuen!

+1

Anstatt die Größe jedes Frames jedes Videos einmal pro Screenshot zu ändern, wäre es nicht sinnvoller, die Screenshots einmal der Größe des Videos anzupassen? –

+0

@ DanMašek Vielleicht werde ich es versuchen. Screenshots haben eine niedrigere Auflösung als Videoframes, daher dachte ich, dass die Verwendung der kleineren Auflösung die Berechnung von SSIM beschleunigen wird. –

+2

Warum nicht perceptual-hash (img -> 128 bit zum Beispiel) und dann effiziente kd-trees/ball-trees oder ähnliches für die Suche/Suche verwenden? – sascha

Antwort

0

Basierend auf sascha Vorschlag, berechnete ich Dhashes (source) aller Bilder in Videos und Dhashs aller Bildschirmschoner, und verglichen sie mit Hamming-Abstand (source).

Diese Lösung ist schnell und genug genau für meine Bedürfnisse. Die Ergebnisse würden höchstwahrscheinlich verbessert werden, wenn ich different hashing function (z. B. OpenCVs pHash) verwenden würde, aber ich konnte sie nicht in OpenCV python biding finden.

Verwandte Themen