Skip to content

Commit

Permalink
Implement Camera.measure_scene_conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
johningve committed Dec 6, 2024
1 parent f11e9b6 commit c3e03b9
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,7 @@ def generate_all_datamodels(dest_dir: Path) -> None:
),
(_zivid.CameraIntrinsics, "camera_intrinsics.py", []),
(_zivid.NetworkConfiguration, "network_configuration.py", []),
(_zivid.SceneConditions, "scene_conditions.py", []),
]:
_generate_datamodel_frontend(
internal_class=internal_class,
Expand Down
1 change: 1 addition & 0 deletions modules/_zivid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
infield_correction,
Matrix4x4,
NetworkConfiguration,
SceneConditions,
data_model,
PixelMapping,
projection,
Expand Down
1 change: 1 addition & 0 deletions modules/zivid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
from zivid.camera_intrinsics import CameraIntrinsics
from zivid.matrix4x4 import Matrix4x4
from zivid.network_configuration import NetworkConfiguration
from zivid.scene_conditions import SceneConditions
16 changes: 16 additions & 0 deletions modules/zivid/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
_to_internal_network_configuration,
_to_network_configuration,
)
from zivid.scene_conditions import _to_scene_conditions
from zivid.settings import Settings, _to_internal_settings
from zivid.settings2d import Settings2D, _to_internal_settings2d

Expand Down Expand Up @@ -177,6 +178,21 @@ def release(self):
else:
impl.release()

def measure_scene_conditions(self):
"""Measure and analyze the conditions of the scene.
The returned value will report if noticeable ambient light flicker indicative of a 50 Hz or 60 Hz power grid
was detected. If light flicker is detected in the scene, it is recommended to use capture settings that are
optimized for that power grid frequency.
`measure_scene_conditions` will raise a RuntimeException if the camera status (see `CameraState.Status`) is not
"connected".
Returns:
The current scene conditions.
"""
return _to_scene_conditions(self.__impl.measure_scene_conditions())

def __enter__(self):
return self

Expand Down
174 changes: 174 additions & 0 deletions modules/zivid/scene_conditions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
"""Auto generated, do not edit."""

# pylint: disable=too-many-lines,protected-access,too-few-public-methods,too-many-arguments,line-too-long,missing-function-docstring,missing-class-docstring,redefined-builtin,too-many-branches,too-many-boolean-expressions
import _zivid


class SceneConditions:

class AmbientLight:

class FlickerClassification:

grid50hz = "grid50hz"
grid60hz = "grid60hz"
noFlicker = "noFlicker"
unknownFlicker = "unknownFlicker"

_valid_values = {
"grid50hz": _zivid.SceneConditions.AmbientLight.FlickerClassification.grid50hz,
"grid60hz": _zivid.SceneConditions.AmbientLight.FlickerClassification.grid60hz,
"noFlicker": _zivid.SceneConditions.AmbientLight.FlickerClassification.noFlicker,
"unknownFlicker": _zivid.SceneConditions.AmbientLight.FlickerClassification.unknownFlicker,
}

@classmethod
def valid_values(cls):
return list(cls._valid_values.keys())

def __init__(
self,
flicker_classification=_zivid.SceneConditions.AmbientLight.FlickerClassification().value,
):

if isinstance(
flicker_classification,
_zivid.SceneConditions.AmbientLight.FlickerClassification.enum,
):
self._flicker_classification = (
_zivid.SceneConditions.AmbientLight.FlickerClassification(
flicker_classification
)
)
elif isinstance(flicker_classification, str):
self._flicker_classification = (
_zivid.SceneConditions.AmbientLight.FlickerClassification(
self.FlickerClassification._valid_values[flicker_classification]
)
)
else:
raise TypeError(
"Unsupported type, expected: str, got {value_type}".format(
value_type=type(flicker_classification)
)
)

@property
def flicker_classification(self):
if self._flicker_classification.value is None:
return None
for key, internal_value in self.FlickerClassification._valid_values.items():
if internal_value == self._flicker_classification.value:
return key
raise ValueError(
"Unsupported value {value}".format(value=self._flicker_classification)
)

@flicker_classification.setter
def flicker_classification(self, value):
if isinstance(value, str):
self._flicker_classification = (
_zivid.SceneConditions.AmbientLight.FlickerClassification(
self.FlickerClassification._valid_values[value]
)
)
elif isinstance(
value, _zivid.SceneConditions.AmbientLight.FlickerClassification.enum
):
self._flicker_classification = (
_zivid.SceneConditions.AmbientLight.FlickerClassification(value)
)
else:
raise TypeError(
"Unsupported type, expected: str, got {value_type}".format(
value_type=type(value)
)
)

def __eq__(self, other):
if self._flicker_classification == other._flicker_classification:
return True
return False

def __str__(self):
return str(_to_internal_scene_conditions_ambient_light(self))

def __init__(
self,
ambient_light=None,
):

