Obtenez Razpai 3B + et picamera pour les cours universitaires. Comme j'ai du temps libre, j'ai décidé de laisser Razpai classer en utilisant le deep learning. Cependant, au lieu de classer les photos prises à l'avance, les objets de l'image en temps réel de picamera sont classés et affichés de manière agréable.
Ce sera peut-être au niveau des étudiants, mais j'espère que ce sera utile en partie.
J'ai décidé de créer une «fonction qui ** classe et affiche ** en temps réel lorsque plusieurs effets personnels sont placés dans le champ visuel fixe de la picamera» dans Razpie.
Plus précisément, l'objet est extrait par ** différence d'arrière-plan ** (une méthode d'extraction de la partie modifiée de l'image d'arrière-plan) et l'apprentissage en profondeur est effectué par ** PyTorch [PyTorch] ** (similaire à Keras, TensorFlow). Nous adopterons une politique de classification par.
** (* YOLO, SSD, etc. ne sont pas gérés!) **
Je l'ai donc implémenté à l'étape suivante.
Raspeye est lent, j'ai donc appris ** sur mon propre PC et l'ai classé sur Raspai en utilisant le fichier de paramètres obtenu **. J'ai donc mis PyTorch sur PC et Raspberry.
Voici une série de processus. Notez les parties avec lesquelles vous avez eu du mal avec le symbole ** [⚠Remarque] **.
Préparez l'environnement d'exécution sur le PC et Raspeye.
Les versions du même package sont différentes pour PC et Raspeye, mais ne vous inquiétez pas. Votre propre PC est destiné à l'apprentissage.
** * Torchvision ** est un ensemble avec PyTorch et est une bibliothèque utilisée pour ** le prétraitement d'images et la création de jeux de données **.
Raspberry Pi 3 Model B+ (Raspbian Stretch)
J'ai utilisé ** Raspberry Pi Camera Module V2 ** comme caméra à brancher sur le Raspberry Pi. J'ai également mis VNC Viewer sur mon PC et utilisé Raspeye avec ** connexion SSH **.
Mettez la version ci-dessus du package sur chaque ordinateur. J'omettrai les détails, mais je me suis référé à la zone de lien du site.
PyTorch / Torchvision
Installez sur ** PC ** en sélectionnant l'environnement depuis PyTorch Official.
** [⚠Remarque] ** Le GPU ne peut pas être utilisé sauf s'il est fabriqué par NVIDIA, donc si vous avez "Intel", sélectionnez ** CUDA → Aucun ** (utilise normalement le processeur).
À ** Raspberry Pi **, "Mettre PyTorch v1.3.0 dans Raspberry Pi 3" et "Code source de PyTorch Deep Learning Framework dans Raspberry Pi" Comment construire à partir de " est une bonne référence pour la construction.
** [⚠Remarque] ** Spécifiez la version comme git clone ~~~ -b v1.3.0
etc.
** [⚠Remarque] ** Dans PyTorch 1.4.0, erreur fatale: immintrin.h
n'existe pas et la compilation s'est arrêtée à environ 80%. Un mystère. (2020/03/20)
OpenCV
"Installer OpenCV 3 sur Raspberry Pi + Python 3 aussi facilement que possible", etc., et installez-le sur ** Raspberry **.
Les deux prennent quelques heures à construire ...
Après de nombreux essais et erreurs, je viens de créer un script Python.
J'ai créé les données d'image de mes effets personnels à utiliser pour l'apprentissage. On suppose que la picamera est insérée dans la tarte de la râpe et ** fixée de sorte que la picamera ne bouge pas **.
Après avoir tourné l'écran avec la touche "r", appuyez sur "p" pour photographier l'arrière-plan sans rien capturer. Si vous placez les effets personnels que vous souhaitez photographier et photographiez à nouveau avec "p", la différence d'arrière-plan sera faite et la photo dans le ** cadre vert ** sera enregistrée.
Cette fois, je vais classer les trois catégories de ** "certains téléphones", "regarder" et "portefeuille" **, donc je vais juste prendre ces trois photos.
take_photo.py
# coding: utf-8
import cv2
from datetime import datetime
import picamera
import picamera.array
MIN_LEN = 50 #Longueur minimale d'un côté du cadre de détection d'objet
GRAY_THR = 20 #Seuil de changement de concentration
CUT_MODE = True # True:Couper et enregistrer l'objet détecté, False:Enregistrez l'image entière telle quelle
def imshow_rect(img, contour, minlen=0):
"""
Entourez tous les points de détection d'objet de l'image acquise avec un cadre carré
argument:
img:Image de la caméra
contour:Contour
minlen:Seuil de taille de détection (à l'exclusion des zones où un côté du cadre est plus court que cela)
"""
for pt in contour:
x, y, w, h = cv2.boundingRect(pt)
if w < minlen and h < minlen: continue
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.imshow('Preview', img)
def save_cutimg(img, contour, minlen=0):
"""
Découpez et enregistrez tous les points de détection d'objet dans l'image acquise
argument:
Comme ci-dessus
"""
#Obtenez la date et l'heure et utilisez-les pour le nom du fichier
dt = datetime.now()
f_name = '{}.jpg'.format(dt.strftime('%y%m%d%H%M%S'))
imgs_cut = []
for pt in contour:
x, y, w, h = cv2.boundingRect(pt)
if w < minlen and h < minlen: continue
imgs_cut.append(img[y:y+h, x:x+w])
#Découpez et enregistrez l'objet
if not imgs_cut: return -1
if len(imgs_cut) > 1:
for i in range(len(imgs_cut)):
cv2.imwrite(f_name[:-4]+'_'+str(i+1)+f_name[-4:], imgs_cut[i])
else:
cv2.imwrite(f_name, imgs_cut[0])
return len(imgs_cut)
def save_img(img):
"""
Enregistrez l'image acquise telle quelle
argument:
Comme ci-dessus
"""
dt = datetime.now()
fname = '{}.jpg'.format(dt.strftime('%y%m%d%H%M%S'))
cv2.imwrite(fname, img)
def take_photo():
"""
Prise de vue en arrière-plan->Photographie d'objets,sauvegarder
Entrée clé:
"p":prendre une photo
"q":Arrêtez
"r":Faire pivoter l'écran (lors de la prise de vue en arrière-plan)
"i":Recommencer depuis le début (lors de la prise de vue d'un objet)
"""
cnt = 0
#Démarrer la picamera
with picamera.PiCamera() as camera:
camera.resolution = (480, 480) #résolution
camera.rotation = 0 #Angle de rotation de la caméra(À chaque fois)
#Commencer le streaming
with picamera.array.PiRGBArray(camera) as stream:
print('Set background ... ', end='', flush=True)
#Commencez par photographier l'arrière-plan
while True:
#Obtenir et afficher des images en streaming
camera.capture(stream, 'bgr', use_video_port=True)
cv2.imshow('Preview', stream.array)
wkey = cv2.waitKey(5) & 0xFF #Réception des entrées clés
stream.seek(0) #2 sorts pour capturer de nouveaux
stream.truncate()
if wkey == ord('q'):
cv2.destroyAllWindows()
return print()
elif wkey == ord('r'):
camera.rotation += 90
elif wkey == ord('p'):
camera.exposure_mode = 'off' #Balance des blancs fixe
save_img(stream.array)
#Échelle de gris et définie comme image de fond
back_gray = cv2.cvtColor(stream.array,
cv2.COLOR_BGR2GRAY)
print('done')
break
#Après avoir réglé l'arrière-plan,Photographier des objets sans déplacer la caméra
print('Take photos!')
while True:
camera.capture(stream, 'bgr', use_video_port=True)
#Échelle de gris du cadre actuel
stream_gray = cv2.cvtColor(stream.array,
cv2.COLOR_BGR2GRAY)
#Calculez la valeur absolue de la différence et binarisez-la,Fabrication de masques
diff = cv2.absdiff(stream_gray, back_gray)
mask = cv2.threshold(diff, GRAY_THR, 255,
cv2.THRESH_BINARY)[1]
cv2.imshow('mask', mask)
#Contour pour la détection d'objets,Fabrication de masques
contour = cv2.findContours(mask,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
#Tous les objets détectés sont affichés dans un carré
stream_arr = stream.array.copy()
imshow_rect(stream_arr, contour, MIN_LEN)
wkey = cv2.waitKey(5) & 0xFF
stream.seek(0)
stream.truncate()
if wkey == ord('q'):
cv2.destroyAllWindows()
return
elif wkey == ord('i'):
break
elif wkey == ord('p'):
if CUT_MODE:
num = save_cutimg(stream.array, contour, MIN_LEN)
if num > 0:
cnt += num
print(' Captured: {} (sum: {})'.format(num, cnt))
else:
save_img(stream.array)
cnt += 1
print(' Captured: 1 (sum: {})'.format(cnt))
print('Initialized')
take_photo()
if __name__ == '__main__':
take_photo()
Je prends juste des photos. L'image recadrée pour chaque cadre vert est enregistrée comme ceci.
➡ & &
** [⚠Remarque] S'il y a trop peu de photos, cela n'apprendra pas bien. ** ** J'ai pris plus de 50 photos pour chaque classe pour les données d'entraînement, mais je me demande s'il y en a encore peu ... Pour le moment, divers bruits sont ajoutés lors de l'apprentissage et la quantité de données augmente.
Mettez les photos dans un dossier et utilisez Slack ou quelque chose pour ** les déplacer vers votre PC **. (Semi-analogique) Et stockez chaque photo personnelle dans la structure de dossiers ci-dessous **. ** **
image_data
├─train
│ ├─phone
│ │ 191227013419.jpg
│ │ 191227013424.jpg
│ │ :
│ ├─wallet
│ │ 191227013300.jpg
│ │ 191227013308.jpg
│ │ :
│ └─watch
│ 191227013345.jpg
│ 191227013351.jpg
| :
└─val
├─phone
│ 191227013441.jpg
│ 191227013448.jpg
| :
├─wallet
│ 191227013323.jpg
│ 191227013327.jpg
| :
└─watch
191227013355.jpg
191227013400.jpg
:
Construisez un réseau et entraînez-vous avec l'image ci-dessus.
Lorsqu'il est exécuté, il lit l'image du dossier précédent, commence l'apprentissage et génère le fichier de progression, le diagramme de transition de perte et de précision et le fichier de paramètres final.
En le créant, je me suis référé au "PyTorch Neural Network Implementation Handbook" (Hidewa System).
Même si vous interrompez avec "Ctrl + C", la progression de l'apprentissage jusqu'à ce point est enregistrée sous ** "train_process.ckpt" **, et vous pouvez continuer à apprendre à partir de la prochaine exécution. Il est normal de changer les hyper paramètres en cours de route.
À propos, le ** dossier d'images ** de torchvsion crée un ensemble de données avec le nom du dossier contenant les photos comme nom de classe. Facile! !! Les photos du dossier train sont utilisées pour l'apprentissage et les photos du dossier val sont utilisées pour l'évaluation.
train_net.py
# coding: utf-8
import os
import re
import torch.nn as nn
import torch.optim as optim
import torch.utils
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
DATA_DIR = 'image_data' #Nom du dossier d'images
CKPT_PROCESS = 'train_process.ckpt' #Progression de l'apprentissage enregistrer le nom du fichier
CKPT_NET = 'trained_net.ckpt' #Nom du fichier de paramètres appris
NUM_CLASSES = 3 #Nombre de cours
NUM_EPOCHS = 100 #Nombre d'apprentissage
#Hyper paramètres qui changent fréquemment
LEARNING_RATE = 0.001 #Taux d'apprentissage
MOMENTUM = 0.5 #inertie
checkpoint = {} #Variables pour enregistrer la progression
#Définition de la conversion des données d'image (volumineux)
#Avec la taille de Redimensionner,Lié à la première taille d'entrée linéaire du classificateur
data_transforms = transforms.Compose([
transforms.Resize((112, 112)), #redimensionner
transforms.RandomRotation(30), #Faire une rotation aléatoire
transforms.Grayscale(), #Binarisation
transforms.ToTensor(), #Tensolisation
transforms.Normalize(mean=[0.5], std=[0.5]) #Normalisation (les nombres sont texto)
])
val_transforms = transforms.Compose([
transforms.Resize((112, 112)),
transforms.Grayscale(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.5], std=[0.5])
])
#Création de l'ensemble de données
train_dataset = datasets.ImageFolder(
root=os.path.join(DATA_DIR, 'train'),
transform=train_transforms
)
val_dataset = datasets.ImageFolder(
root=os.path.join(DATA_DIR, 'val'),
transform=val_transforms
)
#Obtenez un mini lot
train_loader = torch.utils.data.DataLoader(
dataset=train_dataset,
batch_size=10, #Taille du lot au moment de l'apprentissage
shuffle=True #Mélanger les données d'entraînement
)
val_loader = torch.utils.data.DataLoader(
dataset=val_dataset,
batch_size=10,
shuffle=True
)
class NeuralNet(nn.Module):
"""Définition du réseau. nn.Héritage du module"""
def __init__(self, num_classes):
super(NeuralNet, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 8, kernel_size=11, stride=4, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(8, 16, kernel_size=5, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
)
self.classifier = nn.Sequential(
nn.Dropout(p=0.5),
nn.Linear(400, 200),
nn.ReLU(inplace=True),
nn.Dropout(p=0.5),
nn.Linear(200, num_classes)
)
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), -1)
x = self.classifier(x)
return x
def main():
"""Lire les données pendant l'entraînement->Apprentissage(->Sauvegarde des données pendant l'entraînement)->Illustration des résultats"""
global checkpoint
print('[Settings]')
#Réglages de l'appareil
device = 'cuda' if torch.cuda.is_available() else 'cpu'
#réseau,Fonction d'évaluation,Réglage de la fonction d'optimisation
net = NeuralNet(NUM_CLASSES).to(device)
criterion = nn.CrossEntropyLoss() #Fonction d'évaluation
optimizer = optim.SGD( #Algorithme d'optimisation
net.parameters(),
lr=LEARNING_RATE,
momentum=MOMENTUM,
weight_decay=5e-4
)
#Paramètres d'affichage
# print(' Device :', device)
# print(' Dataset Class-Index :', train_dataset.class_to_idx)
# print(' Network Model :', re.findall('(.*)\(', str(net))[0])
# print(' Criterion :', re.findall('(.*)\(', str(criterion))[0])
# print(' Optimizer :', re.findall('(.*)\(', str(optimizer))[0])
# print(' -Learning Rate :', LEARNING_RATE)
# print(' -Momentum :', MOMENTUM)
t_loss_list = []
t_acc_list = []
v_loss_list = []
v_acc_list = []
epoch_pre = -1
#Acquisition de données de formation (en cours de route)
if os.path.isfile(CKPT_PROCESS):
checkpoint = torch.load(CKPT_PROCESS)
net.load_state_dict(checkpoint['net'])
optimizer.load_state_dict(checkpoint['optimizer'])
t_loss_list = checkpoint['t_loss_list']
t_acc_list = checkpoint['t_acc_list']
v_loss_list = checkpoint['v_loss_list']
v_acc_list = checkpoint['v_acc_list']
epoch_pre = checkpoint['epoch']
print("Progress until last time = {}/{} epochs"\
.format(epoch_pre+1, NUM_EPOCHS))
print('[Main process]')
for epoch in range(epoch_pre+1, NUM_EPOCHS):
t_loss, t_acc, v_loss, v_acc = 0, 0, 0, 0
#Apprentissage---------------------------------------------------------
net.train() #Mode d'apprentissage
for _, (images, labels) in enumerate(train_loader):
images, labels = images.to(device), labels.to(device)
optimizer.zero_grad()
outputs = net(images)
loss = criterion(outputs, labels)
t_loss += loss.item()
t_acc += (outputs.max(1)[1] == labels).sum().item()
loss.backward()
optimizer.step()
avg_t_loss = t_loss / len(train_loader.dataset)
avg_t_acc = t_acc / len(train_loader.dataset)
#Évaluation---------------------------------------------------------
net.eval() #Mode d'évaluation
with torch.no_grad(): #Arrêter de mettre à jour le dégradé
for images, labels in val_loader:
images, labels = images.to(device), labels.to(device)
images = images.to(device)
labels = labels.to(device)
outputs = net(images)
loss = criterion(outputs, labels)
v_loss += loss.item()
v_acc += (outputs.max(1)[1] == labels).sum().item()
avg_v_loss = v_loss / len(val_loader.dataset)
avg_v_acc = v_acc / len(val_loader.dataset)
# --------------------------------------------------------------
print('\rEpoch [{}/{}] | Train [oss:{:.3f}, acc:{:.3f}] | Val [loss:{:.3f}, acc:{:.3f}]'\
.format(epoch+1, NUM_EPOCHS, avg_t_loss, avg_t_acc, avg_v_loss, avg_v_acc), end='')
#perte,Record de précision
t_loss_list.append(avg_t_loss)
t_acc_list.append(avg_t_acc)
v_loss_list.append(avg_v_loss)
v_acc_list.append(avg_v_acc)
#Processus de sauvegarde des progrès
checkpoint['net'] = net.state_dict()
checkpoint['optimizer'] = optimizer.state_dict()
checkpoint['t_loss_list'] = t_loss_list
checkpoint['t_acc_list'] = t_acc_list
checkpoint['v_loss_list'] = v_loss_list
checkpoint['v_acc_list'] = v_acc_list
checkpoint['epoch'] = epoch
graph()
save_process()
save_net()
def save_process():
"""Enregistrer la progression"""
global checkpoint
if not checkpoint: return
torch.save(checkpoint, CKPT_PROCESS)
def save_net():
"""Enregistrer uniquement les informations du réseau"""
global checkpoint
if not checkpoint: return
torch.save(checkpoint['net'], CKPT_NET)
def graph():
"""perte,Précision graphique"""
global checkpoint
if not checkpoint: return
t_loss_list = checkpoint['t_loss_list']
t_acc_list = checkpoint['t_acc_list']
v_loss_list = checkpoint['v_loss_list']
v_acc_list = checkpoint['v_acc_list']
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.plot(range(len(t_loss_list)), t_loss_list,
color='blue', linestyle='-', label='t_loss')
plt.plot(range(len(v_loss_list)), v_loss_list,
color='green', linestyle='--', label='v_loss')
plt.legend()
plt.xlabel('epoch')
plt.ylabel('loss')
plt.title('Training and validation loss')
plt.grid()
plt.subplot(1, 2, 2)
plt.plot(range(len(t_acc_list)), t_acc_list,
color='blue', linestyle='-', label='t_acc')
plt.plot(range(len(v_acc_list)), v_acc_list,
color='green', linestyle='--', label='v_acc')
plt.legend()
plt.xlabel('epoch')
plt.ylabel('acc')
plt.title('Training and validation accuracy')
plt.grid()
plt.show()
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print()
graph()
save_process()
** [⚠Note] L'échelle du réseau est modérée. ** **
Si vous augmentez trop le nombre de couches et de nœuds, vous obtiendrez l'erreur DefaultCPUAllocator: impossible d'allouer de la mémoire: vous avez essayé d'allouer 685198800 octets.
..
Cliquez ici pour la progression de l'apprentissage. La gauche est la perte et la droite est la précision. La ligne bleue correspond aux données d'entraînement et la ligne verte en pointillé aux données de vérification. La précision des données de vérification est d'environ 72%. Il y a place à amélioration ...
Lorsque vous aurez terminé l'entraînement, vous aurez un fichier ** "" training_net.ckpt "" ** qui ne stockera que les paramètres entraînés, et vous le renverrez à Rasppie avec Slack ou quelque chose **.
Dans un but, les objets de l'image de la caméra sont classés en temps réel et affichés de manière agréable.
Commencez par photographier l'arrière-plan, puis divisez l'arrière-plan des images suivantes, découpez les objets émergents et créez un lot de tenseur en 4 dimensions grâce à un prétraitement défini. Le lot entier est passé à travers le réseau, converti en probabilité de chaque classe, et la classe (nom de l'objet) avec la probabilité la plus élevée est superposée et affichée dans la fenêtre.
Chargez le "training_net.ckpt" créé précédemment.
** [⚠Remarque] Si vous ne définissez pas de limite supérieure sur la taille du lot (le nombre d'objets à détecter en même temps), la tarte aux râpes peut geler lorsque vous essayez de traiter une grande quantité de zones détectées à la fois. ** **
raltime_classification.py
# coding: utf-8
import os
from PIL import Image
from time import sleep
import cv2
import picamera
import picamera.array
import torch
#Dans le répertoire pytorch"export OMP_NUM_THREADS=1 or 2 or 3"Obligatoire(La valeur par défaut est 4)
#Le nombre de cœurs de traitement parallèles"print(torch.__config__.parallel_info())"Confirmer avec
import torch.nn as nn
import torch.utils
from torchvision import transforms
CKPT_NET = 'trained_net.ckpt' #Fichier de paramètres formés
OBJ_NAMES = ['Phone', 'Wallet', 'Watch'] #Afficher le nom de chaque classe
MIN_LEN = 50
GRAY_THR = 20
CONTOUR_COUNT_MAX = 3 #Taille du lot(Nombre d'objets à détecter à la fois)Limite supérieure de
SHOW_COLOR = (255, 191, 0) #Couleur du cadre(B,G,R)
NUM_CLASSES = 3
PIXEL_LEN = 112 #Taille après redimensionnement(1 côté)
CHANNELS = 1 #Nombre de canaux de couleur(BGR:3,niveaux de gris:1)
#Définition de la conversion des données d'image
#Avec redimensionner,Lié à la première entrée linéaire du classificateur
data_transforms = transforms.Compose([
transforms.Resize((PIXEL_LEN, PIXEL_LEN)),
transforms.Grayscale(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.5], std=[0.5])
])
class NeuralNet(nn.Module):
"""Définition du réseau.Doit être le même que celui utilisé pour l'apprentissage"""
def __init__(self, num_classes):
super(NeuralNet, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 8, kernel_size=11, stride=4, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(8, 16, kernel_size=5, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
)
self.classifier = nn.Sequential(
nn.Dropout(p=0.5),
nn.Linear(400, 200),
nn.ReLU(inplace=True),
nn.Dropout(p=0.5),
nn.Linear(200, num_classes)
)
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), -1)
x = self.classifier(x)
return x
def detect_obj(back, target):
"""
Avec le traitement des différences de fond OpenCV,Créer un tapple d'objets détectés
argument:
back:Image d'arrière-plan d'entrée
Image couleur
target:Image pour la différence de fond
Image couleur.Découpez plusieurs objets,Assembler dans une image couleur taple
"""
print('Detecting objects ...')
#Binarisation
b_gray = cv2.cvtColor(back, cv2.COLOR_BGR2GRAY)
t_gray = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
#Calculez la différence
diff = cv2.absdiff(t_gray, b_gray)
#Contour selon le seuil,Créer un masque,Extraire des objets
#L'index de findContours est, cv2.__version__ == 4.2.0->[0], 3.4.7->[1]
mask = cv2.threshold(diff, GRAY_THR, 255, cv2.THRESH_BINARY)[1]
cv2.imshow('mask', mask)
contour = cv2.findContours(mask,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
#Coordonnées de la zone de changement détectées au-dessus d'une certaine hauteur et largeur,Créer un lot de taille
pt_list = list(filter(
lambda x: x[2] > MIN_LEN and x[3] > MIN_LEN,
[cv2.boundingRect(pt) for pt in contour]
))[:CONTOUR_COUNT_MAX]
#Découpez le cadre en fonction des informations de position,Convertir en un tuple d'image PIL et retourner
obj_imgaes = tuple(map(
lambda x: Image.fromarray(target[x[1]:x[1]+x[3], x[0]:x[0]+x[2]]),
pt_list
))
return (obj_imgaes, pt_list)
def batch_maker(tuple_images, transform):
"""
Transformez le tuple d'une image au format PIL,Convertir en un lot de tenseurs pouvant être traité sur le réseau
argument:
tuple_images:Image PIL taple
transform:définition de conversion d'image torchvision
"""
return torch.cat([transform(img) for img
in tuple_images]).view(-1, CHANNELS, PIXEL_LEN, PIXEL_LEN)
def judge_what(img, probs_list, pos_list):
"""
Déterminer l'objet à partir de la probabilité d'appartenir à chaque classe,Afficher le cadre et le nom à cette position,Renvoie l'index de la classe
argument:
probs_list:Tableau secondaire de probabilités.Format de lot
pos_list:Tableau secondaire de positions.Format de lot
"""
print('Judging objects ...')
#Convertir en une liste des probabilités les plus élevées et leurs index
ip_list = list(map(lambda x: max(enumerate(x), key = lambda y:y[1]),
F.softmax(probs_list, dim=-1))) # <- 4/30 corrections
#Convertir l'index en nom d'objet,Ecrire et afficher le nom et la certitude de l'objet à la position de l'objet
for (idx, prob), pos in zip(ip_list, pos_list):
cv2.rectangle(img, (pos[0], pos[1]), (pos[0]+pos[2], pos[1]+pos[3]), SHOW_COLOR, 2)
cv2.putText(img, '%s:%.1f%%'%(OBJ_NAMES[idx], prob*100), (pos[0]+5, pos[1]+20),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, SHOW_COLOR, thickness=2)
return ip_list
def realtime_classify():
"""Chargement du modèle formé->Lire les données de test->Classification->Afficher le résultat superposé sur l'image"""
#Réglages de l'appareil
device = 'cuda' if torch.cuda.is_available() else 'cpu'
#paramètres réseau
net = NeuralNet(NUM_CLASSES).to(device)
#Acquisition de données formée
if os.path.isfile(CKPT_NET):
checkpoint = torch.load(CKPT_NET)
net.load_state_dict(checkpoint)
else:
raise FileNotFoundError('No trained network file: {}'.format(CKPT_NET))
#Mode d'évaluation
net.eval()
#Démarrer la picamera
with picamera.PiCamera() as camera:
camera.resolution = (480, 480)
#Commencer le streaming
with picamera.array.PiRGBArray(camera) as stream:
print('Setting background ...')
sleep(2)
camera.exposure_mode = 'off' #Balance des blancs fixe
camera.capture(stream, 'bgr', use_video_port=True)
#Définir comme arrière-plan
img_back = stream.array
stream.seek(0)
stream.truncate()
print('Start!')
with torch.no_grad():
while True:
camera.capture(stream, 'bgr', use_video_port=True)
#Différence d'arrière-plan pour les futures images d'entrée
img_target = stream.array
#Détecte les objets et leurs positions
obj_imgs, positions = detect_obj(img_back, img_target)
if obj_imgs:
#Convertir les objets détectés au format d'entrée réseau
obj_batch = batch_maker(obj_imgs, data_transforms)
#Classification
outputs = net(obj_batch)
#Jugement
result = judge_what(img_target, outputs, positions)
print(' Result:', result)
#afficher
cv2.imshow('detection', img_target)
if cv2.waitKey(200) == ord('q'):
cv2.destroyAllWindows()
return
stream.seek(0)
stream.truncate()
if __name__ == "__main__":
try:
realtime_classify()
except KeyboardInterrupt:
cv2.destroyAllWindows()
Apportez le précédent "training_net.ckpt" sur la tarte râpe et exécutez-le dans le même répertoire. Le nom de l'objet détecté et sa certitude s'affichent.
Le résultat de l'exécution est ... Je suis satisfait du classement de haute précision à partir du moment où je l'ai mis! !!
➡ ➡
** [⚠Remarque] Il est recommandé de changer le nombre de cœurs utilisés pour l'exécution (par défaut 4). ** **
Il y a un grand risque de gel lorsqu'il est utilisé avec 4 cœurs pleins.
Dans le répertoire pytorch, changez la commande comme ʻexport OMP_NUM_THREADS = 2(en utilisant 2 cœurs). Vous pouvez vérifier le nombre de cœurs avec
print (torch .__ config __. Parallel_info ()). Cependant, lorsque le shell est fermé, les modifications sont annulées, donc pour le rendre persistant, sous le bas
... ~ fi de **". Profile "** in
/ home / pi`, ʻexport OMP_NUM_THREADS Écrivez = 2 et redémarrez.
J'ai pu faire ce que je voulais faire! (Je suis désolé pour le manque de lisibilité ...) Si vous utilisez la détection de visage OpenCV, il semble que vous puissiez l'appliquer immédiatement à une reconnaissance de visage très simple.
Au départ, je pensais implémenter un SSD, mais je pensais qu'il serait difficile de créer un ensemble de données avec des informations de localisation, et j'ai abandonné car je ne pouvais pas résoudre l'erreur que j'avais en essayant de m'entraîner avec des échantillons de données. ..
Contrairement aux SSD, l'inconvénient est que la différence d'arrière-plan cette fois ne permet pas de séparer les objets qui se chevauchent et est considérée comme un.
C'était une bonne étude ~