How to implement AutoFocus in Camerapagerenderer in Android xamarin forms

Viewed 465

I've used CameraPageRenderer where there is no implementation of AutoFocus. I don't know how to implement it in Xamarin Android.

public async void OnSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)
        {
            camera = global::Android.Hardware.Camera.Open((int)cameraType);
            textureView.LayoutParameters = new FrameLayout.LayoutParams(width, height);
            surfaceTexture = surface;

            camera.SetPreviewTexture(surface);
            PrepareAndStartCamera();
        }
2 Answers

From CameraPageRenderer, setup the "Focus Mode" in the Camera properties by implementing IAutoFocusCallback in CameraPageRenderer.

  public class CameraPageRenderer : PageRenderer, TextureView.ISurfaceTextureListener, IAutoFocusCallback
{

Then implementing OnAutoFocus method, setting AutoFocus.

 public void OnAutoFocus(bool success, Camera camera)
    {
        var parameters = camera.GetParameters();
        if (parameters.FocusMode != Android.Hardware.Camera.Parameters.FocusModeContinuousPicture)
        {
            parameters.FocusMode = Android.Hardware.Camera.Parameters.FocusModeContinuousPicture;

            if (parameters.MaxNumFocusAreas > 0)
            {
                parameters.FocusAreas = null;
            }
            camera.SetParameters(parameters);
            camera.StartPreview();
        }
    }

Update:

I following this thread(How to implement visual indicator when camera is focused), to add AutoFocus for CameraPageRenderer.

  private void TextureView_Touch(object sender, TouchEventArgs e)
    {
        if (camera != null)
        {
            var parameters = camera.GetParameters();
            camera.CancelAutoFocus();
            Rect focusRect = CalculateTapArea(e.Event.GetX(), e.Event.GetY(), 1f);

            if (parameters.FocusMode != Android.Hardware.Camera.Parameters.FocusModeAuto)
            {
                parameters.FocusMode = Android.Hardware.Camera.Parameters.FocusModeAuto;
            }
            if (parameters.MaxNumFocusAreas > 0)
            {
                List<Area> mylist = new List<Area>();
                mylist.Add(new Android.Hardware.Camera.Area(focusRect, 1000));
                parameters.FocusAreas = mylist;
            }

            try
            {
                camera.CancelAutoFocus();
                camera.SetParameters(parameters);
                camera.StartPreview();
                camera.AutoFocus(this);

                MarginLayoutParams margin = new MarginLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent,
       ViewGroup.LayoutParams.WrapContent));
                margin.SetMargins(focusRect.Left, focusRect.Top,
                    focusRect.Right, focusRect.Bottom);
                FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(margin);
                layoutParams.Height = 200;
                layoutParams.Width = 200;
                takePhotoButton.LayoutParameters = layoutParams;
                takePhotoButton.Visibility = ViewStates.Visible;
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Console.Write(ex.StackTrace);
            }
            //return true;
        }
        else
        {
            //return false;
        }
    }
private Rect CalculateTapArea(object x, object y, float coefficient)
    {
        var focusAreaSize = Math.Max(textureView.Width, textureView.Height) / 8; //Recommended focus area size from the manufacture is 1/8 of the image
        int areaSize = focusAreaSize * (int)coefficient;

        int left = clamp(Convert.ToInt32(x) - areaSize / 2, 0, textureView.Width - areaSize);
        int top = clamp(Convert.ToInt32(y) - areaSize / 2, 0, textureView.Height - areaSize);

        RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);
        Matrix.MapRect(rectF);

        return new Rect((int)System.Math.Round(rectF.Left), (int)System.Math.Round(rectF.Top), (int)System.Math.Round(rectF.Right), (int)System.Math.Round(rectF.Bottom));
    }

    private int clamp(int x, int min, int max)
    {
        if (x > max)
        {
            return max;
        }
        if (x < min)
        {
            return min;
        }
        return x;
    }

    public void OnAutoFocus(bool success, Camera camera)
    {
        var parameters = camera.GetParameters();
        if (parameters.FocusMode != Android.Hardware.Camera.Parameters.FocusModeContinuousPicture)
        {
            parameters.FocusMode = Android.Hardware.Camera.Parameters.FocusModeContinuousPicture;

            if (parameters.MaxNumFocusAreas > 0)
            {
                parameters.FocusAreas = null;
            }
            camera.SetParameters(parameters);
            camera.StartPreview();
            
        }
        if(success)
        {
            Task.Delay(1000);
            this.takePhotoButton.Visibility = ViewStates.Invisible;
        }
       
    }

Update:

enter image description here

If you're using the Camera API 1 (the old one) you can set the focus mode to continuous like this:

public void OnSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)
{
    try
    {
        var camera = Camera.Open((int)cameraType);
        var parameters = camera.GetParameters();

        //SET FOCUS MODE HERE
        parameters.FocusMode = Camera.Parameters.FocusModeContinuousPicture;

        camera.SetParameters(parameters);
    }
    catch (Exception ex)
    {
        //log error
        return;
    }

    //other code related to the camera
    textureView.LayoutParameters = new FrameLayout.LayoutParams(width, height);
    surfaceTexture = surface;

    camera.SetPreviewTexture(surface);
    PrepareAndStartCamera();
}
Related