Visual Servoing Platform  version 3.2.0 under development (2019-01-17)
vpMomentAlpha Class Reference

#include <visp3/core/vpMomentAlpha.h>

+ Inheritance diagram for vpMomentAlpha:

Public Member Functions

 vpMomentAlpha ()
 
 vpMomentAlpha (const std::vector< double > &mu3_ref, double alpha_ref, double threshold=1e-6)
 
virtual ~vpMomentAlpha ()
 
void compute ()
 
double get () const
 
const char * name () const
 
bool is_ref () const
 
bool is_symmetric () const
 
void printDependencies (std::ostream &os) const
 
Inherited functionalities from vpMoment
const vpMomentObjectgetObject () const
 
void linkTo (vpMomentDatabase &moments)
 
void update (vpMomentObject &object)
 

Protected Member Functions

vpMomentDatabasegetMoments () const
 

Protected Attributes

std::vector< double > values
 

Friends

VISP_EXPORT std::ostream & operator<< (std::ostream &os, const vpMomentAlpha &v)
 

Detailed Description

This class defines the orientation of the object inside the plane parallel to the object.

In general the value of the moment is computed in $ [-\pi/2 ; \pi/2] $ interval by the formula $ \alpha = \frac{1}{2} \mathrm{atan2}(2\mu_{11}, \mu_{20}-\mu_{02}) $.

To obtain a $ [-\pi ; \pi] $ precision for non symetric object, you have to specify a reference information. This reference information is an alpha computed using the previous formula in $ [-\pi/2 ; \pi/2] $. Obtaining this precision comes from third-order centered moments and this reference information.

Therefore there are two modes for vpMomentAlpha and one constructor per mode:

  • Reference mode using the empty constructor vpMomentAlpha(): The vpMomentAlpha doesn't need any additionnal information, it will compute its values from available moments in $ [-\pi/2 ; \pi/2] $.
  • Relative mode using non-empty constructor vpMomentAlpha(std::vector<double>&, double): The vpMomentAlpha is computed in $ [-\pi ; \pi] $ from the available moments and the reference information. By knowing the reference, it may distinguish in-plane rotations of $ \alpha $ from rotations of $ \alpha + \pi $.

The following code demonstrates a calculation of a reference alpha and then uses this alpha to estimate the orientation of the same object after performing a 180 degrees rotation. Therefore the first and second alpha should have opposite values.

