[PYTHON] Machen Sie ein Zeichnungsquiz mit kivy + PyTorch

Zusammenfassung

Dieser Artikel ist der zweite Tag des Docomo Dovent-Kalenders.

Kennen Sie das Zeichenquiz? Dies ist ein Quiz, bei dem der Fragesteller ein Bild zeichnet und errät, was andere Leute zeichnen. Es gibt viele Apps da draußen.

Es scheint, dass sogar eine Person spielen kann, indem sie das vom Benutzer gezeichnete Bild erkennt und es errät. Folgen Sie also Letztes Jahr, der Bibliothek für maschinelles Lernen [PyTorch](https :: Erstellen wir eine Kombination aus //pytorch.org/) und kivy, einer Bibliothek, mit der Sie Apps erstellen können.

abst2.gif

Was ist Kivy?

Es hat die größte Dynamik und ist am einfachsten in Pythons GUI-Bibliothek zu verwenden (subjektiv).

Es gab eine Zeit, in der gesagt wurde, dass die Schwelle hoch war, weil es keine Informationen auf Japanisch gab, aber jetzt gibt es verrückte Informationen. Dank der Freiwilligen gibt es auch ein japanisches Dokument. Dieser Artikel wird als Lernprogramm für Erstbenutzer empfohlen.

Überprüfungsumgebung

Layoutformulierung

Wenn Sie die folgenden Funktionen haben, können Sie anscheinend ein Zeichenquiz durchführen.

Wenn Sie [kviewer] verwenden (https://qiita.com/gotta_dive_into_python/items/c32cdcb58c66f0a1b840), können Sie die Benutzeroberfläche ohne die Python-Datei des Hauptteils überprüfen. Erstellen Sie also zuerst nur das Layout.

ui_test.kv


BoxLayout:
    orientation: 'vertical' #Ordnen Sie vier untergeordnete Objekte vertikal an
    BoxLayout:
        size_hint_y: 0.1 #Vertikale Breite 10%Besetzen
        Label: #Thema anzeigen
            size_hint_x: 0.7 #Breite 70%Besetzen
            text: 'Draw "XXX"'
        Button: #Schaltfläche zum Ändern des Themas
            size_hint_x: 0.3 #Breite 30%Besetzen
            text: 'Change'
    Label: #Leinwandteil (vorläufig)
        text: 'CANVAS'
        size_hint_y: 0.7 #Vertikale Breite 70%Besetzen
    BoxLayout:
        size_hint_y: 0.1 #Vertikale Breite 10%Besetzen
        Button: #Schaltfläche "Rückgängig"
            text: 'Undo'
        Button: #Alle Löschtaste
            text: 'Clear'
    Label: #Zeigen Sie das Ergebnis der KI an, die das Bild trifft
        size_hint_y: 0.1 #Vertikale Breite 10%Besetzen
        text: 'I guess it is "YYY"'

Bei der Anzeige wurde der folgende Bildschirm angezeigt. Das Layout ist nun festgelegt.

python -m kivy.tools.kviewer ui_test.kv

ui_test.png

Vorbereitung des Erkennungsmodells

Wir benötigen ein Modell, um das vom Benutzer gezeichnete Bild zu erraten, aber dieses Mal verwenden wir das folgende trainierte Modell (MIT-Lizenz). Anstatt leicht zu sein, gibt es nur 20 Kategorien. Wenn Sie also alle 345 Kategorien im Originaldatensatz erkennen möchten, lernen Sie dies bitte selbst.

Das diesmal verwendete Modell verwendet keine Zeitreiheninformationen (Reihenfolge, in der Linien gezeichnet werden). Da der Originaldatensatz jedoch auch Zeitreiheninformationen enthält, verbessert das Lernen in diesem Sinne die Erkennungsgenauigkeit beim Zeichnen. Sollte tun. Die Ordnerstruktur ist wie folgt. Verwenden Sie die beiden Ordner "src" und "trainierte_Modelle" aus dem obigen GitHub-Repository.

├─paintquiz.py #Die zu implementierende Python-Datei
├─paintquiz.kv #Kivy-Datei implementiert werden
├─src #Im obigen Repository
└─trained_models #Im obigen Repository

Implementierung

Wir werden die notwendigen Funktionen in Python implementieren und die Kivy-Seite ein wenig entsprechend ändern. Ich konnte Python mit ungefähr 120 Zeilen und Kivy mit ungefähr 60 Zeilen für insgesamt ungefähr 180 Zeilen implementieren. Die Zeichenfläche wird jede Sekunde erkannt und das vorläufige Erkennungsergebnis wird angezeigt. Die implementierten Funktionen sind wie folgt.

--Funktionen jeder im Layout definierten Schaltfläche

Python-Code

paintquiz.py


import random

from kivy.config import Config
#Fenstergröße beim Start
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '700')

from kivy.app import App
from kivy.clock import Clock
from kivy.properties import StringProperty
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.graphics import Line, Color

import numpy as np
import cv2
import torch
import torch.nn as nn

#Liste der erkennbaren Klassen
classes = ["apple", "book", "bowtie", "candle", "cloud", "cup", "door", "envelope", "eyeglasses", "guitar", "hammer",
           "hat", "ice cream", "leaf", "scissors", "star", "t-shirt", "pants", "lightning", "tree"]

class Net():
	#Laden Sie das Erkennungsmodell
    def __init__(self):
        self.model = torch.load("./trained_models/whole_model_quickdraw", map_location=lambda storage, loc: storage) #Lesen Sie die trainierte Gewichtsdatei
        self.model.eval() #Diesmal kein Lernen
        self.sm = nn.Softmax(dim=1) #Wenn alle Ergebnisse unzuverlässig sind, möchte ich mit der Punktzahl abschneiden, also normalisiere ich mit Softmax

	#Geben Sie den Namen der Bilddatei ein und geben Sie das Erkennungsergebnis zurück
    def predict(self, fn, th=.5):
        image = cv2.imread(fn, cv2.IMREAD_UNCHANGED)[:,:,-1] #Holen Sie sich Alpha-Kanal und gehen Sie zum Binärbild
        image = cv2.resize(image, (28, 28))
        image = np.array(image, dtype=np.float32)[None, None, :, :]
        image = torch.from_numpy(image)
        pred = self.model(image)
        pred = self.sm(pred)
        return torch.max(pred[0]), torch.argmax(pred[0]) #Gibt den Erkennungswert und die Erkennungsklasse zurück

class Paint(Widget):
    pred_word = StringProperty() #Erkennungsergebniswort
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.line_width = 10 #Dicke der Linie
        self.lines = [] #Liste zum Speichern von Zeilen zum Rückgängigmachen
        self.in_drawing = False #Beurteilen Sie, ob gerade gezeichnet wird
        self.canvas.add(Color(0,0,0))
        self.model = Net()
        Clock.schedule_interval(self.predict, 1.0)

    def calc_pos(self, bbox):
        xmin = min(bbox[0], bbox[2])
        ymin = min(bbox[1], bbox[3])
        xmax = max(bbox[0], bbox[2])
        ymax = max(bbox[1], bbox[3])
        return xmin,ymin,xmax,ymax

    #Bedienung beim Klicken (Zeichnen)
    def on_touch_move(self, touch):
        if self.in_drawing == False:
            if self.pos[0]<touch.x<self.pos[0]+self.size[0] and self.pos[1]<touch.y<self.pos[1]+self.size[1]:
                self.in_drawing = True
                with self.canvas:
                    touch.ud['line'] = Line(points=(touch.x, touch.y), width=self.line_width)
        elif touch.ud:
            if self.pos[0]<touch.x<self.pos[0]+self.size[0] and self.pos[1]<touch.y<self.pos[1]+self.size[1]:
                touch.ud['line'].points += [touch.x, touch.y]

    #Verhalten am Ende des Klicks
    def on_touch_up(self, touch):
        if self.in_drawing:
            self.lines.append(touch.ud['line'])
            self.in_drawing = False

    #Löschen Sie die vorherige Zeile
    def undo(self):
        if len(self.lines)>0:
            line = self.lines.pop(-1)
            self.canvas.remove(line)

    #Löschen Sie die gesamte Leinwand
    def clear_canvas(self):
        for line in self.lines:
            self.canvas.remove(line)
        self.lines = []

    #Erkennen Sie Bilder alle dt Sekunden
    def predict(self, dt):
        self.export_to_png('image.png')
        with torch.no_grad():
            score, label = self.model.predict('./image.png')
            #Wird als unbekannt angezeigt, wenn der Erkennungswert unter einem bestimmten Wert liegt
            if score < 0.5:
                self.pred_word = "CPU: I have no idea"
            else:
                self.pred_word = 'CPU: I guess it is "{}"'.format(classes[label].upper())

class PaintQuiz(BoxLayout):
    word = StringProperty('Draw "{}"'.format(random.choice(classes).upper())) #Themenwort
    def __init__(self, **kwargs):
        super(PaintQuiz, self).__init__(**kwargs)
        pass

    def reset(self):
        self.word = 'Draw "{}"'.format(random.choice(classes).upper())

class PaintQuizApp(App):
    def __init__(self, **kwargs):
        super(PaintQuizApp, self).__init__(**kwargs)
        self.title = 'PAINT QUIZ'

    def build(self):
        return PaintQuiz()

if __name__ == '__main__':
    app = PaintQuizApp()
    app.run()

Kivy-Code

paintquiz.kv


<PaintQuiz>:
    canvas:
        Color:
            rgb: .9,.9,.9
        Rectangle:
            pos: self.pos
            size: self.size
    BoxLayout:
        size: root.size
        orientation: 'vertical'
        
        BoxLayout:
            size_hint_y: 0.1
            orientation: 'horizontal'
            Label:
                canvas.before:
                    Color:
                        rgb: 1.,.3,.3
                    Rectangle:
                        pos: self.pos
                        size: self.size
                size_hint_x: 0.7
                text: root.word
                font_size: 18
            Button:
                id: button_reset
                size_hint_x: 0.3
                text: 'Change'
                on_release: root.reset()
        Paint:
            size_hint_y: 0.7
            id: paint_area
            allow_stretch: True
        BoxLayout:
            size_hint_y: 0.1
            Button:
                id: button_undo
                text: 'Undo'
                on_release: paint_area.undo()
            Button:
                id: button_clear
                text: 'Clear'
                on_release: paint_area.clear_canvas()
        Label:
            canvas.before:
                Color:
                    rgb: 1.,.3,.3
                Rectangle:
                    pos: self.pos
                    size: self.size
            size_hint_y: 0.1
            text: paint_area.pred_word
            font_size: 18

Ausführungsergebnis

Das aktuelle Thema wird oben links angezeigt, und das Erkennungsergebnis (was Sie zu zeichnen glauben) wird unten angezeigt.

Ich habe Äpfel und Scheren gezeichnet, aber sie erkennen sie richtig. Ein Apfel sieht aus wie ein Hammer oder ein Blatt, wenn nur der Saum gezogen wird, aber er wird sicherlich als Hammer oder Blatt erkannt. Es ist eher die richtige Antwort, weil der Saum des Apfels = Blätter. apple.gif scissors.gif

abschließend

Im Bereich Datenanalyse gibt es Personen, die die Ergebnisse zum Zeitpunkt eines Meetings mit Jupyter Notebook anstelle von Powerpo anzeigen. Dies wird jedoch empfohlen, da es einfach ist, eine Bewerbung mit diesem Gefühl zu erstellen und Interesse zu wecken.

Eigentlich wollte ich eine Mal-App machen (die sich mit KI abwechselt, um zu malen), aber nur für erfahrene Kivy-Benutzer! Ich gab auf, weil es ein Artikel zu sein schien. Bitte mach jemanden und lass mich spielen.

Recommended Posts

Machen Sie ein Zeichnungsquiz mit kivy + PyTorch
Machen Sie Ja Nein Popup mit Kivy
Machen Sie mit Kivy SF-ähnliche Knöpfe
Machen Sie eine Lotterie mit Python
Machen Sie ein Feuer mit kdeplot
Lassen Sie uns eine GUI mit Python erstellen.
Erstellen Sie ein Empfehlungssystem mit Python
Machen Sie einen Filter mit einer Django-Vorlage
Lassen Sie uns ein Diagramm mit Python erstellen! !!
Machen wir mit xCAT einen Spacon
Erstellen Sie mit PySide einen Modelliterator
Machen Sie eine schöne Grafik mit Plotly
Lassen Sie uns mit Python ein Shiritori-Spiel machen
Erstellen Sie einen Videoplayer mit PySimpleGUI + OpenCV
Versuchen Sie, mit matplotlib eine Normalverteilung zu zeichnen
[Python] Zeichnen eines Wirbelmusters mit einer Schildkröte
Machen Sie einen seltenen Gacha-Simulator mit Flask
Erstellen Sie eine Notebook-Pipeline mit Kedro + Papermill
Machen Sie mit matplotlib eine teilweise gezoomte Figur
Lassen Sie uns mit Python langsam sprechen
Erstellen Sie einen Kaskadenklassifizierer mit Google Colaboratory
Lassen Sie uns mit PLY 1 eine einfache Sprache erstellen
Machen Sie eine Logikschaltung mit Perceptron (Multilayer Perceptron)
Machen Sie einen Waschtrocknungs-Timer mit Raspberry Pi
Erstellen Sie eine GIF-Animation mit Ordnerüberwachung
Erstellen Sie ein Webframework mit Python! (1)
Machen wir mit Pylearn 2 eine dreiäugige KI
Versuchen Sie, eine Karte mit Python + Cartopy 0.18.0 zu zeichnen
Erstellen Sie eine Desktop-App mit Python mit Electron
Machen wir einen Twitter-Bot mit Python!
Erstellen Sie ein Webframework mit Python! (2)
Zeichnen Sie ein Diagramm mit PyQtGraph Part 1-Drawing
Ein Memorandum, um WebDAV nur mit Nginx zu erstellen
Machen Sie Twitter Trend Bot mit Heroku + Python
Stellen Sie ein Überwachungsgerät mit einem Infrarotsensor her
Erstellen Sie mit Flask einen einfachen Punktbildgenerator
Spiele mit PyTorch
So erstellen Sie ein Wörterbuch mit einer hierarchischen Struktur.
Ich möchte ein Spiel mit Python machen
Versuchen Sie, in Python einen "Entschlüsselungs" -Code zu erstellen
Ersetzen wir UWSC durch Python (5) Machen wir einen Roboter
Kreuzvalidierung mit PyTorch
Beginnend mit PyTorch
Versuchen Sie, mit Python eine Diedergruppe zu bilden
Verfahren zur Erstellung plattformübergreifender Apps mit kivy
[Chat De Tornado] Erstellen Sie einen Chat mit WebSocket in Tornado
Machen Sie Urlaubsdaten mit Pandas zu einem Datenrahmen
Erstellen Sie mit Amazon Lex einen LINE WORKS-Bot
Versuchen Sie, eine Karte mit Pythons Folium-Paket zu zeichnen
Ich habe versucht, die Datenbank (sqlite3) mit kivy zu verwenden
(Memorandum) Erstellen Sie mit matplodlib ein 3D-Streudiagramm
Kombinieren Sie sich wiederholende Zeichenfolgen mit regulären Python-Ausdrücken zu einer.
Machen Sie mit LINE + Flask einen morphologischen Analyse-Bot
Trainieren Sie MNIST-Daten mit PyTorch mithilfe eines neuronalen Netzwerks
Lassen Sie uns ein Befehls-Standby-Tool mit Python erstellen
Machen Sie mit PyTorch und Scikit-Learn sichtbarere Leistungsindikatoren
[Übung] Erstellen Sie eine Watson-App mit Python! # 2 [Übersetzungsfunktion]
[Übung] Erstellen Sie eine Watson-App mit Python! # 1 [Sprachdiskriminierung]