Cet article est le deuxième jour du calendrier Docomo Dovent.
Connaissez-vous le quiz de dessin? Il s'agit d'un quiz où le questionneur dessine une image et devine ce que les autres dessinent. Il existe de nombreuses applications.
Il semble que même une personne puisse jouer en reconnaissant l'image dessinée par l'utilisateur et en la devinant, donc après L'année dernière, la bibliothèque d'apprentissage automatique [PyTorch](https :: Créons une combinaison de //pytorch.org/) et kivy, une bibliothèque qui vous permet de créer des applications.
Il a le plus d'élan et est facile à utiliser dans la bibliothèque GUI de Python (subjectif).
Il fut un temps où l'on disait que le seuil était élevé parce qu'il n'y avait pas d'informations en japonais, mais maintenant il y a des informations insensées. Grâce aux bénévoles, il existe également un document japonais. Cet article est recommandé comme tutoriel pour les nouveaux utilisateurs.
Si vous disposez des fonctions suivantes, il semble que vous puissiez réaliser un quiz de dessin.
--Affichage du thème à dessiner --Bouton pour changer le thème --Partie de toile
Si vous utilisez kviewer, vous pouvez vérifier l'interface utilisateur sans le fichier python du corps principal, donc créons d'abord uniquement la mise en page.
ui_test.kv
BoxLayout:
orientation: 'vertical' #Disposer verticalement quatre objets enfants
BoxLayout:
size_hint_y: 0.1 #Largeur verticale 10%Occuper
Label: #Afficher le thème
size_hint_x: 0.7 #Largeur 70%Occuper
text: 'Draw "XXX"'
Button: #Bouton pour changer de thème
size_hint_x: 0.3 #Largeur 30%Occuper
text: 'Change'
Label: #Partie toile (provisoire)
text: 'CANVAS'
size_hint_y: 0.7 #Largeur verticale 70%Occuper
BoxLayout:
size_hint_y: 0.1 #Largeur verticale 10%Occuper
Button: #Bouton Annuler
text: 'Undo'
Button: #Bouton tout effacer
text: 'Clear'
Label: #Afficher le résultat de l'IA frappant l'image
size_hint_y: 0.1 #Largeur verticale 10%Occuper
text: 'I guess it is "YYY"'
Lorsqu'il est affiché, l'écran suivant apparaît. La disposition est maintenant décidée.
python -m kivy.tools.kviewer ui_test.kv
Nous avons besoin d'un modèle pour deviner l'image dessinée par l'utilisateur, mais cette fois nous utiliserons le modèle formé suivant (licence MIT). Au lieu d'être léger, il n'y a que 20 catégories, donc si vous voulez reconnaître les 345 catégories de l'ensemble de données d'origine, veuillez apprendre par vous-même.
Le modèle utilisé cette fois n'utilise pas les informations de série chronologique (ordre dans lequel les lignes sont tracées), mais comme l'ensemble de données d'origine contient également des informations de série chronologique, l'apprentissage dans cet esprit améliorera la précision de la reconnaissance pendant le dessin. Devrait faire. La structure des dossiers est la suivante. Utilisez les deux dossiers "src" et "training_models" du référentiel GitHub ci-dessus.
├─paintquiz.py #Le fichier python à implémenter
├─paintquiz.kv #Fichier Kivy à implémenter
├─src #Dans le référentiel ci-dessus
└─trained_models #Dans le référentiel ci-dessus
Nous allons implémenter les fonctions nécessaires en python et changer un peu le côté kivy en conséquence. J'ai pu implémenter python avec environ 120 lignes et kivy avec environ 60 lignes, pour un total d'environ 180 lignes. Le canevas est reconnu toutes les secondes et le résultat de la reconnaissance provisoire est affiché. Les fonctions implémentées sont les suivantes.
--Fonctions de chaque bouton définies dans la mise en page
paintquiz.py
import random
from kivy.config import Config
#Taille de la fenêtre au démarrage
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 des classes reconnaissables
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():
#Charger le modèle de reconnaissance
def __init__(self):
self.model = torch.load("./trained_models/whole_model_quickdraw", map_location=lambda storage, loc: storage) #Lire le fichier de poids entraîné
self.model.eval() #Pas d'apprentissage cette fois
self.sm = nn.Softmax(dim=1) #Si tous les résultats ne sont pas fiables, je veux couper avec le score, donc je normalise avec softmax
#Entrez le nom du fichier image et renvoyez le résultat de la reconnaissance
def predict(self, fn, th=.5):
image = cv2.imread(fn, cv2.IMREAD_UNCHANGED)[:,:,-1] #Obtenez le canal alpha et accédez à l'image binaire
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]) #Renvoie le score de reconnaissance et la classe de reconnaissance
class Paint(Widget):
pred_word = StringProperty() #Mot de résultat de reconnaissance
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.line_width = 10 #Épaisseur de ligne
self.lines = [] #Liste pour stocker les lignes à annuler
self.in_drawing = False #Juger si le dessin est en cours
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
#Opération pendant le clic (dessin)
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]
#Comportement à la fin du clic
def on_touch_up(self, touch):
if self.in_drawing:
self.lines.append(touch.ud['line'])
self.in_drawing = False
#Effacer la ligne précédente
def undo(self):
if len(self.lines)>0:
line = self.lines.pop(-1)
self.canvas.remove(line)
#Effacer toute la toile
def clear_canvas(self):
for line in self.lines:
self.canvas.remove(line)
self.lines = []
#Reconnaître les images toutes les dt secondes
def predict(self, dt):
self.export_to_png('image.png')
with torch.no_grad():
score, label = self.model.predict('./image.png')
#Affiché comme inconnu lorsque le score de reconnaissance est inférieur à un certain niveau
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())) #Mot de thème
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
Le thème actuel est affiché en haut à gauche et le résultat de la reconnaissance (ce que vous pensez dessiner) est affiché ci-dessous.
J'ai dessiné des pommes et des ciseaux, mais ils les reconnaissent correctement. Une pomme ressemble à un marteau ou à une feuille lorsque seul l'ourlet est dessiné, mais elle est certainement reconnue comme un marteau ou une feuille. C'est plutôt la bonne réponse car l'ourlet de la pomme = feuilles.
Dans la zone d'analyse des données, il y a des gens qui affichent les résultats avec Jupyter Notebook au lieu de Powerpo au moment d'une réunion, mais c'est recommandé car il est facile de faire une application avec ce sentiment et il est facile de s'y intéresser.
En fait, je voulais créer une application de dessin (qui alterne avec l'IA pour dessiner des images), mais uniquement pour les utilisateurs expérimentés de kivy! J'ai abandonné parce que cela semblait être un article. S'il vous plaît, faites quelqu'un et laissez-moi jouer.
Recommended Posts