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

Interface to discover camera functionality #5

Open
maxfreu opened this issue May 3, 2022 · 3 comments
Open

Interface to discover camera functionality #5

maxfreu opened this issue May 3, 2022 · 3 comments

Comments

@maxfreu
Copy link

maxfreu commented May 3, 2022

Hi! When I'm working with new cameras in python the initial struggle is always to get an overview of the functionalities the camera provides. For example, how do I set exposure time or sensitivity, and which other parameters are there to tune, e.g. region of interest boundaries and how to I set them. I think it would be a good idea to make stuff like this discoverable and accessible in a standardized, procedural way. One could e.g. write a function which returns all the properties of the camera, e.g. as list of symbols, and define the behaviour for getproperty and setproperty. I don't know how this could fit in here, but if this can be formalized as API, it should maybe be done here. I know this isn't well thought through, but maybe one can elaborate a bit :)

@stemann
Copy link
Owner

stemann commented May 3, 2022

Sounds like a good idea. Contributions are more than welcome :-)

Would be neat to be able to get a list of properties (e.g. from an iterable).

This discussion comes to mind: https://discourse.julialang.org/t/julia-for-live-control-of-usb3-0-camera-and-dac-adc-boards-with-gui/14195/18 - do check out Spinnaker.jl which has a quite extensive set of properties to get/set.

Also, GenICam and https://github.com/genicam/harvesters might be worth a look.

My random thoughts on properties: A property might be

  • Settable (e.g. some camera might be able to configure exposure time, while a consumer camera may not have this option). E.g. is_settable(property, camera).
  • Have a limited range of valid values (e.g. range(property, camera)).

@maxfreu
Copy link
Author

maxfreu commented May 4, 2022

How about:

getproperties(cam) -> list of symbols
validvalues(cam, property::Symbol) -> list of strings, range or whatever is valid for this property
set!(cam, property::Symbol, value)
get(cam, property)
issettable(cam, property)

# or even shorter
cam.property = value  # sets value
cam.property  # returns value

These could internally dispatch to e.g. Spinnaker's exposure! or framerate! or whatever the mechanism is to set a certain thing. How would it look like?

getproperties(cam::SpinnakerCamera) = [:isinitialized, :serialnumber, :exposure, ...]
set!(cam, property::Symbol, value) = set!(cam, Val(property), value)
# dispatch on values of the symbol
set!(cam, property::Val{:exposure}, value) = exposure!(cam, value)  # I think this could be automated, maybe with eval()

# or
function Base.setproperty!(cam::SpinnakerCamera, property::Symbol, value)
  # long list of if else or dispatch on values, just like above
  if property == :exposure
    exposure!(cam, value)
  elseif ...
  end
end

The other option would be to define traits, but I have to think about how flexible that would be.

@stemann
Copy link
Owner

stemann commented May 5, 2022

I like the property::Symbol approach - I guess it should map nicely to the (names defined in the) GenICam SNFC ?
Cf. https://www.emva.org/wp-content/uploads/GenICam_Standard_v2_1_1.pdf and https://www.emva.org/wp-content/uploads/GenICam_SFNC_v2_7.pdf

GenICam groups features/properties by categories (for e.g. UI purposes). Should this be accounted for?

Regarding GenICam, and machine vision cameras: An idea might be to have AbstractGenICamCamera <: AbstractCamera - to provide more GenICam-compliant/compatible functionality for sub-types of AbstractGenICamCamera.

I like the Base.getproperty, Base.setproperty!-overload approach too, but it might put constraints on Camera/AbstractCamera-implementations - i.e. if a property would shadow a field with the same name: E.g. if a camera implementation would like to cache the set exposure time to not have to re-query the camera when reading properties (e.g. for a camera UI app.). What do you think?

I know I suggested "is settable", but maybe "is mutable" (or conversely, "is read-only") is better?

Getting/setting properties in the way you suggested won't be type-stable, but I guess that is fine.

FYI - as a side note: One to-be-implemented idea I have had is that it should be possible to get an ImageFormat-specific Camera, such that take! is type-stable - e.g.:

camera = SomeCamera()
configured_camera = SomeCamera{UInt16}(camera)
image = take!(configured_camera) # type-stable - AbstractArray{UInt16,2} is returned

There are also types/interfaces defined in GenICam that could have corresponding types on the Julia side. E.g. to constrain the types of values and their range (valid values). E.g. it could look something like:

get_property(camera::AbstractCamera, property_symbol::Symbol)::AbstractCameraProperty 
get_value_type(property::AbstractCameraProperty)::Type
# where valid values could then be gotten from Type-dependent functions
# E.g. for numbers
get_value_range(property::AbstractCameraProperty)
# E.g. for enums
get_valid_values(property::AbstractCameraProperty)

I wonder if it would then be possible to define the Base.getproperty, Base.setproperty!-overloads once (in Cameras.jl) - for GenICam standard-feature-names - such that implementations should only define the "type-stable" methods.

Maybe similar to what you were thinking with traits?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants