SoftBank Robotics documentation What's new in NAOqi 2.8?

Processing images

<< return to C++ examples

Principle

This section explains how to implement an access to NAO’s images when the module is remote.

To retrieve the images, subscribe as usual using a proxy to ALVideoDevice, and specify the framerate, resolution etc.

The image buffer and metadata is returned within an AnyValue. This example shows how to parse the fields of the AnyValue.

Example: ImageService

This example implements a module retrieving images optimally. As an example, the image is stored in a RAW ppm image file.

The whole example is available here: imageservice.zip

Camera definitions:

cameradefs.h

#pragma once

/** \file cameradefs.hpp
 *  \brief vision defines
 */

namespace qi
{
  namespace camera
    {
    /**
    *Camera Model ID
    */
    const int kOV5640  = 3;

    /**
    *Camera Index
    */
    const int kTopCamera = 0;
    const int kBottomCamera = 1;

    /**
    *Format of the image
    */
    const int k16VGA = 4; // 2560*1920
    const int k4VGA  = 3; // 1280* 960
    const int kVGA   = 2;  // 640* 480
    const int kQVGA  = 1;  // 320* 240

    /**
    *ColorSpace
    */
    const int kYuvColorSpace = 0;
    const int kyUvColorSpace = 1;
    const int kyuVColorSpace = 2;
    const int kRgbColorSpace = 3;
    const int krGbColorSpace = 4;
    const int krgBColorSpace = 5;
    const int kHsyColorSpace = 6;
    const int khSyColorSpace = 7;
    const int khsYColorSpace = 8;
    const int kYUV422ColorSpace = 9;
    const int kYUVColorSpace = 10;
    const int kRGBColorSpace = 11;
    const int kHSYColorSpace = 12;
    const int kBGRColorSpace = 13;     // for opencv ease of use
    const int kYYCbCrColorSpace = 14;  // for tiff io implementation
    const int kH2RGBColorSpace = 15;   // H from HSY to RGB in fake colors
    const int kHSMixedColorSpace = 16; // HS and (H +S)/2

    /**
     * Parameter Id (used for camera registers configuration)
     */
    const int kCameraBrightnessID             = 0;
    const int kCameraContrastID               = 1;
    const int kCameraSaturationID             = 2;
    const int kCameraHueID                    = 3;
    const int kCameraGainID                   = 6;
    const int kCameraHFlipID                  = 7;
    const int kCameraVFlipID                  = 8;
    const int kCameraAutoExpositionID         = 11;
    const int kCameraAutoWhiteBalanceID       = 12;
    const int kCameraExposureID               = 17;
    const int kCameraSharpnessID              = 24;
    const int kCameraBacklightCompensationID  = 34;
    const int kCameraAverageLuminanceID       = 39;
    const int kCameraAutoFocusID              = 40;
    const int kCameraFocusID                  = 43;

  } //namespace camera
} // namespace qi

Source:

imageservice.cpp

#include "imageservice.h"
#include "cameradefs.h"

#include <qi/anyobject.hpp>
#include <qi/log.hpp>

#include <fstream>

qiLogCategory("imageService");


ImageService::ImageService(qi::SessionPtr session)
  :_session(session)
{
  _alvideodevice = session->service("ALVideoDevice");
  _camera = _alvideodevice.call<std::string>("subscribe", "CameraTop", qi::camera::kVGA, qi::camera::kRGBColorSpace, 5);
}

ImageService::~ImageService() {
  try {
    _alvideodevice.call<std::string>("unsubscribe", _camera);
  }
  catch (...) {
    qiLogError() << "Error while unsubscribing";
  }
}

void ImageService::imageProcessing() {
  /** Retrieve a pointer to the image. */
  qi::AnyValue imageData = _alvideodevice.call<qi::AnyValue>("getImageRemote",
                                                              _camera);

  /** Parse the AnyValue **/

  int width = imageData.at(0).to<int>();
  int height = imageData.at(1).to<int>();
  int colorspace = imageData.at(3).to<int>();

  qiLogInfo() << "Got an image: width=" << width << ", height=" <<
          height << ", colorspace=" << colorspace;

  long long timestamp =
      (imageData.at(4).to<long long>() * 1000000LL + imageData.at(5).to<long long>()) * 1000LL;

  qiLogInfo() << "Image timestamp: " << timestamp << " ns";

  float leftAngle = imageData.at(8).to<float>();
  float topAngle = imageData.at(9).to<float>();
  float rightAngle = imageData.at(10).to<float>();
  float bottomAngle = imageData.at(11).to<float>();

  qiLogInfo() << "Image angles: " << leftAngle << ", " << topAngle << ", "
                                  << rightAngle << ", " << bottomAngle;

  /** Get the image buffer **/
  std::pair<char*, size_t> imageBuffer = imageData.at(6).content().asRaw();

  qiLogInfo() << "Image size: " << imageBuffer.second << " bytes";

  /** Do whatever processing you want...    **/
  /** Here, writing raw image into a ppm file **/

  std::ofstream outfile("/tmp/testimage.ppm",std::ofstream::binary);

  outfile << "P6\n"
      << width << " " << height << "\n"
      << "255\n";

  outfile.write(imageBuffer.first, imageBuffer.second);
  outfile.close();

}

QI_REGISTER_MT_OBJECT(ImageService, imageProcessing);

Main:

main.cpp

#include <qi/applicationsession.hpp>
#include <boost/shared_ptr.hpp>
#include "imageservice.h"

int main(int argc, char* argv[])
{
  qi::ApplicationSession app(argc, argv);
  app.startSession();
  qi::SessionPtr session = app.session();
  session->registerService("ImageService", qi::AnyObject(boost::make_shared<ImageService>(session)));
  app.run();
  return 0;
}

CMakeLists.txt:

CMakeLists.txt

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

set(_srcs
  main.cpp
  cameradefs.h
  imageservice.h
  imageservice.cpp
)

qi_create_bin(imageservice SRC ${_srcs} DEPENDS QI)