Reacting to a vision event: face detected

<< return to C++ examples

This section explains how to implement a module reacted to a complex event and how to retrieve the information stored in this event.

Principle

This example follows the same principle as here Reacting to an event: bumper, but is based on an event generated by ALVideoDevice: FaceDetetected.

This time, the data put into the memory corresponding to the “FaceDetected” key is more complex than aboolean: it is an ALValue containing information about the detected face(s).

To retrieve this information, use a proxy to ALMemory, and retrieve the data stored in the corresponding key.

Example: OnFaceDetection module

This example follows the same principle as here Reacting to an event: bumper, but is based on an event generated by ALVideoDevice: FaceDetetected. This time, the data put into the memory corresponding to the “FaceDetected” key is more complex than a boolean: it is an ALValue containing information about the detected face(s).

This example will make NAO say the number of faces it detects.

The whole example is available here: onfacedetection.zip Header: +++++++

onfacedetection.h

/**
 *
 * This file was generated by Aldebaran Robotics ModuleGenerator
 */

#ifndef ONFACEDETECTION_ONFACEDETECTION_H
#define ONFACEDETECTION_ONFACEDETECTION_H

#include <boost/shared_ptr.hpp>
#include <alcommon/almodule.h>
#include <string>

#include <alproxies/almemoryproxy.h>
#include <alproxies/altexttospeechproxy.h>

#include <althread/almutex.h>

namespace AL
{
  class ALBroker;
}

class OnFaceDetection : public AL::ALModule
{
  public:

    OnFaceDetection(boost::shared_ptr<AL::ALBroker> broker, const std::string& name);

    virtual ~OnFaceDetection();

    virtual void init();

    /**
    * Method called each time a face is detected.
    * Makes NAO say the number of detected faces.
    */
    void callback();

  private:
    /** Memory proxy for event subscription and data access. */
    AL::ALMemoryProxy fMemoryProxy;
    /** TTS proxy to make NAO talk. */
    AL::ALTextToSpeechProxy fTtsProxy;

    /** ALValue containing the information on detected faces. */
    AL::ALValue fFaces;
    /** Current count of detected faces. */
    unsigned int fFacesCount;
    /** Mutex to make the callback function thread-safe. */
    boost::shared_ptr<AL::ALMutex> fCallbackMutex;

};

#endif  // ONFACEDETECTION_ONFACEDETECTION_H

Source file:

onfacedetection.cpp

/**
 *
 * Version : $Id$
 * This file was generated by Aldebaran Robotics ModuleGenerator
 */

#include "onfacedetection.h"

#include <alvalue/alvalue.h>
#include <alcommon/alproxy.h>
#include <alcommon/albroker.h>
#include <althread/alcriticalsection.h>

#include <qi/log.hpp>


OnFaceDetection::OnFaceDetection(
  boost::shared_ptr<AL::ALBroker> broker,
  const std::string& name):
    AL::ALModule(broker, name),
    fMemoryProxy(getParentBroker()),
    fFaces(AL::ALValue()),
    fFacesCount(0),
    fCallbackMutex(AL::ALMutex::createALMutex())
{
  setModuleDescription("This is an autogenerated module, this descriptio needs to be updated.");

  functionName("callback", getName(), "");
  BIND_METHOD(OnFaceDetection::callback);

}

OnFaceDetection::~OnFaceDetection() {}

void OnFaceDetection::init() {
  try {
    /** See if there is any face already detected at initialization. */
    fFaces = fMemoryProxy.getData("FaceDetected");
    if (fFaces.getSize() < 2) {
      qiLogInfo("module.example") << "No face detected" << std::endl;
      fTtsProxy.say("No face detected");
    }
    /** Subscribe to the event FaceDetected, with appropriate callback function. */
    fMemoryProxy.subscribeToEvent("FaceDetected", "OnFaceDetection", "callback");
  }
  catch (const AL::ALError& e) {
    qiLogError("module.name") << e.what() << std::endl;
  }
}

void OnFaceDetection::callback() {
  /** Use a mutex to make it all thread safe. */
  AL::ALCriticalSection section(fCallbackMutex);
  try {
    /** Retrieve the data raised by the event. */
    fFaces = fMemoryProxy.getData("FaceDetected");
    /** Check that there are faces effectively detected. */
    if (fFaces.getSize() < 2 ) {
      if (fFacesCount != 0) {
        qiLogInfo("module.example") << "No face detected" << std::endl;
        fTtsProxy.say("No face detected.");
        fFacesCount = 0;
      }
      return;
    }
    /** Check the number of faces from the FaceInfo field, and check that it has
    * changed from the last event.*/
    if (fFaces[1].getSize() - 1 != fFacesCount) {
      qiLogInfo("module.name") << fFaces[1].getSize() - 1 << " face(s) detected." << std::endl;
      char buffer[50];
      sprintf(buffer, "%d faces detected.", fFaces[1].getSize() - 1);
      fTtsProxy.say(std::string(buffer));
      /** Update the current number of detected faces. */
      fFacesCount = fFaces[1].getSize() - 1;
    }
  }
  catch (const AL::ALError& e) {
    qiLogError("module.name") << e.what() << std::endl;
  }
}

Main:

main.cpp

/**
 * @author
 *
 * \section Description
 * This file was generated by Aldebaran Robotics ModuleGenerator
 */

#include <signal.h>
#include <boost/shared_ptr.hpp>
#include <alcommon/albroker.h>
#include <alcommon/almodule.h>
#include <alcommon/albrokermanager.h>
#include <alcommon/altoolsmain.h>

#include "onfacedetection.h"


#ifdef ONFACEDETECTION_IS_REMOTE
# define ALCALL
#else
# ifdef _WIN32
#  define ALCALL __declspec(dllexport)
# else
#  define ALCALL
# endif
#endif

extern "C"
{
  ALCALL int _createModule(boost::shared_ptr<AL::ALBroker> pBroker)
  {
    // init broker with the main broker instance
    // from the parent executable
    AL::ALBrokerManager::setInstance(pBroker->fBrokerManager.lock());
    AL::ALBrokerManager::getInstance()->addBroker(pBroker);
      AL::ALModule::createModule<OnFaceDetection>( pBroker, "OnFaceDetection" );

    return 0;
  }

  ALCALL int _closeModule()
  {
    return 0;
  }
}

#ifdef ONFACEDETECTION_IS_REMOTE
  int main(int argc, char *argv[])
  {
    // pointer to createModule
    TMainType sig;
    sig = &_createModule;
    // call main
    ALTools::mainFunction("onfacedetection", argc, argv, sig);
  }
#endif

CMakeLists.txt:

The CMakeLists.txt file is:

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(onfacedetection)
find_package(qibuild)

option(ONFACEDETECTION_IS_REMOTE
  "module is compiled as a remote module (ON or OFF)"
  ON)

set(_srcs
  main.cpp
  onfacedetection.h
  onfacedetection.cpp
)

if(ONFACEDETECTION_IS_REMOTE)
  add_definitions(" -DONFACEDETECTION_IS_REMOTE ")
  qi_create_bin(onfacedetection ${_srcs})
else()
  qi_create_lib(onfacedetection SHARED ${_srcs} SUBFOLDER naoqi)
endif()

qi_use_lib(onfacedetection ALCOMMON ALPROXIES ALTHREAD)