Compter les personnes avec OpenCV, Python et Ubidots

Le traitement d'images numériques (DIP) connaît une croissance rapide, en grande partie grâce à l'augmentation des techniques d'apprentissage automatique auxquelles les développeurs peuvent accéder via le cloud. La possibilité de traiter des images numériques sur le cloud contourne toute exigence matérielle dédiée, faisant finalement de DIP le choix incontournable. En tant que méthode de traitement d’images la moins chère et la plus polyvalente, le DIP a trouvé de nombreuses applications. L’une des plus courantes est la détection et le comptage des piétons – une mesure utile pour les aéroports, les gares, les magasins de détail, les stades, les événements publics et les musées.

Les compteurs de personnes traditionnels prêts à l'emploi ne sont pas seulement chers : les données qu'ils génèrent sont souvent liées à des systèmes propriétaires qui limitent vos options d'extraction de données et d'optimisation des KPI. À l'inverse, un DIP intégré utilisant votre propre caméra et votre SBC vous permettra non seulement d'économiser du temps et de l'argent, mais vous donnera également la liberté d'adapter votre application aux KPI qui vous intéressent et d'extraire du cloud des informations qui ne seraient pas possibles autrement. .

L'utilisation du cloud pour activer votre application DIP IoT permet une fonctionnalité globale améliorée. Avec des capacités accrues sous forme de visualisations , de rapports, d'alertes et de références croisées avec des sources de données externes (telles que la météo, les prix en direct des fournisseurs ou les systèmes de gestion d'entreprise), DIP donne aux développeurs la liberté qu'ils désirent.

Imaginez un épicier avec un réfrigérateur à glaces : il souhaite suivre le nombre de personnes qui passent et sélectionnent un produit, ainsi que le nombre de fois que la porte a été ouverte et la température interne du réfrigérateur. À partir de ces quelques points de données, un détaillant peut effectuer une analyse de corrélation pour mieux comprendre et optimiser le prix de ses produits et la consommation énergétique globale du réfrigérateur.

Pour démarrer votre application de traitement d'images numériques, Ubidots a créé le didacticiel suivant sur le système de comptage de personnes en utilisant OpenCV et Python pour analyser le nombre de personnes dans une zone donnée . Développez vos applications au-delà du simple comptage de personnes grâce aux ressources supplémentaires de IoT Ubidots . Ici, vous pouvez voir un véritable dashboard de comptage de personnes en direct construit avec Ubidots .

Dans cet article, nous verrons comment implémenter une simple superposition DIP pour créer un compteur de personnes à l'aide d'OpenCV et Ubidots . Cet exemple fonctionne mieux avec n'importe quelle distribution basée sur Linux ainsi que dans un Raspberry Pi, Orange Pi ou des systèmes embarqués similaires.

Pour des demandes d'intégration supplémentaires, contactez le support Ubidots et découvrez comment votre entreprise peut tirer parti de cette technologie à valeur ajoutée.

Table des matières:

  1. Exigences de candidature
  2. Codage – 8 sous-sections
  3. Essai
  4. Création de votre Dashboard
  5. Résultats

1) Conditions de candidature

  • Tout Linux embarqué avec une version dérivée d'Ubuntu
  • Python 3 ou version ultérieure installé sur votre système d'exploitation.
  • OpenCV 3.0 ou supérieur installé sur votre système d'exploitation. Si vous utilisez Ubuntu ou ses dérivés, suivez le tutoriel d'installation officiel ou exécutez la commande ci-dessous :
pip installer opencv-contrib-python
  • Une fois que vous avez installé avec succès Python 3 et OpenCV, vérifiez votre configuration en exécutant ce petit morceau de code (tapez simplement 'python' dans votre terminal) :
importer cv2 cv2.__version__

Vous devriez obtenir un écran d'impression avec votre version d'OpenCV :

  • Installez Numpy en suivant les officielles ou en exécutant simplement la commande ci-dessous :