if ambient_light is None:
ambient_light = self.AmbientLight()
if not isinstance(ambient_light, self.AmbientLight):
raise TypeError(
"Unsupported type: {value}".format(value=type(ambient_light))
)
self._ambient_light = ambient_light

@property
def ambient_light(self):
return self._ambient_light

@ambient_light.setter
def ambient_light(self, value):
if not isinstance(value, self.AmbientLight):
raise TypeError("Unsupported type {value}".format(value=type(value)))
self._ambient_light = value

@classmethod
def load(cls, file_name):
return _to_scene_conditions(_zivid.SceneConditions(str(file_name)))

def save(self, file_name):
_to_internal_scene_conditions(self).save(str(file_name))

@classmethod
def from_serialized(cls, value):
return _to_scene_conditions(_zivid.SceneConditions.from_serialized(str(value)))

def serialize(self):
return _to_internal_scene_conditions(self).serialize()

def __eq__(self, other):
if self._ambient_light == other._ambient_light:
return True
return False

def __str__(self):
return str(_to_internal_scene_conditions(self))


def _to_scene_conditions_ambient_light(internal_ambient_light):
return SceneConditions.AmbientLight(
flicker_classification=internal_ambient_light.flicker_classification.value,
)


def _to_scene_conditions(internal_scene_conditions):
return SceneConditions(
ambient_light=_to_scene_conditions_ambient_light(
internal_scene_conditions.ambient_light
),
)


def _to_internal_scene_conditions_ambient_light(ambient_light):
internal_ambient_light = _zivid.SceneConditions.AmbientLight()

internal_ambient_light.flicker_classification = (
_zivid.SceneConditions.AmbientLight.FlickerClassification(
ambient_light._flicker_classification.value
)
)

return internal_ambient_light


def _to_internal_scene_conditions(scene_conditions):
internal_scene_conditions = _zivid.SceneConditions()

internal_scene_conditions.ambient_light = (
_to_internal_scene_conditions_ambient_light(scene_conditions.ambient_light)
)
return internal_scene_conditions
3 changes: 2 additions & 1 deletion src/ReleasableCamera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace ZividPython
.def("write_user_data", &ReleasableCamera::writeUserData)
.def_property_readonly("user_data", &ReleasableCamera::userData)
.def_property_readonly("network_configuration", &ReleasableCamera::networkConfiguration)
.def("apply_network_configuration", &ReleasableCamera::applyNetworkConfiguration);
.def("apply_network_configuration", &ReleasableCamera::applyNetworkConfiguration)
.def("measure_scene_conditions", &ReleasableCamera::measureSceneConditions);
}
} // namespace ZividPython
1 change: 1 addition & 0 deletions src/Wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ ZIVID_PYTHON_MODULE // NOLINT
ZIVID_PYTHON_WRAP_DATA_MODEL(module, FrameInfo);
ZIVID_PYTHON_WRAP_DATA_MODEL(module, CameraIntrinsics);
ZIVID_PYTHON_WRAP_DATA_MODEL(module, NetworkConfiguration);
ZIVID_PYTHON_WRAP_DATA_MODEL(module, SceneConditions);

ZIVID_PYTHON_WRAP_CLASS_AS_SINGLETON(module, Application);
ZIVID_PYTHON_WRAP_CLASS_AS_RELEASABLE(module, Camera);
Expand Down
4 changes: 4 additions & 0 deletions src/include/ZividPython/ReleasableCamera.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#pragma once

#include <Zivid/Camera.h>

#include <ZividPython/Releasable.h>
#include <ZividPython/ReleasableFrame.h>
#include <ZividPython/ReleasableFrame2D.h>
#include <ZividPython/Wrappers.h>

#include <Zivid/SceneConditions.h>

namespace ZividPython
{
class ReleasableCamera : public Releasable<Zivid::Camera>
Expand All @@ -27,6 +30,7 @@ namespace ZividPython
ZIVID_PYTHON_FORWARD_1_ARGS(applyNetworkConfiguration,
const Zivid::NetworkConfiguration &,
networkConfiguration)
ZIVID_PYTHON_FORWARD_0_ARGS(measureSceneConditions)
};

void wrapClass(pybind11::class_<ReleasableCamera> pyClass);
Expand Down
20 changes: 20 additions & 0 deletions test/test_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,23 @@ def test_state(shared_file_camera):
state = shared_file_camera.state
assert state
assert isinstance(state, zivid.CameraState)


@pytest.mark.physical_camera
def test_measure_scene_conditions(physical_camera):
from zivid import SceneConditions

scene_conditions = physical_camera.measure_scene_conditions()
assert scene_conditions
assert isinstance(scene_conditions, SceneConditions)
assert (
scene_conditions.ambient_light.flicker_classification
in SceneConditions.AmbientLight.FlickerClassification.valid_values()
)


def test_measure_scene_conditions_fails_with_file_camera(file_camera):
with pytest.raises(
RuntimeError, match="This camera cannot measure surrounding conditions"
):
file_camera.measure_scene_conditions()

0 comments on commit c3e03b9

Please sign in to comment.