File: tutorial-pose-estimation.dox

package info (click to toggle)
visp 3.6.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 119,296 kB
  • sloc: cpp: 500,914; ansic: 52,904; xml: 22,642; python: 7,365; java: 4,247; sh: 482; makefile: 237; objc: 145
file content (138 lines) | stat: -rw-r--r-- 10,143 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/**

\page tutorial-pose-estimation Tutorial: Pose estimation from points
\tableofcontents

\section tutorial_pose_intro Introduction

This tutorial focuses on pose estimation from planar or non planar points. From their 2D coordinates in the image plane, and their corresponding 3D coordinates specified in an object frame, ViSP is able to estimate the relative pose between the camera and the object frame. This pose is returned as an homogeneous matrix cMo. Note that to estimate a pose at least four points need to be considered.

In this tutorial we assume that you are familiar with ViSP blob tracking. If not, see \ref tutorial-tracking-blob.

Note that all the material (source code and image) described in this tutorial is part of ViSP source code and could be downloaded using the following command:

\code
$ svn export https://github.com/lagadic/visp.git/trunk/tutorial/computer-vision
\endcode

\section tutorial_pose_est Pose estimation from 4 planar points

\subsection tutorial_pose_est_image Principle on a single image

In this section we consider the case of four planar points. An image processing done by our blob tracker allows to extract the pixel coordinates of each blob center of gravity. Then using the camera intrinsic parameters we convert these pixel coordinates in meters in the image plane. Knowing the 3D coordinates of the points we then estimate the pose of the object.

The corresponding source code also provided in tutorial-pose-from-points-image.cpp is the following.

\include tutorial-pose-from-points-image.cpp

Here is a screen shot of the resulting program:

\image html img-pose-square.jpg

And here is the detailed explanation of some lines introduced in the source code.

First we include the header pose_helper.h that contains helper functions dedicated to pose estimation.
\snippet tutorial-pose-from-points-image.cpp Include

In pose_helper.h header we include the vpPoint header class that is a container for 3D points with their 3D coordinates in the object frame, and their 2D coordinates in the image plane obtained after perspective projection. These 3D and 2D coordinates will be used as input in the pose estimation algorithm implemented in vpPose class. Then we include the vpCameraParameters header class that contains the camera intrinsic parameters. These parameters are typically used to convert coordinates of a blog cog obtained in pixels from the tracking of the blob, into 2D coordinates expressed in the image plane. The next header concerns the vpHomogeneousMatrix class that is a pose container. Finally, the vpDot2 header class corresponds to the tracker that will be used to track the 4 blobs.
\snippet pose_helper.h Include

If we have a look in pose_helper.cpp we will find the `computePose()` function that does the pose estimation. This function uses as input two vectors. The first one is a vector of vpPoint that contains the 3D coordinates in meters of a point, while the second one is a vector of vpImagePoints that contains the 2D coordinates in pixels of a blob center of gravity. The 3D and 2D coordinates of the points need to be matched. That means that `point[i]` and `ip[i]` should refer to the same physical point. Other inputs are \c cam that corresponds to the camera intrinsic parameters, and \c init that indicates if the pose needs to be initialized the first time. We have \c cMo [in/out] parameter that is as input the pose estimated from the previous image, and, as output the resulting pose estimated from the input points.
\snippet pose_helper.cpp Compute pose

In the `computePose()` function, we create first an instance of the vpPose class. Then we convert each coordinates of the blob center
of gravity `ip` in 2D coordinates \c (x,y) in meter in the image plane using vpPixelMeterConversion::convertPoint(). We update then the
\c point instance with the corresponding 2D coordinates and add this point to the vpPose class.
Once all the points are added, when `init` is `true` we can estimate an initial pose using vpPose::DEMENTHON_LAGRANGE_VIRTUAL_VS method that runs first Dementhon and Lagrange
linear pose estimation algorithms, then retain the result that has the lowest residual and finaly use this result to initialize the non linear virtual visual-servoing algorithm to estimate the pose
that will converge to the solution with a lower residue than on of the linear approaches.
When `init` is `false`, we consider that the previous pose `cMo` is near the solution so that it can be used as initialization for the non linear visual servoing minimization.

If we come back in tutorial-pose-from-points-image.cpp in the `main()` function, instead of using an image sequence of the object, we consider always the same image `square.pgm`. In this image we consider a 12cm by 12 cm square. The corners are represented by a blob. Their center of gravity correspond to a corner position. This gray level image is read thanks to:
\snippet tutorial-pose-from-points-image.cpp Read image

After the instantiation of a window able to display the image and at the end the result of the estimated pose as a pose frame, we setup the camera parameters. We consider here the following camera model \f${\bf a}=(p_x,p_y, u_0,v_0)\f$ where \f$p_x = p_y = 800 \f$ are the ratio between the focal length and the size of a pixel, and where the principal point \f$(u_0, v_0)\f$ is located at the image center position.
\snippet tutorial-pose-from-points-image.cpp Camera parameters

Each blob is then tracked using a vector of four vpDot2 trackers. To avoid human interaction, we initialize the tracker with a pixel position inside each blob. Here we also instantiate a vector of vpImagePoint `ip` that will be updated in the while loop with the 2D coordinates in pixels of the blob center of gravity.
\snippet tutorial-pose-from-points-image.cpp Blob tracking

We also define the 3D model of our 12cm by 12cm square by setting the 3D coordinates of the corners in an object frame located in this example in the middle of the square. We consider here that the points are located in the plane \f$z=0\f$.
\snippet tutorial-pose-from-points-image.cpp 3D model

Next, we created an homogeneous matrix \c cMo that will contain the estimated pose.
\snippet tutorial-pose-from-points-image.cpp Homogeneous matrix

In the infinite loop, at each iteration we read a new image (in this example it remains the same), display its content in the window, track each blob and update the coordinates of the center of gravity in `ip` vector.
\snippet tutorial-pose-from-points-image.cpp Tracking

Then we call the pose estimation function `computePose() presented previously. It uses the 3D coordinates of the points defined as our model in the object frame, and their corresponding 2D positions in the image obtained by the blob tracker to estimate the pose \c cMo. This homogeneous transformation gives the position of the object frame in the camera frame.
\snippet tutorial-pose-from-points-image.cpp Pose estimation

The resulting pose is displayed as an RGB frame in the window overlay. Red,  green and blue colors are for X, Y and Z axis respectively. Each axis is 0.05 meter long. All the drawings are then flushed to update the window content.
\snippet tutorial-pose-from-points-image.cpp Display pose

At the end of the first iteration, we turn off the \c init flag that indicates that the next pose estimation could use our non linear vpPose::VIRTUAL_VS estimation method with the previous pose as initial value.
\snippet tutorial-pose-from-points-image.cpp Next pose uses previous one as initialization

Finally, we interrupt the infinite loop by a user mouse click in the window.
\snippet tutorial-pose-from-points-image.cpp The end

We also introduce a 40 milliseconds sleep to slow down the loop and relax the CPU.
\snippet tutorial-pose-from-points-image.cpp Slow down

\subsection tutorial_pose_est_live Using a camera

We provide also an other example in tutorial-pose-from-points-live.cpp that works on live images acquired by a camera. Compared to the previous example, we replace the single image reader by one of the frame grabber available in ViSP (see \ref tutorial-grabber).

<b>1. Download and print, a square made of 4 blobs</b>
- 4 black blobs on a white background defining a 0.1 meter width square [<a href="http://visp-doc.inria.fr/download/square-blob/square-10cm-black.pdf" target="_blank">square-10cm-black.pdf</a>] (recommended);
- 4 white blobs on a black background defining a 0.1 meter width square [<a href="http://visp-doc.inria.fr/download/square-blob/square-10cm-white.pdf" target="_blank">square-10cm-white.pdf</a>].

<b>2. Run the corresponding binary</b>

To get the usage of the binary run:
\code
./tutorial-pose-from-points-live --help
\endcode

Have a trial adapting the size of your square:
\code
./tutorial-pose-from-points-live --square_width 0.1
\endcode

If your camera is calibrated (see \ref tutorial-calibration-intrinsic), you may use your own camera parameters with something similar to:
\code
./tutorial-pose-from-points-live --square_width 0.1 --intrinsic camera.xml --camera_name Camera
\endcode

If you get the following error:
\code
$ ./tutorial-pose-from-points-live --square_width 0.1
Catch an exception: No cameras found
\endcode

it means probably that your camera is not detected by the first grabber that is enabled using:
\snippet tutorial-pose-from-points-live.cpp Grabber

If this is the case we suggest to modify the following lines in tutorial-pose-from-points-live.cpp by uncommenting all the grabber that you don't want to use:
\snippet tutorial-pose-from-points-live.cpp Undef grabber

For example, if you want to force OpenCV usage to grab images, uncomment the lines:
\code
#undef VISP_HAVE_V4L2
#undef VISP_HAVE_DC1394
#undef VISP_HAVE_CMU1394
#undef VISP_HAVE_FLYCAPTURE
#undef VISP_HAVE_REALSENSE2
\endcode

After modification, build and run again this binary.

\section tutorial_pose_next Next tutorial

You are now ready to see the next \ref tutorial-pose-estimation-qrcode that gives a use case.

If you have an RGB-D camera, you may also continue with \ref tutorial-planar-object-pose.

*/