Créer un nouveau module

Créer un nouveau module#

Dans ce tutoriel, nous allons voir comment créer un module en utilisant le cas précis de la détection d’un objet rouge via la caméra.

Le code#

Code pour ColorDetector.h
 1/**
 2* @file ColorDetector.h
 3*
 4* This file declares a module that detects red color in images with opencv.
 5*
 6* @author Louis Le Lay
 7*/
 8
 9#include "Representations/Infrastructure/CameraInfo.h"
10#include "Representations/Infrastructure/CameraImage.h"
11#include "Representations/Perception/ColorDetects/ColorDetect.h"
12
13#include <opencv2/dnn.hpp>
14#include <opencv2/imgproc.hpp>
15#include <opencv2/highgui.hpp>
16
17#include <iostream>
18#include <random>
19#include <set>
20#include <cmath>
21#include <algorithm>  // for std::min, std::max
22
23
24MODULE (ColorDetector,
25{,
26    REQUIRES(CameraInfo),
27    REQUIRES(CameraImage),
28    PROVIDES(ColorDetect),
29});
30
31class ColorDetector : public ColorDetectorBase
32{
33private:
34    inline unsigned char clamp(int value);
35    BGRImage getBGRImage();
36    cv::Mat BGRImageToMat(const BGRImage &img);
37    bool getRedColor(const cv::Mat &image);
38
39/**
40 * This method is called when the representation provided needs to be updated.
41 * @param ColorDetect The representation updated.
42 */
43    void update(ColorDetect& theColorDetect) override;
44};
Code pour ColorDetector.cpp
  1/**
  2* @file ColorDetector.cpp
  3*
  4* This file declares a module that detects red color in images with opencv.
  5*
  6* @author Louis Le Lay
  7*/
  8
  9#include "ColorDetector.h"
 10
 11MAKE_MODULE(ColorDetector, perception);
 12
 13#include "Platform/File.h"
 14
 15
 16/*----- methodes -----*/
 17
 18
 19// Helper function to clamp values between 0 and 255.
 20inline unsigned char ColorDetector::clamp(int value) {
 21    return static_cast<unsigned char>(std::min(255, std::max(0, value)));
 22}
 23
 24BGRImage ColorDetector::getBGRImage() const {
 25    // Create a BGR image with doubled width (each YUYV pixel produces two BGR pixels)
 26    BGRImage ret(width * 2, height);
 27    unsigned char* dest = ret[0];
 28    const PixelTypes::YUYVPixel* src = (*this)[0];
 29
 30    for (unsigned y = 0; y < height; y++) {
 31        for (unsigned x = 0; x < width; x++) {
 32            // Each YUYVPixel contains two Y values and shared U and V.
 33            int y0 = src->y0;
 34            int y1 = src->y1;
 35            int u = src->u;
 36            int v = src->v;
 37
 38            // Conversion formulas from YUV to RGB:
 39            // R = Y + 1.403 * (V - 128)
 40            // G = Y - 0.344 * (U - 128) - 0.714 * (V - 128)
 41            // B = Y + 1.770 * (U - 128)
 42            // We output in BGR order.
 43
 44            // First pixel (using y0)
 45            int r = static_cast<int>(y0 + 1.403 * (v - 128));
 46            int g = static_cast<int>(y0 - 0.344 * (u - 128) - 0.714 * (v - 128));
 47            int b = static_cast<int>(y0 + 1.770 * (u - 128));
 48            dest[0] = clamp(b);
 49            dest[1] = clamp(g);
 50            dest[2] = clamp(r);
 51            dest += 3;
 52
 53            // Second pixel (using y1)
 54            r = static_cast<int>(y1 + 1.403 * (v - 128));
 55            g = static_cast<int>(y1 - 0.344 * (u - 128) - 0.714 * (v - 128));
 56            b = static_cast<int>(y1 + 1.770 * (u - 128));
 57            dest[0] = clamp(b);
 58            dest[1] = clamp(g);
 59            dest[2] = clamp(r);
 60            dest += 3;
 61
 62            // Move to next YUYV pixel
 63            src++;
 64        }
 65    }
 66    return ret;
 67}
 68
 69cv::Mat ColorDetector::BGRImageToMat(const BGRImage &img) {
 70    // Wrap the image data into a cv::Mat without copying:
 71    // Note: Make sure the BGRImage's lifetime covers the cv::Mat usage.
 72    return cv::Mat(img.height, img.width, CV_8UC3, (void*)img.data());
 73}
 74
 75bool ColorDetector::getRedColor(const cv::Mat &image) {
 76    if (image.empty() || image.channels() != 3) {
 77        return false;
 78    }
 79
 80    cv::Mat hsv;
 81    cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
 82
 83    cv::Mat mask1, mask2;
 84    cv::inRange(hsv, cv::Scalar(0, 100, 100), cv::Scalar(10, 255, 255), mask1);
 85    cv::inRange(hsv, cv::Scalar(160, 100, 100), cv::Scalar(180, 255, 255), mask2);
 86
 87    cv::Mat mask = mask1 | mask2;
 88    return cv::countNonZero(mask) > 0;
 89}
 90
 91
 92/*----- méthode particulière au module -----*/
 93
 94void ColorDetector::update(ColorDetect& theColorDetect)
 95{
 96    BGRImage bgrImage;
 97    bgrImage = theColorDetect.getBGRImage();
 98
 99    cv::Mat input;
100    input = BGRImageToMat(bgrImage);
101
102    bool ans;
103    ans = getRedColor(input);
104    theColorDetect.isThereRedColor = ans;
105
106    OUTPUT_TEXT("The red color is there: " << theColorDetect.isThereRedColor);
107}

