Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Camera.measure_scene_conditions #304

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ per-file-ignores =
camera_intrinsics.py:D101,D102,D106,D107
frame_info.py:D101,D102,D106,D107
network_configuration.py:D101,D102,D106,D107
scene_conditions.py:D101,D102,D106,D107
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 @@ -66,6 +66,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 @@ -41,6 +41,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()
Loading