I have a rectangular target of known size and location on the wall and a mobile camera on the robot. When the robot moves around the room, I need to find the target and calculate the location of the camera and its position. As an additional rotation, the height and azimuth of the camera can be changed using servos. I can find the target using OpenCV, but I'm still fuzzy when calculating the position of the camera (in fact, I got a flat spot on my forehead, hitting my head against the wall last week). That's what I'm doing:
- Reading in a previously computed embedded camera file
- Get the pixel coordinates of the four points of the target rectangle from the path
- Call solvePnP with the world coordinates of the rectangle, pixel coordinates, camera matrix and distortion matrix.
- Calling up projection points with rotation and translation vectors
- ???
I read the OpenCV book, but I think I just missed something, how to use the predicted points, rotation and translation vectors to calculate the world coordinates of the camera and its position (I'm not a mathematical wiz): - (
2013-04-02 Following the advice of "morynicz", I wrote this simple stand-alone program.
#include <Windows.h> #include "opencv\cv.h" using namespace cv; int main (int argc, char** argv) { const char *calibration_filename = argc >= 2 ? argv [1] : "M1011_camera.xml"; FileStorage camera_data (calibration_filename, FileStorage::READ); Mat camera_intrinsics, distortion; vector<Point3d> world_coords; vector<Point2d> pixel_coords; Mat rotation_vector, translation_vector, rotation_matrix, inverted_rotation_matrix, cw_translate; Mat cw_transform = cv::Mat::eye (4, 4, CV_64FC1); // Read camera data camera_data ["camera_matrix"] >> camera_intrinsics; camera_data ["distortion_coefficients"] >> distortion; camera_data.release (); // Target rectangle coordinates in feet world_coords.push_back (Point3d (10.91666666666667, 10.01041666666667, 0)); world_coords.push_back (Point3d (10.91666666666667, 8.34375, 0)); world_coords.push_back (Point3d (16.08333333333334, 8.34375, 0)); world_coords.push_back (Point3d (16.08333333333334, 10.01041666666667, 0)); // Coordinates of rectangle in camera pixel_coords.push_back (Point2d (284, 204)); pixel_coords.push_back (Point2d (286, 249)); pixel_coords.push_back (Point2d (421, 259)); pixel_coords.push_back (Point2d (416, 216)); // Get vectors for world->camera transform solvePnP (world_coords, pixel_coords, camera_intrinsics, distortion, rotation_vector, translation_vector, false, 0); dump_matrix (rotation_vector, String ("Rotation vector")); dump_matrix (translation_vector, String ("Translation vector")); // We need inverse of the world->camera transform (camera->world) to calculate // the camera location Rodrigues (rotation_vector, rotation_matrix); Rodrigues (rotation_matrix.t (), camera_rotation_vector); Mat t = translation_vector.t (); camera_translation_vector = -camera_rotation_vector * t; printf ("Camera position %f, %f, %f\n", camera_translation_vector.at<double>(0), camera_translation_vector.at<double>(1), camera_translation_vector.at<double>(2)); printf ("Camera pose %f, %f, %f\n", camera_rotation_vector.at<double>(0), camera_rotation_vector.at<double>(1), camera_rotation_vector.at<double>(2)); }
The pixel coordinates I used in my test is a real image that was taken at a distance of about 27 feet from the target rectangle (62 inches wide and 20 inches high) at an angle of 45 degrees. Exit is not what I expect. What am I doing wrong?
Rotation vector 2.7005 0.0328 0.4590 Translation vector -10.4774 8.1194 13.9423 Camera position -28.293855, 21.926176, 37.650714 Camera pose -2.700470, -0.032770, -0.459009
Will there be a problem if my world coordinates have an inverted Y axis from the Y axis of OpenCV? (the origin of my coordinate system is on the floor to the left of the target, and OpenCV orgin is in the upper left corner of the screen).
What units is the pose in?