[PYTHON] J'ai essayé l'analyse d'image du livre de score de tir à l'arc (un livret qui enregistre les résultats des coups). (Google Colaboratory)

Qu'est-ce qu'un livre de score de tir à l'arc?

Il s'agit d'un livret qui enregistre si la flèche de tir a été touchée ou manquée.

Il existe différentes méthodes d'enregistrement selon les groupes, mais cette fois j'ai relevé le défi d'analyser celles marquées d'un cercle à l'encre vermillon.

saitenbo_sample1.png

C'est un mauvais code, mais j'espère que cela aide quelqu'un.

Structure de ce programme

Utilisation de la collaboration google

J'ai créé le programme en partant du principe que ** google collaboratery ** sera utilisé.

https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja

google collab est un environnement de notebook Jupyter qui s'exécute entièrement dans le cloud. Vous n'avez pas d'ordinateur car vous pouvez l'utiliser gratuitement sans aucun réglage! À ce moment-là, je n'ai pas mis python sur mon ordinateur! Même dans ce cas, il est facile à utiliser.

De plus, bien que l'installation de la bibliothèque sur votre propre ordinateur prenne du temps, il est étonnamment grand avantage de pouvoir l'exécuter avec la mort cérébrale car la plupart des bibliothèques sont déjà installées dans google collab.

Cette fois, je vais lire et écrire des images, j'ai donc décidé de les lier à ** google Drive **.

Plan de conversion de données électroniques

La conception de ce code est la suivante.

** 1. Lien avec Google Drive pour créer des dossiers 2. Obtenir l'image, changer la taille de l'image 3. Reconnaître le cadre du livre de notation 4. Reconnaissez le cercle rouge dans le livre de notation 5. Organisez les informations de position du cercle 6. Écrire dans Excel **

Reconnaissance du cadre extérieur du livret

Une ligne droite a été reconnue dans certaines conditions, et les lignes verticales et horizontales au bord de l'image ont été spécifiées comme valeurs de retour.

--Utilise la détection linéaire par conversion Huff.

http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_houghlines/py_houghlines.html

