MomentObject

class MomentObject(*args, **kwargs)

Bases: pybind11_object

Class for generic objects.

It contains all basic moments often described by \(m_{ij}\) of order \(i+j\) going from \(m_{00}\) to the order used as parameter in vpMomentObject() constructor. All other moments implemented in ViSP (gravity center, alpha orientation, centered moments…) use this moment object as a combination of its different values.

When constructing a vpMomentObject() you need first to specify the maximum used moment order as parameter.

Then there are three ways to initialize a vpMomentObject . Firstly using fromImage() you can considerer a dense object O defined by an image. Secondly, as described in fromVector() you can also define a dense object O by a closed contour. In these two cases, 2D basic moments are defined by:

\[m_{ij} = \int \int_{O} x^i y^j dx dy\]

Lastly, as presented in fromVector() you can consider a discrete set of n points. In that last case, the basic moments are defined by

\[m_{ij} = \sum_{k=1}^{n} x_k^i y_k^j \]

With setType() method you can specify the object type.

The implementation is based on the following references [39] , [5] , [40] , [2] .

Warning

Be careful with the object order. When you specify a maximum order in the vpMomentObject::vpMomentObject constructor (see its detailed description), it will compute all moment orders up to the order you specified. If you want to access the values \(m_{ij}\) with the vpMomentObject::get method, you can do object.get()[j*(order+1)+i].

A few tips about which orders to use in different situations:

  • moment based visual servoing: use vpMomentObject(6) . This will compute moment values up to order 6 which will enable vpFeatureMoments up to order 5 which is the maximum order required for common moments.

  • computing gravity center: use vpMomentObject(1) . You only need \(m_{00},m_{01},m_{10}\) . You should compute moments up to order 1.

  • computing gravity center interaction matrix with vpFeatureMomentGravityCenter : use vpMomentObject(2) . This will compute moment values till order 2 since they are needed for the interaction matrix of vpFeatureMoments of order 1.

The following example shows how to create a moment object from 4 discrete points locate on a plane one meter in front of the camera. It shows also how to get the basic moments that are computed and how to compute other classical moments such as the gravity center or the centered moments.

#include <visp3/core/vpMomentCommon.h>
#include <visp3/core/vpMomentObject.h>
#include <visp3/core/vpPoint.h>

int main()
{
  // Define an object as 4 clockwise points on a plane (Z=0)
  std::vector<vpPoint> vec_p; // vector that contains the 4 points

  vec_p.push_back( vpPoint(-0.2, 0.1,  0.0) ); // values in meters
  vec_p.push_back( vpPoint(+0.3, 0.1,  0.0) ); // values in meters
  vec_p.push_back( vpPoint(+0.2,-0.1,  0.0) ); // values in meters
  vec_p.push_back( vpPoint(-0.2,-0.15, 0.0) ); // values in meters

  // These points are observed by a camera
  vpHomogeneousMatrix cMo(0, 0, 1, 0, 0, 0); // We set the camera to be 1m far the object
  // ... update cMo from an image processing

  // Apply the perspective projection to update the points coordinates in the camera plane
  for (unsigned int i=0; i<vec_p.size(); ++i)
    vec_p[i].project(cMo);

  std::cout << "Considered points: " << std::endl;
  for(unsigned int i=0; i<vec_p.size(); ++i)
    std::cout << "point " << i << ": " << vec_p[i].get_x() << ", " << vec_p[i].get_y() << std::endl;

  // Define an image moment object from the previous points
  vpMomentObject obj(5); // use moments up to order 5
  obj.setType(vpMomentObject::DISCRETE); // initialize the object as constituted by discrete points
  obj.fromVector(vec_p); // init the object from the points

  // --- Access the computed moments by querying the moment object

  // 1. Getting a vector of doubles
  std::vector<double> moment = obj.get();
  std::cout << std::endl << "Basic moment available (from vector of doubles)" << std::endl;
  for(unsigned int k=0; k<=obj.getOrder(); k++) {
    for(unsigned int l=0; l<(obj.getOrder()+1)-k; l++) {
      std::cout << "m" << l << k << "=" << moment[k*(momobj.getOrder()+1)+ l] << "\t";
    }
    std::cout<<std::endl;
  }

  // 2. Print the contents of moment object directly
  std::cout << std::endl << "Basic moment available: ";
  std::cout << obj << std::endl;

  // 3. Directly indexing the moment object
  std::cout << std::endl << "Direct access to some basic moments: " << std::endl;
  std::cout << "m00: " << obj.get(0, 0) << std::endl;
  std::cout << "m10: " << obj.get(1, 0) << std::endl;
  std::cout << "m01: " << obj.get(0, 1) << std::endl;
  std::cout << "m22: " << obj.get(2, 2) << std::endl;
  std::cout << "m20: " << obj.get(2, 0) << std::endl;
  std::cout << "m02: " << obj.get(0, 2) << std::endl;

  // Get common moments computed using basic moments
  double m00 = vpMomentCommon::getSurface(obj); // surface = m00
  double alpha = vpMomentCommon::getAlpha(obj); // orientation
  std::vector<double> mu_3 = vpMomentCommon::getMu3(obj); // centered moment up to 3rd order

  std::cout << std::endl << "Common moments computed using basic moments:" << std::endl;
  std::cout << "Surface: " << m00 << std::endl;
  std::cout << "Alpha: " << alpha << std::endl;
  std::cout << "Centered moments (mu03, mu12, mu21, mu30): ";
  for(unsigned int i=0; i<mu_3.size(); ++i)
    std::cout << mu_3[i] << " ";
  std::cout << std::endl;

  return 0;
}

