[PYTHON] Ich habe versucht, die Trefferergebnisse von Hachinai mithilfe der Bildverarbeitung zu erhalten

Nachtrag (02.09.2017)

Ich habe das Programm geändert, weil den Bällen vier Bälle hinzugefügt wurden.

Was ist Hachinai?

Dies ist ein auf Jugenderfahrung basierendes Baseball-Social-Game, das im Juni 2017 veröffentlicht wurde. Der offizielle Titel lautet "August Cinderella Nine"

Kurz gesagt, es ist ein Spiel, in dem Sie Charaktere erheben, Befehle erteilen und das Spiel beobachten. Es fühlt sich an, als würde ich einen Power Pro Opener machen. Es scheint, dass die Verarbeitung des Spiels gut gemacht ist, und auf diese Weise (obwohl es einige Punkte gibt, über die Sie sich Sorgen machen müssen) können Sie die Trefferergebnisse für jedes Spiel überprüfen.

Screenshot_20170901-014026.png

Es ist jedoch nicht möglich, die Gesamtergebnisse des Spielers in diesem Spiel zu überprüfen. Um eine angemessene Bestellung aufzugeben, müssen Sie Ihre eigenen Noten, Bedingungen und Gegner verwalten. Da es schwierig ist, die Noten manuell einzugeben, habe ich ein Programm erstellt, um die Noten automatisch mithilfe der Bildverarbeitung zu erhalten.

Ziel

Umgebung

Verwendete Sprache

Python3.5

Bibliothek verwendet

Spezifische Methode

Nummernerkennung

Dieses Mal werden wir Zahlen mithilfe des Vorlagenabgleichs erkennen, ohne schwierige Techniken wie maschinelles Lernen zu verwenden. Wie in der folgenden Abbildung gezeigt, ist der Vorlagenabgleich eine Methode zum Durchsuchen des Zielbilds, während der Teil, der der Vorlage entspricht, schrittweise verschoben wird. テンプレートマッチング.PNG

Dieses Mal wird der Vorlagenabgleich mit den von OpenCV bereitgestellten Funktionen durchgeführt. Darüber hinaus werden die folgenden Bilder für den Vorlagenabgleich vorbereitet. Da es bei der Verarbeitung in ein Graustufenbild umgewandelt wird, hat der Farbunterschied meines Erachtens keine großen Auswirkungen. テンプレ群.PNG

Tonerkennung

Die Tonerkennung ist einfacher. Nehmen Sie die Differenz zwischen den Pixelwerten des Zielbilds und der Vorlage und wählen Sie die mit der geringsten Differenz aus. 差分計算.PNG

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

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

    #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):
        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 = []

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

        return img_res, df

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

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

#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)
                add_widget.show()

#Fenster zum Löschen eines Bildes
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)

Programmausführung

Um dieses Programm auszuführen, muss das Bild wie in der Abbildung der konkreten Methode gezeigt in "template / number /" und "template / condition /" eingefügt werden. Wenn Sie das Programm ausführen, wird das folgende düstere Fenster angezeigt. 起動.png

Wenn Sie das Bild in dieses Fenster ziehen und dort ablegen, erhalten Sie die Note. Bilder mit Japanisch im Pfad können nicht gelesen werden. 取得.png

Da die Bewertungszelle an der absoluten Position erfasst wird, kann sie nicht korrekt erkannt werden, wenn sich die Tabelle erheblich verschiebt. Wenn die Erkennung ansonsten fehlschlägt, kann das Ändern des Schwellenwerts funktionieren. Anschließend können Sie die Note kopieren, indem Sie auf "In Zwischenablage kopieren" klicken und in Excel einfügen. エクセル.PNG

abschließend

Vorerst konnte ich mein Ziel erreichen. Was den Eindruck betrifft, den ich verwendet habe, denke ich, dass es etwas einfacher sein wird, Noten zu verwalten, wenn er mit dem Excel-Makro kombiniert wird.

Referenz

Vorlagenabgleich mit OpenCV Bilddaten anzeigen, die von OpenCV / numpy im Qt-Widget verarbeitet werden [GUI mit Python] PyQt5 -Widget II- Einführung in die plattformübergreifende Erstellung von GUI-Anwendungen mit PyQt of Python Fastest way to populate QTableView from Pandas data frame copy pyqt table selection, including column and row headers Dateien mit PyQt ziehen und ablegen

Recommended Posts