detect_line.py



  def resize_im(self, im): #Taille d'image fixe
  # --------------------------------------------
    size = self.x_pixel
    h, w, c = im.shape
    width,height = size, round(size * ( h / w ))
    im_resize = cv2.resize(im,(width, height))
    return im_resize


  def detect_line(self): #Détecter les cadres
  # -----------------------------------------
    im = cv2.imread(path_Now_Projects + self.FileName)
    im_resize = self.resize_im(im)
    # parameter
    G = 1 + 2 * self.nomalization(10)
    T1 = 1 + 2 * self.nomalization(7)
    T2 = 1 + 2 * self.nomalization(2)

    #Traiter l'image (suppression du bruit, flou, binarisation)
    im_denoise = cv2.fastNlMeansDenoising(im_resize)
    im_gray = cv2.cvtColor(im_denoise, cv2.COLOR_BGR2GRAY)
    im_gau = cv2.GaussianBlur(im_gray,(G,G),0)
    im_th = cv2.adaptiveThreshold(im_gau, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,T1,T2)
    if detail2 == True:
      cv2.imwrite(self.path_project + self.ImName + "_th.jpg ", im_th)
    #Extraire une ligne droite.
    imgEdge = cv2.Canny(im_th,50,150,apertureSize = 3) #Détection des bords par la méthode Canny
    minLineLength = self.nomalization(200) #Seuil de la longueur de la ligne droite à détecter (en fonction du nombre de pixels)
    maxLineGap = self.nomalization(20) #La plus longue distance entre les lignes droites qui peut être considérée comme continue (en fonction du nombre de pixels)
    th = self.nomalization(50)
    lines = cv2.HoughLinesP(imgEdge,2,np.pi/180,th,minLineLength=minLineLength,maxLineGap=maxLineGap) #Détection de lignes droites par approximation de Huff
    #Sélectionnez les lignes droites du cadre tout en dessinant les lignes droites en bleu.
    im_line = im_resize
    frame_left,frame_under, frame_over, frame_right = [10000]*4,[1]*4, [10000]*4, [1]*4 #Réglage de la valeur initiale
    #Tracez toutes les lignes droites
    for i in range(len(lines)):
      for x1,y1,x2,y2 in lines[i]:
        cv2.line(im_line,(x1,y1),(x2,y2),(255,0,0),2)

        #Trier les lignes droites du cadre
        if frame_left[0] > x1 and abs(y1-y2) >3*abs(x1-x2) : #Ligne verticale avec la plus petite coordonnée x
          frame_left = [x1,y1,x2,y2]
        if frame_under[1] < y1 and 3*abs(y1-y2) < abs(x1-x2) : #Ligne horizontale avec la plus grande coordonnée y
          frame_under = [x1,y1,x2,y2]
        if frame_over[1] > y1 and 3*abs(y1-y2) < abs(x1-x2) : #Ligne horizontale avec la plus petite coordonnée y
          frame_over = [x1,y1,x2,y2]
        if frame_right[0]  < x1 and abs(y1-y2) >3*abs(x1-x2) : #Ligne verticale avec la plus grande coordonnée x
          frame_right = [x1,y1,x2,y2]
    #Tracez une ligne droite indiquant le cadre en vert.
    cv2.line(im_line,(frame_left[0], frame_left[1]),(frame_left[2], frame_left[3]),(0,255,0),2)
    cv2.line(im_line,(frame_under[0], frame_under[1]),(frame_under[2], frame_under[3]),(0,255,0),2)
    cv2.line(im_line,(frame_over[0], frame_over[1]),(frame_over[2], frame_over[3]),(0,255,0),2)
    cv2.line(im_line,(frame_right[0], frame_right[1]),(frame_right[2], frame_right[3]),(0,255,0),2)

    if detail2 == True: #Enregistrez l'image pour le débogage.
      cv2.imwrite(self.path_project + self.ImName + "_line.jpg ", im_line)
    return frame_left, frame_under, frame_over, frame_right



Trouvez l'intersection de chacune des quatre lignes droites

get_4point.py


  def cross_point(self, p1, p2): #Dérivation de l'intersection de deux droites passant par deux points
  # -----------------------------------------------------------
    return solve( [ solve(p1,[1,1]), solve(p2,[1,1]) ], [1,1] )



  def get_4point(self, f_under, f_left,f_over,f_right):#Obtenez 4 intersections de 4 lignes droites passant par 2 points
  # ------------------------------------------------------------------------------------
    f_under = np.array([f_under[0:2], f_under[2:4]])
    f_left = np.array([f_left[0:2], f_left[2:4]])
    f_over = np.array([f_over[0:2], f_over[2:4]])
    f_right = np.array([f_right[0:2], f_right[2:4]])
    UL = self.cross_point(f_under, f_left)
    OL = self.cross_point(f_over , f_left)
    UR = self.cross_point(f_under, f_right)
    OR = self.cross_point(f_over, f_right)
    return  [OL, OR, UL, UR]

Découper un quadrilatère en 4 points

