L'un des algorithmes de recherche d'images similaires est dHash. Pour le contenu de l'algorithme, voir "Calculer la similitude des images à l'aide de Perceptual Hash". C'est facile à comprendre, mais je comprends qu'il s'agit d'un algorithme de recherche d'images similaire avec les caractéristiques suivantes.
J'ai donc essayé d'utiliser ce dHash pour identifier la position de la scène sur le parcours à partir d'une scène (vidéo embarquée) du jeu du jeu de course Assetto Corsa.
Plus précisément, le flux est le suivant.
① Tout d'abord, toutes les images sont extraites et enregistrées en tant qu'images PNG à partir d'une vidéo de lecture (vidéo intégrée) qui fait le tour du parcours.
② Calcule la valeur de hachage dHash pour toutes les images de cadre enregistrées. De plus, comme il est possible d'identifier la position du véhicule à un certain moment à partir des données de télémétrie acquises lors de la prise de vue de la vidéo de lecture, la valeur de hachage calculée en combinaison avec les informations de position est enregistrée dans le fichier CSV de recherche.
③ D'autre part, sélectionnez une scène dans laquelle vous souhaitez identifier la position sur le parcours à partir d'une autre vidéo de lecture.
④ Calcule la valeur de hachage dHash pour l'image à une scène sélectionnée.
⑤ Recherchez le fichier CSV pour rechercher l'image avec la valeur de hachage la plus proche de la valeur de hachage dHash calculée. Puisque les informations de position sont liées à l'image touchée par la recherche en (2), cette position est considérée comme la position sur le parcours de la scène sélectionnée.
Dans une scène d'un jeu de course, même si vous êtes près du parcours, il y aura un léger désalignement dû aux différences dans les lignes qui passent à travers chaque jeu. Je pense que le but de cette époque est d'absorber ces différences et de rechercher des images similaires.
Cette fois, nous allons implémenter le processus ci-dessus en Python.
J'ai utilisé OpenCV cette fois pour extraire toutes les images d'image du fichier vidéo de lecture (fichier mp4). Je me réfère à la page suivante.
L'image du cadre est enregistrée sous le nom de fichier "(numéro du cadre) .png ".
01_extract_frames.py
import cv2
import sys
def extract_frame(video_file, save_dir):
capture = cv2.VideoCapture(video_file)
frame_no = 0
while True:
retval, frame = capture.read()
if retval:
cv2.imwrite(r'{}\{:06d}.png'.format(save_dir, frame_no), frame)
frame_no = frame_no + 1
else:
break
if __name__ == '__main__':
video_file = sys.argv[1]
save_dir = sys.argv[2]
extract_frame(video_file, save_dir)
Ce script est également utilisé dans ③.
Parmi les images de trame extraites, la valeur de hachage de dHash est calculée à l'aide de la fonction dhash du package ImageHash pour l'image correspondant à une certaine période (une partie de tour spécifique). En outre, il est lié aux données de télémétrie (extrayant uniquement la partie pertinente à l'avance) acquises par le script d'application du jeu suivant et générées dans le fichier CSV de recherche.
02_calc_dhash.py
from PIL import Image, ImageFilter
import imagehash
import csv
import sys
frame_width = 1280
frame_hight = 720
trim_lr = 140
trim_tb = 100
dhash_size = 8
def calc_dhash(frame_dir, frame_no_from, frame_no_to, telemetry_file, output_file):
#Lire le fichier de données de télémétrie
position_data = [row for row in csv.reader(open(telemetry_file), delimiter = '\t')]
writer = csv.writer(open(output_file, mode = 'w', newline=''))
for i in range(frame_no_from, frame_no_to + 1):
#Lisez l'image du cadre extraite et coupez-la (pour effacer l'heure, etc. affichée au bord de l'image)
frame = Image.open(r'{}\{:06d}.png'.format(frame_dir, i))
trimed_frame = frame.crop((
trim_lr,
trim_tb,
frame_width - trim_lr,
frame_hight - trim_tb))
#Calcul de la valeur dHash
dhash_value = str(imagehash.dhash(trimed_frame, hash_size = dhash_size))
#Liaison avec les données de télémétrie
#Comme les images et la télémétrie sont produites à intervalles réguliers, elles sont simplement liées proportionnellement au nombre de lignes.
position_no = round((len(position_data) - 1) * (i - frame_no_from) / (frame_no_to - frame_no_from))
writer.writerow([
i,
dhash_value,
position_data[position_no][9],
position_data[position_no][10]
])
if __name__ == '__main__':
frame_dir = sys.argv[1]
frame_no_from = int(sys.argv[2])
frame_no_to = int(sys.argv[3])
telemetry_file = sys.argv[4]
output_file = sys.argv[5]
calc_dhash(frame_dir, frame_no_from, frame_no_to, telemetry_file, output_file)
À la suite de ce script, les informations suivantes (numéro d'image), (valeur de hachage) et (position des coordonnées 2D en mètres) sont générées dans le fichier CSV.
731,070b126ee741c080,-520.11,139.89
732,070b126ee7c1c080,-520.47,139.90
733,070b126ee7c1c480,-520.84,139.92
Ce script est également utilisé dans ④.
L'image avec la valeur de hachage la plus proche de la valeur de hachage spécifiée est recherchée à partir de la sortie du fichier CSV de recherche en 2-2.
La distance de bourdonnement est utilisée pour la proximité des valeurs de hachage. J'utilise popcount du package gmpy2 pour calculer la distance de bourdonnement (car cela semble être très rapide).
03_match_frame.py
import csv
import gmpy2
import sys
def match_frame(base_file, search_hash):
base_data = [row for row in csv.reader(open(base_file))]
min_distance = 64
min_line = None
results = []
for base_line in base_data:
distance = gmpy2.popcount(
int(base_line[1], 16) ^
int(search_hash, 16)
)
if distance < min_distance:
min_distance = distance
results = [base_line]
elif distance == min_distance:
results.append(base_line)
print("Distance = {}".format(min_distance))
for min_line in results:
print(min_line)
if __name__ == '__main__':
base_file = sys.argv[1]
search_hash = sys.argv[2]
match_frame(base_file, search_hash)
Comme indiqué ci-dessous, les informations de position associées aux informations de l'image avec la valeur de hachage la plus proche sont sorties. (S'il y a plusieurs images avec la même distance, toutes les informations sur l'image seront affichées.)
> python.exe 03_match_frame.py dhash_TOYOTA_86.csv cdc9cebc688f3f47
Distance = 8
['13330', 'c9cb4cb8688f3f7f', '-1415.73', '-58.39']
['13331', 'c9eb4cbc688f3f7f', '-1415.39', '-58.44']
Cette fois, la vidéo de lecture qui a couru sur le parcours nord du Nürburgring (longueur totale 20,81 km) avec TOYOTA 86 GT a été extraite de toutes les images ⇒ Le calcul de la valeur de hachage a été effectué, et il est proche de l'image de certaines scènes d'une autre vidéo de lecture qui a couru sur BMW Z4 Je chercherai l'image.
Tout d'abord, vérifions si les images des trois célèbres coins peuvent être recherchées correctement.
Image utilisée pour la recherche | Image frappée | |
---|---|---|
image | ||
Valeur de hachage | ced06061edcf9f2d | 0c90e064ed8f1f3d |
Information de Lieu | (-2388.29, 69.74) | (-2416.50, 66.67) |
Distance de valeur de hachage = 10, écart d'informations de position = 28,4 m
Dans dHash, il est dit que si la distance de valeur de hachage est de 10 ou moins, elle est considérée comme la même image, mais c'est à peine. Même sur l'image, la forme des coins est similaire, mais les positions des arbres environnants sont légèrement différentes, il est donc difficile de juger s'ils sont similaires ou non.
Image utilisée pour la recherche | Image frappée | |
---|---|---|
image | ||
Valeur de hachage | 7c5450640c73198c | 7c7c50642d361b0a |
Information de Lieu | (317.58, -121.52) | (316.18, -121.45) |
Distance de valeur de hachage = 11, écart des informations de position = 1,4 m
C'est assez proche de l'image. Cependant, la distance de valeur de hachage est de 11, ce qui est plus grand qu'avant.
Image utilisée pour la recherche | Image frappée | |
---|---|---|
image | ||
Valeur de hachage | 665d1d056078cde6 | 665c1d856050da8d |
Information de Lieu | (2071.48, 77.01) | (2071.23, 77.12) |
Distance de valeur de hachage = 13, écart des informations de position = 0,27 m
La position du véhicule est également très proche et les images se ressemblent beaucoup, mais si vous regardez de près, l'orientation est légèrement différente. La distance de valeur de hachage est de 13, ce qui est assez grand.
Comme mentionné ci-dessus, je l'ai essayé dans trois virages célèbres, mais il semble que je puisse identifier la position la plus proche.
De plus, je l'ai essayé dans 10 scènes sélectionnées au hasard, et c'est devenu comme suit.
Un seul cas où seule la mauvaise position a été atteinte est illustré ci-dessous.
Image utilisée pour la recherche | Image frappée | |
---|---|---|
image | ||
Valeur de hachage | b7b630b24c1e1f1e | b7b43839481e3f1f |
Information de Lieu | (1439.61, -18.69) | (2059.41, 37.44) |
Distance de valeur de hachage = 9, écart des informations de position = 622,34 m
Il semble que la façon dont les arbres poussent à gauche et à droite et la pointe du parcours soient assez différentes de la courbe gauche ou droite, mais la distance de valeur de hachage est relativement proche de 9.
Au fait, les images que j'aimerais que vous voyiez sont les suivantes.
Image utilisée pour la recherche | Image frappée |
---|---|
Différence de valeur de hachage = 13
À première vue, les images se ressemblent, mais si vous regardez de près, elles ne sont pas alignées et, par conséquent, je pense que la différence est relativement grande.
Dans cet article, j'ai recherché des images similaires avec dHash dans la scène du jeu de course.
La précision est relativement bonne pour les scènes caractéristiques telles que les coins célèbres, mais lorsque j'ai sélectionné au hasard les scènes, le taux de victoire était de 70% (veuillez pardonner le fait que le nombre de cas confirmés est aussi petit que 10).
Ce n'est pas une interprétation solide, mais comme une impression personnelle, c'est comme suit.
Si vous souhaitez améliorer la précision, je pense que vous pouvez penser aux mesures suivantes.