Hi everybody,

I was wondering if anyone ever tried to convert the lens position values (0-255) to cm values that could be used more intuitively, e.g. when setting manual focus or autofocus lens range.

If this was not already done, I would like to do this and report the conversion values here. Does anyone have recommendations e.g. for some standardized templates that could be used to evaluate the focus "quality" as precise as possible?

  • jakaskerl and cycob replied to this.
  • cycob likes this.
  • Hi @jakaskerl @cycob

    I finally tested the relationship between lens position (0-255) and distance to object (cm) to set the auto focus range with cm values. As expected, with increased distance from camera to object, the differences in optimal lens position values decrease. Also it seems like a lens position of 120 is already more or less focused to infinity. When using default auto focus, the minimum lens position was 120 in my tests, even for objects with a distance of > 3 m to the camera.

    I am now using the following code to set the auto focus range with user input values in cm:

    parser = argparse.ArgumentParser()
    parser.add_argument("-af", "--af_range", nargs=2, type=int,
        help="set auto focus range in cm (min distance, max distance)", metavar=("cm_min", "cm_max"))
    args = parser.parse_args()
    
    if args.af_range:
        xin_ctrl = pipeline.create(dai.node.XLinkIn)
        xin_ctrl.setStreamName("control")
        xin_ctrl.out.link(cam_rgb.inputControl)
    
    
    def set_focus_range():
        """Convert closest cm values to lens position values and set auto focus range."""
        cm_lenspos_dict = {
            6: 250,
            8: 220,
            10: 190,
            12: 170,
            14: 160,
            16: 150,
            20: 140,
            25: 135,
            30: 130,
            40: 125,
            60: 120
        }
    
        closest_cm_min = min(cm_lenspos_dict.keys(), key=lambda k: abs(k - args.af_range[0]))
        closest_cm_max = min(cm_lenspos_dict.keys(), key=lambda k: abs(k - args.af_range[1]))
    
        lenspos_min = cm_lenspos_dict[closest_cm_max]  # minimum lens position = 0 (infinity)
        lenspos_max = cm_lenspos_dict[closest_cm_min]  # maximum lens position = 255 (macro)
    
        af_ctrl = dai.CameraControl().setAutoFocusLensRange(lenspos_min, lenspos_max)
        q_ctrl.send(af_ctrl)
    
    
    with dai.Device(pipeline, maxUsbSpeed=dai.UsbSpeed.HIGH) as device:
    
        if args.af_range:
            q_ctrl = device.getInputQueue(name="control")
            set_focus_range()

    Please let me know if you have any recommendations regarding optimization of this approach!

    Hi maxsitt
    Not that I know of. This is difficult to do mathematically since the relationship between lens position and focus distance is generally non-linear and is dependent on a variety of factor which skew the results. You'd need to do this empirically, then do interpolation. You can do it by checking the resolution with ISO 12233 Chart or something similar.

    Thanks,
    Jaka

    maxsitt do this and report the conversion values

    For Oak-D-Lite?
    I was thinking to put robot/camera at various distances and see what lens position is returned after auto focus trigger.

    22 days later

    Hi @jakaskerl @cycob

    I finally tested the relationship between lens position (0-255) and distance to object (cm) to set the auto focus range with cm values. As expected, with increased distance from camera to object, the differences in optimal lens position values decrease. Also it seems like a lens position of 120 is already more or less focused to infinity. When using default auto focus, the minimum lens position was 120 in my tests, even for objects with a distance of > 3 m to the camera.

    I am now using the following code to set the auto focus range with user input values in cm:

    parser = argparse.ArgumentParser()
    parser.add_argument("-af", "--af_range", nargs=2, type=int,
        help="set auto focus range in cm (min distance, max distance)", metavar=("cm_min", "cm_max"))
    args = parser.parse_args()
    
    if args.af_range:
        xin_ctrl = pipeline.create(dai.node.XLinkIn)
        xin_ctrl.setStreamName("control")
        xin_ctrl.out.link(cam_rgb.inputControl)
    
    
    def set_focus_range():
        """Convert closest cm values to lens position values and set auto focus range."""
        cm_lenspos_dict = {
            6: 250,
            8: 220,
            10: 190,
            12: 170,
            14: 160,
            16: 150,
            20: 140,
            25: 135,
            30: 130,
            40: 125,
            60: 120
        }
    
        closest_cm_min = min(cm_lenspos_dict.keys(), key=lambda k: abs(k - args.af_range[0]))
        closest_cm_max = min(cm_lenspos_dict.keys(), key=lambda k: abs(k - args.af_range[1]))
    
        lenspos_min = cm_lenspos_dict[closest_cm_max]  # minimum lens position = 0 (infinity)
        lenspos_max = cm_lenspos_dict[closest_cm_min]  # maximum lens position = 255 (macro)
    
        af_ctrl = dai.CameraControl().setAutoFocusLensRange(lenspos_min, lenspos_max)
        q_ctrl.send(af_ctrl)
    
    
    with dai.Device(pipeline, maxUsbSpeed=dai.UsbSpeed.HIGH) as device:
    
        if args.af_range:
            q_ctrl = device.getInputQueue(name="control")
            set_focus_range()

    Please let me know if you have any recommendations regarding optimization of this approach!

      maxsitt

      Thanks - tried it out - worked for my simple test. Very nice work.