transform_by4.py


  def transform_by4(self, points):#Couper de n'importe quel 4 points à un rectangle
  # --------------------------------------------------------------
    im = cv2.imread(path_Now_Projects + self.FileName)
    im_resize = self.resize_im(im)
    points = sorted(points, key=lambda x:x[1])  #Trier par ordre croissant de y.
    top = sorted(points[:2], key=lambda x:x[0])  #Les deux premiers sont sur la place. Vous pouvez également voir la gauche et la droite en triant par x.
    bottom = sorted(points[2:], key=lambda x:x[0], reverse=True)  #Les deux derniers sont en dessous du carré. Également trié par x.
    points = np.array(top + bottom, dtype='float32')  #Rejoignez les deux parties séparées.
    width = max(np.sqrt(((points[0][0]-points[2][0])**2)*2), np.sqrt(((points[1][0]-points[3][0])**2)*2))
    height = max(np.sqrt(((points[0][1]-points[2][1])**2)*2), np.sqrt(((points[1][1]-points[3][1])**2)*2))
    dst = np.array([
      np.array([0, 0]),
      np.array([width-1, 0]),
      np.array([width-1, height-1]),
      np.array([0, height-1]),
      ], np.float32)
    trans = cv2.getPerspectiveTransform(points, dst)  #Si vous passez la correspondance entre les coordonnées avant la conversion et les coordonnées après la conversion, une matrice de conversion de perspective sera créée.
    im_trimming = cv2.warpPerspective(im_resize, trans, (int(width), int(height)))  #Recadrer à l'aide d'une matrice de transformation de perspective.

    if detail2 == True:
      cv2.imwrite(self.path_project +  self.ImName +'_trimming.jpg', im_trimming)
    return im_trimming

Extraction du cercle rouge

La méthode d'extraction de la couleur rouge est gênante, comme le masquage dans une certaine plage de l'espace colorimétrique hsv.

image.png

--Sites référencés dans le traitement des masques

https://note.nkmk.me/python-opencv-numpy-alpha-blend-mask/

https://www.blog.umentu.work/python-opencv3%E3%81%A7%E3%83%9E%E3%82%B9%E3%82%AF%E5%87%A6%E7%90%86%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B%EF%BC%88%E3%81%8A%E3%81%BE%E3%81%91%E3%81%82%E3%82%8A%EF%BC%89/


  def detect_red(self, im_trimming):#Extraire uniquement le rouge
  # ------------------------------------------------
    im = im_trimming
    im_resize = self.resize_im(im)

    #rouge(H vaut 0~30,150~La gamme 180 est rouge)Préparez un masque
    hsv = cv2.cvtColor(im_resize, cv2.COLOR_BGR2HSV)
    lower1 = np.array([150, 30, 100]) # HSV
    upper1 = np.array([179, 255, 255]) # HSV
    img_mask1 = cv2.inRange(hsv, lower1, upper1)
    lower2 = np.array([0, 30, 100]) # HSV
    upper2 = np.array([30, 255, 255]) # HSV
    img_mask2 = cv2.inRange(hsv, lower2, upper2)

    #Combinez deux masques rouges
    mask = cv2.bitwise_or(img_mask1, img_mask2)

    #Mettez le masque et ne laissez que le cercle rouge
    im_red = cv2.bitwise_and(im_resize, im_resize, mask=mask)

    if detail2 == True: #Enregistrer l'image pour le débogage
      cv2.imwrite(self.path_project + self.ImName + "_red.jpg ",  im_red)
    return im_red



Détection de cercle

La détection de cercle est effectuée sur l'image extraite uniquement en rouge. Si vous faites une erreur en définissant les conditions, chaque motif sera reconnu comme un cercle, les conditions sont donc essentielles.

Cette fois, comme pour la détection linéaire, la fonction Huff est utilisée.

--Détection de cercle par conversion Huff

http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_houghlines/py_houghlines.html

detect_circle.py


 
 
  def detect_circle(self, im_trimming):#Obtenez la position du cercle
  # ---------------------------------------------------
    # parameter
    minD = self.nomalization(58)
    p2= self.nomalization(12)
    minR = self.nomalization(30)
    maxR = self.nomalization(36)
    Lx0 = self.nomalization(10)
    Ly0 = self.nomalization(86)
    Lx = self.nomalization(90)
    Ly = self.nomalization(72)
  
    #Détectez un cercle de l'image extraite en rouge.
    im_red = self.detect_red(im_trimming)
    im_gray = cv2.cvtColor(im_red,cv2.COLOR_BGR2GRAY)
  
    #Définissez la taille du cercle à détecter avant et après la taille du cercle en fonction du nombre de pixels
    circles = cv2.HoughCircles(im_gray, 
                               cv2.HOUGH_GRADIENT, 
                               dp=1, 
                               minDist = minD, #Intervalles par cercle permettant la détection
                               param1=1,
                               param2=p2, #Seuil de détection
                               minRadius=minR, #Rayon minimum à détecter
                               maxRadius=maxR) #Rayon maximum à détecter
  

