diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index 8c412513..e86c012c 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -5453,8 +5453,8 @@ excluded; this is because sensor calculations are independent of the visualizer. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This element creates a camprojection sensor, which returns the location of a target site, projected onto a camera image -in pixel coordinates. The origin of this system is located at the center of the top left pixel, so a target which -projects exactly onto the corner of the image, will have value (-0.5, -0.5). Values are not clipped, so targets which +in pixel coordinates. The origin of this system is located at the top-left corner of the first pixel, so a target +which projects exactly onto the corner of the image, will have value (0, 0). Values are not clipped, so targets which fall outside the camera image will take values above or below the pixel limits. Moreover, points behind the camera are also projected onto the image, so it is up to the user to filter out such points, if desired. This can be done using a `framepos` sensor with the camera as reference frame, then a negative/positive value in the diff --git a/src/engine/engine_sensor.c b/src/engine/engine_sensor.c index fa149f2b..4fbf5b1e 100644 --- a/src/engine/engine_sensor.c +++ b/src/engine/engine_sensor.c @@ -225,8 +225,8 @@ static void cam_project(mjtNum sensordata[2], const mjtNum target_xpos[3], image[0][0] = 1; image[1][1] = 1; image[2][2] = 1; - image[0][2] = ((mjtNum)cam_res[0] - 1) / 2.0; - image[1][2] = ((mjtNum)cam_res[1] - 1) / 2.0; + image[0][2] = (mjtNum)cam_res[0] / 2.0; + image[1][2] = (mjtNum)cam_res[1] / 2.0; // projection matrix (3x4): product of all 4 matrices mjtNum proj[3][4] = {0}; diff --git a/test/engine/engine_sensor_test.cc b/test/engine/engine_sensor_test.cc index 815c0472..53101197 100644 --- a/test/engine/engine_sensor_test.cc +++ b/test/engine/engine_sensor_test.cc @@ -467,12 +467,12 @@ TEST_F(SensorTest, CameraProjection) { EXPECT_THAT(model->cam_resolution[0], 1920); EXPECT_THAT(model->cam_resolution[1], 1200); mjtNum eps = 1e-4; - EXPECT_NEAR(data->sensordata[0], -0.5, eps); - EXPECT_NEAR(data->sensordata[1], -0.5, eps); - EXPECT_NEAR(data->sensordata[2], 1919.5, eps); - EXPECT_NEAR(data->sensordata[3], 1199.5, eps); - EXPECT_NEAR(data->sensordata[4], 959.5, eps); - EXPECT_NEAR(data->sensordata[5], 599.5, eps); + EXPECT_NEAR(data->sensordata[0], 0, eps); + EXPECT_NEAR(data->sensordata[1], 0, eps); + EXPECT_NEAR(data->sensordata[2], 1920, eps); + EXPECT_NEAR(data->sensordata[3], 1200, eps); + EXPECT_NEAR(data->sensordata[4], 960, eps); + EXPECT_NEAR(data->sensordata[5], 600, eps); mj_deleteData(data); mj_deleteModel(model);