This example produces the following results:

Considered points:
point 0: -0.2, 0.1
point 1: 0.3, 0.1
point 2: 0.2, -0.1
point 3: -0.2, -0.15

Basic moment available (from vector of doubles):
m00=4   m10=0.1 m20=0.21        m30=0.019       m40=0.0129      m50=0.00211
m01=-0.05       m11=0.02        m21=0.003       m31=0.0023      m41=0.00057
m02=0.0525      m12=-0.0015     m22=0.0026      m32=9e-05
m03=-0.002375   m13=0.000575    m23=-4.5e-05
m04=0.00080625  m14=-7.125e-05
m05=-6.59375e-05

Basic moment available:
4   0.1 0.21    0.019   0.0129  0.00211
-0.05   0.02    0.003   0.0023  0.00057 x
0.0525  -0.0015 0.0026  9e-05   x   x
-0.002375   0.000575    -4.5e-05    x   x   x
0.00080625  -7.125e-05  x   x   x   x
-6.59375e-05    x   x   x   x   x

Direct access to some basic moments:
m00: 4
m10: 0.1
m01: -0.05
m22: 0.0026
m20: 0.21
m02: 0.0525

Common moments computed using basic moments:
Surface: 0.259375
Alpha: 0.133296
Centered moments (mu03, mu12, mu21, mu30): 0.003375 0.0045625 -0.00228125 -0.000421875

Note that in the continuous case, the moment object \(m_{00}\) corresponds to the surface \(a\) of the object. In the discrete case, it is the number of discrete points \(n\) .

Overloaded function.

  1. __init__(self: visp._visp.core.MomentObject, order: int) -> None

Default constructor. Initializes the object with the maximum used order. You cannot use higher order moments than the order of the moment object. The parameter specified is the highest desired included order. All orders up to this values will be computed. In other words, a vpMomentObject will compute all \(m_{ij}\) moments with \(i+j \in [0..order]\) .

Mani : outsourced the constructor work to void init (unsigned int orderinp);

  1. __init__(self: visp._visp.core.MomentObject, srcobj: visp._visp.core.MomentObject) -> None

Copy constructor

Methods

__init__

Overloaded function.

convertTovpMatrix

Converts the raw moments contained in vpMomentObject to a vpMatrix This function returns a vpMatrix of size (order+1, order+1).

fromImage

Overloaded function.

fromVector

<unparsed orderedlist <doxmlparser.compound.docListType object at 0x7ff6a1000820>>

get

Overloaded function.

getOrder

return:

The maximal order. The basic moments \(m_{ij}\) that will be computed are for \(i+j \in [0:\mbox{order}]\) .

getType

return:

The type of object that is considered.

init

Overloaded function.

printWithIndices

Outputs raw moments in indexed form like m[1,1] = value of moment m11Outputs the raw moment values \(m_{ij}\) in indexed form.

setType

Specifies the type of the input data.

Inherited Methods

Operators

__doc__

__init__

Overloaded function.

__module__

__repr__

Attributes

BLACK

DENSE_FULL_OBJECT

DENSE_POLYGON

DISCRETE

WHITE

__annotations__

flg_normalize_intensity

class CameraImgBckGrndType(self, value: int)

Bases: pybind11_object

Type of camera image background.

Values:

  • BLACK: Black background.

  • WHITE: Not functional right now.

__and__(self, other: object) object
__eq__(self, other: object) bool
__ge__(self, other: object) bool
__getstate__(self) int
__gt__(self, other: object) bool
__hash__(self) int
__index__(self) int
__init__(self, value: int)
__int__(self) int
__invert__(self) object
__le__(self, other: object) bool
__lt__(self, other: object) bool
__ne__(self, other: object) bool
__or__(self, other: object) object
__rand__(self, other: object) object
__ror__(self, other: object) object
__rxor__(self, other: object) object
__setstate__(self, state: int) None
__xor__(self, other: object) object
property name : str
class ObjectType(self, value: int)

