Dieses Mal habe ich es möglich gemacht, die in "Ich habe versucht, die Trefferergebnisse von Hachinai mithilfe der Bildverarbeitung zu erhalten" zur Datenbank und zur Datenbank hinzuzufügen Ich möchte meine Noten verwalten.
Die beim Princess Cup gesammelten Daten werden im Blog veröffentlicht. Hachinai-Ergebnistagebuch
Python3.5
# -*- 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
import json
import sqlite3
#Konvertieren Sie OpenCV-Bilder so, dass sie mit PyQt angezeigt werden können
#Verwenden Sie diesen Quellcode
#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
#Führen Sie einen Vorlagenabgleich durch
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]):
#Erkannte Duplikate ausschließen
flag=True
for pt2 in res_loc:
if pt2[0] + w > pt[0]:
flag = False
if flag:
res_loc.append(pt)
#Zeichnen Sie erkannte Zahlen und Rahmen auf das Originalbild
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
#Das Fenster, das geöffnet wird, wenn Sie ein Bild ablegen
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+6)
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.button = QtWidgets.QPushButton("Zur Datenbank hinzufügen")
self.button.clicked.connect(self.add_database)
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()
#Aktualisieren Sie mit den Noten aus der Tabelle
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))))
#Ton identifizieren und Zahlen erkennen
def detection_value(self,frame,threshold):
try:
f = open("player.json", 'r')
player_data = json.load(f)
except UnicodeDecodeError:
f = open("player.json", 'r', encoding='utf-8')
player_data = json.load(f)
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]
#Holen Sie sich Noten Zeile für Zeile
for row in range(9):
player_list = []
player_list.append(player_data["date"])
player_list.append(player_data["opponent"])
player_list.append(player_data["player{}".format(row+1)]["scene"])
player_list.append(player_data["player{}".format(row+1)]["name"])
player_list.append(player_data["player{}".format(row+1)]["position"])
#Streikreihenfolge
player_list.append(row+1)
player_list.append(player_data["team_buff"])
#Identifizierung des Tons
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))
#Berechnen Sie den Differenzwert
sad = np.sum(np.abs(condi_cell.astype(np.float32) - condi.astype(np.float32)))
condi_list[i] = sad
#Wählen Sie das Bild mit dem kleinsten Unterschied
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)
#Nach Spalten aufgeteilt
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~Führen Sie einen Vorlagenabgleich bis zu 9 durch
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]])
#Nach x-Koordinate sortieren
list_num.sort(key=lambda x:(x[1]))
#Verketten Sie Zahlen, sortiert nach x-Koordinaten
s = ""
for i in range(len(list_num)):
#Im Falle der Schlagrate"0."Anfügen
if col == 6 and i == 0:
s += "0."
s += "{}".format(list_num[i][0])
#Für RC nach der ersten Nummer"."(Angenommen, RC ist selten zweistellig)
if col == 7 and i == 0:
s += "."
#Die kombinierte Schlagrate ist endlich"0.100"Wenn es wird"1.00"(Angenommen, es gibt keinen Treffer in 10 Schlägen in einem Spiel)
if col == 6 and s == "0.100":
s = "1.00"
#Wenn die Nummer nicht erkannt werden kann-Auf 10000 einstellen
try:
res_num = float(s)
except ValueError:
res_num = -10000.0
#Wenn RC erkannt wird, wird der Vorlagenabgleich für Minus durchgeführt, und wenn Minus vorhanden ist, wird er mit -1 multipliziert.
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)
#Fügen Sie Noten Zeile für Zeile mit Pandas hinzu
se = pd.Series(player_list)
df = df.append(se, ignore_index=True)
self.df = df
return img_res
#Kopieren Sie den Inhalt der Tabelle in die Zwischenablage
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)
#Zur Datenbank hinzufügen
def add_database(self):
try:
db_name = "hachinai.db"
con = sqlite3.connect(db_name)
for i in range(9):
con.execute("insert into results("\
+ "date,"\
+ "opponent,"\
+ "scene,"\
+ "name,"\
+ "position,"\
+ "batting_order,"\
+ "team_buff,"\
+ "condition,"\
+ "at_bat,"\
+ "hit,"\
+ "homerun,"\
+ "RBI,"\
+ "BB,"
+ "base_hit,"\
+ "batting_average,"\
+ "RC"\
+ ")"\
+ " values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",tuple(self.df.ix[i]))
con.commit()
con.close()
self.accept()
except sqlite3.OperationalError:
w = Message_Widget()
w.exec_()
#Noten bekommen
def get_result(self):
img_res = self.detection_value(self.frame,self.spinbox.value())
self.update_table(self.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_()
#Anzeige der Fehlermeldung
class Message_Widget(QtWidgets.QMessageBox):
def __init__(self,parent=None):
super(Message_Widget, self).__init__(parent)
self.initUI(parent)
def initUI(self,parent):
self.setText("Datenbank existiert nicht")
self.setIcon(QtWidgets.QMessageBox.Warning)
self.setStandardButtons(QtWidgets.QMessageBox.Close)
#QLabel-Klasse, die Drag & Drop unterstützt
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))
#Laden Sie das abgelegte Bild
frame = cv2.imread(f)
#Wenn das Lesen fehlschlägt, wird keine Verarbeitung durchgeführt
if frame is not None:
frame = cv2.resize(frame, self.parent.size)
add_widget = Add_widget(frame,self.parent.clipboard,self)
add_widget.show()
#Fenster zum Löschen des Bildes
class Hachinai_widget(QtWidgets.QWidget):
def __init__(self,clipboard=None,parent=None):
super(Hachinai_widget, self).__init__(parent)
super().__init__()
self.initUI(clipboard,parent)
def initUI(self,clipboard,parent):
self.parent=parent
self.height = 1080
self.width = 1920
self.size = (self.width,self.height)
self.clipboard = clipboard
self.lbl = DropLabel(self)
self.lbl.setMinimumSize(640,480)
self.lbl.setFrameStyle(QtWidgets.QFrame.Box | QtWidgets.QFrame.Plain)
self.vbox = QtWidgets.QVBoxLayout()
self.vbox.addWidget(self.lbl)
self.setLayout(self.vbox)
self.setWindowTitle('hachinai')
self.show()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
clipboard = app.clipboard()
screen = Hachinai_widget(clipboard)
sys.exit(app.exec_())
Führen Sie vor dem Ausführen des obigen Programms das folgende Programm aus, um eine Ergebnistabelle zu erstellen, in der Ihre Noten gespeichert sind. Diese Tabelle wird in einer Datei namens hachinai.db gespeichert.
# -*- coding: utf-8 -*-
import sqlite3
db_name = "hachinai.db"
con = sqlite3.connect(db_name)
#Bestätigung der Tabellenexistenz
cur = con.execute("SELECT * FROM sqlite_master WHERE type='table' and name='results'")
if cur.fetchone() == None: #Mach es, weil es nicht existiert
con.execute("CREATE TABLE results("\
+ "id INTEGER PRIMARY KEY,"\
+ "date DATE,"\
+ "opponent TEXT,"\
+ "scene TEXT,"\
+ "name TEXT,"\
+ "position TEXT,"\
+ "batting_order INTEGER,"\
+ "team_buff TEXT,"\
+ "condition INTEGER,"\
+ "at_bat INTEGER,"\
+ "hit INTEGER,"\
+ "homerun INTEGER,"\
+ "RBI INTEGER,"\
+ "BB INTEGER,"\
+ "base_hit INTEGER,"\
+ "batting_average DOUBLE,"\
+ "RC DOUBLE)"\
)
con.commit()
con.close()
Dieses Mal werden die Spielerinformationen in einer Datei mit dem Namen player.json beschrieben und durch Lesen im Programm zur Note hinzugefügt.
player.json
{
"date":"2017-11-06",
"opponent":"Aschenputtel Match",
"team_buff":"0",
"player1":{
"scene":"Traumstartpunkt",
"name":"Tsubasa Arihara",
"position":"6"
},
"player2":{
"scene":"Unter dem selben Himmel",
"name":"Akino Weizen",
"position":"3"
},
"player3":{
"scene":"Rauschender Schuss!",
"name":"Aya Taketomi",
"position":"8"
},
"player4":{
"scene":"Dies ist der Ort zum Spielen!",
"name":"Chie Hebei",
"position":"4"
},
"player5":{
"scene":"Ich möchte mehr hervorstechen!",
"name":"Osaka hier",
"position":"9"
},
"player6":{
"scene":"Aufregender Probetreffer",
"name":"Yoshimi Iwaki",
"position":"5"
},
"player7":{
"scene":"Vorsichtige Dehnung",
"name":"Hiiragi Kotoha",
"position":"7"
},
"player8":{
"scene":"Detaillierte Strategie",
"name":"Waka Suzuki",
"position":"2"
},
"player9":{
"scene":"Eine Ballseele!",
"name":"Yuhime Nozaki",
"position":"1"
}
}
"_2" ist ein tragender Charakter. Das Training ist komplizierter als das Haupttraining.
Wenn Sie das Programm ausführen, sehen Sie ein Fenster wie dieses.
Sie können Noten erhalten, indem Sie das Bild ablegen. Zu diesem Zeitpunkt werden Spielerinformationen aus player.json gelesen.
Wenn Sie hier auf "Zur Datenbank hinzufügen" klicken, werden der zuvor erstellten Tabelle Daten hinzugefügt und das Notenfenster geschlossen.
Führen Sie PupSQLite aus und öffnen Sie hachinai.db. Doppelklicken Sie dann auf Ergebnisse in Tabellen, um die gespeicherten Noten wie unten gezeigt anzuzeigen.
Klicken Sie auf "SQL-Anweisungseingabe" -> "Abfragefenster öffnen", um den SQL-Eingabebildschirm anzuzeigen. Hier können Sie die Gesamtergebnisse des Players anzeigen, indem Sie die folgende SQL-Anweisung eingeben und ausführen.
Szene AUSWÄHLEN,Name,Verteidigungsposition,Bedingung, round((Treffer*1.0) / (Anzahl der Striche*1.0), 3)als Schlagrate,Anzahl von Spielen,Eine Fledermaus, Anzahl der Striche, Treffer,Heimatbasis,Punktpunkt,Vier Bälle,Basistreffer, round(((Treffer +Vier Bälle)*1.0) / (Eine Fledermaus*1.0), 3)als Basiszinssatz, round((Basistreffer*1.0) / (Anzahl der Striche*1.0), 3)so lange Trefferquote, round(((Treffer +Vier Bälle)*1.0) / (Eine Fledermaus*1.0) + (Basistreffer*1.0) / (Anzahl der Striche*1.0), 3) as OPS, RC from (
Szene als Szene AUSWÄHLEN,Name als Name,Position als Verteidigungsposition, round(avg(condition), 2)als Bedingung, count(scene)als Anzahl der Spiele, sum(at_bat)wie bei Fledermaus, sum(at_bat) - sum(BB)als Anzahl der Striche, sum(hit)als Treffer, sum(homerun)als Heimatbasis, sum(RBI)als Punkt, sum(BB)als vier Bälle, sum(base_hit)als Basistreffer, round(avg(RC), 2) as RC FROM results GROUP BY scene ) ;results GROUP BY scene ) ;
Sie können auch sortieren, indem Sie auf den Spaltennamen klicken.
Wenn ich mir die Daten anschaue, habe ich das Gefühl, dass Spieler, die in guter Form sind, tendenziell gute Leistungen erbringen. Ich denke, der Grund, warum Kana Kujus Trefferquote so hoch ist, ist, dass sie das Limit zweimal überschritten hat. Ich bin mir nicht sicher, warum Minako Nitta eine hohe Long-Hit-Rate hat.
Darüber hinaus können verschiedene Daten ausgegeben werden, indem die SQL-Anweisung erstellt wird. Wenn Sie beispielsweise die SQL-Anweisung wie folgt ändern, können Sie die Gesamtnote für jede Bedingung abrufen.
Szene AUSWÄHLEN,Name,Verteidigungsposition,Bedingung, round((Treffer*1.0) / (Anzahl der Striche*1.0), 3)als Schlagrate,Anzahl von Spielen,Eine Fledermaus, Anzahl der Striche, Treffer,Heimatbasis,Punktpunkt,Vier Bälle,Basistreffer, round(((Treffer +Vier Bälle)*1.0) / (Eine Fledermaus*1.0), 3)als Basiszinssatz, round((Basistreffer*1.0) / (Anzahl der Striche*1.0), 3)so lange Trefferquote, round(((Treffer +Vier Bälle)*1.0) / (Eine Fledermaus*1.0) + (Basistreffer*1.0) / (Anzahl der Striche*1.0), 3) as OPS, RC from (
Szene als Szene AUSWÄHLEN,Name als Name,Position als Verteidigungsposition, round(avg(condition), 2)als Bedingung, count(scene)als Anzahl der Spiele, sum(at_bat)wie bei Fledermaus, sum(at_bat) - sum(BB)als Anzahl der Striche, sum(hit)als Treffer, sum(homerun)als Heimatbasis, sum(RBI)als Punkt, sum(BB)als vier Bälle, sum(base_hit)als Basistreffer, round(avg(RC), 2) as RC FROM results WHERE scene = 'Machen Sie eine Pause' GROUP BY condition ) ;
Die Datenverwaltung ist viel einfacher geworden, da ich die Ergebnisse nicht mehr kopieren und in Excel einfügen muss. Ich möchte Daten in einem Ranglisten-Match sammeln, das bald stattfinden wird.