Suivre les balles de baseball avec Python + OpenCV

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.

Environnement

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é.

Quoi préparer

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.

template.jpeg

procédure

Suivez les étapes ci-dessous pour effectuer le suivi.

  1. Enregistrer sous forme d'image pour chaque image de la vidéo
  2. Image de cadre en échelle de gris et image modèle
  3. Binariser l'image du cadre et l'image du modèle 4.Faites une différence d'arrière-plan entre les images d'image précédente et suivante
  4. Effectuez une correspondance de modèle à partir de l'image résultant de la différence de fond
  5. Dessinez les résultats du 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:

gray.jpeg

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.

binary.jpeg

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.

sub.jpeg

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.

templatebi.jpeg

Cela permettra à la balle d'être détectée sans être affectée par la luminosité ou l'arrière-plan.

Code source

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)

résultat

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.

result.jpeg

Il y avait un moyen de corriger le bruit et les valeurs aberrantes, mais j'ai oublié, donc je m'en souviens à nouveau.

Résumé

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

Suivre les balles de baseball avec Python + OpenCV
Binarisation avec OpenCV / Python
"Traitement Apple" avec OpenCV3 + Python3
Édition d'image avec python OpenCV
Capture de caméra avec Python + OpenCV
[Python] Utilisation d'OpenCV avec Python (basique)
Détection de visage avec Python + OpenCV
Utiliser OpenCV avec Python @Mac
Briller la vie avec Python et OpenCV
[Python] Utilisation d'OpenCV avec Python (filtrage d'image)
Réseau neuronal avec OpenCV 3 et Python 3
[Python] Utilisation d'OpenCV avec Python (transformation d'image)
[Python] Utilisation d'OpenCV avec Python (détection des bords)
Programmation facile Python + OpenCV avec Canopy
Découpez le visage avec Python + OpenCV
Reconnaissance faciale avec caméra avec opencv3 + python2.7
Charger une image gif avec Python + OpenCV
Trouver la similitude d'image avec Python + OpenCV
Segmentation basée sur un graphique avec Python + OpenCV
Dessinez une flèche (vecteur) avec opencv / python
Etude de base d'OpenCV avec Python
Détection de visage avec Python + OpenCV (rotation invariante)
Enregistrer la vidéo image par image avec Python OpenCV
Capturer des images avec Pupil, python et OpenCV
J'ai essayé le rendu non réaliste avec Python + opencv
Traitement d'image avec Python et OpenCV [Tone Curve]
Acquisition d'images depuis une caméra avec Python + OpenCV
[python, openCV] base64 Reconnaissance faciale dans les images
Créez diverses vidéos Photoshop avec Python + OpenCV ③ Créez diverses vidéos Photoshop
[Python] Lire des images avec OpenCV (pour les débutants)
Jusqu'à ce que vous puissiez utiliser opencv avec python
Traitement d'image léger avec Python x OpenCV
Lissage des bords enregistrés avec python + OpenCV (BilateralFilter, NLMeansFilter)
FizzBuzz en Python3
Grattage avec Python
Statistiques avec python
Grattage avec Python
Twilio avec Python
Intégrer avec Python
Jouez avec 2016-Python
AES256 avec python
python commence par ()
Exemples OpenCV (Python)
Bingo avec python
Zundokokiyoshi avec python
[Remarque] openCV + python
Suivre les programmes Python
Excel avec Python
Micro-ordinateur avec Python
Cast avec python
Hello World et détection de visage avec OpenCV 4.3 + Python
J'ai essayé de "lisser" l'image avec Python + OpenCV
Suivez les objets de votre vidéo avec OpenCV Tracker
Comparaison des performances du détecteur de visage avec Python + OpenCV
J'ai essayé de "différencier" l'image avec Python + OpenCV
Extraction de bords avec python + OpenCV (filtre Sobel, filtre laplacien)
Comment recadrer une image avec Python + OpenCV
Installez OpenCV 4.0 et Python 3.7 sur Windows 10 avec Anaconda
Suivi des objets verts avec python + numpy (filtre à particules)
Rendre OpenCV3 disponible à partir de python3 installé avec pyenv
J'ai essayé de "binariser" l'image avec Python + OpenCV