Bases: pybind11_object

Type of camera image background.

Values:

  • BLACK: Black background.

  • WHITE: Not functional right now.

__and__(self, other: object) object
__eq__(self, other: object) bool
__ge__(self, other: object) bool
__getstate__(self) int
__gt__(self, other: object) bool
__hash__(self) int
__index__(self) int
__init__(self, value: int)
__int__(self) int
__invert__(self) object
__le__(self, other: object) bool
__lt__(self, other: object) bool
__ne__(self, other: object) bool
__or__(self, other: object) object
__rand__(self, other: object) object
__ror__(self, other: object) object
__rxor__(self, other: object) object
__setstate__(self, state: int) None
__xor__(self, other: object) object
property name : str
__init__(*args, **kwargs)

Overloaded function.

  1. __init__(self: visp._visp.core.MomentObject, order: int) -> None

Default constructor. Initializes the object with the maximum used order. You cannot use higher order moments than the order of the moment object. The parameter specified is the highest desired included order. All orders up to this values will be computed. In other words, a vpMomentObject will compute all \(m_{ij}\) moments with \(i+j \in [0..order]\) .

Mani : outsourced the constructor work to void init (unsigned int orderinp);

  1. __init__(self: visp._visp.core.MomentObject, srcobj: visp._visp.core.MomentObject) -> None

Copy constructor

static convertTovpMatrix(momobj: visp._visp.core.MomentObject) visp._visp.core.Matrix

Converts the raw moments contained in vpMomentObject to a vpMatrix This function returns a vpMatrix of size (order+1, order+1).

vpMomentObject obj(8);
obj.setType(vpMomentObject::DENSE_FULL_OBJECT);
obj.fromImageWeighted(I, cam, vpMomentObject::BLACK); // cam should have the camera parameters
vpMatrix Mpq = vpMomentObject::convertTovpMatrix(obj);

Instead of accessing the moment m21 as obj.get(2,1), you can now do Mpq[2][1]. This is useful when you want to use the functions available in vpMatrix . One use case i see now is to copy the contents of the matrix to a file or std::cout. For instance, like

// Print to console
Mpq.maplePrint(std::cout);
// Or write to a file
std::ofstream fileMpq("Mpq.csv");
Mpq.maplePrint(fileMpq);

The output can be copied and pasted to MAPLE as a matrix.

Warning

The moments that are not calculated have zeros. For instance, for a vpMomentObject of order 8, the moment m[7,2] is not calculated. It will have 0 by default. User discretion is advised.

Parameters:
momobj: visp._visp.core.MomentObject

A vpMomentObject

fromImage(*args, **kwargs)

Overloaded function.

  1. fromImage(self: visp._visp.core.MomentObject, image: visp._visp.core.ImageGray, threshold: int, cam: visp._visp.core.CameraParameters) -> None

Computes basic moments from an image based on this reference [2] .

There is no assumption made about whether the input is dense or discrete but it’s more common to use vpMomentObject::DENSE_FULL_OBJECT with this method.

The code below shows how to use this function.

#include <visp3/core/vpImage.h>
#include <visp3/core/vpMomentObject.h>

int main()
{
  vpCameraParameters cam;             // Camera parameters used for pixel to
meter conversion vpImage<unsigned char> I(288, 384); // Image used to define
the object
  // ... Initialize the image

  unsigned char threshold = 128; // Gray level used to define which part of
the image belong to the dense object

  vpMomentObject obj(3); // Create an image moment object with 3 as maximum
order obj.fromImage(I, threshold, cam); // Initialize the object from the
image

  return 0;
}
Parameters:
image

Image to consider.

threshold

Pixels with a luminance lower than this threshold will be considered.

cam

Camera parameters used to convert pixels coordinates in meters in the image plane.

  1. fromImage(self: visp._visp.core.MomentObject, image: visp._visp.core.ImageGray, cam: visp._visp.core.CameraParameters, bg_type: visp._visp.core.MomentObject.CameraImgBckGrndType, normalize_with_pix_size: bool = true) -> None

Computes basic moments from an image based on this reference [2] .

Intended to be used by vpMomentObject with DENSE_FULL_OBJECT object type, see setType() .

Parameters:
image

Grayscale image

cam

Camera parameters (to change to )

bg_type

White/Black background surrounding the image

normalize_with_pix_size

When this flag if set, the moments, after calculation are normalized w.r.t pixel size available from camera parameters.

fromVector(self, points: list[visp._visp.core.Point]) list[visp._visp.core.Point]

<unparsed orderedlist <doxmlparser.compound.docListType object at 0x7ff6a1000820>>

