Specify camera parameters using standard robotics conventions.

PiperOrigin-RevId: 569147555
Change-Id: I3443f95e5de56a17024f5e5c03f33888dd583edb
This commit is contained in:
Alessio Quaglino
2023-09-28 05:18:36 -07:00
committed by Copybara-Service
parent ca60de79c8
commit 36d2ffe4f2
28 changed files with 528 additions and 40 deletions
+30
View File
@@ -0,0 +1,30 @@
<!-- Please activate Camera rendering when loading this model.
The frustum should match exactly the fron face of the box. -->
<mujoco>
<visual>
<map znear="0.01"/>
</visual>
<asset>
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".8 .6 .4" rgb2=".2 .3 .4"/>
<material name="grid" texture="grid" texrepeat="9 16" texuniform="false" reflectance=".2"/>
</asset>
<worldbody>
<light pos="0 0 3"/>
<geom type="plane" size="10 10 .01"/>
<geom type="box" size=".375 .6 .1" pos="1.1 0 1" material="grid" euler="0 90 0"/>
<!-- 8mm focal length lenses -->
<camera pos="0 0 1" xyaxes="0 -1 0 0 0 1" focalpixel="1600 1600" resolution="1920 1200"
sensorsize="9.6e-3 6e-3"/>
<body euler="0 0 90">
<geom type="box" size=".375 .6 .1" pos="1.1 2 1" material="grid" euler="0 90 0"/>
<!-- 8mm focal length lenses -->
<camera pos="0 2 1" xyaxes="0 -1 0 0 0 1" focal="8e-3 8e-3" resolution="1920 1200"
sensorsize="9.6e-3 6e-3" principalpixel="200 0"/>
</body>
</worldbody>
</mujoco>
+75
View File
@@ -754,6 +754,81 @@ TEST_F(CameraSpecTest, FovyLimits) {
mj_deleteModel(m);
}
TEST_F(CameraSpecTest, DuplicatedFocalIgnorePixel) {
static constexpr char xml[] = R"(
<mujoco>
<visual>
<map znear="0.01"/>
</visual>
<worldbody>
<body>
<geom size="1"/>
<camera focal="8e-3 8e-3" focalpixel="100 100"
resolution="1920 1200" sensorsize="9.6e-3 6e-3"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, NotNull()) << error.data();
EXPECT_NEAR(m->cam_intrinsic[0], 5e-4, 1e-6); // focal length in meters (x)
EXPECT_NEAR(m->cam_intrinsic[1], 5e-4, 1e-6); // focal length in meters (y)
mj_deleteModel(m);
}
TEST_F(CameraSpecTest, FovyFromResolution) {
static constexpr char xml[] = R"(
<mujoco>
<visual>
<map znear="0.01"/>
</visual>
<worldbody>
<body>
<geom size="1"/>
<!-- 8mm focal length lenses -->
<camera focal="8e-3 8e-3" resolution="1920 1200" sensorsize="9.6e-3 6e-3"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, NotNull()) << error.data();
EXPECT_NEAR(m->cam_fovy[0], 41.112, 1e-3);
EXPECT_NEAR(m->cam_intrinsic[0], 8e-3, 1e-6); // focal length in meters (x)
EXPECT_NEAR(m->cam_intrinsic[1], 8e-3, 1e-6); // focal length in meters (y)
EXPECT_EQ(m->cam_intrinsic[2], 0); // principal point in meters (x)
EXPECT_EQ(m->cam_intrinsic[3], 0); // principal point in meters (y)
mj_deleteModel(m);
}
TEST_F(CameraSpecTest, FovyFromResolutionPixel) {
static constexpr char xml[] = R"(
<mujoco>
<visual>
<map znear="0.01"/>
</visual>
<worldbody>
<body>
<geom size="1"/>
<!-- 8mm focal length lenses -->
<camera focalpixel="1600 1600" resolution="1920 1200" sensorsize="9.6e-3 6e-3"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, NotNull()) << error.data();
EXPECT_NEAR(m->cam_fovy[0], 41.112, 1e-3);
EXPECT_NEAR(m->cam_intrinsic[0], 8e-3, 1e-6); // focal length in meters (x)
EXPECT_NEAR(m->cam_intrinsic[1], 8e-3, 1e-6); // focal length in meters (y)
EXPECT_EQ(m->cam_intrinsic[2], 0); // principal point in meters (x)
EXPECT_EQ(m->cam_intrinsic[3], 0); // principal point in meters (y)
mj_deleteModel(m);
}
// ------------- test actuator order -------------------------------------------
using ActuatorTest = MujocoTest;
+55
View File
@@ -407,6 +407,61 @@ TEST_F(XMLReaderTest, InvalidDoubleOrientation) {
}
}
// ---------------------- test camera parsing ---------------------------------
TEST_F(XMLReaderTest, CameraInvalidFovyAndSensorsize) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<camera fovy="1" sensorsize="1 1" resolution="100 100"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, testing::IsNull());
EXPECT_THAT(error.data(), HasSubstr("either 'fovy' or 'sensorsize'"));
}
TEST_F(XMLReaderTest, CameraPricipalRequiresSensorsize) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<camera principal="1 1"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, testing::IsNull());
EXPECT_THAT(error.data(), HasSubstr("attribute missing: 'sensorsize'"));
}
TEST_F(XMLReaderTest, CameraSensorsizeRequiresResolution) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom size="1"/>
<camera sensorsize="1 1"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, testing::IsNull());
EXPECT_THAT(error.data(), HasSubstr("attribute missing: 'resolution'"));
}
// ---------------------- test inertia parsing --------------------------------
TEST_F(XMLReaderTest, InvalidInertialOrientation) {
static constexpr char xml[] = R"(
<mujoco>