Why is this projection wrong? 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&lt;cv::Matx31d&gt; 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.
My translation should have described a rotation around the center of the cube, but it was wrong. I changed it to:

rotate45 * (translation - center) + center


and I get the cube in the middle with the right angle.