pip installer numpy
  • Installer imutils
pip installer imutils
  • Demandes d'installation
demandes d'installation pip

2) Codage

Toute la routine de détection et d'envoi des données peut être trouvée ici . Pour une meilleure explication de notre codage, nous diviserons le code en huit sections afin de mieux expliquer chaque aspect du code pour une meilleure compréhension.

Section 1 :

depuis imutils.object_detection importer non_max_suppression importer numpy as np importer imutils importer cv2 requêtes d'importation temps d'importation importer argparse URL_EDUCATIONAL = "http://things. ubidots .com" URL_INDUSTRIAL = "http://industrial.api. ubidots .com" INDUSTRIAL_USER = True # Réglez ceci sur False si vous êtes un utilisateur éducatif TOKEN = "...." # Mettez ici votre Ubidots TOKEN DEVICE = "detector" # Appareil où sera stocké le résultat VARIABLE = "people" # Variable où sera stocké le résultat # SVM pré-entraîné Opencv avec les fonctionnalités des personnes HOG HOGCV = cv2.HOGDescriptor() HOGCV.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())

Dans la section 1, nous importons les bibliothèques nécessaires pour implémenter notre détecteur, imutils est un outil de bibliothèque utile pour DIP et nous permettra d'effectuer différentes transformations à partir de nos résultats, cv2 est notre wrapper OpenCV Python, les requêtes nous permettront d'envoyer nos données/résultats via HTTP vers Ubidots et argparse nous permettront de lire les commandes de notre terminal de commande dans notre script.

IMPORTANT : N'oubliez pas de mettre à jour ce code avec votre TOKEN de compte Ubidots , et si vous êtes un utilisateur éducatif , assurez-vous de définir INDUSTRIAL_USER sur FALSE .

Une fois la bibliothèque importée, nous initialiserons notre descripteur d’objet orienté histogramme. HOG, en bref, est l'une des techniques de détection d'objets les plus populaires et a été implémentée dans plusieurs applications avec des résultats positifs et, heureusement, OpenCV a déjà implémenté de manière efficace pour combiner l'algorithme HOG avec une machine à vecteurs de support. , ou SVM, qui est une technique classique d'apprentissage automatique à des fins de prédiction.

Cette déclaration : cv2.HOGDescriptor_getDefaultPeopleDetector() appelle le modèle pré-entraîné pour la détection des personnes d'OpenCV et alimentera notre fonction d'évaluation des fonctionnalités de la machine à vecteurs de support.

Section 2

def detector(image): ''' @image est un tableau numpy ''' image = imutils.resize(image, width=min(400, image.shape[1])) clone = image.copy() (rects, poids) = HOGCV.detectMultiScale(image, winStride=(8, 8), padding=(32, 32), scale=1.05) # Applique la suppression non maximale du package imutils au coup d'envoi superposé # boxes rects = np.array ([[x, y, x + w, y + h] for (x, y, w, h) in rects]) résultat = non_max_suppression (rects, probs = None, chevauchementThresh = 0,65) résultat de retour

La detector() est l'endroit où la « magie » se produit, elle reçoit une image RVB divisée en trois canaux de couleur. Pour éviter les problèmes de performances, nous redimensionnons l'image à l'aide de imutils , puis appelons la detectMultiScale() à partir de notre objet HOG. La méthode de détection multi-échelle nous permet ensuite d'analyser l'image et de savoir si une personne existe en utilisant le résultat de classification de notre SVM. Les paramètres de cette méthode dépassent le cadre de ce tutoriel, mais si vous souhaitez en savoir plus, reportez-vous à la documentation officielle d'OpenCV ou consultez l'excellente explication d'Adrian Rosebrock .

L'analyse HOG générera des zones de capture (objets détectés), mais parfois ces zones se chevauchent, provoquant des faux positifs ou des erreurs de détection. Pour contourner cette confusion, nous utiliserons l'utilitaire de suppression non-maxima de la imutils pour supprimer les cases qui se chevauchent – ​​comme indiqué ci-dessous :

