Holen Sie sich Razpai 3B + und Picamera für Universitätsklassen. Da ich Freizeit habe, habe ich beschlossen, Razpai mithilfe von Deep Learning klassifizieren zu lassen. Anstatt die im Voraus aufgenommenen Fotos zu klassifizieren, werden die Objekte im Echtzeitbild von Picamera klassifiziert und auf schöne Weise angezeigt.
Es mag auf Studentenebene sein, aber ich hoffe, es wird teilweise hilfreich sein.
Ich habe beschlossen, in Razpie eine "Funktion zu erstellen, die ** in Echtzeit klassifiziert und anzeigt **, wenn mehrere persönliche Gegenstände im festen Gesichtsfeld der Picamera platziert werden".
Insbesondere wird das Objekt durch ** Hintergrunddifferenz ** (eine Methode zum Extrahieren des geänderten Teils aus dem Hintergrundbild) extrahiert, und tiefes Lernen wird durch ** PyTorch [PyTorch] ** (ähnlich wie Keras, TensorFlow) durchgeführt. Wir werden eine Politik der Klassifizierung nach verfolgen.
** (* YOLO, SSD usw. werden nicht behandelt!) **
Also habe ich es im nächsten Schritt implementiert.
Raspeye ist langsam, also habe ich ** auf meinem eigenen PC gelernt und es auf Raspai anhand der erhaltenen Parameterdatei ** klassifiziert. Also habe ich PyTorch sowohl auf dem PC als auch auf Raspberry installiert.
Das Folgende ist eine Reihe von Prozessen. Notieren Sie sich die Bereiche, in denen Sie mit dem Symbol ** [⚠Hinweis] ** zu kämpfen hatten.
Bereiten Sie die Ausführungsumgebung auf dem PC und Raspeye vor.
Die Versionen desselben Pakets unterscheiden sich für PC und Raspeye, aber keine Sorge. Ihr eigener PC dient zum Lernen.
** * Torchvision ** ist ein Set mit PyTorch und eine Bibliothek, die für die ** Bildvorverarbeitung und Datensatzerstellung ** verwendet wird.
Raspberry Pi 3 Model B+ (Raspbian Stretch)
Ich habe ** Raspberry Pi Camera Module V2 ** als Kamera zum Anschließen an den Raspberry Pi verwendet. Ich habe auch VNC Viewer auf meinen PC installiert und Raspeye mit ** SSH-Verbindung ** betrieben.
Stellen Sie die obige Version des Pakets auf jeden Computer. Ich werde die Details weglassen, aber ich habe auf den Link-Site-Bereich verwiesen.
PyTorch / Torchvision
Installieren Sie auf ** PC **, indem Sie die Umgebung unter PyTorch Official auswählen.
** [⚠Hinweis] ** Die GPU kann nur verwendet werden, wenn sie von NVIDIA erstellt wurde. Wenn Sie also "Intel" haben, wählen Sie ** CUDA → Keine ** (normalerweise CPU verwenden).
Zu ** Raspberry Pi **, "PyTorch v1.3.0 in Raspberry Pi 3 einfügen" und "Quellcode des PyTorch Deep Learning Framework in Raspberry Pi" Erstellen aus " ist eine gute Referenz für das Erstellen.
** [⚠Hinweis] ** Geben Sie die Version als git clone ~~~ -b v1.3.0
usw. an.
** [⚠Hinweis] ** In PyTorch 1.4.0 ist "schwerwiegender Fehler: immintrin.h" nicht vorhanden, und der Build wurde bei etwa 80% gestoppt. Ein Geheimnis. (2020/3/20)
OpenCV
"OpenCV 3 so einfach wie möglich auf Raspberry Pi + Python 3 installieren" usw. und auf ** Raspberry ** installieren.
Beide brauchen ein paar Stunden, um ...
Nach vielen Versuchen und Irrtümern habe ich gerade ein Python-Skript erstellt.
Ich habe die Bilddaten meiner persönlichen Gegenstände erstellt, um sie zum Lernen zu verwenden. Es wird angenommen, dass der Picamera in die Raspeltorte eingeführt und ** fixiert ist, damit sich der Picamera nicht bewegt **.
Nachdem Sie den Bildschirm mit der Taste "r" gedreht haben, drücken Sie "p", um den Hintergrund aufzunehmen, ohne etwas aufzunehmen. Wenn Sie die persönlichen Gegenstände, die Sie aufnehmen möchten, platzieren und erneut mit "p" aufnehmen, wird der Hintergrundunterschied hergestellt und das Foto im ** grünen Rahmen ** gespeichert.
Dieses Mal werde ich die drei Kategorien ** "bestimmtes Telefon", "Uhr" und "Brieftasche" ** klassifizieren, also mache ich nur diese drei Bilder.
take_photo.py
# coding: utf-8
import cv2
from datetime import datetime
import picamera
import picamera.array
MIN_LEN = 50 #Mindestlänge einer Seite des Objekterkennungsrahmens
GRAY_THR = 20 #Konzentrationsänderungsschwelle
CUT_MODE = True # True:Schneiden Sie das erkannte Objekt aus und speichern Sie es, False:Speichern Sie das gesamte Bild wie es ist
def imshow_rect(img, contour, minlen=0):
"""
Schließen Sie alle Objekterkennungspunkte im erfassten Bild mit einem quadratischen Rahmen ein
Streit:
img:Kamerabild
contour:Kontur
minlen:Schwellenwert für die Erkennungsgröße (ausgenommen Bereiche, in denen eine Seite des Rahmens kürzer ist)
"""
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):
"""
Schneiden Sie alle Objekterkennungspunkte im aufgenommenen Bild aus und speichern Sie sie
Streit:
Das gleiche wie oben
"""
#Holen Sie sich Datum und Uhrzeit und verwenden Sie sie für den Dateinamen
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])
#Schneiden Sie das Objekt aus und speichern Sie es
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):
"""
Speichern Sie das aufgenommene Bild so wie es ist
Streit:
Das gleiche wie oben
"""
dt = datetime.now()
fname = '{}.jpg'.format(dt.strftime('%y%m%d%H%M%S'))
cv2.imwrite(fname, img)
def take_photo():
"""
Hintergrundaufnahmen->Objektfotografie,sparen
Tasteneingabe:
"p":machen Sie ein Foto
"q":Halt
"r":Drehen Sie den Bildschirm (beim Aufnehmen des Hintergrunds)
"i":Beginnen Sie von vorne (beim Aufnehmen eines Objekts)
"""
cnt = 0
#Starten Sie picamera
with picamera.PiCamera() as camera:
camera.resolution = (480, 480) #Auflösung
camera.rotation = 0 #Kameradrehwinkel(Jedes Mal)
#Starten Sie das Streaming
with picamera.array.PiRGBArray(camera) as stream:
print('Set background ... ', end='', flush=True)
#Schießen Sie zuerst den Hintergrund
while True:
#Streaming-Bilder abrufen und anzeigen
camera.capture(stream, 'bgr', use_video_port=True)
cv2.imshow('Preview', stream.array)
wkey = cv2.waitKey(5) & 0xFF #Tastatureingang
stream.seek(0) #2 Zauber, um neue zu erfassen
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' #Weißabgleich behoben
save_img(stream.array)
#Graustufen und als Hintergrundbild festgelegt
back_gray = cv2.cvtColor(stream.array,
cv2.COLOR_BGR2GRAY)
print('done')
break
#Nach dem Einstellen des Hintergrunds,Aufnehmen von Objekten ohne Bewegen der Kamera
print('Take photos!')
while True:
camera.capture(stream, 'bgr', use_video_port=True)
#Graustufen des aktuellen Rahmens
stream_gray = cv2.cvtColor(stream.array,
cv2.COLOR_BGR2GRAY)
#Berechnen Sie den absoluten Wert der Differenz und binärisieren Sie ihn,Maskenherstellung
diff = cv2.absdiff(stream_gray, back_gray)
mask = cv2.threshold(diff, GRAY_THR, 255,
cv2.THRESH_BINARY)[1]
cv2.imshow('mask', mask)
#Kontur zur Objekterkennung,Maskenherstellung
contour = cv2.findContours(mask,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
#Alle erkannten Objekte werden in einem Quadrat angezeigt
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()
Ich mache nur Fotos. Das zugeschnittene Bild für jeden grünen Rahmen wird wie folgt gespeichert.
➡ & &
** [⚠Hinweis] Wenn zu wenige Fotos vorhanden sind, wird es nicht gut gelernt. ** **. Ich habe mehr als 50 Fotos für jede Klasse für Trainingsdaten gemacht, aber ich frage mich, ob es noch wenige gibt ... Während des Lernens werden vorerst verschiedene Geräusche hinzugefügt, und die Datenmenge nimmt zu.
Legen Sie die Fotos in einen Ordner und verschieben Sie sie mit Slack oder etwas anderem auf Ihren PC. (Semi-Analog) Und speichern Sie jedes persönliche Foto in der Ordnerstruktur unten **. ** **.
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
:
Bauen Sie ein Netzwerk auf und trainieren Sie mit dem obigen Bild.
Bei der Ausführung wird das Bild aus dem vorherigen Ordner gelesen und das Lernen gestartet, und die Fortschrittsdatei, das Verlust- und Genauigkeitsübergangsdiagramm und die endgültige Parameterdatei werden ausgegeben.
Bei der Erstellung habe ich auf "PyTorch Neural Network Implementation Handbook" (Hidewa-System) verwiesen.
Selbst wenn Sie mit "Strg + C" unterbrechen, wird der Lernfortschritt bis zu diesem Punkt als ** "train_process.ckpt" ** gespeichert und Sie können ab der nächsten Ausführung weiter lernen. Es ist in Ordnung, die Hyperparameter unterwegs zu ändern.
Übrigens erstellt der ** Bildordner ** von torchvsion einen Datensatz mit dem Ordnernamen, der die Fotos als Klassennamen enthält. Einfach! !! Die Fotos im Zugordner werden zum Lernen verwendet, und die Fotos im Val-Ordner werden zur Auswertung verwendet.
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' #Name des Bildordners
CKPT_PROCESS = 'train_process.ckpt' #Lernfortschritt Dateinamen speichern
CKPT_NET = 'trained_net.ckpt' #Name der gelernten Parameterdatei
NUM_CLASSES = 3 #Anzahl der Klassen
NUM_EPOCHS = 100 #Anzahl des Lernens
#Hyperparameter, die sich häufig ändern
LEARNING_RATE = 0.001 #Lernrate
MOMENTUM = 0.5 #Trägheit
checkpoint = {} #Variablen zum Speichern des Fortschritts
#Definition der Bilddatenkonvertierung (sperrig)
#Mit der Größe von Resize,Bezogen auf die erste lineare Eingabegröße des Klassifikators
data_transforms = transforms.Compose([
transforms.Resize((112, 112)), #Größe ändern
transforms.RandomRotation(30), #Nach dem Zufallsprinzip drehen
transforms.Grayscale(), #Binarisierung
transforms.ToTensor(), #Tensolisierung
transforms.Normalize(mean=[0.5], std=[0.5]) #Normalisierung (Zahlen sind Text)
])
val_transforms = transforms.Compose([
transforms.Resize((112, 112)),
transforms.Grayscale(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.5], std=[0.5])
])
#Datensatzerstellung
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
)
#Holen Sie sich Mini-Batch
train_loader = torch.utils.data.DataLoader(
dataset=train_dataset,
batch_size=10, #Chargengröße zum Zeitpunkt des Lernens
shuffle=True #Mische Trainingsdaten
)
val_loader = torch.utils.data.DataLoader(
dataset=val_dataset,
batch_size=10,
shuffle=True
)
class NeuralNet(nn.Module):
"""Netzwerkdefinition. nn.Modulvererbung"""
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():
"""Lesen Sie die Daten während des Trainings->Lernen(->Speichern von Daten während des Trainings)->Darstellung der Ergebnisse"""
global checkpoint
print('[Settings]')
#Geräteeinstellungen
device = 'cuda' if torch.cuda.is_available() else 'cpu'
#Netzwerk,Bewertungsfunktion,Einstellung der Optimierungsfunktion
net = NeuralNet(NUM_CLASSES).to(device)
criterion = nn.CrossEntropyLoss() #Bewertungsfunktion
optimizer = optim.SGD( #Optimierungsalgorithmus
net.parameters(),
lr=LEARNING_RATE,
momentum=MOMENTUM,
weight_decay=5e-4
)
#Einstellungen anzeigen
# 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
#Schulung (unterwegs) Datenerfassung
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
#Lernen---------------------------------------------------------
net.train() #Lernmodus
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)
#Auswertung---------------------------------------------------------
net.eval() #Bewertungsmodus
with torch.no_grad(): #Beenden Sie die Aktualisierung des Verlaufs
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='')
#Verlust,Genauigkeitsaufzeichnung
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)
#Prozess zum Speichern des Fortschritts
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():
"""Fortschritt speichern"""
global checkpoint
if not checkpoint: return
torch.save(checkpoint, CKPT_PROCESS)
def save_net():
"""Speichern Sie nur Netzwerkinformationen"""
global checkpoint
if not checkpoint: return
torch.save(checkpoint['net'], CKPT_NET)
def graph():
"""Verlust,Grafikgenauigkeit"""
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()
** [⚠Hinweis] Der Umfang des Netzwerks ist moderat. ** **. Wenn Sie die Anzahl der Ebenen und Knoten zu stark erhöhen, wird die Fehlermeldung "DefaultCPUAllocator: Speicher kann nicht zugeordnet werden: Sie haben versucht, 685198800 Byte zuzuweisen" angezeigt ..
Klicken Sie hier für den Lernfortschritt. Die linke ist der Verlust und die rechte ist die Genauigkeit. Die blaue Linie steht für Trainingsdaten und die grüne gestrichelte Linie für Verifizierungsdaten. Die Genauigkeit der Verifizierungsdaten beträgt ca. 72%. Es gibt Raum für Verbesserungen ...
Wenn Sie das Training beendet haben, haben Sie eine ** "" trainierte_net.ckpt "" ** Datei, in der nur die trainierten Parameter gespeichert sind, und senden Sie sie erneut mit Slack oder etwas ** an Rasppie.
Als Ziel werden die Objekte im Kamerabild in Echtzeit klassifiziert und auf schöne Weise angezeigt.
Nehmen Sie zuerst den Hintergrund auf, teilen Sie dann den Hintergrund von den nachfolgenden Bildern, schneiden Sie die entstehenden Objekte aus und erstellen Sie durch definierte Vorverarbeitung einen 4-dimensionalen Tensor-Batch. Der gesamte Stapel wird durch das Netzwerk geleitet, in die Wahrscheinlichkeit jeder Klasse konvertiert, und die Klasse (Name des Objekts) mit der höchsten Wahrscheinlichkeit wird überlagert und im Fenster angezeigt.
Laden Sie die zuvor erstellte "trainierte_net.ckpt".
** [⚠Hinweis] Wenn Sie keine Obergrenze für die Stapelgröße festlegen (die Anzahl der gleichzeitig zu erkennenden Objekte), friert der Raspeltorte möglicherweise ein, wenn Sie versuchen, eine große Anzahl erkannter Bereiche gleichzeitig zu verarbeiten. ** **.
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
#Im Pytorch-Verzeichnis"export OMP_NUM_THREADS=1 or 2 or 3"Verpflichtend(Der Standardwert ist 4)
#Die Anzahl der Parallelverarbeitungskerne"print(torch.__config__.parallel_info())"Bestätigen mit
import torch.nn as nn
import torch.utils
from torchvision import transforms
CKPT_NET = 'trained_net.ckpt' #Geschulte Parameterdatei
OBJ_NAMES = ['Phone', 'Wallet', 'Watch'] #Anzeigename jeder Klasse
MIN_LEN = 50
GRAY_THR = 20
CONTOUR_COUNT_MAX = 3 #Chargengröße(Anzahl der Objekte, die gleichzeitig erkannt werden sollen)Obergrenze von
SHOW_COLOR = (255, 191, 0) #Rahmenfarbe(B,G,R)
NUM_CLASSES = 3
PIXEL_LEN = 112 #Größe nach Größenänderung(1 Seite)
CHANNELS = 1 #Anzahl der Farbkanäle(BGR:3,Graustufen:1)
#Definition der Bilddatenkonvertierung
#Mit Größe ändern,Bezogen auf die erste lineare Eingabe des Klassifikators
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):
"""Netzwerkdefinition.Muss mit dem zum Lernen verwendeten identisch sein"""
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):
"""
Mit OpenCV Hintergrunddifferenzverarbeitung,Erstellen Sie einen Tapple mit erkannten Objekten
Streit:
back:Hintergrundbild eingeben
Farbbild
target:Bild für Hintergrundunterschied
Farbbild.Schneiden Sie mehrere Objekte aus,In einem Farbbild Taple zusammenfügen
"""
print('Detecting objects ...')
#Binarisierung
b_gray = cv2.cvtColor(back, cv2.COLOR_BGR2GRAY)
t_gray = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
#Berechnen Sie die Differenz
diff = cv2.absdiff(t_gray, b_gray)
#Kontur entsprechend der Schwelle,Erstellen Sie eine Maske,Objekte extrahieren
#Der Index von findContours ist, 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]
#Koordinaten des Änderungsbereichs über einer bestimmten Höhe und Breite erfasst,Größenstapel erstellen
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]
#Schneiden Sie den Rahmen gemäß den Positionsinformationen aus,In ein Tupel PIL-Bild konvertieren und zurückkehren
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):
"""
Transformieren Sie das Tupel des Bilds im PIL-Format,Konvertieren Sie in einen Tensor-Batch, der im Netzwerk verarbeitet werden kann
Streit:
tuple_images:PIL Bild Taple
transform:Definition der Fackelbildkonvertierung
"""
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):
"""
Bestimmen Sie das Objekt aus der Wahrscheinlichkeit, zu jeder Klasse zu gehören,Zeigen Sie den Rahmen und den Namen an dieser Position an,Gibt den Index der Klasse zurück
Streit:
probs_list:Sekundäres Array von Wahrscheinlichkeiten.Stapelformat
pos_list:Sekundäre Anordnung von Positionen.Stapelformat
"""
print('Judging objects ...')
#Konvertieren Sie in eine Liste der höchsten Wahrscheinlichkeiten und ihrer Indizes
ip_list = list(map(lambda x: max(enumerate(x), key = lambda y:y[1]),
F.softmax(probs_list, dim=-1))) # <- 4/30 Korrekturen
#Index in Objektnamen konvertieren,Schreiben Sie den Objektnamen und die Sicherheit an der Position des Objekts und zeigen Sie sie an
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():
"""Geschulte Modellbeladung->Testdaten lesen->Einstufung->Zeigen Sie das dem Bild überlagerte Ergebnis an"""
#Geräteeinstellungen
device = 'cuda' if torch.cuda.is_available() else 'cpu'
#Netzwerkeinstellungen
net = NeuralNet(NUM_CLASSES).to(device)
#Geschulte Datenerfassung
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))
#Bewertungsmodus
net.eval()
#Starten Sie picamera
with picamera.PiCamera() as camera:
camera.resolution = (480, 480)
#Starten Sie das Streaming
with picamera.array.PiRGBArray(camera) as stream:
print('Setting background ...')
sleep(2)
camera.exposure_mode = 'off' #Weißabgleich behoben
camera.capture(stream, 'bgr', use_video_port=True)
#Als Hintergrundsbild festlegen
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)
#Hintergrundunterschied für zukünftige Eingabebilder
img_target = stream.array
#Erkennt Objekte und ihre Positionen
obj_imgs, positions = detect_obj(img_back, img_target)
if obj_imgs:
#Konvertieren Sie erkannte Objekte in das Netzwerkeingabeformat
obj_batch = batch_maker(obj_imgs, data_transforms)
#Einstufung
outputs = net(obj_batch)
#Beurteilung
result = judge_what(img_target, outputs, positions)
print(' Result:', result)
#Anzeige
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()
Bringen Sie die vorherige "trainierte_net.ckpt" auf den Raspelkuchen und führen Sie sie im selben Verzeichnis aus. Der Name des erkannten Objekts und seine Sicherheit werden angezeigt.
Das Ausführungsergebnis ist ... Ich bin von dem Moment an mit der hochpräzisen Klassifizierung zufrieden! !!
➡ ➡
** [⚠Hinweis] Es wird empfohlen, die Anzahl der für die Ausführung verwendeten Kerne zu ändern (Standard 4). ** **.
Bei Verwendung mit 4 vollen Kernen besteht eine große Frostgefahr.
Ändern Sie den Befehl im Pytorch-Verzeichnis in "export OMP_NUM_THREADS = 2" (mit 2 Kernen). Sie können die Anzahl der Kerne mit print (torch .__ config __. Parallel_info ())
überprüfen.
Wenn Sie die Shell jedoch schließen, werden die Änderungen verworfen, um sie dauerhaft zu machen, und zwar unter "... ~ fi" am Ende von ** ". Profil" ** in "/ home / pi", "exportiere OMP_NUM_THREADS" Schreiben Sie = 2` und starten Sie neu.
Ich konnte machen was ich wollte! (Es tut mir leid für die mangelnde Lesbarkeit ...) Wenn Sie die OpenCV-Gesichtserkennung verwenden, können Sie sie anscheinend sofort auf die sehr einfache Gesichtserkennung anwenden.
Ursprünglich dachte ich über die Implementierung von SSD nach, aber ich dachte, es wäre schwierig, einen Datensatz mit Standortinformationen zu erstellen, und gab auf, weil ich den Fehler, den ich beim Training mit Beispieldaten bekam, nicht lösen konnte. ..
Im Gegensatz zu SSDs besteht der Nachteil darin, dass der Hintergrundunterschied diesmal nicht die Trennung der überlappenden Objekte ermöglicht und als eins beurteilt wird.
Es war eine gute Studie ~
Recommended Posts