[PYTHON] Hachinais Notenverwaltung mit SQL

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.

Nachtrag (08.09.2017)

Die beim Princess Cup gesammelten Daten werden im Blog veröffentlicht. Hachinai-Ergebnistagebuch

Ziel

Umgebung

Verwendete Sprache

Python3.5

Bibliothek verwendet

Quellcode


# -*- 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_())

Vorbereitung der Programmausführung

Eine Tabelle erstellen

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() 

Beschreibung der Spielerinformationen

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.

Programmausführung

Wenn Sie das Programm ausführen, sehen Sie ein Fenster wie dieses. 起動.png

Sie können Noten erhalten, indem Sie das Bild ablegen. Zu diesem Zeitpunkt werden Spielerinformationen aus player.json gelesen. qiitaSQL実行.PNG

Wenn Sie hier auf "Zur Datenbank hinzufügen" klicken, werden der zuvor erstellten Tabelle Daten hinzugefügt und das Notenfenster geschlossen.

Notenmanagement

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. データ一覧.PNG

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 ) ;

SQL実行.PNG

Sie können auch sortieren, indem Sie auf den Spaltennamen klicken. opsソート.PNG

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 ) ;

SQL調子別.PNG

abschließend

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.

Recommended Posts

Hachinais Notenverwaltung mit SQL
SQL-Verbindungsmethode mit pyodbc
Analysieren Sie Daten im CSV-Format mit SQL