Tous les codes

kaiseki.py



# coding: utf-8
#Numérisez la photo à succès du carnet de notes
# ________________________________
#Paramètres utilisateur de sortie"True"or"False"
detail1 = True
detail2 = True
# 1 =Image pour confirmation
# 2 =Image pour le réglage des paramètres
# ________________________________
 
 
#liste d'importation
import numpy as np
from numpy.linalg import solve
import os
import cv2
import sys
import pandas as pd
import openpyxl as excel
from pandas import ExcelWriter
import matplotlib.pyplot as plt
 
#Fonctionne avec Google Drive
from google.colab import drive
drive.mount('/content/drive')
 
#liste de chemins
path_Now_Projects = 'drive/My Drive/OU_kyudo/Now_Projects/'
path_Past_Projects = 'drive/My Drive/OU_kyudo/Past_Projects/'
 
#Créer un dossier
def make_folder(path):
  if os.path.exists(path)==False:
    os.mkdir(path)
make_folder(path_Now_Projects)
make_folder(path_Past_Projects)
 
#Obtenez le nom de l'image
files = []
for filename in os.listdir(path_Now_Projects):
  if os.path.isfile(os.path.join(path_Now_Projects, filename)): #Obtenez uniquement des fichiers
    files.append(filename)
if len(files)==0:
  print("Maintenant l'image_Mettez-le dans le dossier Projets.")
  sys.exit()
 
 
 
#=============================
#<<<<<<  C l a s s  >>>>>>>>>>
 
