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