Ich habe versucht, die Trefferergebnisse von Hachinai mithilfe der Bildverarbeitung zu erhalten
Ich habe versucht, den Index der Liste mithilfe der Aufzählungsfunktion abzurufen
Ich habe versucht, die Trapezform des Bildes zu korrigieren
Ich habe versucht, den Bildfilter von OpenCV zu verwenden
Ich habe versucht, das Gesichtsbild mit sparse_image_warp von TensorFlow Addons zu transformieren
Ich habe versucht, das Bild mithilfe von maschinellem Lernen zu komprimieren
Ich habe versucht, die Entropie des Bildes mit Python zu finden
Ich habe versucht, die Standortinformationen des Odakyu-Busses zu erhalten
Ich habe versucht, den Text in der Bilddatei mit Tesseract der OCR-Engine zu extrahieren
Ich habe versucht, mit Pandas eine Pferderenn-Datenbank zu erstellen
Ich habe versucht, das SD-Boot-Image von LicheePi Nano zu erstellen
Ich habe versucht, mit Boto3 eine Liste der AMI-Namen zu erhalten
Ich habe versucht, durch Schaben ein Bild zu bekommen
Ich habe versucht, die Ähnlichkeit der Frageabsicht mit Doc2Vec von gensim abzuschätzen
Ich habe versucht, die Version 2020 mit 100 Sprachverarbeitung zu lösen [Kapitel 3: Reguläre Ausdrücke 25-29]
Ich habe versucht, den Authentifizierungscode der Qiita-API mit Python abzurufen.
Ich habe versucht, die Phase der Geschichte mit COTOHA zu extrahieren und zu veranschaulichen
Ich habe versucht, das RSS des Top-Songs des iTunes Store automatisch abzurufen
Ich habe versucht, die Filminformationen der TMDb-API mit Python abzurufen
Ich habe die übliche Geschichte ausprobiert, Deep Learning zu verwenden, um den Nikkei-Durchschnitt vorherzusagen
Mit COTOHA habe ich versucht, den emotionalen Verlauf des Laufens von Meros zu verfolgen.
Ich habe versucht, die Texte von Hinatazaka 46 zu vektorisieren!
Ich habe versucht, die Verschlechterung des Lithium-Ionen-Akkus mithilfe des Qore SDK vorherzusagen
Ich habe versucht, die 2020-Version von 100 Sprachverarbeitungsproblemen zu lösen [Kapitel 3: Reguläre Ausdrücke 20 bis 24]
Ich habe versucht, die 2020-Version von 100 Sprachverarbeitungsproblemen zu lösen [Kapitel 1: Vorbereitungsbewegung 00-04]
Ich habe versucht, die Gesichtsverdeckungsarbeit des Koordinationsbildes für das Tragen zu automatisieren
Ich habe versucht, die 2020-Version von 100 Sprachverarbeitungsproblemen zu lösen [Kapitel 1: Vorbereitungsbewegung 05-09]
Ich habe versucht, Iris aus dem Kamerabild zu erkennen
Ich habe versucht, die Grundform von GPLVM zusammenzufassen
Ich habe versucht, mit AWS Lambda einen AMI zu erhalten
Ich habe versucht, die Sündenfunktion mit Chainer zu approximieren
Ich habe versucht, die API von Sakenowa Data Project zu verwenden
Ich habe versucht, die Spacha-Informationen von VTuber zu visualisieren
Ich habe versucht, den negativen Teil von Meros zu löschen
[Python] Ich habe versucht, Json von Tintenfischring 2 zu bekommen
Ich habe versucht, die Sprache mit CNN + Melspectogram zu identifizieren
Ich habe versucht, das Wissensdiagramm mit OpenKE zu ergänzen
Ich habe versucht, die Stimmen der Sprecher zu klassifizieren
Ich habe versucht, die String-Operationen von Python zusammenzufassen
Ich habe versucht, die Informationen der ASPX-Site, die mit Selenium IDE ausgelagert wird, so programmlos wie möglich abzurufen
Ich habe versucht, den Sieg oder die Niederlage der Premier League mit dem Qore SDK vorherzusagen
Ich habe versucht, das Update von "Werde ein Romanautor" mit "IFTTT" und "Werde ein Romanautor API" zu benachrichtigen.
Python-Übung 100 Schläge Ich habe versucht, den Entscheidungsbaum von Kapitel 5 mit graphviz zu visualisieren
Ich wollte viele Bilder sammeln, also habe ich versucht, "Google Image Download" zu verwenden.
Ich habe versucht, Objekte aus dem Bild des Steak-Sets zu sortieren
Ich habe versucht, die Verarbeitungsgeschwindigkeit mit dplyr von R und pandas von Python zu vergleichen
Ich habe versucht, das Bild mit Python + OpenCV "gammakorrektur" zu machen
Ich habe versucht, mit TensorFlow den Durchschnitt mehrerer Spalten zu ermitteln
Ich habe versucht, das CNN-Modell von TensorFlow mit TF-Slim umzugestalten
Ich habe versucht, die Anzeigenoptimierung mithilfe des Banditenalgorithmus zu simulieren
Ich habe versucht, die Informationen des Webs mit "Requests" und "lxml" abzurufen.
Ich habe versucht, das Lachproblem mit Keras zu erkennen.
Ich möchte Betriebsinformationen über die Yahoo-Route erhalten
Sprachverarbeitung 100 Knocks-29: Holen Sie sich die URL des Flaggenbildes
[Python] Ich habe versucht, die folgende Beziehung von Twitter zu visualisieren
[TF] Ich habe versucht, das Lernergebnis mit Tensorboard zu visualisieren
[Maschinelles Lernen] Ich habe versucht, die Theorie von Adaboost zusammenzufassen
[Python] Ich habe versucht, Daten mit der API von Wikipedia zu sammeln
Ich habe versucht, das lokale Minimum der Goldstein-Preis-Funktion zu bekämpfen