Images reproduites à partir de https://www.pyimagesearch.com

Section 3 :

def localDetect(image_path) : result = [] image = cv2.imread(image_path) if len(image) <= 0 : print("[ERREUR] n'a pas pu lire votre image locale") return result print("[INFO] Détection people") result = detector(image) # affiche le résultat pour (xA, yA, xB, yB) dans result : cv2.rectangle(image, (xA, yA), (xB, yB), (0, 255, 0 ), 2) cv2.imshow("result", image) cv2.waitKey(0) cv2.destroyAllWindows() renvoie (résultat, image)

Maintenant, dans cette partie de notre code, nous devons définir une fonction pour lire une image à partir d'un fichier local et détecter toutes les personnes qui s'y trouvent. Pour ce faire, vous verrez que j'ai simplement appelé la fonction detector() et ajouté une simple boucle pour peindre les boîtes rondes du détecteur. Il renvoie le nombre de cases détectées et l'image avec la détection peinte. Ensuite, recréez simplement le résultat dans une nouvelle fenêtre du système d’exploitation.

Section 4 :

def cameraDetect(token, device, variable, sample_time=5) : cap = cv2.VideoCapture(0) init = time.time() # Le temps d'échantillonnage autorisé pour Ubidots est de 1 point/seconde si sample_time < 1 : sample_time = 1 while( True): # Capturez le ret image par image, frame = cap.read() frame = imutils.resize(frame, width=min(400, frame.shape[1])) result = detector(frame.copy() ) # affiche le résultat pour (xA, yA, xB, yB) dans le résultat : cv2.rectangle(frame, (xA, yA), (xB, yB), (0, 255, 0), 2) cv2.imshow( 'frame', frame) # Envoie les résultats if time.time() - init >= sample_time: print("[INFO] Envoi des résultats du frame réel") # Convertit l'image en base 64 et l'ajoute au contexte b64 = convert_to_base64( frame) context = {"image": b64} sendTo Ubidots (jeton, périphérique, variable, len(result), context=context) init = time.time() if cv2.waitKey(1) & 0xFF == ord(' q'): break # Quand tout est terminé, relâchez la capture cap.release() cv2.destroyAllWindows() def convert_to_base64(image): image = imutils.resize(image, width=400) img_str = cv2.imencode('.png ', image)(1].tostring() b64 = base64.b64encode(img_str) return b64.decode('utf-8')

Semblable à la fonction de la section 3 , cette de la section 4 appellera la detector() et peindre les boîtes et l'image sera récupérée directement depuis la webcam en utilisant la méthode VideoCapture() Nous avons également légèrement modifié l' officiel pour obtenir des images de la caméra et envoyer les résultats à un Ubidots toutes les « n » secondes (la sendTo Ubidots () sera revue plus loin dans ce tutoriel). La fonction convert_to_base64() convertira votre image en chaîne base 64, cette chaîne est très importante pour regarder nos résultats dans Ubidots en utilisant du code JavaScript dans un widget HTML Canvas.

Article 5 :

def detectorPeople(args): image_path = args["image"] camera = True if str(args["camera"]) == 'true' else False # Routine pour lire l'image locale si image_path != Aucun et pas de caméra : imprimer ("[INFO] Chemin de l'image fourni, tentative de lecture de l'image") (result, image) = localDetect(image_path) print("[INFO] envoi des résultats") # Convertit l'image en base 64 et l'ajoute au contexte b64 = convert_to_base64(image) context = {"image": b64} # Envoie le résultat req = sendTo Ubidots (TOKEN, DEVICE, VARIABLE, len(result), context=context) if req.status_code >= 400 : print("[ERROR ] Impossible d'envoyer des données à Ubidots ") return req # Routine pour lire les images de la webcam si la caméra : print("[INFO] lecture des images de la caméra") cameraDetect(TOKEN, DEVICE, VARIABLE)

