J'ai changé de programme parce que quatre balles ont été ajoutées aux notes.
Il s'agit d'un jeu social de baseball basé sur l'expérience pour les jeunes, sorti en juin 2017. Le titre officiel est "August Cinderella Nine"
En un mot, c'est un jeu dans lequel vous élevez des personnages, passez des commandes et regardez le match. J'ai l'impression de faire un opener power pro. Il semble que le traitement du jeu soit bien fait, et de cette manière (bien qu'il y ait quelques points à craindre), vous pouvez vérifier les résultats de frappe pour chaque jeu.
Cependant, il n'est pas possible de vérifier les résultats totaux du joueur dans ce jeu. Pour passer un ordre approprié, vous devez gérer vos propres notes, conditions et adversaires. Comme il est difficile de saisir manuellement les notes, j'ai créé un programme pour obtenir automatiquement les notes en utilisant le traitement d'image.
Python3.5
Cette fois, nous détecterons les nombres à l'aide de la correspondance de modèles sans utiliser de techniques difficiles telles que l'apprentissage automatique. Comme le montre la figure ci-dessous, la correspondance de modèle est une méthode de recherche de l'image cible tout en décalant progressivement la partie qui correspond au modèle.
Cette fois, la correspondance des modèles est effectuée à l'aide des fonctions fournies par OpenCV. De plus, les images suivantes sont préparées pour la mise en correspondance des modèles. Puisqu'elle est convertie en image en échelle de gris lors du traitement, je pense que la différence de couleur n'a pas beaucoup d'effet.
La reconnaissance des tons est plus simple, prenez la différence entre les valeurs de pixel de l'image cible et du modèle et sélectionnez celle avec la plus petite différence.
# -*- coding: utf-8 -*-
import sys
import cv2
import numpy as np
import PyQt5.QtCore as QtCore
import PyQt5.QtGui as QtGui
import PyQt5.QtWidgets as QtWidgets
import pandas as pd
#Convertir les images OpenCV afin qu'elles puissent être affichées avec PyQt
#Utilisez ce code source
#http://qiita.com/odaman68000/items/c8c4093c784bff43d319
def create_QPixmap(image):
qimage = QtGui.QImage(image.data, image.shape[1], image.shape[0], image.shape[1] * image.shape[2], QtGui.QImage.Format_RGB888)
pixmap = QtGui.QPixmap.fromImage(qimage)
return pixmap
#Effectuer la mise en correspondance des modèles
def matching(img,num,threshold,img_res,cell_y,cell_x):
template = cv2.imread('./template/number/{}.png'.format(num),0)
template = template[6:-6,:]
w, h = template.shape[::-1]
res = cv2.matchTemplate(img,template,cv2.TM_CCOEFF_NORMED)
loc = np.where( res >= threshold)
res_loc = []
for pt in zip(*loc[::-1]):
#Exclure les doublons détectés
flag=True
for pt2 in res_loc:
if pt2[0] + w > pt[0]:
flag = False
if flag:
res_loc.append(pt)
#Dessinez les nombres et les cadres détectés sur l'image d'origine
cv2.rectangle(img_res, (pt[0]+cell_x, pt[1]+cell_y), (pt[0]+cell_x+w, pt[1]+cell_y+h), (0,0,255), 2)
n = "-" if num == "mai" else num
cv2.putText(img_res, str(n), (pt[0]+cell_x,pt[1]+cell_y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 3)
return res_loc
#La fenêtre qui s'ouvre lorsque vous déposez une image
class Add_widget(QtWidgets.QDialog):
def __init__(self,frame,clipboard,parent=None):
super(Add_widget, self).__init__(parent)
self.initUI(frame,clipboard,parent)
def initUI(self,frame,clipboard,parent):
self.lbl = QtWidgets.QLabel()
self.frame = frame
self.datatable = QtWidgets.QTableWidget()
self.datatable.setColumnCount(9)
self.datatable.setRowCount(9)
self.spinlbl = QtWidgets.QLabel("threshold")
self.spinbox = QtWidgets.QDoubleSpinBox()
self.spinbox.setRange(0,1)
self.spinbox.setSingleStep(0.01)
self.spinbox.setValue(0.90)
self.spinbox.valueChanged.connect(self.get_result)
self.sbin_hbox = QtWidgets.QHBoxLayout()
self.sbin_hbox.addWidget(self.spinlbl)
self.sbin_hbox.addWidget(self.spinbox)
self.sbin_hbox.addStretch(1)
self.button = QtWidgets.QPushButton("copy to clipboard")
self.button.clicked.connect(self.copy_to_clipboard)
self.vbox = QtWidgets.QVBoxLayout()
self.vbox.addWidget(self.lbl)
self.vbox.addWidget(self.datatable)
self.vbox.addLayout(self.sbin_hbox)
self.vbox.addWidget(self.button)
self.setLayout(self.vbox)
self.setWindowTitle('result')
self.clipboard = clipboard
self.get_result()
#Mise à jour avec les notes obtenues à partir du tableau
def update_table(self,df):
for i in range(len(df.index)):
for j in range(len(df.columns)):
self.datatable.setItem(i,j,QtWidgets.QTableWidgetItem(str(df.get_value(i, j))))
#Identifier la tonalité et détecter les nombres
def detection_value(self,frame,threshold):
img_res = frame.copy()
img_gray = cv2.cvtColor(img_res, cv2.COLOR_BGR2GRAY)
df = pd.DataFrame()
li=[0,2,3,2,2,3,2,3,2]
#Obtenez les notes ligne par ligne
for row in range(9):
player_list = []
#Identification du ton
condi_cell = frame[210+sum(li[:row+1])+(84*(row)):210+sum(li[:row+1])+(84*(row+1)),687:758]
condi_list = np.zeros(5)
for i in range(5):
condi = cv2.imread("./template/condition/{}.png ".format(i))
#Calculez la valeur de la différence
sad = np.sum(np.abs(np.mean(condi_cell.astype(np.float32),axis=(0,1))-np.mean(condi.astype(np.float32),axis=(0,1))))
#sad = np.sum(np.abs(condi_cell.astype(np.float32) - condi.astype(np.float32)))
condi_list[i] = sad
#Sélectionnez l'image avec la plus petite différence
c = np.argmin(condi_list)
player_list.append(c+1)
cv2.putText(img_res, str(c+1), (687, 210+sum(li[:row+1])+(84*(row+1))), cv2.FONT_HERSHEY_PLAIN, 4, (0, 0, 0), 5)
#Diviser par colonne
for col in range(8):
cell_y = 210+sum(li[:row+1])+(84*(row))
cell_width = 105 if col < 7 else 128
cell_x = 759+col*105
img_cell = img_gray[cell_y:cell_y+84,cell_x:cell_x+cell_width]
list_num = []
#0~Effectuer une correspondance de modèle jusqu'à 9
for num in range(10):
loc = matching(img_cell,num,threshold,img_res,cell_y,cell_x)
for pt in loc:
list_num.append([num,pt[0],pt[1]])
#Trier par coordonnée x
list_num.sort(key=lambda x:(x[1]))
#Concaténer les nombres triés par coordonnée x
s = ""
for i in range(len(list_num)):
#Dans le cas du taux au bâton"0."Attacher
if col == 6 and i == 0:
s += "0."
s += "{}".format(list_num[i][0])
#Pour RC, après le premier numéro"."(En supposant que RC est rarement à deux chiffres)
if col == 7 and i == 0:
s += "."
#Le taux de frappeur combiné est enfin"0.100"Si ça devient"1.00"(En supposant qu'il n'y a pas 1 coup en 10 coups dans une partie)
if col == 6 and s == "0.100":
s = "1.00"
#Si le numéro ne peut pas être détecté-Réglé sur 10000
try:
res_num = float(s)
except ValueError:
res_num = -10000.0
#Lorsque RC est détecté, la correspondance de modèle est effectuée pour moins, et s'il y a moins, il est multiplié par -1.
if col == 7:
loc = matching(img_cell,"mai",threshold,img_res,cell_y,cell_x)
if len(loc) > 0:
res_num *= -1
player_list.append(res_num)
#Ajoutez des notes ligne par ligne en utilisant des pandas
se = pd.Series(player_list)
df = df.append(se, ignore_index=True)
return img_res, df
#Copiez le contenu du tableau dans le presse-papiers
def copy_to_clipboard(self):
s = ""
for r in range(self.datatable.rowCount()):
for c in range(self.datatable.columnCount()):
try:
s += str(self.datatable.item(r,c).text()) + "\t"
except AttributeError:
s += "\t"
s = s[:-1] + "\n"
self.clipboard.setText(s)
#Obtenez des notes
def get_result(self):
img_res, df = self.detection_value(self.frame,self.spinbox.value())
self.update_table(df)
img_res = cv2.cvtColor(img_res, cv2.COLOR_BGR2RGB)
img_res = cv2.resize(img_res, (1280,720))
qt_img = create_QPixmap(img_res)
self.lbl.setPixmap(qt_img)
def show(self):
self.exec_()
#Classe QLabel prenant en charge le glisser-déposer
class DropLabel(QtWidgets.QLabel):
def __init__(self,parent):
super().__init__(parent)
self.parent = parent
self.setAcceptDrops(True)
self.setAlignment(QtCore.Qt.AlignCenter);
self.setText("Drop here")
def dragEnterEvent(self, e):
e.accept()
def dropEvent(self, e):
mimeData = e.mimeData()
files = [u.toLocalFile() for u in mimeData.urls()]
for f in files:
print("loading {}".format(f))
#Chargez l'image déposée
frame = cv2.imread(f)
#Si la lecture échoue, aucun traitement n'est effectué
if frame is not None:
frame = cv2.resize(frame, self.parent.size)
add_widget = Add_widget(frame,self.parent.clipboard)
add_widget.show()
#Fenêtre pour déposer une image
class Image_widget(QtWidgets.QWidget):
def __init__(self,clipboard):
super().__init__()
self.initUI(clipboard)
def initUI(self,clipboard):
self.height = 1080
self.width = 1920
self.size = (self.width,self.height)
self.clipboard = clipboard
self.lbl = DropLabel(self)
self.lbl.resize(640,480)
self.vbox = QtWidgets.QVBoxLayout()
self.vbox.addWidget(self.lbl)
self.setWindowTitle('hachinai')
self.show()
sys.exit(app.exec_())
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
clipboard = app.clipboard()
screen = Image_widget(clipboard)
Pour exécuter ce programme, il est nécessaire de mettre l'image comme le montre la figure de la méthode concrète dans "template / number /" et "template / condition /". Lorsque vous exécutez le programme, vous verrez la fenêtre sombre suivante.
Si vous faites glisser et déposez l'image dans cette fenêtre, vous obtiendrez la note. Les images contenant du japonais dans le chemin ne peuvent pas être lues.
Puisque la cellule de note est acquise à la position absolue, elle ne peut pas être reconnue correctement si la table se déplace de manière significative. Si la reconnaissance échoue dans le cas contraire, la modification du seuil peut fonctionner. Ensuite, vous pouvez copier la note en cliquant sur "Copier dans le presse-papiers" et la coller dans Excel.
Pour le moment, j'ai pu atteindre mon objectif. Quant à l'impression que j'ai utilisée, je pense qu'il sera un peu plus facile de gérer les notes si elle est combinée avec la macro Excel.
Correspondance de modèles avec OpenCV Afficher les données d'image gérées par OpenCV / numpy sur Qt Widget [GUI avec Python] PyQt5 -Widget II- Introduction à la création d'applications d'interface graphique multiplateforme avec PyQt of Python Fastest way to populate QTableView from Pandas data frame copy pyqt table selection, including column and row headers [Faites glisser et déposez des fichiers avec PyQt](http://doloop while.hatenablog.com/entry/20100108/1275174371)
Recommended Posts