Explications#

Tout d’abord, il faut savoir qu’un module suit toujours une structure précise. Par exemple :

MODULE(SimpleBallLocator,
{,
    REQUIRES(BallPercept),
    REQUIRES(FrameInfo),
    PROVIDES(BallModel),
    DEFINES_PARAMETERS(
    {,
        (Vector2f)(5.f, 0.f) offset,
        (float)(1.1f) scale,
    }),
});

class SimpleBallLocator : public SimpleBallLocatorBase
{
    void update(BallModel& ballModel)
    {
        if(theBallPercept.wasSeen)
        {
            ballModel.position = theBallPercept.position * scale + offset;
            ballModel.wasLastSeen = theFrameInfo.time;
        }
    }
};

Ensuite, pour notre module de détection d’objets rouges, nous allons procéder comme suit :

  1. Création des fichiers Créez deux fichiers : ColorDetector.h et ColorDetector.cpp que vous placerez dans le dossier Src/Modules/Perception/ColorPerceptors/.

  2. Fichier d’en-tête (*.h*) - Commencez par un commentaire précisant le nom du fichier, l’objectif du module et l’auteur :

    /*
    * @file ColorDetector.h
    *
    * This file declares a module that detects red color in images with opencv.
    *
    * @author Louis Le Lay
    */
    
    • Incluez les représentations nécessaires (CameraInfo, CameraImage, ColorDetect). (Référez-vous au tutoriel Créer une nouvelle représentation pour la création de ColorDetect).

      #include "Representations/Infrastructure/CameraInfo.h"
      #include "Representations/Infrastructure/CameraImage.h"
      #include "Representations/Perception/ColorDetects/ColorDetect.h"
      
    • Déclarez ensuite le module en précisant son nom, les représentations requises (REQUIRES) et celle fournie (PROVIDES). Vous pouvez définir des paramètres si nécessaire, mais ce n’est pas le cas ici.

      MODULE (ColorDetector,
      {,
          REQUIRES(CameraInfo),
          REQUIRES(CameraImage),
          PROVIDES(ColorDetect),
      });
      
    • Déclarez la classe en respectant la convention de nommage (nom du module suivi de Base).

      class ColorDetector : public ColorDetectorBase
      {
          // Déclaration des méthodes et attributs privés
          void update(ColorDetect& theColorDetect) override;
      };
      
  3. Fichier d’implémentation (*.cpp*) - Comme pour le fichier d’en-tête, commencez par un commentaire expliquant le contenu du fichier.

    /**
    * @file ColorDetector.cpp
    *
    * This file declares a module that detects red color in images with opencv.
    *
    * @author Louis Le Lay
    */
    
    • Incluez ensuite le fichier d’en-tête, déclarez le module avec MAKE_MODULE et incluez les outils nécessaires :

      #include "ColorDetector.h"
      
      MAKE_MODULE(ColorDetector, perception);
      
      #include "Platform/File.h"
      
    • Pour la méthode update, notez que nous récupérons la représentation à mettre à jour (theColorDetect), traitons l’image et affectons un booléen pour indiquer si l’objet rouge a été détecté. Pour le débogage, un OUTPUT_TEXT est utilisé.

      void ColorDetector::update(ColorDetect& theColorDetect)
      {
          BGRImage bgrImage;
          bgrImage = theColorDetect.getBGRImage();
      
          cv::Mat input;
          input = BGRImageToMat(bgrImage);
      
          bool ans;
          ans = getRedColor(input);
          theColorDetect.isThereRedColor = ans;
      
          OUTPUT_TEXT("The red color is there: " << theColorDetect.isThereRedColor);
      }
      

En suivant cette logique, vous venez de créer un module qui détecte des objets rouges. Passez maintenant au tutoriel suivant pour créer une représentation.