MomentAlpha

class MomentAlpha(*args, **kwargs)

Bases: Moment

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 symmetric 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 additional 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/vpMomentAlpha.h>
#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>

//generic function for printing
void print (double i) { std::cout << i << "\t";}

int main()
{
  vpPoint p;
 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);

  //////////////////////////////REFERENCE VALUES////////////////////////////////
  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;

  ////////////CURRENT VALUES (same object rotated 180deg - must be
  ////////////entered in reverse order)////////////////
  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 contains 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 - 2023 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 https://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.
 *
*****************************************************************************/

#include <string>
#include <visp3/core/vpMomentAlpha.h>
#include <visp3/core/vpMomentBasic.h>
#include <visp3/core/vpMomentCentered.h>
#include <visp3/core/vpMomentDatabase.h>
#include <visp3/core/vpMomentGravityCenter.h>
#include <visp3/core/vpMomentObject.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)
{
  vpImage<unsigned char>  I;

  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
    {
      vpMomentObject  obj(3);
      obj.setType( vpMomentObject::DENSE_FULL_OBJECT );
      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
    {
      vpMomentObject  obj(3);
      obj.setType( vpMomentObject::DENSE_FULL_OBJECT );
      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());

    vpMomentObject  obj(3);
    obj.setType( vpMomentObject::DENSE_FULL_OBJECT );
    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 .

Overloaded function.

  1. __init__(self: visp._visp.core.MomentAlpha) -> None

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.

  1. __init__(self: visp._visp.core.MomentAlpha, mu3_ref: list[float], alpha_ref: float, threshold: float = 1e-6) -> None

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]\) ]

Methods

__init__

Overloaded function.

compute

Compute the value of the alpha-moment.

get

Overloaded function.

is_ref

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

is_symmetric

Returns true if the alpha moment is computed on a symmetric object along its two axis.

name

Moment name.

printDependencies

Overloaded function.

Inherited Methods

linkTo

Links the moment to a database of moment primitives.

getObject

update

Updates the moment with the current object.

Operators

__doc__

__init__

Overloaded function.

__module__

__repr__

Attributes

__annotations__

__init__(*args, **kwargs)

Overloaded function.

  1. __init__(self: visp._visp.core.MomentAlpha) -> None

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.

  1. __init__(self: visp._visp.core.MomentAlpha, mu3_ref: list[float], alpha_ref: float, threshold: float = 1e-6) -> None

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]\) ]

compute(self) None

Compute the value of the alpha-moment. Depends on vpMomentCentered .

get(*args, **kwargs)

Overloaded function.

  1. get(self: visp._visp.core.MomentAlpha) -> float

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

  1. get(self: visp._visp.core.Moment) -> list[float]

Returns:

vector of values

getObject(self) visp._visp.core.MomentObject
is_ref(self) bool

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

is_symmetric(self) bool

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}\) .

linkTo(self, moments: visp._visp.core.MomentDatabase) None

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.

Warning

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()
{
  vpPoint p;
  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)
  vec_p.push_back(p);

  vpMomentObject obj(2);
  obj.setType(vpMomentObject::DISCRETE); // Discrete mode.
  obj.fromVector(vec_p); // Init the dense object with the polygon

  vpMomentDatabase db;
  vpMomentGravityCenter G; // declaration of gravity center
  vpMomentCentered mc;     // mc contains 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;
}
name(self) str

Moment name.

printDependencies(*args, **kwargs)

Overloaded function.

  1. printDependencies(self: visp._visp.core.MomentAlpha, os: std::ostream) -> None

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

  1. printDependencies(self: visp._visp.core.Moment, os: std::ostream) -> None

Prints values of all dependent moments required to calculate a specific vpMoment . Not made pure to maintain compatibility Recommended : Types inheriting from vpMoment should implement this function

update(self, object: visp._visp.core.MomentObject) None

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