#include <visp3/core/vpMomentObject.h>
#include <visp3/core/vpPoint.h>
#include <visp3/core/vpMomentGravityCenter.h>
#include <visp3/core/vpMomentDatabase.h>
#include <visp3/core/vpMomentCentered.h>
#include <visp3/core/vpMomentAlpha.h>
//generic function for printing
void print (double i) { std::cout << i << "\t";}
int main()
{
std::vector<vpPoint> vec_p; // Vector that contains the vertices of the contour polygon
p.set_x(1); p.set_y(1); // Coordinates in meters in the image plane (vertex 1)
vec_p.push_back(p);
p.set_x(2); p.set_y(2); // Coordinates in meters in the image plane (vertex 2)
vec_p.push_back(p);
p.set_x(-3); p.set_y(0); // Coordinates in meters in the image plane (vertex 3)
vec_p.push_back(p);
p.set_x(-3); p.set_y(-1); // Coordinates in meters in the image plane (vertex 4)
vec_p.push_back(p);
vpMomentObject objRef(3); // Reference object. Must be of order 3 because we will
// need the 3rd order centered moments
objRef.setType(vpMomentObject::DENSE_POLYGON); // Object is the inner part of a polygon
objRef.fromVector(vec_p); // Init the dense object with the polygon
vpMomentDatabase dbRef; // Reference database
vpMomentGravityCenter gRef; // Declaration of gravity center
vpMomentCentered mcRef; // Centered moments
vpMomentAlpha alphaRef; // Declare alpha as reference
gRef.linkTo(dbRef); // Add gravity center to database
mcRef.linkTo(dbRef); // Add centered moments
alphaRef.linkTo(dbRef); // Add alpha depending on centered moments
dbRef.updateAll(objRef); // All of the moments must be updated, not just alpha
gRef.compute(); // Compute the moment
mcRef.compute(); // Compute centered moments AFTER gravity center
alphaRef.compute(); // Compute alpha AFTER centered moments.
// The order of values in the vector must be as follows: mu30 mu21 mu12 mu03
std::vector<double> mu3ref = {mcRef.get(3,0), mcRef.get(2,1), mcRef.get(1,2), mcRef.get(0,3)};
std::cout << "--- Reference object ---" << std::endl;
std::cout << "alphaRef=" << vpMath::deg(alphaRef.get()) << " deg" << std::endl << "mu3="; // print reference alpha
std::for_each (mu3ref.begin(), mu3ref.end(), print);
std::cout << std::endl;
vec_p.clear();
p.set_x(-3); p.set_y(1); // Coordinates in meters in the image plane (vertex 4)
vec_p.push_back(p);
p.set_x(-3); p.set_y(0); // Coordinates in meters in the image plane (vertex 3)
vec_p.push_back(p);
p.set_x(2); p.set_y(-2); // Coordinates in meters in the image plane (vertex 2)
vec_p.push_back(p);
p.set_x(1); p.set_y(-1); // Coordinates in meters in the image plane (vertex 1)
vec_p.push_back(p);
vpMomentObject obj(3); // Second object. Order 3 is also required because of the Alpha
// will compare third-order centered moments to given reference.
obj.setType(vpMomentObject::DENSE_POLYGON); // Object is the inner part of a polygon
obj.fromVector(vec_p); // Init the dense object with the polygon
vpMomentDatabase db; // Database
vpMomentGravityCenter g; // Declaration of gravity center
vpMomentCentered mc; // mc containts centered moments
vpMomentAlpha alpha(mu3ref, alphaRef.get()); // Declare alpha as relative to a reference
g.linkTo(db); // Add gravity center to database
mc.linkTo(db); // Add centered moments
alpha.linkTo(db); // Add alpha depending on centered moments
db.updateAll(obj); // All of the moments must be updated
g.compute(); // Compute the moment
mc.compute(); // Compute centered moments AFTER gravity center
alpha.compute(); // Compute alpha AFTER centered moments.
std::cout << "--- current object ---" << std::endl;
std::cout << "alpha=" << vpMath::deg(alpha.get()) << " deg" << std::endl;
return 0;
}

This program outputs:

--- Reference object ---
alphaRef=25.3019 deg
mu3=1.80552 0.921882 0.385828 0.122449
--- current object ---
alpha=-25.3019 deg

There is also testMomentAlpha.cpp example that shows how to compute alpha in the range $ [-\pi ; \pi] $ using arrow images as input. The code is given below:

