Pendant mes études, je voulais déplacer le modèle que j'avais créé de manière appropriée dans Touch Designer, alors je l'ai essayé.
Quand je l'essaye, ça ressemble à ça! (Il est différent du modèle utilisé dans cet article, mais il ressemble à ceci)
https://www.youtube.com/watch?v=ycBvOQUzisU
Le référentiel d'exemples est ici!
Au fait, cette fois j'ai écrit un article en supposant Windows, mais cela peut aussi fonctionner sur Mac!
TouchDesigner vous permet d'utiliser Python comme extension (Python 3.7.2 semble fonctionner en interne dans mon environnement).
Vous pouvez utiliser l'interpréteur Python à partir de Dialogues> Textport et DAT.
En pré-installation, vous pouvez utiliser des bibliothèques standard, OpenCV, numpy, etc.
Cette fois, en plus de cela, j'aimerais utiliser une bibliothèque souvent utilisée dans l'apprentissage automatique pour effectuer la détection d'objets dans Touch Desginer.
La façon de le faire est de spécifier le chemin vers la bibliothèque externe dans "Ajouter Python externe au chemin de recherche" de Edition> Préférences afin qu'il puisse être utilisé dans Touch Designer.
Je n'expliquerai pas les détails d'ObjectDetection, mais c'est comme détecter des objets tels que des personnes et des choses comme l'image ci-dessous (entourées d'un carré pour indiquer ce que c'est).
Cette fois, je vais essayer d'utiliser MobileNetv2-SSD, qui fonctionne sur les terminaux mobiles, avec l'esprit d'essayer de gagner des FPS en adoptant un algorithme le plus léger possible!
En tant que bibliothèque (framework) qui gère l'apprentissage automatique (principalement DNN) en Python
Quelque chose existe.
Je traite généralement ** Tensorflow / Keras ** (parfois j'utilise aussi Pytorch), mais cette fois j'utilise ONNX. (Pour être exact, il utilise un environnement d'inférence appelé ONNX Runtime)
La raison en est que dans mon environnement, lors de l'utilisation de Tensorflow ou Pytorch de Python dans TouchDesigner, TouchDesigner se bloque sans lancer de message d'erreur.
Après cela, j'ai essayé ONNX sans aucune utilité et cela a fonctionné, donc je vais l'utiliser! (Je ne connais pas MXNet ...)
Pour le modèle essentiel, nous avons préparé un modèle créé avec Tensorflow et exporté au format ONNX. (Inclus dans Repository)
Une fois que vous avez un environnement de travail, essayez d'installer ONNX!
$conda create -n touchdesigner python=3.7.2
$source activate touchdesigner
$pip install onnxruntime==1.1.0
Cliquez sur Modifier> Préférences pour ouvrir les Préférences.
Cochez "Ajouter Python externe au chemin de recherche" comme indiqué dans l'image ci-dessous, et passez le chemin vers l'environnement virtuel d'Anaconda à "Chemin du module Python 64 bits".
Dans mon environnement, je suivrais le chemin suivant.
C:/Users/T-Sumida/Anaconda3/envs/touchdesigner/Lib/site-packages
Veuillez vous y référer et essayer le chemin!
Maintenant, confirmons que ONNX fonctionne sur Touch Desiger!
Lancez l'interpréteur Python à partir de Dialogues> Textport et DAT, collez-y le code suivant et exécutez-le.
** * Veuillez définir le chemin d'accès au modèle et le chemin de l'image que vous souhaitez essayer de manière appropriée. ** **
import cv2
import numpy as np
import onnxruntime
#numéro de classe du jeu de données coco: nom de la classe
coco_classes = {
1: 'person',
2: 'bicycle',
3: 'car',
4: 'motorcycle',
5: 'airplane',
6: 'bus',
7: 'train',
8: 'truck',
9: 'boat',
10: 'traffic light',
11: 'fire hydrant',
12: 'stop sign',
13: 'parking meter',
14: 'bench',
15: 'bird',
16: 'cat',
17: 'dog',
18: 'horse',
19: 'sheep',
20: 'cow',
21: 'elephant',
22: 'bear',
23: 'zebra',
24: 'giraffe',
25: 'backpack',
26: 'umbrella',
27: 'handbag',
28: 'tie',
29: 'suitcase',
30: 'frisbee',
31: 'skis',
32: 'snowboard',
33: 'sports ball',
34: 'kite',
35: 'baseball bat',
36: 'baseball glove',
37: 'skateboard',
38: 'surfboard',
39: 'tennis racket',
40: 'bottle',
41:'wine glass',
42: 'cup',
43: 'fork',
44: 'knife',
45: 'spoon',
46: 'bowl',
47: 'banana',
48: 'apple',
49: 'sandwich',
50: 'orange',
51: 'broccoli',
52: 'carrot',
53: 'hot dog',
54: 'pizza',
55: 'donut',
56: 'cake',
57: 'chair',
58: 'couch',
59: 'potted plant',
60: 'bed',
61: 'dining table',
62: 'toilet',
63: 'tv',
64: 'laptop',
65: 'mouse',
66: 'remote',
67: 'keyboard',
68: 'cell phone',
69: 'microwave',
70: 'oven',
71: 'toaster',
72: 'sink',
73: 'refrigerator',
74: 'book',
75: 'clock',
76: 'vase',
77: 'scissors',
78: 'teddy bear',
79: 'hair drier',
80: 'toothbrush'
}
#Chargez le modèle
session = onnxruntime.InferenceSession("Spécifiez le chemin d'accès au modèle ONNX")
#Charger l'image
img = cv2.imread("Spécifiez le chemin de l'image que vous souhaitez essayer")
#OpenCV lit les données d'image avec BGR, alors convertissez-les en BGR
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
width, height = img.shape[0], img.shape[1]
img_data = np.expand_dims(img, axis=0)
#Préparation de l'inférence de modèle
input_name = session.get_inputs()[0].name # 'image'
output_name_boxes = session.get_outputs()[0].name # 'boxes'
output_name_classes = session.get_outputs()[1].name # 'classes'
output_name_scores = session.get_outputs()[2].name # 'scores'
output_name_num = session.get_outputs()[3].name # 'number of detections'
#inférence
outputs_index = session.run(
[output_name_num, output_name_boxes, output_name_scores, output_name_classes],
{input_name: img_data}
)
#Recevoir des résultats
output_num = outputs_index[0] #Nombre d'objets détectés
output_boxes = outputs_index[1] #Boîte indiquant l'emplacement de l'objet détecté
output_scores = outputs_index[2] #Probabilité de prédiction de l'objet détecté
output_classes = outputs_index[3] #Numéro de classe de l'objet détecté
#Seuil de probabilité de prédiction
threshold = 0.6
#Convertir les résultats d'inférence en images
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
for detection in range(0, int(output_num[0])):
if output_scores[0][detection] > threshold:
classes = output_classes[0][detection]
boxes = output_boxes[0][detection]
scores = output_scores[0][detection]
top = boxes[0] * width
left = boxes[1] * height
bottom = boxes[2] * width
right = boxes[3] * height
top = max(0, top)
left = max(0, left)
bottom = min(width, bottom)
right = min(height, right)
img = cv2.rectangle(img, (int(left), int(top)), (int(right), int(bottom)), (0,0,255), 3)
img = cv2.putText(
img, "{}: {:.2f}".format(coco_classes[classes], scores),
(int(left), int(top)),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA
)
cv2.imshow('img', img)
k = cv2.waitKey(0)
Lorsque vous l'exécutez, l'image suivante sera dessinée.
Si cela fonctionne bien, ça va!
Ensuite, nous allons le faire fonctionner avec le patch Touch Desiger.
Je vais me référer à cet article (merci!) Et faire une détection d'objet pour l'entrée de l'image de la caméra.
https://qiita.com/komakinex/items/5b84b88d537d393afc98
Le projet lui-même est très simple, et je l'ai fait quelque chose comme recevoir l'entrée de "Video Device In" avec "OP Execute" et dessiner avec la fonction Opencv.
Le contenu de "OP Execute" est le suivant.
# me - this DAT.
# changeOp - the operator that has changed
#
# Make sure the corresponding toggle is enabled in the OP Execute DAT.
import cv2
import numpy as np
import onnxruntime
#Comme c'est le même que le test ci-dessus, il est omis (lors de son utilisation, copiez-le par le haut et utilisez-le)
coco_classes = {
1: 'person',
2: 'bicycle',
...
}
session = onnxruntime.InferenceSession("C:/Users/TomoyukiSumida/Documents/Hatena/ObjetDetection4TD/ssdlite_mobilenetv2.onnx")
def onPreCook(changeOp):
return
def onPostCook(changeOp):
#Chargement des images
frame = changeOp.numpyArray(delayed=True)
arr = frame[:, :, 0:3]
arr = arr * 255
arr = arr.astype(np.uint8)
arr = np.flipud(arr)
width, height = arr.shape[0:2]
image_data = np.expand_dims(arr, axis=0)
#Préparation de l'inférence de modèle
input_name = session.get_inputs()[0].name # 'image'
output_name_boxes = session.get_outputs()[0].name # 'boxes'
output_name_classes = session.get_outputs()[1].name # 'classes'
output_name_scores = session.get_outputs()[2].name # 'scores'
output_name_num = session.get_outputs()[3].name # 'number of detections'
#inférence
outputs_index = session.run([output_name_num, output_name_boxes,
output_name_scores, output_name_classes],
{input_name: image_data})
#Recevoir des résultats
output_num = outputs_index[0] #Nombre d'objets détectés
output_boxes = outputs_index[1] #Boîte indiquant l'emplacement de l'objet détecté
output_scores = outputs_index[2] #Probabilité de prédiction de l'objet détecté
output_classes = outputs_index[3] #Numéro de classe de l'objet détecté
#Seuil de probabilité de prédiction
threshold = 0.6
#Convertir les résultats d'inférence en images
for detection in range(0, int(output_num[0])):
if output_scores[0][detection] > threshold:
classes = output_classes[0][detection]
boxes = output_boxes[0][detection]
scores = output_scores[0][detection]
top = boxes[0] * width
left = boxes[1] * height
bottom = boxes[2] * width
right = boxes[3] * height
top = max(0, top)
left = max(0, left)
bottom = min(width, bottom)
right = min(height, right)
arr = cv2.rectangle(arr, (int(left), int(top)), (int(right), int(bottom)), (0,0,255), 3)
arr = cv2.putText(
arr, "{}: {:.2f}".format(coco_classes[classes], scores),
(int(left), int(top)),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA)
arr = cv2.cvtColor(arr, cv2.COLOR_RGB2BGR)
cv2.imshow('img', arr)
return
def onDestroy():
return
def onFlagChange(changeOp, flag):
return
def onWireChange(changeOp):
return
def onNameChange(changeOp):
return
def onPathChange(changeOp):
return
def onUIChange(changeOp):
return
def onNumChildrenChange(changeOp):
return
def onChildRename(changeOp):
return
def onCurrentChildChange(changeOp):
return
def onExtensionChange(changeOp, extension):
return
Si vous pouvez écrire ceci, spécifiez "Video Device In" dans Monitor OPs de "OP Execute" et activez Post Cook.
**déplacé! ** **
Cette fois, j'ai essayé de déplacer la détection d'objets en utilisant ONNX dans Touch Designer. J'avais des problèmes parce que Tensorflow n'a pas fonctionné pour une raison quelconque, mais je suis content d'avoir réussi à faire quelque chose qui fonctionne.
Cependant, l'exécution de la détection d'objets (et donc de l'apprentissage automatique) dans TouchDesigner présente les inconvénients suivants.
Par conséquent, il est préférable de démarrer un processus Python derrière TouchDesigner et d'envoyer des informations à partir de là avec OSC (cela peut être utile si le multithreading peut être utilisé avec TouchDesigner à l'avenir).
J'ai également essayé le modèle ONNX avec mon propre modèle cette fois, mais il est possible de télécharger le fichier de modèle depuis onnx / model et de l'utiliser. (J'ai également téléchargé mask-rcnn à partir de là et confirmé que cela fonctionne)
De plus, l'inférence à grande vitesse à l'aide du GPU est également possible. (Ce modèle en utilisait un qui fonctionne à grande vitesse même avec un processeur)
$pip install onnxruntime==1.1.0
Au lieu de cela
$pip install onnxruntime-gpu==1.1.0
Si vous installez cela, l'inférence sera effectuée sur le GPU. Est-ce intéressant d'essayer diverses choses?
Le côté expression a été difficile à atteindre, mais je pense que je devrais aborder ce domaine à l'avenir!