Cette méthode est destinée à insérer les arguments via votre terminal et à déclencher une routine qui recherche des personnes dans un fichier image stocké localement ou via votre webcam.

Article 6 :

def buildPayload(variable, valeur, contexte) : return {variable : {"valeur": valeur, "context": contexte}} def sendTo Ubidots (jeton, appareil, variable, valeur, contexte={}, industriel=True) : # Construit le point de terminaison url = URL_INDUSTRIAL si industriel else URL_EDUCATIONAL url = "{}/api/v1.6/devices/{}".format(url, device) payload = buildPayload(variable, value, context) headers = {"X -Auth-Token": jeton, "Content-Type": "application/json"} tentatives = 0 statut = 400 tandis que statut >= 400 et tentatives <= 5 : req = requêtes.post(url=url, en-têtes=en-têtes , json=payload) status = req.status_code tentatives += 1 time.sleep(1) return req

Ces deux fonctions de la section 6 sont l'autoroute pour envoyer vos résultats à Ubidots pour comprendre et visualiser vos données. La première fonction def buildPayload construit la charge utile à l'intérieur de la requête, tandis que la deuxième fonction def sendTo Ubidots reçoit vos Ubidots (TOKEN , la variable et les étiquettes de périphérique) pour stocker les résultats. Qui dans ce cas est la longueur des boîtes rondes détectées par OpenCV. En option, un contexte peut également être envoyé pour stocker les résultats sous forme d'image base64 afin de pouvoir les récupérer ultérieurement.

Article 7 :

def argsParser() : ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", default=Aucun, help="chemin d'accès au répertoire du fichier de test de l'image") ap.add_argument("-c" , "--camera", default=False, help="Définir comme true si vous souhaitez utiliser la caméra") args = vars(ap.parse_args()) return args

Maintenant, dans la section 7 , nous arrivons à la fin de notre analyse de code. La fonction argsParser() analyse simplement et renvoie sous forme de dictionnaire les arguments transmis via votre terminal à notre script. Il y aura deux arguments dans l'analyseur :

  • image : Le chemin d'accès au fichier image dans votre système
  • camera : une variable qui, si elle est définie sur "true", appellera la méthode cameraDetect().

Article 8 :

def main() : args = argsParser() detectPeople(args) if __name__ == '__main__' : main()

La section 8 et le dernier morceau de notre code est la main() qui appelle simplement les arguments depuis la console et lance la routine spécifiée.

N'oubliez pas que l'intégralité du code peut être extraite de Github ici .

3) Tests

Ouvrez votre texte de processeur préféré (sublime-text, bloc-notes, nano, etc.) et copiez et collez le code complet disponible ici . Mettez à jour le code avec votre TOKEN Ubidots et enregistrez votre fichier sous « peopleCounter.py ».

Une fois votre code correctement enregistré, testons les quatre images aléatoires suivantes sélectionnées dans l'ensemble de données Caltech et l'ensemble de données public Pexels :

Pour analyser ces images, vous devez d'abord stocker les images sur votre ordinateur portable ou PC et suivre le chemin pour analyser les images.

python peopleCounter.py PATH_TO_IMAGE_FILE

Dans mon cas, j'ai stocké les images dans un chemin intitulé « ensemble de données ». Pour exécuter une commande valide, exécutez la commande ci-dessous mais avec le chemin de votre image.

python peopleCounter.py -i dataset/image_1.png

Si vous souhaitez prendre des images depuis votre appareil photo au lieu d'un fichier local, exécutez simplement la commande ci-dessous :

python peopleCounter.py -c vrai

Résultats des tests :

En plus de ces contrôles de tests, vous verrez également, en temps réel, les résultats de ces tests stockés dans votre compte Ubidots :

4) Création de votre Dashboard

Nous utiliserons un HTML Canvas pour regarder en temps réel nos résultats, ce tutoriel n'est pas destiné aux widgets HTML Canvas, donc si vous ne savez pas comment les utiliser merci de vous référer aux articles ci-dessous :

