9.0 KiB
Compter le stock depuis votre appareil IoT - Wio Terminal
Une combinaison des prédictions et de leurs boîtes englobantes peut être utilisée pour compter le stock dans une image.
Compter le stock
Dans l'image ci-dessus, les boîtes englobantes ont un léger chevauchement. Si ce chevauchement était beaucoup plus important, les boîtes englobantes pourraient indiquer le même objet. Pour compter correctement les objets, vous devez ignorer les boîtes avec un chevauchement significatif.
Tâche - compter le stock en ignorant le chevauchement
-
Ouvrez votre projet
stock-counter
s'il n'est pas déjà ouvert. -
Au-dessus de la fonction
processPredictions
, ajoutez le code suivant :const float overlap_threshold = 0.20f;
Cela définit le pourcentage de chevauchement autorisé avant que les boîtes englobantes ne soient considérées comme le même objet. 0.20 définit un chevauchement de 20 %.
-
En dessous de cela, et au-dessus de la fonction
processPredictions
, ajoutez le code suivant pour calculer le chevauchement entre deux rectangles :struct Point { float x, y; }; struct Rect { Point topLeft, bottomRight; }; float area(Rect rect) { return abs(rect.bottomRight.x - rect.topLeft.x) * abs(rect.bottomRight.y - rect.topLeft.y); } float overlappingArea(Rect rect1, Rect rect2) { float left = max(rect1.topLeft.x, rect2.topLeft.x); float right = min(rect1.bottomRight.x, rect2.bottomRight.x); float top = max(rect1.topLeft.y, rect2.topLeft.y); float bottom = min(rect1.bottomRight.y, rect2.bottomRight.y); if ( right > left && bottom > top ) { return (right-left)*(bottom-top); } return 0.0f; }
Ce code définit une structure
Point
pour stocker les points sur l'image, et une structureRect
pour définir un rectangle à l'aide d'une coordonnée en haut à gauche et en bas à droite. Il définit ensuite une fonctionarea
qui calcule la surface d'un rectangle à partir d'une coordonnée en haut à gauche et en bas à droite.Ensuite, il définit une fonction
overlappingArea
qui calcule la surface de chevauchement de 2 rectangles. S'ils ne se chevauchent pas, elle retourne 0. -
En dessous de la fonction
overlappingArea
, déclarez une fonction pour convertir une boîte englobante en unRect
:Rect rectFromBoundingBox(JsonVariant prediction) { JsonObject bounding_box = prediction["boundingBox"].as<JsonObject>(); float left = bounding_box["left"].as<float>(); float top = bounding_box["top"].as<float>(); float width = bounding_box["width"].as<float>(); float height = bounding_box["height"].as<float>(); Point topLeft = {left, top}; Point bottomRight = {left + width, top + height}; return {topLeft, bottomRight}; }
Cela prend une prédiction de l'objet détecteur, extrait la boîte englobante et utilise les valeurs de la boîte englobante pour définir un rectangle. Le côté droit est calculé à partir de la gauche plus la largeur. Le bas est calculé comme le haut plus la hauteur.
-
Les prédictions doivent être comparées entre elles, et si 2 prédictions ont un chevauchement supérieur au seuil, l'une d'elles doit être supprimée. Le seuil de chevauchement est un pourcentage, donc il doit être multiplié par la taille de la plus petite boîte englobante pour vérifier que le chevauchement dépasse le pourcentage donné de la boîte englobante, et non le pourcentage donné de l'image entière. Commencez par supprimer le contenu de la fonction
processPredictions
. -
Ajoutez ce qui suit à la fonction
processPredictions
vide :std::vector<JsonVariant> passed_predictions; for (int i = 0; i < predictions.size(); ++i) { Rect prediction_1_rect = rectFromBoundingBox(predictions[i]); float prediction_1_area = area(prediction_1_rect); bool passed = true; for (int j = i + 1; j < predictions.size(); ++j) { Rect prediction_2_rect = rectFromBoundingBox(predictions[j]); float prediction_2_area = area(prediction_2_rect); float overlap = overlappingArea(prediction_1_rect, prediction_2_rect); float smallest_area = min(prediction_1_area, prediction_2_area); if (overlap > (overlap_threshold * smallest_area)) { passed = false; break; } } if (passed) { passed_predictions.push_back(predictions[i]); } }
Ce code déclare un vecteur pour stocker les prédictions qui ne se chevauchent pas. Il parcourt ensuite toutes les prédictions, créant un
Rect
à partir de la boîte englobante.Ensuite, ce code parcourt les prédictions restantes, en commençant par celle qui suit la prédiction actuelle. Cela empêche les prédictions d'être comparées plus d'une fois - une fois que 1 et 2 ont été comparées, il n'est pas nécessaire de comparer 2 avec 1, seulement avec 3, 4, etc.
Pour chaque paire de prédictions, la surface de chevauchement est calculée. Elle est ensuite comparée à la surface de la plus petite boîte englobante - si le chevauchement dépasse le pourcentage seuil de la plus petite boîte englobante, la prédiction est marquée comme non validée. Si après avoir comparé tous les chevauchements, la prédiction passe les vérifications, elle est ajoutée à la collection
passed_predictions
.💁 C'est une méthode très simpliste pour supprimer les chevauchements, en supprimant simplement la première dans une paire qui se chevauche. Pour du code en production, vous voudriez ajouter plus de logique ici, comme prendre en compte les chevauchements entre plusieurs objets, ou si une boîte englobante est contenue dans une autre.
-
Après cela, ajoutez le code suivant pour envoyer les détails des prédictions validées au moniteur série :
for(JsonVariant prediction : passed_predictions) { String boundingBox = prediction["boundingBox"].as<String>(); String tag = prediction["tagName"].as<String>(); float probability = prediction["probability"].as<float>(); char buff[32]; sprintf(buff, "%s:\t%.2f%%\t%s", tag.c_str(), probability * 100.0, boundingBox.c_str()); Serial.println(buff); }
Ce code parcourt les prédictions validées et imprime leurs détails sur le moniteur série.
-
En dessous de cela, ajoutez du code pour imprimer le nombre d'articles comptés sur le moniteur série :
Serial.print("Counted "); Serial.print(passed_predictions.size()); Serial.println(" stock items.");
Cela pourrait ensuite être envoyé à un service IoT pour alerter si les niveaux de stock sont bas.
-
Téléchargez et exécutez votre code. Pointez la caméra vers des objets sur une étagère et appuyez sur le bouton C. Essayez d'ajuster la valeur
overlap_threshold
pour voir les prédictions ignorées.Connecting to WiFi.. Connected! Image captured Image read to buffer with length 17416 tomato paste: 35.84% {"left":0.395631,"top":0.215897,"width":0.180768,"height":0.359364} tomato paste: 35.87% {"left":0.378554,"top":0.583012,"width":0.14824,"height":0.359382} tomato paste: 34.11% {"left":0.699024,"top":0.592617,"width":0.124411,"height":0.350456} tomato paste: 35.16% {"left":0.513006,"top":0.647853,"width":0.187472,"height":0.325817} Counted 4 stock items.
💁 Vous pouvez trouver ce code dans le dossier code-count/wio-terminal.
😀 Votre programme de compteur de stock a été un succès !
Avertissement :
Ce document a été traduit à l'aide du service de traduction automatique Co-op Translator. Bien que nous nous efforcions d'assurer l'exactitude, veuillez noter que les traductions automatisées peuvent contenir des erreurs ou des inexactitudes. Le document original dans sa langue d'origine doit être considéré comme la source faisant autorité. Pour des informations critiques, il est recommandé de recourir à une traduction professionnelle réalisée par un humain. Nous déclinons toute responsabilité en cas de malentendus ou d'interprétations erronées résultant de l'utilisation de cette traduction.