I am trying to figure out why a 3D cube doesn't project in the right place in the image.
I start with the camera at origin and the cube centered at (0,0,1)
world coordinates:
Then I create a 3D rotation R
of 45 degrees around the Y axis:
(0.707106781, 0, 0.707106781,
0, 1, 0,
-0.707106781, 0, 0.707106781)
And I set the camera to use rotation R^-1
, with a translation of R * (0,0,1)
(these are camera to world transformations). The camera should have rotated 45 degrees CCW around the cube (I can confirm I have 0.707106781
translation on x and z).
At this point, I would expect to see the cube with the same scale, still centered, and with one of the edges right in the middle of the image. But this is what I get:
The procedure I use to project a 3d point X
is (pseudo code):
- bring into camera coordinates:
Xc = R^-1 * X - R^1 * translation
- transform into image coordinates:
x = Xc * focal length / Xc.z + principal point
I have read the theory from various sources and it seems I am following the rules.
This is just artificial data, so not sure if focal length and principal point can have any effect on it? What am I doing wrong? Why is the cube not centered?
EDIT:
I construct the cube like this (duplicate vertices are there because I need them to draw lines):
cv::Matx31d center(0,0,1);
double delta = 0.2;
std::vector<cv::Matx31d> volumeCorners = {
// back
(center + cv::Matx31d(-delta, delta, delta)),
(center + cv::Matx31d(delta, delta, delta)),
(center + cv::Matx31d(delta, delta, delta)),
(center + cv::Matx31d(delta, -delta, delta)),
(center + cv::Matx31d(delta, -delta, delta)),
(center + cv::Matx31d(-delta, -delta, delta)),
(center + cv::Matx31d(-delta, -delta, delta)),
(center + cv::Matx31d(-delta, delta, delta)),
// right
(center + cv::Matx31d(delta, delta, delta)),
(center + cv::Matx31d(delta, delta, -delta)),
(center + cv::Matx31d(delta, delta, -delta)),
(center + cv::Matx31d(delta, -delta, -delta)),
(center + cv::Matx31d(delta, -delta, -delta)),
(center + cv::Matx31d(delta, -delta, delta)),
// front
(center + cv::Matx31d(delta, delta, -delta)),
(center + cv::Matx31d(-delta, delta, -delta)),
(center + cv::Matx31d(-delta, -delta, -delta)),
(center + cv::Matx31d(delta, -delta, -delta)),
(center + cv::Matx31d(-delta, -delta, -delta)),
(center + cv::Matx31d(-delta, delta, -delta)),
// left
(center + cv::Matx31d(-delta, delta, -delta)),
(center + cv::Matx31d(-delta, delta, delta)),
(center + cv::Matx31d(-delta, -delta, delta)),
(center + cv::Matx31d(-delta, -delta, -delta)),
};
I use a right-handed coordinate system, with the y axis pointing down, for world and camera coordinates, while image has origin at top left.