Dans l'article précédent, j'ai résumé comment créer un environnement pour exécuter du code Python en C ++. Exécutez Python en C ++ sur Visual Studio 2017 Je ne pense pas que vous puissiez comprendre ** merci ** d'avoir appelé Python en C ++ à partir de cet article uniquement. Par conséquent, j'aimerais exécuter YOLO v3 qui peut détecter des objets par apprentissage en profondeur. Vous pouvez utiliser le modèle d'apprentissage en profondeur en C ++, mais ce n'est pas aussi bon que le Python actuel (pleurer).
・ Système d'exploitation: windos10 64 bits -CPU: Intel i3-8100 ・ GPU: NVIDIA GeForce GTX 1050 Ti ・ Visual Studio 2017 ・ C ++ ・ Python 3.7.3 Article précédent a des spécifications plus élevées que l'environnement ().
Les deux constructions d'environnement suivantes sont requises comme prérequis. Nous travaillerons sur chaque construction une fois qu'elle sera terminée. -Reportez-vous à l'article suivant pour savoir comment créer un environnement qui appelle Python en C ++. Exécutez Python en C ++ sur Visual Studio 2017 -Vérifiez l'article suivant pour savoir comment créer un environnement qui vous permet d'utiliser le GPU avec Python. Préférences tensorflow-gpu
Je voudrais continuer avec le flux suivant. Si vous le souhaitez, rejoignez-nous. Ceux qui sont venus des articles précédents peuvent sauter certaines étapes.
Je souhaite extraire le fichier directement sous le lecteur C.
URL
git clone https://github.com/yusa0827/200121_Cplus2_with_Python
La méthode est 2.
En regardant le contenu du dossier DL, il y a un fichier .sln. Parce que l'exemple de programme est inclus dans .sln Double-cliquez ici ou Faites un clic droit ⇒ Ouvrir à partir du programme ⇒ Cliquez sur Microsoft Visual Studio 2017 Ensuite, vous pouvez démarrer l'exemple de programme dans Visual Studio. Ce programme est construit avec ver2017. Je pense qu'il peut être utilisé en 2019, mais d'ici 2019 Je dois le déposer dans la version 2017.
Vous devez modifier le chemin de l'environnement.
1.Configuration de la solution et plateforme de solution
Changé de Debug à Release
x86 → x64
2. C++→ Général → Inclure supplémentaire
C:\boost_1_70_0
C:\Users\○○\AppData\Local\Programs\Python\Python37\include
↑ Correction requise
3. C++→ Génération de code → Avec bibliothèque d'exécution
Multithread (/Changer en MT)
4.Linker → Général → Répertoire de bibliothèque supplémentaire
C:\boost_1_70_0\stage\lib\x64
C:\Users\○○\AppData\Local\Programs\Python\Python37\libs
↑ Correction requise
Le résultat de l'exécution est le suivant.
Si cela ne fonctionne pas, vérifiez le chemin de votre environnement.
YOLOv3 est une méthode de détection d'objets qui utilise l'apprentissage en profondeur et se caractérise par ses excellentes performances en temps réel. Cette fois, nous utiliserons la version keras couramment utilisée. Beaucoup de gens apprennent à l'utiliser, donc si vous le recherchez sur Google, ce sera un coup, mais je vais le décrire.
URL
git clone https://github.com/qqwweee/keras-yolo3.git
Accédez à ce répertoire. (Cd keras-yolov3) Les modules requis pour Python incluent Tensorflow, Keras, Matplotlib, Pillow et opencv (installés avec opencv-python). Si vous ne l'avez pas encore installé sur python, veuillez l'installer avec pip.
Vous pouvez également DL directement à partir de l'URL suivante sans utiliser wget. Après le téléchargement, placez-le dans le dossier keras-yolo3. Nom du fichier: yolov3.weights Taille: 237MB
URL
wget https://pjreddie.com/media/files/yolov3.weights
Passez à la version keras. Entrez le code suivant sur l'invite de commande.
python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5
Le résultat de l'exécution est le suivant.
:
:
conv2d_75 (Conv2D) (None, None, None, 2 65535 leaky_re_lu_72[0][0]
==================================================================================================
Total params: 62,001,757
Trainable params: 61,949,149
Non-trainable params: 52,608
__________________________________________________________________________________________________
None
Saved Keras model to model_data/yolo.h5
Read 62001757 of 62001757.0 from Darknet weights.
C:\demo_Cplus2_Py_YOLOv3\keras-yolo3>
Cette fois, nous utiliserons une webcam. Vous pouvez utiliser une vidéo au lieu d'une caméra, mais j'ai choisi cette option car la caméra était plus facile à vérifier.
Modifiez facilement yolo.py, le code principal pour la détection d'objets. C'est autour de la 173ème ligne.
yolo.py
import cv2
vid = cv2.VideoCapture(video_path)
#↓ Corrigé ci-dessous
import cv2
#vid = cv2.VideoCapture(video_path)
vid = cv2.VideoCapture(0)
Si vous donnez 0 à l'argument de VideoCapture, vous avez sélectionné l'appareil photo. Modifiez le code et exécutez YOLO V3.
Code d'exécution.
cmd
python yolo_video.py
Résultat de l'exécution. Doraemon semble être un ballon de sport.
J'ai pu confirmer que YOLO v3 fonctionne. Ensuite, je vais imaginer d'extraire le code Pyhton en C ++.
Afin d'appeler YOLOv3 à partir de C ++, nous devons concevoir certaines choses. L'un d'eux est de définir l'objet généré à partir de la classe YOLO sur C ++. Normalement, la détection d'objet doit être effectuée en Python, mais si vous ne créez pas d'objet, vous devrez appeler Tensoflow à chaque fois que vous détectez un objet, ce qui entraînera un retard important. Il faut environ 15 secondes sur mon PC pour lancer Tensorflow. Par conséquent, en créant un objet YOLO à l'avance, il est possible d'empêcher chaque appel.
Modifiez le yolo.py.
Détectez les objets avec une webcam.
Préparez le fichier visul stusio cloné git et le fichier keras-yolo3. Copiez uniquement les fichiers keras-yolo3 requis pour la détection d'objet dans le fichier visul stusio. La configuration est la suivante. Modifiez les fichiers marqués d'un cercle. De plus, les fichiers requis pour YOLO v3 ont été placés directement sous le lecteur C.
Lecteur C ── modèle_data
│ ├── yolo.h5 ← keras-modèle yolo3_Existe dans le dossier de données
│ ├── yolo_anchors.txt ← keras-modèle yolo3_Existe dans le dossier de données
│ ├── coco_classes.txt ← keras-modèle yolo3_Existe dans le dossier de données
│ └── FiraMono-Medium.otf ← keras-Existe dans le dossier des polices de yolo3
│
└─ 200121_Cplus2_with_Python
├── test_Cplus2_with_Python
│ ├── test_Cplus2_with_Python.cpp 〇
│ ├── x64
│ └── others
├── x64
│ └── Release
│ ├── test_Cplus2_with_Python.exe
│ ├── yolo3 ← keras-Existe dans le dossier yolo3
│ ├── yolo.py 〇 ← keras-Existe dans le dossier yolo3
│ └── others
├── (others( .git .vs))
└── test_Cplus2_with_Python.sln
Il y a deux cercles dans la structure du fichier. C'est la partie principale du code de C ++ et Python, respectivement. Modifiez chacun comme suit.
J'ai apporté quelques corrections à l'article précédent. Il définit les fichiers py Python, les fonctions de fichier py, les objets, etc. Fondamentalement, c'est un type automatique et C ++ décide. Avant de tourner avec while, l'objet YOLO est défini à l'avance. Dans while, exécutez uniquement la fonction de détection d'objet de Pytohn. Si vous souhaitez ajouter un autre traitement original, insérez le code dans un endroit approprié.
test_Cplus2_with_Python.cpp
#define BOOST_PYTHON_STATIC_LIB
#define BOOST_NUMPY_STATIC_LIB
#include <iostream>
#include <boost/python.hpp>
//Définir l'espace de noms
namespace py = boost::python;
/*YOLO v3 C++Courir*/
int main()
{
//Initialiser Python
Py_Initialize();
//Fichier py YOLO v3(yolo.py)Importer
py::object YOLOv3 = py::import("yolo").attr("__dict__");
//yolo.En py"object_YOLOv3"Définir la fonction
auto object_YOLOv3 = YOLOv3["object_YOLOv3"];
//object_Définir des variables d'objet dans la fonction YOLOv3
py::object object_YOLOv3_init;
//object_Initialiser les variables d'objet dans la fonction YOLOv3
auto object_YOLOv3_maker = object_YOLOv3(object_YOLOv3_init);
//Définir une fonction pour la détection d'objets
auto insert_object_YOLOv3 = YOLOv3["insert_object_YOLOv3"];
//Valeur observée
double py_y;
/*Détection d'objets en temps réel par YOLO v3*/
while (true) {
//Déplacement sur l'axe X du centre détecté par l'objet par apprentissage profond
auto x_centor = insert_object_YOLOv3(object_YOLOv3_maker);
//Déplacement C++Convertir en un type pouvant être utilisé dans
py_y = py::extract<double>(x_centor);
/*
Si vous souhaitez traiter d'autres choses, décrivez de manière appropriée
*/
//commentaire
std::cout << "py_y = " << py_y << std::endl;
}
}
Afin d'obtenir l'image de la webcam, l'objet qui a ouvert la webcam est défini dans l'initialisation (init) de la classe YOLO. De plus, le centre de l'axe horizontal qui a détecté l'objet est calculé et renvoyé. De plus, "1_fonction pour initialiser les objets" et "2_fonction pour détecter les objets" sont nouvellement ajoutées.
yolo.py
# -*- coding: utf-8 -*-
"""
Class definition of YOLO_v3 style detection model on image and video
"""
import colorsys
import os
from timeit import default_timer as timer
import numpy as np
from keras import backend as K
from keras.models import load_model
from keras.layers import Input
from PIL import Image, ImageFont, ImageDraw
from yolo3.model import yolo_eval, yolo_body, tiny_yolo_body
from yolo3.utils import letterbox_image
import os
from keras.utils import multi_gpu_model
#ajouter à
import cv2
#Ajouté: Limitation de l'utilisation de la mémoire GPU de TensorFlow
import tensorflow as tf
from keras.backend.tensorflow_backend import set_session
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.3
set_session(tf.Session(config=config))
#Ajouter une définition de variable globale
model_path_ = 'C:/model_data/yolo.h5'
anchors_path_ = 'C:/model_data/yolo_anchors.txt'
classes_path_ = 'C:/model_data/coco_classes.txt'
font_path_ = 'C:/model_data/FiraMono-Medium.otf'
class YOLO(object):
_defaults = {
"model_path": model_path_,#point de changement
"anchors_path": anchors_path_,#point de changement
"classes_path": classes_path_,#point de changement
"score" : 0.3,
"iou" : 0.45,
"model_image_size" : (416, 416),
"gpu_num" : 1,
}
@classmethod
def get_defaults(cls, n):
if n in cls._defaults:
return cls._defaults[n]
else:
return "Unrecognized attribute name '" + n + "'"
def __init__(self, **kwargs):
self.__dict__.update(self._defaults) # set up default values
self.__dict__.update(kwargs) # and update with user overrides
self.class_names = self._get_class()
self.anchors = self._get_anchors()
self.sess = K.get_session()
self.boxes, self.scores, self.classes = self.generate()
#Caméra ajoutée ouverte
self.cap = cv2.VideoCapture(0)
def _get_class(self):
classes_path = os.path.expanduser(self.classes_path)
with open(classes_path) as f:
class_names = f.readlines()
class_names = [c.strip() for c in class_names]
return class_names
def _get_anchors(self):
anchors_path = os.path.expanduser(self.anchors_path)
with open(anchors_path) as f:
anchors = f.readline()
anchors = [float(x) for x in anchors.split(',')]
return np.array(anchors).reshape(-1, 2)
def generate(self):
model_path = os.path.expanduser(self.model_path)
assert model_path.endswith('.h5'), 'Keras model or weights must be a .h5 file.'
# Load model, or construct model and load weights.
num_anchors = len(self.anchors)
num_classes = len(self.class_names)
is_tiny_version = num_anchors==6 # default setting
try:
self.yolo_model = load_model(model_path, compile=False)
except:
self.yolo_model = tiny_yolo_body(Input(shape=(None,None,3)), num_anchors//2, num_classes) \
if is_tiny_version else yolo_body(Input(shape=(None,None,3)), num_anchors//3, num_classes)
self.yolo_model.load_weights(self.model_path) # make sure model, anchors and classes match
else:
assert self.yolo_model.layers[-1].output_shape[-1] == \
num_anchors/len(self.yolo_model.output) * (num_classes + 5), \
'Mismatch between model and given anchor and class sizes'
print('{} model, anchors, and classes loaded.'.format(model_path))
# Generate colors for drawing bounding boxes.
hsv_tuples = [(x / len(self.class_names), 1., 1.)
for x in range(len(self.class_names))]
self.colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples))
self.colors = list(
map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)),
self.colors))
np.random.seed(10101) # Fixed seed for consistent colors across runs.
np.random.shuffle(self.colors) # Shuffle colors to decorrelate adjacent classes.
np.random.seed(None) # Reset seed to default.
# Generate output tensor targets for filtered bounding boxes.
self.input_image_shape = K.placeholder(shape=(2, ))
if self.gpu_num>=2:
self.yolo_model = multi_gpu_model(self.yolo_model, gpus=self.gpu_num)
boxes, scores, classes = yolo_eval(self.yolo_model.output, self.anchors,
len(self.class_names), self.input_image_shape,
score_threshold=self.score, iou_threshold=self.iou)
return boxes, scores, classes
#Correction C++Correction de la position de détection d'objet pour
def detect_image_for_Cplus2(self, image):
if self.model_image_size != (None, None):
assert self.model_image_size[0]%32 == 0, 'Multiples of 32 required'
assert self.model_image_size[1]%32 == 0, 'Multiples of 32 required'
boxed_image = letterbox_image(image, tuple(reversed(self.model_image_size)))
else:
new_image_size = (image.width - (image.width % 32),
image.height - (image.height % 32))
boxed_image = letterbox_image(image, new_image_size)
image_data = np.array(boxed_image, dtype='float32')
image_data /= 255.
image_data = np.expand_dims(image_data, 0) # Add batch dimension.
out_boxes, out_scores, out_classes = self.sess.run(
[self.boxes, self.scores, self.classes],
feed_dict={
self.yolo_model.input: image_data,
self.input_image_shape: [image.size[1], image.size[0]],
K.learning_phase(): 0
})
font = ImageFont.truetype(font=font_path_,
size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32'))
thickness = (image.size[0] + image.size[1]) // 300
#Déplacement X de l'objet
self.x_centor = .0
for i, c in reversed(list(enumerate(out_classes))):
predicted_class = self.class_names[c]
box = out_boxes[i]
score = out_scores[i]
label = '{} {:.2f}'.format(predicted_class, score)
draw = ImageDraw.Draw(image)
label_size = draw.textsize(label, font)
#Il y a une position du centre de gravité ici
top, left, bottom, right = box
top = max(0, np.floor(top + 0.5).astype('int32'))
left = max(0, np.floor(left + 0.5).astype('int32'))
bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))
right = min(image.size[0], np.floor(right + 0.5).astype('int32'))
print(label, (left, top), (right, bottom))
#centre de gravité axe x x_centor = ( x1 + x2 ) / 2
self.x_centor = ( left + right ) / 2.
if top - label_size[1] >= 0:
text_origin = np.array([left, top - label_size[1]])
else:
text_origin = np.array([left, top + 1])
# My kingdom for a good redistributable image drawing library.
for i in range(thickness):
draw.rectangle(
[left + i, top + i, right - i, bottom - i],
outline=self.colors[c])
draw.rectangle(
[tuple(text_origin), tuple(text_origin + label_size)],
fill=self.colors[c])
draw.text(text_origin, label, fill=(0, 0, 0), font=font)
del draw
return image, self.x_centor
def close_session(self):
self.sess.close()
# 1_Fonction d'initialisation d'un objet
def object_YOLOv3(object_YOLO):
#Créer un objet à partir d'une classe
object_YOLO = YOLO()
#C++Renvoie un objet yolo à
return object_YOLO
# 2_Fonction de détection d'objets
def insert_object_YOLOv3(object_YOLO):
#Obtenir l'image de la caméra
ret, frame = object_YOLO.cap.read()
#Changer l'ordre de RGGB
frame = np.asarray(frame)[..., ::-1]
#Passer de l'ouverture à l'oreiller
frame = Image.fromarray(frame)
#Détecte un objet et renvoie le résultat de sortie et le centre de l'axe des x de l'objet
r_image, x_centor = object_YOLO.detect_image_for_Cplus2(frame)
#Affichage de l'image
cv2.imshow("out",np.asarray(r_image)[..., ::-1])
#1 ms pour afficher
cv2.waitKey(1)
#C++Renvoie le centre de l'axe des x de l'objet
return x_centor
Puisqu'il utilise un modèle entraîné, il est détecté en tant que personne, etc.
Puisqu'il s'agit d'un exemple de programme, même si vous souhaitez utiliser le modèle d'origine, vous pouvez l'utiliser simplement en modifiant le chemin d'accès dans le fichier py.
Quand dois-je appeler Python en C ++ ... Je pense que certaines personnes sont inquiètes. La raison est -Lorsque vous souhaitez vraiment intégrer le traitement du deep learning sur un appareil compatible C ++ (carte de contrôle de mouvement, etc.) ・ Un ingénieur préféré (personne étrange) qui ne peut pas quitter C ++ ・ Quoi qu'il en soit, bizarre C'est tout pour la blague.
Nous espérons sincèrement qu'il sera utile pour ceux qui s'inquiètent de la dépendance environnementale entre les langues du programme.
Recommended Posts