[PATCH] libcamera: pipeline: uvcvideo: Map focus controls

Cláudio Paulo claudio.paulo at makewise.pt
Sun Sep 15 00:22:31 CEST 2024


Hi Hans,

Our use case is a bit different.

We are working with UVC cameras that have built-in auto-focus and a
V4L2_CID_FOCUS_ABSOLUTE control.

We just need to lock the lens position once they are focused on the
correct point.

After the cameras are installed they should remain about the same
distance from the objects they are recording, with only occasional
refocusing needed. Sometimes, certain objects may appear closer
to the camera, but we do not want the focus to shift when that
happens, in order to avoid losing time.

Best regards,

Cláudio


Hans de Goede <hdegoede at redhat.com> escreveu (sábado, 14/09/2024 à(s)
11:05):

> Hi Cláudio,
>
> On 9/13/24 7:22 PM, Cláudio Paulo wrote:
> > Added mapping of controls::LensPosition and controls::AfMode to
> > v4l2 controls V4L2_CID_FOCUS_ABSOLUTE and V4L2_CID_FOCUS_AUTO
> > respectively when the device supports them.
> >
> > If not supported, they are not registered.
> >
> > Signed-off-by: Cláudio Paulo <claudio.paulo at makewise.pt>
>
> Thank you for your patch.
>
> Like last year I have a group of students from my local university
> working on libcamera for ~1 day/week during the first semester
> of the academic year.
>
> They have just started so they have not introduced themselves to
> the list yet ...
>
> The reason I mention this is that I have given them the assignment
> to add auto-focus support to the software ISP. One of their "could have"
> requirements is to integrate support for software auto-focus into
> the UVC driver, because some cameras like e.g. the Logitech quickcam
> 9000 pro have a non fixed lens / a V4L2_CID_FOCUS_ABSOLUTE control,
> but these cameras do not support autofocus inside the camera instead
> relying on autofocus in the driver / OS.
>
> I know there are also UVC camera with builtin auto-focus so I guess
> you are mostly adding these mappings for those?
>
> I just want to make sure you are not also looking into software
> auto-focus support ?  (to avoid double work getting done)
>
> Regards,
>
> Hans
>
>
>
>
>
>
> > ---
> >  include/linux/v4l2-controls.h                |  4 +
> >  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 88 +++++++++++++++++---
> >  2 files changed, 82 insertions(+), 10 deletions(-)
> >
> > diff --git a/include/linux/v4l2-controls.h
> b/include/linux/v4l2-controls.h
> > index 882a8180..1ac85507 100644
> > --- a/include/linux/v4l2-controls.h
> > +++ b/include/linux/v4l2-controls.h
> > @@ -994,6 +994,10 @@ enum  v4l2_exposure_auto_type {
> >  #define V4L2_CID_FOCUS_ABSOLUTE
> (V4L2_CID_CAMERA_CLASS_BASE+10)
> >  #define V4L2_CID_FOCUS_RELATIVE
> (V4L2_CID_CAMERA_CLASS_BASE+11)
> >  #define V4L2_CID_FOCUS_AUTO
> (V4L2_CID_CAMERA_CLASS_BASE+12)
> > +enum v4l2_focus_auto_type {
> > +     V4L2_FOCUS_MANUAL = 0,
> > +     V4L2_FOCUS_AUTO = 1
> > +};
> >
> >  #define V4L2_CID_ZOOM_ABSOLUTE
>  (V4L2_CID_CAMERA_CLASS_BASE+13)
> >  #define V4L2_CID_ZOOM_RELATIVE
>  (V4L2_CID_CAMERA_CLASS_BASE+14)
> > diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
> b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
> > index 6b32fa18..fe3c71d0 100644
> > --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
> > +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
> > @@ -304,13 +304,14 @@ int PipelineHandlerUVC::processControl(ControlList
> *controls, unsigned int id,
> >               cid = V4L2_CID_EXPOSURE_ABSOLUTE;
> >       else if (id == controls::AnalogueGain)
> >               cid = V4L2_CID_GAIN;
> > +     else if (id == controls::LensPosition &&
> controls->idMap()->count(V4L2_CID_FOCUS_ABSOLUTE)) // Check if device
> supports this control
> > +             cid = V4L2_CID_FOCUS_ABSOLUTE;
> > +     else if (id == controls::AfMode &&
> controls->idMap()->count(V4L2_CID_FOCUS_AUTO)) // Check if device supports
> this control
> > +             cid = V4L2_CID_FOCUS_AUTO;
> >       else
> >               return -EINVAL;
> >
> >       const ControlInfo &v4l2Info = controls->infoMap()->at(cid);
> > -     int32_t min = v4l2Info.min().get<int32_t>();
> > -     int32_t def = v4l2Info.def().get<int32_t>();
> > -     int32_t max = v4l2Info.max().get<int32_t>();
> >
> >       /*
> >        * See UVCCameraData::addControl() for explanations of the
> different
> > @@ -318,6 +319,10 @@ int PipelineHandlerUVC::processControl(ControlList
> *controls, unsigned int id,
> >        */
> >       switch (cid) {
> >       case V4L2_CID_BRIGHTNESS: {
> > +             int32_t min = v4l2Info.min().get<int32_t>();
> > +             int32_t def = v4l2Info.def().get<int32_t>();
> > +             int32_t max = v4l2Info.max().get<int32_t>();
> > +
> >               float scale = std::max(max - def, def - min);
> >               float fvalue = value.get<float>() * scale + def;
> >               controls->set(cid, static_cast<int32_t>(lroundf(fvalue)));
> > @@ -325,6 +330,9 @@ int PipelineHandlerUVC::processControl(ControlList
> *controls, unsigned int id,
> >       }
> >
> >       case V4L2_CID_SATURATION: {
> > +             int32_t min = v4l2Info.min().get<int32_t>();
> > +             int32_t def = v4l2Info.def().get<int32_t>();
> > +
> >               float scale = def - min;
> >               float fvalue = value.get<float>() * scale + min;
> >               controls->set(cid, static_cast<int32_t>(lroundf(fvalue)));
> > @@ -345,6 +353,10 @@ int PipelineHandlerUVC::processControl(ControlList
> *controls, unsigned int id,
> >
> >       case V4L2_CID_CONTRAST:
> >       case V4L2_CID_GAIN: {
> > +             int32_t min = v4l2Info.min().get<int32_t>();
> > +             int32_t def = v4l2Info.def().get<int32_t>();
> > +             int32_t max = v4l2Info.max().get<int32_t>();
> > +
> >               float m = (4.0f - 1.0f) / (max - def);
> >               float p = 1.0f - m * def;
> >
> > @@ -358,6 +370,22 @@ int PipelineHandlerUVC::processControl(ControlList
> *controls, unsigned int id,
> >               break;
> >       }
> >
> > +     case V4L2_CID_FOCUS_ABSOLUTE: {
> > +             int32_t min = v4l2Info.min().get<int32_t>();
> > +             int32_t max = v4l2Info.max().get<int32_t>();
> > +
> > +             float focusedAt50Cm = 0.15f * (max - min);
> > +             float scale = focusedAt50Cm / 2.0f;
> > +
> > +             controls->set(cid, static_cast<int>(min +
> value.get<float>() * scale));
> > +             break;
> > +     }
> > +
> > +     case V4L2_CID_FOCUS_AUTO: {
> > +             controls->set(cid, static_cast<int>(value.get<int>() == 0
> ? V4L2_FOCUS_MANUAL : V4L2_FOCUS_AUTO));
> > +             break;
> > +     }
> > +
> >       default: {
> >               int32_t ivalue = value.get<int32_t>();
> >               controls->set(cid, ivalue);
> > @@ -655,14 +683,17 @@ void UVCCameraData::addControl(uint32_t cid, const
> ControlInfo &v4l2Info,
> >       case V4L2_CID_GAIN:
> >               id = &controls::AnalogueGain;
> >               break;
> > +     case V4L2_CID_FOCUS_ABSOLUTE:
> > +             id = &controls::LensPosition;
> > +             break;
> > +     case V4L2_CID_FOCUS_AUTO:
> > +             id = &controls::AfMode;
> > +             break;
> >       default:
> >               return;
> >       }
> >
> >       /* Map the control info. */
> > -     int32_t min = v4l2Info.min().get<int32_t>();
> > -     int32_t max = v4l2Info.max().get<int32_t>();
> > -     int32_t def = v4l2Info.def().get<int32_t>();
> >
> >       switch (cid) {
> >       case V4L2_CID_BRIGHTNESS: {
> > @@ -673,6 +704,9 @@ void UVCCameraData::addControl(uint32_t cid, const
> ControlInfo &v4l2Info,
> >                * Accommodate this by restricting the range of the
> libcamera
> >                * control, but always within the maximum limits.
> >                */
> > +             int32_t min = v4l2Info.min().get<int32_t>();
> > +             int32_t max = v4l2Info.max().get<int32_t>();
> > +             int32_t def = v4l2Info.def().get<int32_t>();
> >               float scale = std::max(max - def, def - min);
> >
> >               info = ControlInfo{
> > @@ -683,36 +717,42 @@ void UVCCameraData::addControl(uint32_t cid, const
> ControlInfo &v4l2Info,
> >               break;
> >       }
> >
> > -     case V4L2_CID_SATURATION:
> > +     case V4L2_CID_SATURATION: {
> >               /*
> >                * The Saturation control is a float, with 0.0 mapped to
> the
> >                * minimum value (corresponding to a fully desaturated
> image)
> >                * and 1.0 mapped to the default value. Calculate the
> maximum
> >                * value accordingly.
> >                */
> > +             int32_t min = v4l2Info.min().get<int32_t>();
> > +             int32_t max = v4l2Info.max().get<int32_t>();
> > +             int32_t def = v4l2Info.def().get<int32_t>();
> >               info = ControlInfo{
> >                       { 0.0f },
> >                       { static_cast<float>(max - min) / (def - min) },
> >                       { 1.0f }
> >               };
> >               break;
> > -
> > +     }
> >       case V4L2_CID_EXPOSURE_AUTO:
> >               info = ControlInfo{ false, true, true };
> >               break;
> >
> > -     case V4L2_CID_EXPOSURE_ABSOLUTE:
> > +     case V4L2_CID_EXPOSURE_ABSOLUTE: {
> >               /*
> >                * ExposureTime is in units of 1 µs, and UVC expects
> >                * V4L2_CID_EXPOSURE_ABSOLUTE in units of 100 µs.
> >                */
> > +             int32_t min = v4l2Info.min().get<int32_t>();
> > +             int32_t max = v4l2Info.max().get<int32_t>();
> > +             int32_t def = v4l2Info.def().get<int32_t>();
> >               info = ControlInfo{
> >                       { min * 100 },
> >                       { max * 100 },
> >                       { def * 100 }
> >               };
> >               break;
> > -
> > +     }
> >       case V4L2_CID_CONTRAST:
> >       case V4L2_CID_GAIN: {
> >               /*
> > @@ -723,6 +763,9 @@ void UVCCameraData::addControl(uint32_t cid, const
> ControlInfo &v4l2Info,
> >                * maximum values are respectively no lower than 0.5 and no
> >                * higher than 4.0.
> >                */
> > +             int32_t min = v4l2Info.min().get<int32_t>();
> > +             int32_t max = v4l2Info.max().get<int32_t>();
> > +             int32_t def = v4l2Info.def().get<int32_t>();
> >               float m = (4.0f - 1.0f) / (max - def);
> >               float p = 1.0f - m * def;
> >
> > @@ -738,6 +781,31 @@ void UVCCameraData::addControl(uint32_t cid, const
> ControlInfo &v4l2Info,
> >               };
> >               break;
> >       }
> > +     case V4L2_CID_FOCUS_ABSOLUTE: {
> > +             int32_t min = v4l2Info.min().get<int32_t>();
> > +             int32_t max = v4l2Info.max().get<int32_t>();
> > +             int32_t def = v4l2Info.def().get<int32_t>();
> > +
> > +             float focusedAt50Cm = 0.15f * (max - min);
> > +             float scale = 2.0f / focusedAt50Cm;
> > +
> > +             info = ControlInfo{
> > +                     { 0.0f },
> > +                     { scale * (max - min) },
> > +                     { scale * (def - min) }
> > +             };
> > +             break;
> > +     }
> > +     case V4L2_CID_FOCUS_AUTO: {
> > +             bool def = v4l2Info.def().get<bool>();
> > +
> > +             info = ControlInfo{
> > +                     { static_cast<int>(V4L2_FOCUS_MANUAL) },
> > +                     { static_cast<int>(V4L2_FOCUS_AUTO) },
> > +                     { static_cast<int>(def ? V4L2_FOCUS_AUTO :
> V4L2_FOCUS_MANUAL) },
> > +             };
> > +             break;
> > +     }
> >
> >       default:
> >               info = v4l2Info;
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.libcamera.org/pipermail/libcamera-devel/attachments/20240914/76ddcb85/attachment.htm>


More information about the libcamera-devel mailing list