/****************************************************************************
*
* ViSP, open source Visual Servoing Platform software.
* Copyright (C) 2005 - 2019 by Inria. All rights reserved.
*
* This software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* See the file LICENSE.txt at the root directory of this source
* distribution for additional information about the GNU GPL.
*
* For using ViSP with software that can not be combined with the GNU
* GPL, please contact Inria about acquiring a ViSP Professional
* Edition License.
*
* See http://visp.inria.fr for more information.
*
* This software was developed at:
* Inria Rennes - Bretagne Atlantique
* Campus Universitaire de Beaulieu
* 35042 Rennes Cedex
* France
*
* If you have questions regarding the use of this file, please contact
* Inria at visp@inria.fr
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Description:
* Test some vpMomentAlpha functionalities.
*
* Authors:
* Fabien Spindler
*
*****************************************************************************/
#include <string>
#include <visp3/core/vpMomentObject.h>
#include <visp3/core/vpMomentGravityCenter.h>
#include <visp3/core/vpMomentDatabase.h>
#include <visp3/core/vpMomentCentered.h>
#include <visp3/core/vpMomentAlpha.h>
#include <visp3/core/vpMomentBasic.h>
#include <visp3/io/vpImageIo.h>
int test_moment_alpha(const std::string &name, bool symmetry, const std::vector<int> &vec_angle, double tolerance_deg, double symmetry_threshold=1e-6)
{
std::cout << "** Test " << (symmetry == true ? "symmetric " : "non symmetric ") << name << " object" << std::endl;
// ***************
std::cout << "*** Test symmetry detection from mu 3rd order moments" << std::endl;
// ***************
std::vector<double> mu_ref;
double alpha_ref = 0.;
for(unsigned int i = (unsigned int)vec_angle.size(); i >= 1; --i) {
// Compute reference alpha image <name>-<vec_angle>[i]deg.pgm
std::stringstream ss;
ss << name << "-" << vec_angle[i-1] << "deg.pgm";
std::cout << "Process image " << ss.str() << std::endl;
vpImageIo::read(I, ss.str());
// Consider the case of a reference alpha
{
obj.fromImage(I, 127, vpCameraParameters()); // Init the dense object with the image and corresponding camera parameters
vpMomentDatabase db; // Database
vpMomentGravityCenter mg; // Declaration of gravity center moment
vpMomentCentered mc; // Declaration of centered moments
vpMomentAlpha malpha_ref; // Declaration of alpha reference moments
mg.linkTo(db); // Add gravity center moment to database
mc.linkTo(db); // Add centered moments
malpha_ref.linkTo(db); // Add alpha moment
db.updateAll(obj); // All of the moments must be updated, not just alpha
mg.compute(); // Compute gravity center moment
mc.compute(); // Compute centered moments AFTER gravity center
malpha_ref.compute(); // Compute alpha gravity center
mu_ref.clear();
mu_ref.push_back(mc.get(3,0));
mu_ref.push_back(mc.get(2,1));
mu_ref.push_back(mc.get(1,2));
mu_ref.push_back(mc.get(0,3));
alpha_ref = malpha_ref.get();
}
// Consider the case of a relative alpha
{
obj.fromImage(I, 127, vpCameraParameters()); // Init the dense object with the image and corresponding camera parameters
vpMomentDatabase db; // Database
vpMomentGravityCenter mg; // Declaration of gravity center moment
vpMomentCentered mc; // Declaration of centered moments
vpMomentAlpha malpha(mu_ref, alpha_ref, symmetry_threshold); // Declaration of alpha relative moments
mg.linkTo(db); // Add gravity center moment to database
mc.linkTo(db); // Add centered moments
malpha.linkTo(db); // Add alpha moment
db.updateAll(obj); // All of the moments must be updated, not just alpha
mg.compute(); // Compute gravity center moment
mc.compute(); // Compute centered moments AFTER gravity center
malpha.compute(); // Compute alpha gravity center
if (malpha.is_symmetric() != symmetry) {
std::cout << "Error in symmety detection" << std::endl;
return EXIT_FAILURE;
}
}
}
// ***************
std::cout << "*** Compute angle in relative mode using the last reference from the previous test" << std::endl;
// ***************
for(size_t i = 0; i < vec_angle.size(); i++) {
std::stringstream ss;
ss << name << "-" << vec_angle[i] << "deg.pgm";
std::cout << "Process image " << ss.str() << std::endl;
vpImageIo::read(I, ss.str());
obj.fromImage(I, 127, vpCameraParameters()); // Init the dense object with the image
vpMomentDatabase db; // Database
vpMomentGravityCenter g; // Declaration of gravity center
vpMomentCentered mc; // Centered moments
vpMomentAlpha malpha(mu_ref, alpha_ref, symmetry_threshold); // Alpha moment relative to the reference alpha
g.linkTo(db); // Add gravity center to database
mc.linkTo(db); // Add centered moments
malpha.linkTo(db); // Add alpha depending on centered moments
db.updateAll(obj); // All of the moments must be updated, not just alpha
g.compute(); // Compute the moment
mc.compute(); // Compute centered moments AFTER gravity center
malpha.compute(); // Compute alpha AFTER centered moments.
if (! symmetry) {
// Tranform input angle from [0; 360] to [-180; +180] range
double angle = vec_angle[i];
if (angle > 180)
angle -= 360;
if (angle < -180)
angle += 360;
std::cout << "alpha expected " << angle << " computed " << vpMath::deg(malpha.get()) << " deg" << std::endl;
if (! vpMath::equal(angle, vpMath::deg(malpha.get()), tolerance_deg)) { // 0.5 deg of tolerance
std::cout << "Error: result is not in the tolerance: " << tolerance_deg << std::endl;
return EXIT_FAILURE;
}
}
else {
// Tranform input angle from [0; 360] to [0; 180] range
double angle_des1 = vec_angle[i];
double angle_des2 = vec_angle[i] - 180;
// Tranform input angle from [0; 360] to [0; 180] range
double alpha = vpMath::deg(malpha.get());
std::cout << "alpha expected " << angle_des1 << " or " << angle_des2 << " computed " << alpha << " deg" << std::endl;
if (! vpMath::equal(angle_des1, alpha, tolerance_deg) && ! vpMath::equal(angle_des2, alpha, tolerance_deg)) { // 0.5 deg of tolerance
std::cout << "Error: result is not in the tolerance: " << tolerance_deg << std::endl;
return EXIT_FAILURE;
}
}
}
std::cout << "Test succeed" << std::endl;
return EXIT_SUCCESS;
}
int main()
{
std::string name;
bool symmetry;
double tolerance_deg;
std::vector<int> vec_angle;
double symmetry_threshold;
// *******************************
// Test arrow
// *******************************
name = "arrow";
symmetry = false;
tolerance_deg = 0.5;
vec_angle.clear();
vec_angle.push_back(0);
vec_angle.push_back(45);
vec_angle.push_back(90);
vec_angle.push_back(135);
vec_angle.push_back(180);
vec_angle.push_back(225);
vec_angle.push_back(270);
vec_angle.push_back(315);
if (test_moment_alpha(name, symmetry, vec_angle, tolerance_deg) == EXIT_FAILURE) {
return EXIT_FAILURE;
}
// *******************************
// Test ellipse created with gimp
// *******************************
name = "ellipse";
symmetry = true;
tolerance_deg = 0.5;
vec_angle.clear();
vec_angle.push_back(0);
vec_angle.push_back(45);
vec_angle.push_back(90);
vec_angle.push_back(135);
if (test_moment_alpha(name, symmetry, vec_angle, tolerance_deg) == EXIT_FAILURE) {
return EXIT_FAILURE;
}
// *******************************
// Test ellipse created with xfig
// *******************************
name = "ellipse-xfig";
symmetry = true;
tolerance_deg = 2.5;
symmetry_threshold = 1e-2; // Modify default value
vec_angle.clear();
vec_angle.push_back(0);
vec_angle.push_back(45);
vec_angle.push_back(90);
vec_angle.push_back(135);
if (test_moment_alpha(name, symmetry, vec_angle, tolerance_deg, symmetry_threshold) == EXIT_FAILURE) {
return EXIT_FAILURE;
}
// *******************************
// Test baleine created with gimp
// *******************************
name = "baleine";
symmetry = false;
tolerance_deg = 5.;
vec_angle.clear();
vec_angle.push_back(0);
vec_angle.push_back(45);
vec_angle.push_back(90);
vec_angle.push_back(135);
vec_angle.push_back(180);
vec_angle.push_back(225);
vec_angle.push_back(270);
vec_angle.push_back(315);
if (test_moment_alpha(name, symmetry, vec_angle, tolerance_deg) == EXIT_FAILURE) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

From the first image we compute the 3rd order centered moments and the value of the reference alpha that is than used to compute the alpha moment in the range $ [-\pi ; \pi] $. Running this example you will get:

alpha expected 0 computed -0.128108 deg
alpha expected 45 computed 44.8881 deg
alpha expected 90 computed 89.8719 deg
alpha expected 135 computed 134.888 deg
alpha expected 180 computed 179.872 deg
alpha expected -135 computed -135.112 deg
alpha expected -90 computed -90.1281 deg
alpha expected -45 computed -45.1119 deg

Shortcuts for quickly getting those references exist in vpMomentCommon.

This moment depends on vpMomentCentered.

Examples:
testMomentAlpha.cpp.

Definition at line 207 of file vpMomentAlpha.h.

Constructor & Destructor Documentation

vpMomentAlpha::vpMomentAlpha ( )

Empty constructor. Initializes alpha moment as a reference alpha with a value in $[-\pi/2 ; \pi/2]$. A default-constructed alpha moment may be used as a reference information for other alphas. A reference alpha is a class harbouring an alpha value computed for a $[-\pi/2 ; \pi/2]$ portion of the circle.

Definition at line 51 of file vpMomentAlpha.cpp.

References vpMoment::values.

vpMomentAlpha::vpMomentAlpha ( const std::vector< double > &  mu3_ref,
double  alpha_ref,
double  threshold = 1e-6 
)

Common constructor. Initializes alpha moment as a non-reference alpha with a value computed in $[-\pi ; \pi]$ when the object is non symmetric.

Parameters
mu3_ref: Vector of 3rd order centered moments corresponding to the reference alpha in the following order: $\mu_{30},\mu_{21},\mu_{12},\mu_{03}$.
alpha_ref: Value of the reference alpha that has mu3_ref 3rd order moments.
threshold: Threshold used to determine object symmetry along its 2 axis. The object is declared symmetric if all the four 3rd order centered moments mu3_ref have values lower than this threshold. If the object is symmetric, the alpha angle is commuted in [ $[-\pi/2 ; \pi/2]$]. If the object is non symmetric, the alpha angle is commuted in [ $[-\pi ; \pi]$]

Definition at line 64 of file vpMomentAlpha.cpp.

References vpMoment::values.

virtual vpMomentAlpha::~vpMomentAlpha ( )
inlinevirtual

Definition at line 219 of file vpMomentAlpha.h.

References vpMoment::compute().

Member Function Documentation

void vpMomentAlpha::compute ( )
virtual
double vpMomentAlpha::get ( ) const
inline

Retrieve the orientation of the object as a single double value.

Examples:
testMomentAlpha.cpp.

Definition at line 225 of file vpMomentAlpha.h.

Referenced by vpMomentCommon::getAlpha().

bool vpMomentAlpha::is_ref ( ) const
inline

Returns true if the alpha moment was constructed as a reference with values in $ [-\pi/2 ; \pi/2] $, false otherwise.

Definition at line 234 of file vpMomentAlpha.h.

bool vpMomentAlpha::is_symmetric ( ) const
inline

Returns true if the alpha moment is computed on a symmetric object along its two axis. Symmetry is computed using 3rd order centered moments $\mu_{30},\mu_{21},\mu_{12},\mu_{03}$.

Examples:
testMomentAlpha.cpp.

Definition at line 246 of file vpMomentAlpha.h.

References vpMoment::operator<<, and vpMoment::printDependencies().

void vpMoment::linkTo ( vpMomentDatabase data_base)
inherited

Links the moment to a database of moment primitives. If the moment depends on other moments, these moments must be linked to the same database.

Attention
Two moments of the same class cannot be stored in the same database
#include <visp3/core/vpMomentCentered.h>
#include <visp3/core/vpMomentDatabase.h>
#include <visp3/core/vpMomentGravityCenter.h>
#include <visp3/core/vpMomentObject.h>
#include <visp3/core/vpPoint.h>
int main()
{
std::vector<vpPoint> vec_p;
p.set_x(1); p.set_y(1); // coordinates in meters in the image plane (vertex 1)
vec_p.push_back(p); p.set_x(2); p.set_y(2); // coordinates in meters in the image plane (vertex 2)
obj.setType(vpMomentObject::DISCRETE); // Discrete mode.
obj.fromVector(vec_p); // Init the dense object with the polygon
vpMomentGravityCenter G; // declaration of gravity center
vpMomentCentered mc; // mc containts centered moments
G.linkTo(db); //add gravity center to database
mc.linkTo(db); //centered moments depend on gravity, add them to the
//database to grant access
G.update(obj); // specify the object for gravity center
mc.update(obj); // and for centered moments
G.compute(); // compute the moment
mc.compute(); //compute centered moments AFTER gravity center
return 0;
}
Parameters
data_base: database of moment primitives.
Examples:
mbot-apriltag-ibvs.cpp, and testMomentAlpha.cpp.

Definition at line 98 of file vpMoment.cpp.

References vpException::memoryAllocationError, and vpMoment::name().

Referenced by vpMomentCommon::getAlpha(), vpMomentCommon::getMu3(), vpMomentCommon::getSurface(), and vpMomentCommon::vpMomentCommon().

const char* vpMomentAlpha::name ( ) const
inlinevirtual

Moment name.

Implements vpMoment.

Definition at line 229 of file vpMomentAlpha.h.

void vpMomentAlpha::printDependencies ( std::ostream &  os) const
virtual

Prints the dependencies of alpha, namely centered moments mu11, mu20 ad mu02

Reimplemented from vpMoment.

Definition at line 166 of file vpMomentAlpha.cpp.

References vpMomentCentered::get(), vpMomentDatabase::get(), vpMoment::getMoments(), and vpException::notInitialized.

void vpMoment::update ( vpMomentObject moment_object)
inherited

Updates the moment with the current object. This does not compute any values.

Parameters
moment_object: object descriptor of the current camera vision.

Definition at line 115 of file vpMoment.cpp.

Friends And Related Function Documentation

VISP_EXPORT std::ostream& operator<< ( std::ostream &  os,
const vpMomentAlpha v 
)
friend

Prints the value of the major-axis orientation in degrees and rad

Definition at line 156 of file vpMomentAlpha.cpp.

Member Data Documentation