2017-12-27 5 views
1

짧은 동영상 폴더와 이미지가있는 폴더가 있습니다. 대부분의 이미지는 동영상 중 하나에서 가져온 이미지지만 크기가 다르거 나 노이즈, 압축으로 인해 세부 정보가 손실되는 등 정확하게 다를 수 있습니다. 내 목표는 모든 이미지를 찍은 비디오와 일치시키는 것입니다. 지금까지 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") 
... 

이 알고리즘은 이미지와 비디오를 연결하는 좋은 충분한 것 같다,하지만 내가 더 많은 스레드를 사용하는 것입니다 경우에도 매우 느립니다. 빨리 할 수있는 방법이 있습니까? 어쩌면 다른 알고리즘이나 비디오 및 이미지의 일부 사전 처리? 어떤 아이디어라도 기쁠거야!

+1

각 스크린 샷마다 모든 비디오의 모든 프레임의 크기를 조정하지 않고 비디오의 크기와 일치하도록 스크린 샷의 크기를 한 번 더 조정하는 것이 더 좋지 않습니까? –

+0

@ DanMašek 어쩌면, 나는 그것을 시도 할 것이다. 스크린 샷은 비디오 프레임보다 해상도가 낮으므로 더 작은 해상도를 사용하면 SSIM을 더 빨리 계산할 수 있다고 생각했습니다. –

+2

지각 해시 (예 : img -> 128 비트)를 사용한 다음 검색/조회에 효율적인 kd-trees/ball-trees 또는 유사한 방법을 사용하지 않는 이유는 무엇입니까? – sascha

답변

0

sascha 님의 제안에 따라 비디오와 모든 스크린 호스트의 모든 프레임의 대시 (source)를 계산하여 해밍 거리 (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 biding에서 찾을 수 없습니다.

관련 문제