Processing images¶
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:¶
#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
Header:¶
#pragma once
#include <qi/anyobject.hpp>
#include <qi/session.hpp>
#include <string>
class ImageService
{
public:
ImageService(qi::SessionPtr session);
~ImageService();
void imageProcessing();
private:
qi::SessionPtr _session;
qi::AnyObject _alvideodevice;
std::string _camera;
};
Source:¶
#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:¶
#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:¶
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)