Quand j'ai vu le site OpenCV pour la première fois depuis un moment, il était nouveau, alors je l'ai touché un instant.
https://opencv.org/
J'avais l'habitude de suivre les balles de baseball en Java il y a longtemps, donc cette fois je l'ai essayé en Python. Le suivi est une combinaison de différences d'arrière-plan et de correspondance de modèles.
L'environnement est le suivant.
Je crée un environnement avec venv
. Ce n'est pas grave si ce n'est pas «venv».
$ python -m venv pythonOpevCV
$ cd pythonOpenCV
$ Script\activate
$ python -m pip install --upgrade pip
$ pip install opencv-python
Successfully installed numpy-1.18.2 opencv-python-4.2.0.34
numpy
sera également installé.
Veuillez préparer les éléments suivants.
--Vidéo montrant une balle de baseball
L'image de la balle découpée est la suivante. Voici un exemple.
Suivez les étapes ci-dessous pour effectuer le suivi.
Même si la correspondance de modèle est soudainement effectuée sur l'image du cadre d'origine, les nuages et les bâtiments en arrière-plan sont détectés par erreur comme des boules, et la précision n'est pas bonne, donc échelle de gris → binarisation pour créer une image en noir et blanc. Si vous faites une différence d'arrière-plan entre les images précédentes et suivantes dans l'état d'image en noir et blanc, les nuages et l'arrière-plan bougeront à peine en 0,1 seconde environ, vous pouvez donc clairement détecter la balle en mouvement.
L'image en niveaux de gris ressemble à ceci:
Détecte les balles dans la zone entourée par le cadre rouge. Cette image est binarisée en une image en noir et blanc.
La balle peut être détectée en blanc, mais seule la balle ne peut pas être détectée car le fond et la balle sont les mêmes blancs. Ici, la différence d'arrière-plan entre les images d'image précédente et suivante est la suivante.
Le fond blanc ne fonctionne pas et n'est pas détecté par la différence de fond, seuls la balle et les autres bruits sont détectés en blanc. Dans cet état, la mise en correspondance de modèles est effectuée avec l'image binarisée de l'image de modèle suivante.
Cela permettra à la balle d'être détectée sans être affectée par la luminosité ou l'arrière-plan.
Le code source est le suivant. Placez la vidéo cible dans VIDEOPATH
et l'image modèle dans TEMPLATEPATH
.
main.py
import glob
import re
import cv2
VIDEOPATH = "media/video/video.mp4"
IMAGEPATH = "media/image/"
TEMPLATEPATH = "template.jpeg "
def save_frames(video_path, image_dir):
"""
Extraire des images de cadre à partir de vidéos
"""
cap = cv2.VideoCapture(video_path)
digit = len(str(int(cap.get(cv2.CAP_PROP_FRAME_COUNT))))
n = 0
while True:
ret, frame = cap.read()
if ret:
cv2.imwrite("{}original/frame_{}.{}".format(IMAGEPATH, n, "jpeg"), frame)
n += 1
else:
return
def do_grayscale(image_path):
"""
Image en échelle de gris
"""
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
save_image(image_path, "gray", gray)
def do_binarization(image_path):
"""
Binariser l'image
"""
img = cv2.imread(image_path)
ret, img_thresh = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)
save_image(image_path, "binary", img_thresh)
def do_backgroundsub():
"""
Faire la différence
"""
img_list = glob.glob(IMAGEPATH + "binary/frame*.jpeg ")
num = lambda val: int(re.sub("\D","",val))
sorted(img_list,key=(num))
source = img_list[0]
for path in img_list:
diff = cv2.absdiff(cv2.imread(source),cv2.imread(path))
source = path
save_image(path, "bgsub", diff)
def do_template_matching():
"""
Effectuer une correspondance de modèle entre l'image du modèle et l'image du cadre
"""
template_img = cv2.imread(IMAGEPATH + "binary/" + TEMPLATEPATH)
img_list = glob.glob(IMAGEPATH + "bgsub/frame*.jpeg ")
num = lambda val: int(re.sub("\D","",val))
sorted(img_list,key=(num))
location_list = []
for path in img_list:
result = cv2.matchTemplate(cv2.imread(path), template_img, cv2.TM_CCOEFF)
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(result)
location_list.append(maxLoc)
return location_list
def draw_rectangle(location_list):
"""
Dessinez le résultat correspondant sur l'image
"""
source = cv2.imread(IMAGEPATH + "original/frame_0.jpeg ")
cv2.imwrite(IMAGEPATH + "result.jpeg ",source)
source = cv2.imread(IMAGEPATH + "result.jpeg ")
for loc in location_list:
lx, ly, rx, ry = loc[0] - 10, loc[1] - 10, loc[0] + 10, loc[1] + 10
img = cv2.rectangle(source, (lx, ly), (rx, ry), (0, 255, 0), 3)
cv2.imwrite(IMAGEPATH + "result.jpeg ",img)
def save_image(img_path, dir, img):
"""
Enregistrer l'image
img_path :Chemin de l'image
dir :Nom du répertoire
img :données d'image
"""
file_name = img_path.replace("\\","/").split(".")[0].split("/")[-1]
cv2.imwrite("{}{}/{}.{}".format(IMAGEPATH, dir, file_name,"jpeg"), img)
if __name__=="__main__":
#① Divisez la vidéo en images
save_frames(VIDEOPATH,IMAGEPATH)
#(2) Échelle de gris l'image du modèle et l'image du cadre
do_grayscale(IMAGEPATH + TEMPLATEPATH)
for path in glob.glob(IMAGEPATH + "original/*.jpeg "):
do_grayscale(path)
#③ Binarisation de l'image du modèle et de l'image du cadre
for path in glob.glob(IMAGEPATH + "gray/*.jpeg "):
do_binarization(path)
#④ Effectuer une différence de fond
do_backgroundsub()
#⑤ Effectuer la mise en correspondance des modèles
location_list = do_template_matching()
#⑥ Projetez les coordonnées correspondantes
draw_rectangle(location_list)
J'ai essayé de détecter le ballon dans la vidéo de lancement. Bien qu'il puisse être détecté en général, il détecte également des parties autres que la trajectoire de la balle.
Il y avait un moyen de corriger le bruit et les valeurs aberrantes, mais j'ai oublié, donc je m'en souviens à nouveau.
Le suivi des balles de baseball a été effectué en utilisant la différence de fond et la correspondance des modèles avec Python + OpenCV.
Si vous utilisez YOLO
, il semble que vous puissiez détecter la balle de baseball à partir de l'image, alors j'aimerais également essayer cette zone.
Recommended Posts