Nous utiliserons l'exemple de base en temps réel avec des modifications mineures pour regarder nos images. Ci-dessous vous pouvez voir l'extrait de code du widget

HTML

<img id="img" width="400px" height="auto"/>

JS

prise var ; var srv = " ubidots .com:443"; // var srv = "app. ubidots .com:443" // Décommentez cette ligne si vous êtes un utilisateur éducatif var VAR_ID = "5ab402dabbddbd3476d85967"; // Mettez ici votre var Id var TOKEN = "" // Mettez ici votre jeton $ ( document ).ready(function() { function renderImage(imageBase64){ if (!imageBase64) return; $ ('#img'). attr('src', 'data:image/png;base64, ' + imageBase64); // Fonction pour récupérer la dernière valeur, elle ne s'exécute qu'une seule fois function getDataFromVariable(variable, jeton, rappel) { var url = ' ubidots ' + variable + '/var headers = { 'X-Auth-Token' : jeton, 'Content-Type' : 'application/json' }; $ .ajax({ url : url, méthode : 'GET', en-têtes : en-têtes, données : { page_size : 1 }, succès : function (res) { if (res.results.length > 0){ renderImage(res.results[0].context.image } callback( } }); la connexion au serveur socket = io.connect("https://"+ srv, {path: '/notifications'}); var SubscribedVars = []; // Fonction pour publier l'ID de la variable var SubscribeVariable = function (variable, callback) { // Publie l'ID de variable qui souhaite écouter socket.emit('rt/variables/id/last_value', { variable: variable }); // Écoute les modifications socket.on('rt/variables/' + variable + '/last_value', callback); abonnéVars.push(variable); } ; // Fonction à désinscrire pour l'écoute var unSubscribeVariable = function (variable) { socket.emit('unsub/rt/variables/id/last_value', { variable: variable }); var pst = SubscribedVars.indexOf(variable); if (pst !== -1){subscribedVars.splice(pst, 1); } } ; var connectSocket = function (){ // Implémente la connexion socket.on('connect', function(){ console.log('connect'); socket.emit('authentication', {token: TOKEN}); } ); window.addEventListener('online', function () { console.log('online'); socket.emit('authentication', {token: TOKEN}); }); socket.on('authenticated', function () { console.log('authenticated'); SubscribedVars.forEach(function (variable_id) { socket.emit('rt/variables/id/last_value', { variable : variable_id }) ; }); }); } /* Routine principale */ getDataFromVariable(VAR_ID, TOKEN, function(){ connectSocket(); }); connectSocket(); //connectSocket(); // Abonnez-vous à la variable avec votre propre code. SubscribeVariable(VAR_ID, function(value){ var parsedValue = JSON.parse(value); console.log(parsedValue); // $ ('#img').attr('src', 'data:image/png;base64 , ' + parsedValue.context.image); renderImage(parsedValue.context.image }) });

N'oubliez pas de mettre votre TOKEN et l' ID de la variable au début de l'extrait de code.

BIBLIOTHÈQUES TIERS

Ajoutez les prochaines bibliothèques tierces :

Une fois que vous avez enregistré votre widget, vous devriez obtenir quelque chose comme celui-ci :

5) Résultats

Vous pouvez regarder les dashboards avec les résultats dans ce lien .

Dans cet article, nous avons exploré comment créer un IoT à l'aide de DIP (traitement d'image), OpenCV et Ubidots . Grâce à ces services, votre application DIP est bien plus précise que le PIR ou d'autres capteurs optiques lors de la détection et de l'identification des différences entre des personnes, des lieux ou des objets, vous offrant ainsi un compteur de personnes efficace sans toute la statique liée à la manipulation précoce des données.

Faites-nous savoir ce que vous pensez en laissant Ubidots sur nos forums communautaires ou connectez-vous avec Ubidots simplement avec Facebook , Twitter ou Hackster .

Bon piratage !

Articles suggérés