class Tekichu(object): #initialiser.
  # --------------------------------
  def __init__(self):
    #Nom de l'image (avec extension)
    self.FileName = ""
    #Nom de l'image (sans extension)
    self.ImName, self.ext =  "",""
    #nom du projet et son nom de chemin
    self.project = ""
    self.path_project = ""
    #Nombre de pixels dans la direction horizontale de l'image
    self.x_pixel = 1800
 
 
 
  def set_variable(self, file): #Définissez le nom de l'image
  # ----------------------------------------------------
    
    #nom du projet et son nom de chemin
    self.project = input("image("+  file  +") Entrez le nom du projet: ")
    self.path_project = "drive/My Drive/OU_kyudo/Now_Projects/" + self.project +"/"
    #Créez un dossier avec le nom du projet
    if os.path.exists(self.path_project)==False:
      os.mkdir(self.path_project)
   
    #Nom de l'image (avec extension)
    self.FileName = file
    #Nom de l'image (sans extension)
    self.ImName, self.ext =  os.path.splitext(file)
 
  #Normaliser les paramètres qui fluctuent avec les pixels en utilisant des valeurs de référence
  def nomalization(self, val):
    return int(self.x_pixel *(val / 1200))
 
 
 
  def resize_im(self, im): #Taille d'image fixe
  # --------------------------------------------
    size = self.x_pixel
    h, w, c = im.shape
    width,height = size, round(size * ( h / w ))
    im_resize = cv2.resize(im,(width, height))
    return im_resize
 
  
  def detect_line(self): #Détecter les cadres
  # -----------------------------------------
    im = cv2.imread(path_Now_Projects + self.FileName)
    im_resize = self.resize_im(im)
    # parameter
    G = 1 + 2 * self.nomalization(10)
    T1 = 1 + 2 * self.nomalization(7)
    T2 = 1 + 2 * self.nomalization(2)
  
    #Traiter l'image (suppression du bruit, flou, binarisation)
    im_denoise = cv2.fastNlMeansDenoising(im_resize)
    im_gray = cv2.cvtColor(im_denoise, cv2.COLOR_BGR2GRAY)
    im_gau = cv2.GaussianBlur(im_gray,(G,G),0)
    im_th = cv2.adaptiveThreshold(im_gau, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,T1,T2)
    if detail2 == True:
      cv2.imwrite(self.path_project + self.ImName + "_th.jpg ", im_th)
    #Extraire une ligne droite.
    imgEdge = cv2.Canny(im_th,50,150,apertureSize = 3) #Détection des bords par la méthode Canny
    minLineLength = self.nomalization(200) #Seuil de la longueur de la ligne droite à détecter (en fonction du nombre de pixels)
    maxLineGap = self.nomalization(20) #La plus longue distance entre les lignes droites qui peut être considérée comme continue (en fonction du nombre de pixels)
    th = self.nomalization(50)
    lines = cv2.HoughLinesP(imgEdge,2,np.pi/180,th,minLineLength=minLineLength,maxLineGap=maxLineGap) #Détection de lignes droites par approximation de Huff
    #Sélectionnez les lignes droites du cadre tout en dessinant les lignes droites en bleu.
    im_line = im_resize
    frame_left,frame_under, frame_over, frame_right = [10000]*4,[1]*4, [10000]*4, [1]*4 #Réglage de la valeur initiale
    #Tracez toutes les lignes droites
    for i in range(len(lines)):
      for x1,y1,x2,y2 in lines[i]:
        cv2.line(im_line,(x1,y1),(x2,y2),(255,0,0),2)
    
        #Trier les lignes droites du cadre
        if frame_left[0] > x1 and abs(y1-y2) >3*abs(x1-x2) : #Ligne verticale avec la plus petite coordonnée x
          frame_left = [x1,y1,x2,y2]
        if frame_under[1] < y1 and 3*abs(y1-y2) < abs(x1-x2) : #Ligne horizontale avec la plus grande coordonnée y
          frame_under = [x1,y1,x2,y2]
        if frame_over[1] > y1 and 3*abs(y1-y2) < abs(x1-x2) : #Ligne horizontale avec la plus petite coordonnée y
          frame_over = [x1,y1,x2,y2]
        if frame_right[0]  < x1 and abs(y1-y2) >3*abs(x1-x2) : #Ligne verticale avec la plus grande coordonnée x
          frame_right = [x1,y1,x2,y2]
    #Tracez une ligne droite indiquant le cadre en vert.
    cv2.line(im_line,(frame_left[0], frame_left[1]),(frame_left[2], frame_left[3]),(0,255,0),2)
    cv2.line(im_line,(frame_under[0], frame_under[1]),(frame_under[2], frame_under[3]),(0,255,0),2)
    cv2.line(im_line,(frame_over[0], frame_over[1]),(frame_over[2], frame_over[3]),(0,255,0),2)
    cv2.line(im_line,(frame_right[0], frame_right[1]),(frame_right[2], frame_right[3]),(0,255,0),2)
  
    if detail2 == True: #Enregistrez l'image pour le débogage.
      cv2.imwrite(self.path_project + self.ImName + "_line.jpg ", im_line)
    return frame_left, frame_under, frame_over, frame_right
 
 
  
  def cross_point(self, p1, p2): #Dérivation de l'intersection de deux droites passant par deux points
  # -----------------------------------------------------------
    return solve( [ solve(p1,[1,1]), solve(p2,[1,1]) ], [1,1] )
 
 
  
  def get_4point(self, f_under, f_left,f_over,f_right):#Obtenez 4 intersections de 4 lignes droites passant par 2 points
  # ------------------------------------------------------------------------------------
    f_under = np.array([f_under[0:2], f_under[2:4]])
    f_left = np.array([f_left[0:2], f_left[2:4]])
    f_over = np.array([f_over[0:2], f_over[2:4]])
    f_right = np.array([f_right[0:2], f_right[2:4]])
    UL = self.cross_point(f_under, f_left)
    OL = self.cross_point(f_over , f_left)
    UR = self.cross_point(f_under, f_right)
    OR = self.cross_point(f_over, f_right)
    return  [OL, OR, UL, UR]
 
 
  
  def transform_by4(self, points):#Couper de n'importe quel 4 points à un rectangle
  # --------------------------------------------------------------
    im = cv2.imread(path_Now_Projects + self.FileName)
    im_resize = self.resize_im(im)
    points = sorted(points, key=lambda x:x[1])  #Trier par ordre croissant de y.
    top = sorted(points[:2], key=lambda x:x[0])  #Les deux premiers sont sur la place. Vous pouvez également voir la gauche et la droite en triant par x.
    bottom = sorted(points[2:], key=lambda x:x[0], reverse=True)  #Les deux derniers sont en dessous du carré. Également trié par x.
    points = np.array(top + bottom, dtype='float32')  #Rejoignez les deux parties séparées.
    width = max(np.sqrt(((points[0][0]-points[2][0])**2)*2), np.sqrt(((points[1][0]-points[3][0])**2)*2))
    height = max(np.sqrt(((points[0][1]-points[2][1])**2)*2), np.sqrt(((points[1][1]-points[3][1])**2)*2))
    dst = np.array([
      np.array([0, 0]),
      np.array([width-1, 0]),
      np.array([width-1, height-1]),
      np.array([0, height-1]),
      ], np.float32)
    trans = cv2.getPerspectiveTransform(points, dst)  #Si vous passez la correspondance entre les coordonnées avant la conversion et les coordonnées après la conversion, une matrice de conversion de perspective sera créée.
    im_trimming = cv2.warpPerspective(im_resize, trans, (int(width), int(height)))  #Recadrer à l'aide d'une matrice de transformation de perspective.
    
    if detail2 == True:
      cv2.imwrite(self.path_project +  self.ImName +'_trimming.jpg', im_trimming)
    return im_trimming
 
 
 
  
  def detect_red(self, im_trimming):#Extraire uniquement le rouge
  # ------------------------------------------------
    im = im_trimming
    im_resize = self.resize_im(im)
  
    #rouge(H vaut 0~30,150~La gamme 180 est rouge)Préparez un masque
    hsv = cv2.cvtColor(im_resize, cv2.COLOR_BGR2HSV)
    lower1 = np.array([150, 30, 100]) # HSV
    upper1 = np.array([179, 255, 255]) # HSV
    img_mask1 = cv2.inRange(hsv, lower1, upper1)
    lower2 = np.array([0, 30, 100]) # HSV
    upper2 = np.array([30, 255, 255]) # HSV
    img_mask2 = cv2.inRange(hsv, lower2, upper2)
  
    #Combinez deux masques rouges
    mask = cv2.bitwise_or(img_mask1, img_mask2)
  
    #Mettez le masque et ne laissez que le cercle rouge
    im_red = cv2.bitwise_and(im_resize, im_resize, mask=mask)
  
    if detail2 == True: #Enregistrer l'image pour le débogage
      cv2.imwrite(self.path_project + self.ImName + "_red.jpg ",  im_red)
    return im_red
 
 
 
  def detect_circle(self, im_trimming):#Obtenez la position du cercle
  # ---------------------------------------------------
    # parameter
    minD = self.nomalization(58)
    p2= self.nomalization(12)
    minR = self.nomalization(30)
    maxR = self.nomalization(36)
    Lx0 = self.nomalization(10)
    Ly0 = self.nomalization(86)
    Lx = self.nomalization(90)
    Ly = self.nomalization(72)
  
    #Détectez un cercle de l'image extraite en rouge.
    im_red = self.detect_red(im_trimming)
    im_gray = cv2.cvtColor(im_red,cv2.COLOR_BGR2GRAY)
  
    #Définissez la taille du cercle à détecter avant et après la taille du cercle en fonction du nombre de pixels
    circles = cv2.HoughCircles(im_gray, 
                               cv2.HOUGH_GRADIENT, 
                               dp=1, 
                               minDist = minD, #Intervalles par cercle permettant la détection
                               param1=1,
                               param2=p2, #Seuil de détection
                               minRadius=minR, #Rayon minimum à détecter
                               maxRadius=maxR) #Rayon maximum à détecter
    circle_position = [[0 for i in range(20)] for j in range(13)]
    total_number = [0 for i in range(13)]
    warning = False
    if circles is not None:
      circles = circles.squeeze(axis=0) #Obtenez le centre du cercle
      im_circle = self.resize_im(im_trimming)
   
      #Paramètres selon la grille du cahier de score
      x_level = [int(Lx0+i*Lx) for i in range(13)]
      y_level = [int(Ly0+j*Ly) for j in range(21)]
      #Dessiner toutes les grilles
      for i in x_level: 
        cv2.line(im_circle,(i, 0),(i, int(self.x_pixel * 9/16)),(0,0,255),1)
      for j in y_level:
        cv2.line(im_circle,(0, j),(self.x_pixel, j),(0,0,255),1)
    
      #Arrangez la position centrale du cercle en le comparant à la grille
      for cx, cy, r in circles:     
        #Dessinez la circonférence et le centre du cercle.
        cv2.circle(im_circle, (cx, cy), r, (0, 255, 0), 2)
        cv2.circle(im_circle, (cx, cy), 2, (0, 255, 0), 2)
    
        horizontal = int((cx-Lx0) // Lx)
        vertical = int((cy-Ly0)// Ly)
    
        #Si le cercle s'étend au-delà de la grille, les anomalies seront détectées et traitées.
        if vertical >= 20:
          vertical = 19
          warning = True
      
        #Enregistrer dans le tableau
        circle_position[horizontal][vertical] += 1  
    
        #Les anomalies sont enregistrées lorsque deux ou plus sont détectés dans une grille
        if circle_position[horizontal][vertical] >= 2:
          warning = True
    
    if detail1 == True:
      cv2.imwrite(self.path_project + self.ImName + "_circles.jpg ", im_circle)
  
    #Calculer le succès total
    for i in range(13):
      total_number[i] = np.sum(circle_position[i])
   
    #Textification
    for i in range(13):
      for j in range (20):
        if circle_position[i][j] == 1:
          circle_position[i][j] = "○"
        elif circle_position[i][j] == 0:
          circle_position[i][j] = "・"
    
    #Joindre
    data = np.r_[np.array([total_number]), np.array(circle_position).T] #Combinez de façon à ce que le total soit la 0e ligne et que le résultat soit la 1e à la 20e ligne
    df = pd.DataFrame(data) 
  
    #Voir les résultats
    if warning == True :
      print("[Avertissement] Il y a une erreur dans le résultat."+ self.FileName)
    print(df)
    return df
 
  
  def tekichu_main(self):#Programme principal en classe
  # ------------------------------------------------
    f_left, f_under , f_over, f_right = self.detect_line()
    box_points = self.get_4point(f_left, f_under , f_over, f_right)
    im_trimming = self.transform_by4(box_points)
    df = self.detect_circle(im_trimming)
    wb = excel.Workbook() #Créer un nouveau classeur
    wb.save(self.path_project + self.project +".xlsx")
    writer = ExcelWriter(self.path_project + self.project + '.xlsx')
    df.to_excel(writer, sheet_name = self.ImName) #Écrire dans Excel
    writer.save()
    return df
 
 
 
#==================================
#>>>programme principal>>>>>>>>>>>>>>>
if __name__ == '__main__':
  for i in range(len(files)):
    tek1 = Tekichu()
    tek1.set_variable(files[i])
    df = tek1.tekichu_main()
  print("Terminé normalement")


Procédure d'exécution

Je voulais vraiment l'analyser avec une photo prise correctement

Mais c'était impossible.

Afin d'analyser la position du cercle de frappe, il est nécessaire de comprendre la relation de position de la grille dans le livre de score.

J'ai utilisé une fonction de détection linéaire pour le reconnaître, mais ...

S'il y a un arrière-plan, il sera détecté de manière imprévisible. Comme prévu, cela ne peut pas être aidé.

⇒ Faites rogner l'image pour éviter que l'arrière-plan

trimming.png

Avec cela comme condition, nous avons rendu possible une analyse stable.

Préparation du disque

Tout d'abord, en raison des spécifications de ce programme, créez un dossier appelé "kyudo" et deux dossiers appelés "New_Projects" et "Past_Projects" dedans.

Puisqu'il est conçu pour traiter l'image contenue dans "New_Projects", placez-y l'image recadrée.

ドライブ用意.png

Bouton Exécuter lorsque vous êtes prêt! Cela tourne autour ...

J'ai été chargé de monter le lecteur. La première fois que vous ouvrez Google Collab

Si vous ne savez pas comment monter le lecteur, je pense que vous devriez le lire.

Si vous le connaissez, veuillez l'ignorer.

ドライブマウント1.png

Sélectionnez maintenant votre compte.

ドライブマウント2.png

Ceci termine le montage. Entrez ensuite le nom du projet.

Si vous l'exécutez après avoir saisi le nom du projet, le résultat de l'analyse sera affiché et les données du tableau seront enregistrées dans le variateur.

Il était préférable de laisser l'utilisateur en traiter une partie sur l'écran GUI

Après cela, j'ai écrit le code à traiter avec GUI (interface utilisateur graphique) en utilisant Tkinter sans utiliser Google Colab, mais c'était mieux en termes de précision et de fonctionnement.

Eh bien, c'était une expérience d'apprentissage et j'ai apprécié.

Recommended Posts

J'ai essayé l'analyse d'image du livre de score de tir à l'arc (un livret qui enregistre les résultats des coups). (Google Colaboratory)
J'ai écrit un lecteur de corpus qui lit les résultats de l'analyse MeCab
Une histoire qui a analysé la livraison de Nico Nama.
J'ai fait un calendrier qui met à jour automatiquement le calendrier de distribution de Vtuber (édition Google Calendar)
J'ai fait une image ponctuelle de l'image d'Irasutoya. (partie 1)
J'ai fait une image ponctuelle de l'image d'Irasutoya. (partie 2)
J'ai écrit un script qui divise l'image en deux
J'ai créé un robot Line qui devine le sexe et l'âge d'une personne à partir de l'image
J'ai fait un bot mou qui m'informe de la température
Une histoire qui prend en charge la notation électronique des examens avec reconnaissance d'image
Comment exécuter le code pratique du livre "Making Profitable AI with Python" sur Google Colaboratory
J'ai essayé d'analyser les résultats du vote de la région métropolitaine d'Osaka pour chaque quartier
J'ai fait un calendrier qui met à jour automatiquement le calendrier de distribution de Vtuber
J'ai essayé d'obtenir les résultats de Hachinai en utilisant le traitement d'image
D'un livre qui apprend de manière intéressante la façon de penser du programmeur (Python)
Classe qui atteint l'API de DMM
J'ai créé un LINE BOT qui renvoie une image de riz terroriste en utilisant l'API Flickr
Autour de l'authentification de PyDrive2, un package pour faire fonctionner Google Drive avec Python
L'histoire de la création d'une application Web qui enregistre des lectures approfondies avec Django
[Python] Un programme qui calcule le nombre de mises à jour des enregistrements les plus élevés et les plus faibles
[Discode Bot] J'ai essayé de créer un Bot qui me dit la valeur de race de Pokemon
Je veux un bot Slack qui calcule et me dit le salaire d'un emploi à temps partiel à partir du calendrier de Google Agenda!