Skip to content

Commit

Permalink
Addresses various parameter issues (#143)
Browse files Browse the repository at this point in the history
* Rename distortionIsProjection

* Add sync frequency to the complete example

* Remove parentId from transforms

* Addresses #137

* Addresses #133

* Addresses #131

* Put back the transform array

* Improve LensCustom comment
  • Loading branch information
jamesmosys authored Dec 21, 2024
1 parent 53c9251 commit 79e7a75
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 29 deletions.
5 changes: 3 additions & 2 deletions src/main/python/camdkit/examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def _get_complete_dynamic_clip():
clip.timing_sample_rate = (Fraction(24000, 1001),)
clip.timing_timecode = (Timecode(1,2,3,4,TimecodeFormat(Fraction(24000, 1001))),)
clip.timing_synchronization = (Synchronization(
frequency=Fraction(24000,1001),
present=True,
locked=True,
source=SynchronizationSourceEnum.PTP,
Expand All @@ -130,8 +131,8 @@ def _get_complete_dynamic_clip():
v = Vector3(x=1.0, y=2.0, z=3.0)
r = Rotator3(pan=180.0, tilt=90.0, roll=45.0)
clip.transforms = ((Transform(translation=v, rotation=r, id="Dolly"),
Transform(translation=v, rotation=r, scale=v, id="Crane Arm", parentId="Dolly"),
Transform(translation=v, rotation=r, scale=v, id="Camera", parentId="Crane Arm")
Transform(translation=v, rotation=r, scale=v, id="Crane Arm"),
Transform(translation=v, rotation=r, scale=v, id="Camera")
),)

clip.lens_f_number = (4.0,)
Expand Down
7 changes: 3 additions & 4 deletions src/main/python/camdkit/framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,13 @@ class Rotator3:

@dataclasses.dataclass
class Transform:
"""A translation, rotation and scale. 'id' and 'parentId' fields enable
geometry chains
"""A translation, rotation and scale. 'id' optionally provides a
user-friendly name to help identify the transform in a chain.
"""
translation: Vector3
rotation: Rotator3
scale: typing.Optional[Vector3] = None
id: typing.Optional[str] = None
parentId: typing.Optional[str] = None

@dataclasses.dataclass
class FizEncoders:
Expand Down Expand Up @@ -519,7 +518,7 @@ def make_json_schema() -> dict:
"properties": {
"num" : {
"type": "integer",
"minimum": 0,
"minimum": 1,
"maximum": INT_MAX
},
"denom" : {
Expand Down
28 changes: 10 additions & 18 deletions src/main/python/camdkit/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,10 +396,8 @@ def make_json_schema() -> dict:

class Transforms(Parameter):
"""A list of transforms.
Transforms can have a id and parentId that can be used to compose a
transform hierarchy. In the case of multiple children their transforms
should be processed in their order in the array.
X,Y,Z in meters of camera sensor relative to stage origin.
Transforms are composed in order with the last in the list representing
the X,Y,Z in meters of camera sensor relative to stage origin.
The Z axis points upwards and the coordinate system is right-handed.
Y points in the forward camera direction (when pan, tilt and roll are
zero).
Expand All @@ -416,7 +414,7 @@ class Transforms(Parameter):
gimbal lock does not present the physical challenges of a robotic
system.
Conversion to and from quarternions is trivial with an acceptable loss
of precision
of precision.
"""
sampling = Sampling.REGULAR
canonical_name = "transforms"
Expand Down Expand Up @@ -455,11 +453,9 @@ def validate(value) -> bool:
or not isinstance(transform.scale.y, numbers.Real) \
or not isinstance(transform.scale.z, numbers.Real):
return False
# id and parentId are optional
# id is optional
if transform.id != None and not isinstance(transform.id, str):
return False
if transform.parentId != None and not isinstance(transform.parentId, str):
return False

return True

Expand Down Expand Up @@ -545,11 +541,6 @@ def make_json_schema() -> dict:
"type": "string",
"minLength": 1,
"maxLength": 1023
},
"parentId": {
"type": "string",
"minLength": 1,
"maxLength": 1023
}
},
"required": ["translation", "rotation"]
Expand Down Expand Up @@ -1094,7 +1085,7 @@ class DistortionIsProjection(BooleanParameter):
"""

sampling = Sampling.STATIC
canonical_name = "distortionProjection"
canonical_name = "distortionIsProjection"
section = "lens"
units = None

Expand Down Expand Up @@ -1345,9 +1336,10 @@ def make_json_schema() -> dict:
}

class LensCustom(ArrayParameter):
"""Until the OpenLensIO model is finalised, this list provides custom
coefficients for a particular lens model e.g. undistortion, anamorphic
etc
"""This list provides optional additonal custom coefficients that can
extend the existing lens model. The meaning of and how these characeristics
are to be applied to a virtual camera would require negotiation between a
particular producer and consumer.
"""
sampling = Sampling.REGULAR
canonical_name = "custom"
Expand Down Expand Up @@ -1397,7 +1389,7 @@ class Clip(ParameterContainer):
lens_distortion_offset: typing.Optional[typing.Tuple[DistortionOffset]] = LensDistortionOffset()
lens_encoders: typing.Optional[typing.Tuple[LensEncoders]] = LensEncoders()
lens_entrance_pupil_offset: typing.Optional[typing.Tuple[numbers.Real]] = EntrancePupilOffset()
lens_exposure_falloff: typing.Optional[typing.Tuple[Orientations]] = LensExposureFalloff()
lens_exposure_falloff: typing.Optional[typing.Tuple[ExposureFalloff]] = LensExposureFalloff()
lens_f_number: typing.Optional[typing.Tuple[numbers.Real]] = FStop()
lens_focal_length: typing.Optional[typing.Tuple[numbers.Real]] = FocalLength()
lens_focus_distance: typing.Optional[typing.Tuple[numbers.Real]] = FocusDistance()
Expand Down
10 changes: 5 additions & 5 deletions src/test/python/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def test_serialize(self):
self.assertEqual(d["static"]["camera"]["firmwareVersion"], "7.1")
self.assertEqual(d["static"]["camera"]["label"], "A")
self.assertEqual(d["static"]["lens"]["distortionOverscanMax"], 1.2)
self.assertEqual(d["static"]["lens"]["distortionProjection"], False)
self.assertEqual(d["static"]["lens"]["distortionIsProjection"], False)
self.assertEqual(d["static"]["lens"]["undistortionOverscanMax"], 1.2)
self.assertEqual(d["static"]["lens"]["make"], "ABC")
self.assertEqual(d["static"]["lens"]["model"], "FGH")
Expand Down Expand Up @@ -709,10 +709,10 @@ def test_timestamp_limits(self):

def test_timecode_format(self):
self.assertEqual(TimecodeFormat.to_int(TimecodeFormat(24)), 24)
self.assertEqual(TimecodeFormat.to_int(TimecodeFormat(24, True)), 24)
self.assertEqual(TimecodeFormat.to_int(TimecodeFormat(24, 1)), 24)
self.assertEqual(TimecodeFormat.to_int(TimecodeFormat(25)), 25)
self.assertEqual(TimecodeFormat.to_int(TimecodeFormat(30)), 30)
self.assertEqual(TimecodeFormat.to_int(TimecodeFormat(30, True)), 30)
self.assertEqual(TimecodeFormat.to_int(TimecodeFormat(30, 1)), 30)
with self.assertRaises(TypeError):
TimecodeFormat()
with self.assertRaises(ValueError):
Expand All @@ -738,10 +738,10 @@ def test_timecode_formats(self):
self.assertFalse(TimingTimecode.validate(Timecode(1,2,60,4,TimecodeFormat(24))))
self.assertFalse(TimingTimecode.validate(Timecode(1,2,3,-1,TimecodeFormat(24))))
self.assertFalse(TimingTimecode.validate(Timecode(1,2,3,24,TimecodeFormat(24))))
self.assertFalse(TimingTimecode.validate(Timecode(1,2,3,24,TimecodeFormat(24, True))))
self.assertFalse(TimingTimecode.validate(Timecode(1,2,3,24,TimecodeFormat(24, 1))))
self.assertFalse(TimingTimecode.validate(Timecode(1,2,3,25,TimecodeFormat(25))))
self.assertFalse(TimingTimecode.validate(Timecode(1,2,3,30,TimecodeFormat(30))))
self.assertFalse(TimingTimecode.validate(Timecode(1,2,3,30,TimecodeFormat(30, True))))
self.assertFalse(TimingTimecode.validate(Timecode(1,2,3,30,TimecodeFormat(30, 1))))
self.assertTrue(TimingTimecode.validate(Timecode(1,2,3,119,TimecodeFormat(120))))
self.assertFalse(TimingTimecode.validate(Timecode(1,2,3,120,TimecodeFormat(120))))
self.assertFalse(TimingTimecode.validate(Timecode(1,2,3,120,TimecodeFormat(121))))
Expand Down

0 comments on commit 79e7a75

Please sign in to comment.