The code below shows how to use this function to consider a dense object defined by a closed contour.

#include <visp3/core/vpMomentObject.h>
#include <visp3/core/vpPoint.h>

int main()
{
  // Define the contour of an object by a 5 clockwise vertices on a plane
  vpPoint p;
  std::vector<vpPoint> vec_p; // vector that contains the vertices of the contour polygon

  p.set_x(-0.2); p.set_y(0.1); // coordinates in meters in the image plane (vertex 1)
  vec_p.push_back(p);
  p.set_x(+0.3); p.set_y(0.1); // coordinates in meters in the image plane (vertex 2)
  vec_p.push_back(p);
  p.set_x(+0.2); p.set_y(-0.1); // coordinates in meters in the image plane (vertex 3)
  vec_p.push_back(p);
  p.set_x(-0.2); p.set_y(-0.15); // coordinates in meters in the image plane (vertex 4)
  vec_p.push_back(p);
  p.set_x(-0.2); p.set_y(0.1); // close the contour (vertex 5 = vertex 1)
  vec_p.push_back(p);

  vpMomentObject obj(4); // Create an image moment object with 4 as maximum order
  obj.setType(vpMomentObject::DENSE_POLYGON); // The object is defined by a countour polygon
  obj.fromVector(vec_p); // Init the dense object with the polygon

  return 0;
}

This other example shows how to consider an object as a discrete set of four points.

#include <visp3/core/vpMomentObject.h>
#include <visp3/core/vpPoint.h>

int main()
{
  // Define 4 discrete points on a plane
  vpPoint p;
  std::vector<vpPoint> vec_p; // vector that contains the 4 points

  p.set_x(-0.2); p.set_y(0.1); // coordinates in meters in the image plane (point 1)
  vec_p.push_back(p);
  p.set_x(+0.3); p.set_y(0.1); // coordinates in meters in the image plane (point 2)
  vec_p.push_back(p);
  p.set_x(+0.2); p.set_y(-0.1); // coordinates in meters in the image plane (point 3)
  vec_p.push_back(p);
  p.set_x(-0.2); p.set_y(-0.15); // coordinates in meters in the image plane (point 4)
  vec_p.push_back(p);

  vpMomentObject obj(4); // Create an image moment object with 4 as maximum order
  obj.setType(vpMomentObject::DISCRETE); // The object is constituted by discrete points
  obj.fromVector(vec_p); // Init the dense object with the points

  return 0;
}
Parameters:
points: list[visp._visp.core.Point]

Vector of points.

Returns:

A tuple containing:

  • points: Vector of points.

get(*args, **kwargs)

Overloaded function.

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

Returns all basic moment values \(m_{ij}\) with \(i \in [0:\mbox{order}]\) and \(j \in [0:\mbox{order}]\) .

For example, if the maximal order is 3, the following values are provided:

m00 m10 m20 m01 m11 m21 m02 m12 m12 m30 m03

To access for example to the basic moment m12, you should use this kind of code:

vpMomentObject obj(3);
// ... initialise the object using fromVector() or fromImage()
std::vector mij = obj.get();
double m12;
m12 = mij[2*(obj.getOrder()+1)+1]; // i=1 and j=2
Returns:

Vector of moment values. To access \(m_{ij}\) , you have to read vpMomentObject::get() [j*(order+1)+i].

  1. get(self: visp._visp.core.MomentObject, i: int, j: int) -> float

Returns the basic moment value \(m_{ij}\) corresponding to i,j indexes

Parameters:
i

First moment index, with \(i+j \leq order\) .

j

Second moment index, with \(i+j \leq order\) .

getOrder(self) int
Returns:

The maximal order. The basic moments \(m_{ij}\) that will be computed are for \(i+j \in [0:\mbox{order}]\) .

getType(self) visp._visp.core.MomentObject.ObjectType
Returns:

The type of object that is considered.

init(*args, **kwargs)

Overloaded function.

  1. init(self: visp._visp.core.MomentObject, orderinp: int) -> None

Does exactly the work of the default constructor as it existed in the very first version of vpMomentObject .

  1. init(self: visp._visp.core.MomentObject, objin: visp._visp.core.MomentObject) -> None

Helper to copy constructor.

static printWithIndices(momobj: visp._visp.core.MomentObject, os: std::ostream) None

Outputs raw moments in indexed form like m[1,1] = value of moment m11Outputs the raw moment values \(m_{ij}\) in indexed form. The moment values are same as provided by the operator << which outputs x for uncalculated moments.

Parameters:
momobj

A vpMomentObject

os

Output stream.

setType(self, input_type: visp._visp.core.MomentObject.ObjectType) None

Specifies the type of the input data.

Parameters:
input_type: visp._visp.core.MomentObject.ObjectType

An input type.