Compartir a través de


Controles de cámara manuales en Xamarin.iOS

Los controles manuales de Cámara, proporcionados por AVFoundation Framework en iOS 8, permiten que una aplicación móvil tome el control total sobre la cámara de un dispositivo con iOS. Este nivel de control específico se puede usar para crear aplicaciones de cámara de nivel profesional y proporcionar composiciones artísticas mediante el ajuste de los parámetros de la cámara mientras se toma una imagen fija o un vídeo.

Estos controles también pueden ser útiles al desarrollar aplicaciones científicas o industriales, donde los resultados están menos orientados a la corrección o belleza de la imagen, y están orientados más hacia resaltar alguna característica o elemento de la imagen que se está tomando.

Objetos de captura de AVFoundation

Tanto si se toman vídeos o imágenes fijas con la cámara en un dispositivo con iOS, el proceso que se usa para capturar esas imágenes es en gran medida el mismo. Esto es cierto en las aplicaciones que usan los controles de cámara automatizados predeterminados o los que aprovechan los nuevos controles de cámara manuales:

Introducción a Capture Objects de AVFoundation

La entrada se toma de un AVCaptureDeviceInput en un AVCaptureSession mediante un AVCaptureConnection. El resultado es la salida como una imagen fija o como una secuencia de vídeo. Un AVCaptureDevice controla todo el proceso.

Controles manuales proporcionados

Con las nuevas API proporcionadas por iOS 8, la aplicación puede tomar el control de las siguientes características de cámara:

  • Enfoque manual: al permitir que el usuario final tome el control del enfoque directamente, una aplicación puede proporcionar más control sobre la imagen tomada.
  • Exposición manual: al proporcionar control manual sobre la exposición, una aplicación puede proporcionar más libertad a los usuarios y permitirles lograr un aspecto estilizado.
  • Balance de blancos manual: el balance de blancos se usa para ajustar el color de una imagen, a menudo para que parezca realista. Según la fuente de luz hay una temperatura de color diferente y la configuración de la cámara utilizada para capturar una imagen se ajusta para compensar estas diferencias. De nuevo, al permitir el control del usuario sobre el balance de blancos, los usuarios pueden realizar ajustes que no se pueden realizar automáticamente.

iOS 8 proporciona extensiones y mejoras a las API de iOS existentes para proporcionar este control específico sobre el proceso de captura de la imagen.

Requisitos

Se requiere lo siguiente para completar los pasos presentados en este artículo:

  • Xcode 7+ e iOS 8 o posterior: las API de Xcode 7 e iOS 8 o más recientes de Apple deben instalarse y configurarse en el equipo del desarrollador.
  • Visual Studio para Mac: la versión más reciente de Visual Studio para Mac debe instalarse y configurarse en el dispositivo de usuario.
  • Dispositivo con iOS 8: un dispositivo con iOS que ejecute la versión más reciente de iOS 8. Las características de la cámara no se pueden probar en el simulador de iOS.

Configuración general de captura de AV

Al grabar vídeo en un dispositivo con iOS, hay algún código de configuración general que siempre es necesario. En esta sección se trata la configuración mínima necesaria para grabar vídeo desde la cámara del dispositivo con iOS y mostrar ese vídeo en tiempo real en un UIImageView.

Delegado de búfer de ejemplo de salida

Una de las primeras cosas necesarias será un delegado para supervisar el búfer de salida de ejemplo y mostrar una imagen capturada del búfer a un UIImageView en la interfaz de usuario de la aplicación.

La siguiente rutina supervisará el búfer de ejemplo y actualizará la interfaz de usuario:

using System;
using Foundation;
using UIKit;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using AVFoundation;
using CoreVideo;
using CoreMedia;
using CoreGraphics;

namespace ManualCameraControls
{
    public class OutputRecorder : AVCaptureVideoDataOutputSampleBufferDelegate
    {
        #region Computed Properties
        public UIImageView DisplayView { get; set; }
        #endregion

        #region Constructors
        public OutputRecorder ()
        {

        }
        #endregion

        #region Private Methods
        private UIImage GetImageFromSampleBuffer(CMSampleBuffer sampleBuffer) {

            // Get a pixel buffer from the sample buffer
            using (var pixelBuffer = sampleBuffer.GetImageBuffer () as CVPixelBuffer) {
                // Lock the base address
                pixelBuffer.Lock (0);

                // Prepare to decode buffer
                var flags = CGBitmapFlags.PremultipliedFirst | CGBitmapFlags.ByteOrder32Little;

                // Decode buffer - Create a new colorspace
                using (var cs = CGColorSpace.CreateDeviceRGB ()) {

                    // Create new context from buffer
                    using (var context = new CGBitmapContext (pixelBuffer.BaseAddress,
                        pixelBuffer.Width,
                        pixelBuffer.Height,
                        8,
                        pixelBuffer.BytesPerRow,
                        cs,
                        (CGImageAlphaInfo)flags)) {

                        // Get the image from the context
                        using (var cgImage = context.ToImage ()) {

                            // Unlock and return image
                            pixelBuffer.Unlock (0);
                            return UIImage.FromImage (cgImage);
                        }
                    }
                }
            }
        }
        #endregion

        #region Override Methods
        public override void DidOutputSampleBuffer (AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
        {
            // Trap all errors
            try {
                // Grab an image from the buffer
                var image = GetImageFromSampleBuffer(sampleBuffer);

                // Display the image
                if (DisplayView !=null) {
                    DisplayView.BeginInvokeOnMainThread(() => {
                        // Set the image
                        if (DisplayView.Image != null) DisplayView.Image.Dispose();
                        DisplayView.Image = image;

                        // Rotate image to the correct display orientation
                        DisplayView.Transform = CGAffineTransform.MakeRotation((float)Math.PI/2);
                    });
                }

                // IMPORTANT: You must release the buffer because AVFoundation has a fixed number
                // of buffers and will stop delivering frames if it runs out.
                sampleBuffer.Dispose();
            }
            catch(Exception e) {
                // Report error
                Console.WriteLine ("Error sampling buffer: {0}", e.Message);
            }
        }
        #endregion
    }
}

Con esta rutina en su lugar, AppDelegate se puede modificar para abrir una sesión de captura de AV para grabar una fuente de vídeo en directo.

Crear una sesión de captura de AV

La sesión de captura de AV se usa para controlar la grabación de vídeo en directo desde la cámara del dispositivo con iOS y es necesaria para obtener un vídeo en una aplicación de iOS. Dado que la aplicación de ejemplo ManualCameraControl usa la sesión de captura en varios lugares diferentes, se configurará en AppDelegate y estará disponible para toda la aplicación.

Haga lo siguiente para modificar el AppDelegate de la aplicación y agregue el código necesario:

  1. Haga doble clic en el archivo AppDelegate.cs en el Explorador de soluciones para abrirlo para su edición.

  2. Agregue las siguientes instrucciones using en la parte superior del archivo :

    using System;
    using Foundation;
    using UIKit;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Linq;
    using AVFoundation;
    using CoreVideo;
    using CoreMedia;
    using CoreGraphics;
    using CoreFoundation;
    
  3. Agregue las siguientes variables privadas y propiedades calculadas a la clase AppDelegate:

    #region Private Variables
    private NSError Error;
    #endregion
    
    #region Computed Properties
    public override UIWindow Window {get;set;}
    public bool CameraAvailable { get; set; }
    public AVCaptureSession Session { get; set; }
    public AVCaptureDevice CaptureDevice { get; set; }
    public OutputRecorder Recorder { get; set; }
    public DispatchQueue Queue { get; set; }
    public AVCaptureDeviceInput Input { get; set; }
    #endregion
    
  4. Invalide el método terminado y cámbielo a:

    public override void FinishedLaunching (UIApplication application)
    {
        // Create a new capture session
        Session = new AVCaptureSession ();
        Session.SessionPreset = AVCaptureSession.PresetMedium;
    
        // Create a device input
        CaptureDevice = AVCaptureDevice.DefaultDeviceWithMediaType (AVMediaType.Video);
        if (CaptureDevice == null) {
            // Video capture not supported, abort
            Console.WriteLine ("Video recording not supported on this device");
            CameraAvailable = false;
            return;
        }
    
        // Prepare device for configuration
        CaptureDevice.LockForConfiguration (out Error);
        if (Error != null) {
            // There has been an issue, abort
            Console.WriteLine ("Error: {0}", Error.LocalizedDescription);
            CaptureDevice.UnlockForConfiguration ();
            return;
        }
    
        // Configure stream for 15 frames per second (fps)
        CaptureDevice.ActiveVideoMinFrameDuration = new CMTime (1, 15);
    
        // Unlock configuration
        CaptureDevice.UnlockForConfiguration ();
    
        // Get input from capture device
        Input = AVCaptureDeviceInput.FromDevice (CaptureDevice);
        if (Input == null) {
            // Error, report and abort
            Console.WriteLine ("Unable to gain input from capture device.");
            CameraAvailable = false;
            return;
        }
    
        // Attach input to session
        Session.AddInput (Input);
    
        // Create a new output
        var output = new AVCaptureVideoDataOutput ();
        var settings = new AVVideoSettingsUncompressed ();
        settings.PixelFormatType = CVPixelFormatType.CV32BGRA;
        output.WeakVideoSettings = settings.Dictionary;
    
        // Configure and attach to the output to the session
        Queue = new DispatchQueue ("ManCamQueue");
        Recorder = new OutputRecorder ();
        output.SetSampleBufferDelegate (Recorder, Queue);
        Session.AddOutput (output);
    
        // Let tabs know that a camera is available
        CameraAvailable = true;
    }
    
  5. Guarde los cambios en el archivo.

Con este código implementado, los controles de Cámara manuales se pueden implementar fácilmente para la experimentación y las pruebas.

Enfoque manual

Al permitir que el usuario final tome los controles del enfoque directamente, una aplicación puede proporcionar más control artístico sobre la imagen tomada.

Por ejemplo, un fotógrafo profesional puede suavizar el enfoque de una imagen para lograr un efecto bokeh. O bien, cree un efecto de extracción de enfoque.

Para los científicos o un escritor de aplicaciones médicas, es posible que la aplicación quiera mover mediante programación la lente para experimentos. La nueva API permite al usuario final o a la aplicación tomar el control sobre el enfoque en el momento en que se toma la imagen.

Funcionamiento del enfoque

Antes de analizar los detalles del control del foco en una aplicación de iOS 8. Echemos un vistazo rápido a cómo funciona el enfoque en un dispositivo con iOS:

Funcionamiento del foco en un dispositivo iOS

La luz entra en la lente de la cámara del dispositivo con iOS y se centra en un sensor de imagen. La distancia de la lente desde los controles del sensor donde el punto focal (el área donde la imagen aparecerá más nítida) está en relación con el sensor. Cuanto más lejos esté la lente del sensor, los objetos distantes parecen más nítidos y los objetos cercanos parecen más nítidos.

En un dispositivo con iOS, la lente se mueve más cerca o más lejos del sensor por imanes y muelles. Como resultado, el posicionamiento exacto de la lente es imposible, ya que variará de un dispositivo a otro, y puede verse afectado por parámetros como la orientación del dispositivo o la antigüedad del dispositivo y los muelles.

Términos de enfoque importantes

Cuando se trabaja con el enfoque, hay algunos términos con los que el desarrollador debe estar familiarizado:

  • Profundidad del campo: la distancia entre los objetos más cercanos y más lejanos enfocados.
  • Macro: este es el extremo cercano del espectro de enfoque y es la distancia más cercana a la que la lente puede enfocarse.
  • Infinito: este es el extremo lejano del espectro de enfoque y es la distancia más lejana a la que la lente puede enfocarse.
  • Distancia hiperfocal: este es el punto del espectro del enfoque donde el objeto más lejano del marco está justo en la parte más lejana del enfoque. En otras palabras, esta es la posición del enfoque que maximiza la profundidad del campo.
  • Posición de la lente: eso es lo que controla todos los términos anteriores. Esta es la distancia de la lente desde el sensor y, por tanto, el controlador del foco.

Teniendo en cuenta estos términos y conocimientos, los nuevos controles de enfoque manual se pueden implementar correctamente en una aplicación de iOS 8.

Controles de enfoque existentes

iOS 7 y versiones anteriores, proporcionaron controles de enfoque existentes a través de la propiedad FocusMode como:

  • AVCaptureFocusModeLocked: el enfoque está bloqueado en un único punto focal.
  • AVCaptureFocusModeAutoFocus: la cámara barre la lente a través de todos los puntos focales hasta que encuentra el enfoque nítido y luego permanece allí.
  • AVCaptureFocusModeContinuousAutoFocus: la cámara se vuelve a enfocar cada vez que detecta una condición fuera del enfoque.

Los controles existentes también proporcionaron un punto de interés establecido a través de la propiedad FocusPointOfInterest para que el usuario pueda pulsar para enfocar en un área determinada. La aplicación también puede realizar un seguimiento del movimiento de la lente supervisando la propiedad IsAdjustingFocus.

Además, la propiedad AutoFocusRangeRestriction proporcionó una restricción de intervalo como:

  • AVCaptureAutoFocusRangeRestrictionNear: restringe el enfoque automático a profundidades cercanas. Resulta útil en situaciones como escanear un código QR o un código de barras.
  • AVCaptureAutoFocusRangeRestrictionFar: restringe el enfoque automático a profundidades lejanas. Resulta útil en situaciones en las que los objetos que se sabe que son irrelevantes están en el campo de visión (por ejemplo, un marco de ventana).

Por último, la propiedad SmoothAutoFocus ralentiza el algoritmo de enfoque automático y lo pasa en incrementos más pequeños para evitar mover artefactos al grabar vídeo.

Nuevos controles de enfoque en iOS 8

Además de las características ya proporcionadas por iOS 7 y las versiones posteriores, las siguientes características ahora están disponibles para controlar el enfoque en iOS 8:

  • Control manual total de la posición de la lente al bloquear el enfoque.
  • Observación clave-valor de la posición de la lente en cualquier modo de enfoque.

Para implementar las características anteriores, la clase AVCaptureDevice se ha modificado para incluir una propiedad LensPosition de solo lectura utilizada para obtener la posición actual de la lente de la cámara.

Para controlar manualmente la posición de la lente, el dispositivo de captura debe estar en el modo de enfoque bloqueado. Ejemplo:

CaptureDevice.FocusMode = AVCaptureFocusMode.Locked;

El método SetFocusModeLocked del dispositivo de captura se usa para ajustar la posición de la lente de la cámara. Se puede proporcionar una rutina de devolución de llamada opcional para obtener notificaciones cuando el cambio surte efecto. Ejemplo:

ThisApp.CaptureDevice.LockForConfiguration(out Error);
ThisApp.CaptureDevice.SetFocusModeLocked(Position.Value,null);
ThisApp.CaptureDevice.UnlockForConfiguration();

Como se muestra en el código anterior, el dispositivo de captura debe estar bloqueado para la configuración antes de que se pueda realizar un cambio en la posición de lente. Los valores válidos de posición de lente están comprendidos entre 0,0 y 1,0.

Ejemplo de enfoque manual

Con el código general de instalación de captura de AV en su lugar, se puede agregar un UIViewController al Storyboard de la aplicación y configurarlo como se indica a continuación:

Un UIViewController se puede agregar a las aplicaciones Storyboard y configurar como se muestra aquí para el ejemplo de enfoque manual.

La vista contiene los siguientes elementos principales:

  • Un UIImageView que mostrará la fuente de vídeo.
  • Un UISegmentedControl que cambiará el modo de enfoque de Automático a Bloqueado.
  • Un UISlider que mostrará y actualizará la posición actual de lente.

Haga lo siguiente para conectar el controlador de vista para el control de enfoque manual:

  1. Agregue las siguientes instrucciones using:

    using System;
    using Foundation;
    using UIKit;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Linq;
    using AVFoundation;
    using CoreVideo;
    using CoreMedia;
    using CoreGraphics;
    using CoreFoundation;
    using System.Timers;
    
  2. Agregue las variables privadas siguientes:

    #region Private Variables
    private NSError Error;
    private bool Automatic = true;
    #endregion
    
  3. Agregue las siguientes propiedades calculadas:

    #region Computed Properties
    public AppDelegate ThisApp {
        get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
    }
    public Timer SampleTimer { get; set; }
    #endregion
    
  4. Invalide el método ViewDidLoad y agregue el código siguiente:

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
    
        // Hide no camera label
        NoCamera.Hidden = ThisApp.CameraAvailable;
    
        // Attach to camera view
        ThisApp.Recorder.DisplayView = CameraView;
    
        // Create a timer to monitor and update the UI
        SampleTimer = new Timer (5000);
        SampleTimer.Elapsed += (sender, e) => {
            // Update position slider
            Position.BeginInvokeOnMainThread(() =>{
                Position.Value = ThisApp.Input.Device.LensPosition;
            });
        };
    
        // Watch for value changes
        Segments.ValueChanged += (object sender, EventArgs e) => {
    
            // Lock device for change
            ThisApp.CaptureDevice.LockForConfiguration(out Error);
    
            // Take action based on the segment selected
            switch(Segments.SelectedSegment) {
            case 0:
                // Activate auto focus and start monitoring position
                Position.Enabled = false;
                ThisApp.CaptureDevice.FocusMode = AVCaptureFocusMode.ContinuousAutoFocus;
                SampleTimer.Start();
                Automatic = true;
                break;
            case 1:
                // Stop auto focus and allow the user to control the camera
                SampleTimer.Stop();
                ThisApp.CaptureDevice.FocusMode = AVCaptureFocusMode.Locked;
                Automatic = false;
                Position.Enabled = true;
                break;
            }
    
            // Unlock device
            ThisApp.CaptureDevice.UnlockForConfiguration();
        };
    
        // Monitor position changes
        Position.ValueChanged += (object sender, EventArgs e) => {
    
            // If we are in the automatic mode, ignore changes
            if (Automatic) return;
    
            // Update Focus position
            ThisApp.CaptureDevice.LockForConfiguration(out Error);
            ThisApp.CaptureDevice.SetFocusModeLocked(Position.Value,null);
            ThisApp.CaptureDevice.UnlockForConfiguration();
        };
    }
    
  5. Invalide el método ViewDidAppear y agregue lo siguiente para empezar la grabación cuando se cargue la vista:

    public override void ViewDidAppear (bool animated)
    {
        base.ViewDidAppear (animated);
    
        // Start udating the display
        if (ThisApp.CameraAvailable) {
            // Remap to this camera view
            ThisApp.Recorder.DisplayView = CameraView;
    
            ThisApp.Session.StartRunning ();
            SampleTimer.Start ();
        }
    }
    
  6. Con la cámara en el modo Automático, el control deslizante se moverá automáticamente a medida que la cámara ajusta el enfoque:

    El control deslizante se moverá automáticamente a medida que la cámara ajusta el foco en esta aplicación de ejemplo

  7. Pulse el segmento Bloqueado y arrastre el control deslizante de posición para ajustar la posición de la lente manualmente:

    Ajuste manual de la posición de la lente

  8. Detenga la aplicación.

El código anterior ha mostrado cómo supervisar la posición de la lente cuando la cámara está en modo automático o usar un control deslizante para controlar la posición de la lente cuando está en el modo Bloqueado.

Exposición manual

La exposición hace referencia al brillo de una imagen en relación con el brillo de origen y se determina mediante la cantidad de luz que alcanza el sensor, durante cuánto tiempo y por el nivel de ganancia del sensor (asignación ISO). Al proporcionar control manual sobre la exposición, una aplicación puede proporcionar más libertad al usuario final y permitirle lograr un aspecto estilizado.

Con los controles de exposición manual, el usuario puede pasar una imagen de tener un brillo poco realista a ser oscura y taciturna:

Una muestra de una imagen que muestra la exposición de una luz poco realista a oscura y de estado de ánimo

De nuevo, esto se puede hacer automáticamente mediante el control mediante programación para aplicaciones científicas o a través de controles manuales proporcionados por la interfaz de usuario de las aplicaciones. En cualquier caso, las nuevas API de exposición de iOS 8 proporcionan un control específico sobre la configuración de exposición de la cámara.

Cómo funciona la exposición

Antes de analizar los detalles del control de la exposición en una aplicación de iOS 8. Echemos un vistazo rápido a cómo funciona la exposición:

Funcionamiento de la exposición

Los tres elementos básicos que se unen para controlar la exposición son:

  • Velocidad del obturador: es el tiempo que el obturador está abierto para permitir la luz en el sensor de la cámara. Cuanto menor sea el tiempo que el obturador está abierto, menos luz se deja entrar y más nítida será la imagen (menos desenfoque de movimiento). Cuanto más tiempo esté abierto el obturador, más luz se deja entrar y más desenfoque de movimiento se produce.
  • Sensibilidad ISO: se trata de un término prestado de la fotografía cinematográfica y hace referencia a la sensibilidad de los productos químicos de la película a la luz. Los valores ISO bajos en película tienen menos grano y reproducción de color más fino; Los valores ISO bajos en los sensores digitales tienen menos ruido del sensor, pero menos brillo. Cuanto mayor sea el valor ISO, más brillante será la imagen, pero con más ruido del sensor. "ISO" en un sensor digital es una medida de ganancia electrónica, no una característica física.
  • Apertura de lente: este es el tamaño de la apertura de la lente. En todos los dispositivos iOS, la apertura de la lente es fija, por lo que los dos únicos valores que se pueden usar para ajustar la exposición son la velocidad de obturación e ISO.

Cómo funciona la exposición automática continua

Antes de aprender cómo funciona la exposición manual, es una buena idea comprender cómo funciona la exposición automática continua en un dispositivo con iOS.

Funcionamiento de la exposición automática continua en un dispositivo iOS

En primer lugar está el bloqueo de exposición automática, que tiene el trabajo de calcular la exposición ideal y se alimenta continuamente de las estadísticas de medición. Utiliza esta información para calcular la combinación óptima de ISO y velocidad de obturación para que la escena esté bien iluminada. Este ciclo se conoce como bucle AE.

Cómo funciona la exposición bloqueada

A continuación, vamos a examinar cómo funciona la exposición bloqueada en dispositivos con iOS.

Funcionamiento de la exposición bloqueada en dispositivos iOS

De nuevo, tiene el bloqueo de exposición automática que intenta calcular los valores óptimos de iOS y Duración. Sin embargo, en este modo, el bloqueo AE está desconectado del motor de estadísticas de medición.

Controles de exposición existentes

En iOS 7 y las versiones posteriores, proporcione los siguientes controles de exposición existentes a través de la propiedad ExposureMode:

  • AVCaptureExposureModeLocked: muestra la escena una vez y usa esos valores en toda la escena.
  • AVCaptureExposureModeContinuousAutoExposure: muestrea la escena continuamente para asegurarse de que está bien iluminada.

El ExposurePointOfInterest se puede usar para pulsar para exponer la escena seleccionando un objeto de destino en el que exponer y la aplicación puede supervisar la propiedad AdjustingExposure para ver cuándo se ajusta la exposición.

Nuevos controles de exposición en iOS 8

Además de las características ya proporcionadas por iOS 7 y las versiones posteriores, las siguientes características ahora están disponibles para controlar la exposición en iOS 8:

  • Exposición personalizada totalmente manual.
  • Obtener, establecer y observar valores clave de IOS y la velocidad de obturación (duración).

Para implementar las características anteriores, se ha agregado un nuevo modo AVCaptureExposureModeCustom. Cuando la cámara en es el modo personalizado, se puede usar el código siguiente para ajustar la duración de exposición e ISO:

CaptureDevice.LockForConfiguration(out Error);
CaptureDevice.LockExposure(DurationValue,ISOValue,null);
CaptureDevice.UnlockForConfiguration();

En los modos Automático y Bloqueado, la aplicación puede ajustar el bias de la rutina de exposición automática mediante el código siguiente:

CaptureDevice.LockForConfiguration(out Error);
CaptureDevice.SetExposureTargetBias(Value,null);
CaptureDevice.UnlockForConfiguration();

Los intervalos de configuración mínimo y máximo dependen del dispositivo en el que se ejecuta la aplicación, por lo que nunca deben codificarse de forma rígida. En su lugar, use las siguientes propiedades para obtener los intervalos de valor mínimo y máximo:

  • CaptureDevice.MinExposureTargetBias
  • CaptureDevice.MaxExposureTargetBias
  • CaptureDevice.ActiveFormat.MinISO
  • CaptureDevice.ActiveFormat.MaxISO
  • CaptureDevice.ActiveFormat.MinExposureDuration
  • CaptureDevice.ActiveFormat.MaxExposureDuration

Como se muestra en el código anterior, el dispositivo de captura debe estar bloqueado para la configuración antes de que se pueda realizar un cambio en la exposición.

Ejemplo de exposición manual

Con el código general de instalación de captura de AV en su lugar, se puede agregar un UIViewController al Storyboard de la aplicación y configurarlo como se indica a continuación:

Un UIViewController se puede agregar a las aplicaciones Storyboard y configurar como se muestra aquí para el ejemplo de exposición manual.

La vista contiene los siguientes elementos principales:

  • Un UIImageView que mostrará la fuente de vídeo.
  • Un UISegmentedControl que cambiará el modo de enfoque de Automático a Bloqueado.
  • Cuatro controles UISlider que mostrarán y actualizarán el offset, la duración, el ISO y el bias.

Haga lo siguiente para conectar el controlador de vista para el control de exposición manual:

  1. Agregue las siguientes instrucciones using:

    using System;
    using Foundation;
    using UIKit;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Linq;
    using AVFoundation;
    using CoreVideo;
    using CoreMedia;
    using CoreGraphics;
    using CoreFoundation;
    using System.Timers;
    
  2. Agregue las variables privadas siguientes:

    #region Private Variables
    private NSError Error;
    private bool Automatic = true;
    private nfloat ExposureDurationPower = 5;
    private nfloat ExposureMinimumDuration = 1.0f/1000.0f;
    #endregion
    
  3. Agregue las siguientes propiedades calculadas:

    #region Computed Properties
    public AppDelegate ThisApp {
        get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
    }
    public Timer SampleTimer { get; set; }
    #endregion
    
  4. Invalide el método ViewDidLoad y agregue el código siguiente:

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
    
        // Hide no camera label
        NoCamera.Hidden = ThisApp.CameraAvailable;
    
        // Attach to camera view
        ThisApp.Recorder.DisplayView = CameraView;
    
        // Set min and max values
        Offset.MinValue = ThisApp.CaptureDevice.MinExposureTargetBias;
        Offset.MaxValue = ThisApp.CaptureDevice.MaxExposureTargetBias;
    
        Duration.MinValue = 0.0f;
        Duration.MaxValue = 1.0f;
    
        ISO.MinValue = ThisApp.CaptureDevice.ActiveFormat.MinISO;
        ISO.MaxValue = ThisApp.CaptureDevice.ActiveFormat.MaxISO;
    
        Bias.MinValue = ThisApp.CaptureDevice.MinExposureTargetBias;
        Bias.MaxValue = ThisApp.CaptureDevice.MaxExposureTargetBias;
    
        // Create a timer to monitor and update the UI
        SampleTimer = new Timer (5000);
        SampleTimer.Elapsed += (sender, e) => {
            // Update position slider
            Offset.BeginInvokeOnMainThread(() =>{
                Offset.Value = ThisApp.Input.Device.ExposureTargetOffset;
            });
    
            Duration.BeginInvokeOnMainThread(() =>{
                var newDurationSeconds = CMTimeGetSeconds(ThisApp.Input.Device.ExposureDuration);
                var minDurationSeconds = Math.Max(CMTimeGetSeconds(ThisApp.CaptureDevice.ActiveFormat.MinExposureDuration), ExposureMinimumDuration);
                var maxDurationSeconds = CMTimeGetSeconds(ThisApp.CaptureDevice.ActiveFormat.MaxExposureDuration);
                var p = (newDurationSeconds - minDurationSeconds) / (maxDurationSeconds - minDurationSeconds);
                Duration.Value = (float)Math.Pow(p, 1.0f/ExposureDurationPower);
            });
    
            ISO.BeginInvokeOnMainThread(() => {
                ISO.Value = ThisApp.Input.Device.ISO;
            });
    
            Bias.BeginInvokeOnMainThread(() => {
                Bias.Value = ThisApp.Input.Device.ExposureTargetBias;
            });
        };
    
        // Watch for value changes
        Segments.ValueChanged += (object sender, EventArgs e) => {
    
            // Lock device for change
            ThisApp.CaptureDevice.LockForConfiguration(out Error);
    
            // Take action based on the segment selected
            switch(Segments.SelectedSegment) {
            case 0:
                // Activate auto exposure and start monitoring position
                Duration.Enabled = false;
                ISO.Enabled = false;
                ThisApp.CaptureDevice.ExposureMode = AVCaptureExposureMode.ContinuousAutoExposure;
                SampleTimer.Start();
                Automatic = true;
                break;
            case 1:
                // Lock exposure and allow the user to control the camera
                SampleTimer.Stop();
                ThisApp.CaptureDevice.ExposureMode = AVCaptureExposureMode.Locked;
                Automatic = false;
                Duration.Enabled = false;
                ISO.Enabled = false;
                break;
            case 2:
                // Custom exposure and allow the user to control the camera
                SampleTimer.Stop();
                ThisApp.CaptureDevice.ExposureMode = AVCaptureExposureMode.Custom;
                Automatic = false;
                Duration.Enabled = true;
                ISO.Enabled = true;
                break;
            }
    
            // Unlock device
            ThisApp.CaptureDevice.UnlockForConfiguration();
        };
    
        // Monitor position changes
        Duration.ValueChanged += (object sender, EventArgs e) => {
    
            // If we are in the automatic mode, ignore changes
            if (Automatic) return;
    
            // Calculate value
            var p = Math.Pow(Duration.Value,ExposureDurationPower);
            var minDurationSeconds = Math.Max(CMTimeGetSeconds(ThisApp.CaptureDevice.ActiveFormat.MinExposureDuration),ExposureMinimumDuration);
            var maxDurationSeconds = CMTimeGetSeconds(ThisApp.CaptureDevice.ActiveFormat.MaxExposureDuration);
            var newDurationSeconds = p * (maxDurationSeconds - minDurationSeconds) +minDurationSeconds;
    
            // Update Focus position
            ThisApp.CaptureDevice.LockForConfiguration(out Error);
            ThisApp.CaptureDevice.LockExposure(CMTime.FromSeconds(p,1000*1000*1000),ThisApp.CaptureDevice.ISO,null);
            ThisApp.CaptureDevice.UnlockForConfiguration();
        };
    
        ISO.ValueChanged += (object sender, EventArgs e) => {
    
            // If we are in the automatic mode, ignore changes
            if (Automatic) return;
    
            // Update Focus position
            ThisApp.CaptureDevice.LockForConfiguration(out Error);
            ThisApp.CaptureDevice.LockExposure(ThisApp.CaptureDevice.ExposureDuration,ISO.Value,null);
            ThisApp.CaptureDevice.UnlockForConfiguration();
        };
    
        Bias.ValueChanged += (object sender, EventArgs e) => {
    
            // If we are in the automatic mode, ignore changes
            // if (Automatic) return;
    
            // Update Focus position
            ThisApp.CaptureDevice.LockForConfiguration(out Error);
            ThisApp.CaptureDevice.SetExposureTargetBias(Bias.Value,null);
            ThisApp.CaptureDevice.UnlockForConfiguration();
        };
    }
    
  5. Invalide el método ViewDidAppear y agregue lo siguiente para empezar la grabación cuando se cargue la vista:

    public override void ViewDidAppear (bool animated)
    {
        base.ViewDidAppear (animated);
    
        // Start udating the display
        if (ThisApp.CameraAvailable) {
            // Remap to this camera view
            ThisApp.Recorder.DisplayView = CameraView;
    
            ThisApp.Session.StartRunning ();
            SampleTimer.Start ();
        }
    }
    
  6. Con la cámara en el modo Automático, los controles deslizantes se moverán automáticamente a medida que la cámara ajusta la exposición:

    Los controles deslizantes se moverán automáticamente a medida que la cámara ajusta la exposición

  7. Pulse el segmento Bloqueado y arrastre el control deslizante de bias para ajustar el bias de la exposición automática manualmente:

    Ajuste del sesgo de la exposición automática manualmente

  8. Pulse el segmento Personalizado y arrastre los controles deslizantes de Duración e ISO para controlar manualmente la exposición:

    Arrastre los controles deslizantes de Duración e ISO para controlar manualmente la exposición

  9. Detenga la aplicación.

El código anterior ha mostrado cómo supervisar la configuración de exposición cuando la cámara está en modo automático y cómo usar controles deslizantes para controlar la exposición cuando se encuentra en los modos Bloqueado o Personalizado.

Equilibrio manual de blancos

Los controles de balance blancos permiten a los usuarios ajustar el balance de colores en una imagen para que parezcan más realistas. Según la fuente de luz hay una temperatura de color diferente y la configuración de la cámara utilizada para capturar una imagen se debe ajustar para compensar estas diferencias. De nuevo, al permitir que el usuario controle el balance blancos, puede realizar ajustes profesionales que las rutinas automáticas son incapaces de lograr para conseguir efectos artísticos.

Imagen de ejemplo en la que se muestran los ajustes manuales del balance de blancos

Por ejemplo, la luz del día tiene un tono azulado, mientras que las luces fluorescentes de tungsteno tienen un tono amarillo-naranja cálido. (Es confuso, pero los colores «fríos» tienen temperaturas de color más altas que los colores «cálidos». Las temperaturas del color son una medida física, no una medida perceptiva.)

La mente humana es muy buena para compensar las diferencias en la temperatura del color, pero esto es algo que una cámara no puede hacer. La cámara funciona aumentando el color en el espectro opuesto para ajustar las diferencias de color.

La nueva API de exposición de iOS 8 permite a la aplicación tomar el control del proceso y proporcionar un control específico sobre la configuración del balance de blancos de la cámara.

Cómo funciona el balance de blancos

Antes de analizar los detalles del control del balance de blancos en una aplicación de iOS 8. Echemos un vistazo rápido a cómo funciona el balance de blancos:

En el estudio de la percepción del color, el espacio de colores RGB CIE 1931 y el espacio de colores XYZ CIE 1931 son los primeros espacios de color definidos matemáticamente. Fueron creados por la Comisión Internacional de Iluminación (CIE) en 1931.

Espacio de colores RGB CIE 1931 y espacio de colores CIE 1931 XYZ

El gráfico anterior nos muestra todos los colores visibles para el ojo humano, de azul oscuro a verde brillante a rojo brillante. Cualquier punto del diagrama se puede trazar con un valor X e Y, como se muestra en el gráfico anterior.

Como se ve en el gráfico, hay valores X e Y que se pueden trazar en el gráfico que estarían fuera del rango de visión humana y, como resultado, estos colores no se pueden reproducir mediante una cámara.

La curva más pequeña del gráfico anterior se denomina locus planckiano, que expresa la temperatura de color (en grados kelvin), con números más altos en el lado azul (más caliente) y números más bajos en el lado rojo (más frío). Son útiles para situaciones típicas de iluminación.

En condiciones de iluminación mixta, los ajustes de balance de blancos deberán desviarse del locus planckiano para realizar los cambios necesarios. En estas situaciones, el ajuste deberá desplazarse al lado verde o rojo/magenta de la escala de CIE.

Los dispositivos con iOS compensan las conversiones de color aumentando los tonos del color opuesto. Por ejemplo, si una escena tiene demasiado azul, se aumentará la ganancia roja para compensar. Estos valores de ganancia se calibran para dispositivos específicos para que sean dependientes del dispositivo.

Controles de balance de blancos existentes

iOS 7 y las versiones posteriores proporcionaron los siguientes controles de balance de blancos existentes a través de la propiedad WhiteBalanceMode:

  • AVCapture WhiteBalance ModeLocked: muestra la escena una vez y usa esos valores en toda la escena.
  • AVCapture WhiteBalance ModeContinuousAutoExposure: muestrea la escena continuamente para asegurarse de que está bien equilibrada.

Y la aplicación puede supervisar la propiedad AdjustingWhiteBalance para ver cuándo se ajusta la exposición.

Nuevos controles de balance de blancos en iOS 8

Además de las características ya proporcionadas por iOS 7 y las versiones posteriores, las siguientes características ahora están disponibles para controlar el balance de blancos en iOS 8:

  • Control totalmente manual de las ganancias RGB del dispositivo.
  • Obtener, establecer y observar valores clave las ganancias RGB del dispositivo.
  • Compatibilidad del balance de blancos mediante una carta gris.
  • Rutinas de conversión hacia y desde espacios de colores independientes del dispositivo.

Para implementar las características anteriores, la estructura AVCaptureWhiteBalanceGain se ha agregado con los miembros siguientes:

  • RedGain
  • GreenGain
  • BlueGain

La ganancia máxima del balance de blancos es actualmente cuatro (4) y puede estar lista desde la propiedad MaxWhiteBalanceGain. Por lo tanto, el intervalo legal es de uno (1) a MaxWhiteBalanceGain (4) actualmente.

La propiedad DeviceWhiteBalanceGains se puede usar para observar los valores actuales. Use SetWhiteBalanceModeLockedWithDeviceWhiteBalanceGains para ajustar las ganancias del balance cuando la cámara está en el modo de balance de blancos bloqueado.

Rutinas de conversión

Las rutinas de conversión se han agregado a iOS 8 para ayudar a convertir espacios de color independientes hacia y desde el dispositivo. Para implementar las rutinas de conversión, la estructura AVCaptureWhiteBalanceChromaticityValues se ha agregado con los miembros siguientes:

  • X: es un valor de 0 a 1.
  • Y: es un valor de 0 a 1.

También se ha agregado una estructura AVCaptureWhiteBalanceTemperatureAndTintValues con los siguientes miembros:

  • Temperature: es un valor de punto flotante en grados Kelvin.
  • Tint: es un offset de verde o magenta de 0 a 150 con valores positivos hacia la dirección verde y negativo hacia el magenta.

Utilice los métodos CaptureDevice.GetTemperatureAndTintValues y CaptureDevice.GetDeviceWhiteBalanceGains para convertir entre temperatura y tono, cromacidad y espacios de color de ganancia RGB.

Nota:

Las rutinas de conversión son más precisas cuanto más cerca se convierta el valor que se va a convertir es al llocus planckiano.

Compatibilidad con carta gris

Apple usa el término mundo gris para hacer referencia a la compatibilidad con la carta gris integrada en iOS 8. Permite al usuario centrarse en una carta gris física que cubre al menos el 50 % del centro del marco y lo usa para ajustar el balance de blancos. El propósito de la carta gris es lograr un blanco que aparezca neutro.

Esto se puede implementar en una aplicación mediante la solicitud al usuario de colocar una carta gris física delante de la cámara, supervisar la propiedad GrayWorldDeviceWhiteBalanceGains y esperar hasta que los valores se liquiden.

A continuación, la aplicación bloquearía las ganancias del balance de blancos para el método SetWhiteBalanceModeLockedWithDeviceWhiteBalanceGains mediante los valores de la propiedad GrayWorldDeviceWhiteBalanceGains para aplicar los cambios.

El dispositivo de captura debe estar bloqueado para la configuración antes de que se pueda realizar un cambio en el balance de blancos.

Ejemplo manual de balance de blancos

Con el código general de instalación de captura de AV en su lugar, se puede agregar un UIViewController al Storyboard de la aplicación y configurarlo como se indica a continuación:

Un UIViewController se puede agregar a las aplicaciones Storyboard y configurar como se muestra aquí para el ejemplo manual de balance de blancos.

La vista contiene los siguientes elementos principales:

  • Un UIImageView que mostrará la fuente de vídeo.
  • Un UISegmentedControl que cambiará el modo de enfoque de Automático a Bloqueado.
  • Dos controles UISlider que mostrarán y actualizarán la temperatura y el tono.
  • Un UIButton se usa para muestrear un espacio de carta gris (mundo gris) y establecer el balance de blancos con esos valores.

Haga lo siguiente para conectar el controlador de vista para el control de balance de blancos manual:

  1. Agregue las siguientes instrucciones using:

    using System;
    using Foundation;
    using UIKit;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Linq;
    using AVFoundation;
    using CoreVideo;
    using CoreMedia;
    using CoreGraphics;
    using CoreFoundation;
    using System.Timers;
    
  2. Agregue las variables privadas siguientes:

    #region Private Variables
    private NSError Error;
    private bool Automatic = true;
    #endregion
    
  3. Agregue las siguientes propiedades calculadas:

    #region Computed Properties
    public AppDelegate ThisApp {
        get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
    }
    public Timer SampleTimer { get; set; }
    #endregion
    
  4. Agregue el siguiente método privado para establecer el nuevo tono y temperatura del balance de blancos:

    #region Private Methods
    void SetTemperatureAndTint() {
        // Grab current temp and tint
        var TempAndTint = new AVCaptureWhiteBalanceTemperatureAndTintValues (Temperature.Value, Tint.Value);
    
        // Convert Color space
        var gains = ThisApp.CaptureDevice.GetDeviceWhiteBalanceGains (TempAndTint);
    
        // Set the new values
        if (ThisApp.CaptureDevice.LockForConfiguration (out Error)) {
            gains = NomralizeGains (gains);
            ThisApp.CaptureDevice.SetWhiteBalanceModeLockedWithDeviceWhiteBalanceGains (gains, null);
            ThisApp.CaptureDevice.UnlockForConfiguration ();
        }
    }
    
    AVCaptureWhiteBalanceGains NomralizeGains (AVCaptureWhiteBalanceGains gains)
    {
        gains.RedGain = Math.Max (1, gains.RedGain);
        gains.BlueGain = Math.Max (1, gains.BlueGain);
        gains.GreenGain = Math.Max (1, gains.GreenGain);
    
        float maxGain = ThisApp.CaptureDevice.MaxWhiteBalanceGain;
        gains.RedGain = Math.Min (maxGain, gains.RedGain);
        gains.BlueGain = Math.Min (maxGain, gains.BlueGain);
        gains.GreenGain = Math.Min (maxGain, gains.GreenGain);
    
        return gains;
    }
    #endregion
    
  5. Invalide el método ViewDidLoad y agregue el código siguiente:

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
    
        // Hide no camera label
        NoCamera.Hidden = ThisApp.CameraAvailable;
    
        // Attach to camera view
        ThisApp.Recorder.DisplayView = CameraView;
    
        // Set min and max values
        Temperature.MinValue = 1000f;
        Temperature.MaxValue = 10000f;
    
        Tint.MinValue = -150f;
        Tint.MaxValue = 150f;
    
        // Create a timer to monitor and update the UI
        SampleTimer = new Timer (5000);
        SampleTimer.Elapsed += (sender, e) => {
            // Convert color space
            var TempAndTint = ThisApp.CaptureDevice.GetTemperatureAndTintValues (ThisApp.CaptureDevice.DeviceWhiteBalanceGains);
    
            // Update slider positions
            Temperature.BeginInvokeOnMainThread (() => {
                Temperature.Value = TempAndTint.Temperature;
            });
    
            Tint.BeginInvokeOnMainThread (() => {
                Tint.Value = TempAndTint.Tint;
            });
        };
    
        // Watch for value changes
        Segments.ValueChanged += (sender, e) => {
            // Lock device for change
            if (ThisApp.CaptureDevice.LockForConfiguration (out Error)) {
    
                // Take action based on the segment selected
                switch (Segments.SelectedSegment) {
                case 0:
                // Activate auto focus and start monitoring position
                    Temperature.Enabled = false;
                    Tint.Enabled = false;
                    ThisApp.CaptureDevice.WhiteBalanceMode = AVCaptureWhiteBalanceMode.ContinuousAutoWhiteBalance;
                    SampleTimer.Start ();
                    Automatic = true;
                    break;
                case 1:
                // Stop auto focus and allow the user to control the camera
                    SampleTimer.Stop ();
                    ThisApp.CaptureDevice.WhiteBalanceMode = AVCaptureWhiteBalanceMode.Locked;
                    Automatic = false;
                    Temperature.Enabled = true;
                    Tint.Enabled = true;
                    break;
                }
    
                // Unlock device
                ThisApp.CaptureDevice.UnlockForConfiguration ();
            }
        };
    
        // Monitor position changes
        Temperature.TouchUpInside += (sender, e) => {
    
            // If we are in the automatic mode, ignore changes
            if (Automatic)
                return;
    
            // Update white balance
            SetTemperatureAndTint ();
        };
    
        Tint.TouchUpInside += (sender, e) => {
    
            // If we are in the automatic mode, ignore changes
            if (Automatic)
                return;
    
            // Update white balance
            SetTemperatureAndTint ();
        };
    
        GrayCardButton.TouchUpInside += (sender, e) => {
    
            // If we are in the automatic mode, ignore changes
            if (Automatic)
                return;
    
            // Get gray card values
            var gains = ThisApp.CaptureDevice.GrayWorldDeviceWhiteBalanceGains;
    
            // Set the new values
            if (ThisApp.CaptureDevice.LockForConfiguration (out Error)) {
                ThisApp.CaptureDevice.SetWhiteBalanceModeLockedWithDeviceWhiteBalanceGains (gains, null);
                ThisApp.CaptureDevice.UnlockForConfiguration ();
            }
        };
    }
    
  6. Invalide el método ViewDidAppear y agregue lo siguiente para empezar la grabación cuando se cargue la vista:

    public override void ViewDidAppear (bool animated)
    {
        base.ViewDidAppear (animated);
    
        // Start udating the display
        if (ThisApp.CameraAvailable) {
            // Remap to this camera view
            ThisApp.Recorder.DisplayView = CameraView;
    
            ThisApp.Session.StartRunning ();
            SampleTimer.Start ();
        }
    }
    
  7. Guarde los cambios en el código y ejecute la aplicación.

  8. Con la cámara en el modo Automático, los controles deslizantes se moverán automáticamente a medida que la cámara ajusta el balance de blancos:

    Los controles deslizantes se moverán automáticamente a medida que la cámara ajusta el balance de blancos

  9. Pulse el segmento Bloqueado y arrastre los controles deslizantes de temperatura y tono para ajustar el balance de blancos manualmente:

    Arrastre los controles deslizantes de temperatura y tono para ajustar el balance de blancos manualmente

  10. Con el segmento Bloqueado aún seleccionado, coloque una carta gris física delante de la cámara y pulse el botón carta gris para ajustar el balance de blanco al mundo gris:

    Pulse el botón Tarjeta gris para ajustar el balance de blancos al mundo gris

  11. Detenga la aplicación.

El código anterior ha mostrado cómo supervisar la configuración del balance de blancos cuando la cámara está en modo automático o usar controles deslizantes para controlar el balance de blancos cuando está en el modo Bloqueado.

Captura entre corchetes

La captura entre corchetes se basa en la configuración de los controles manuales de la cámara presentados anteriormente y permite a la aplicación capturar un momento en el tiempo de varias maneras diferentes.

En pocas palabras, la captura entre corchetes es una ráfaga de imágenes fijas tomadas con una variedad de configuraciones de imagen a imagen.

Funcionamiento de Bracketed Capture

Con la captura entre corchetes en iOS 8, una aplicación puede preestablecer una serie de controles manuales de la cámara, emitir un único comando y hacer que la escena actual devuelva una serie de imágenes para cada uno de los valores preestablecidos manuales.

Conceptos básicos de captura entre corchetes

De nuevo, la captura entre corchetes es una ráfaga de imágenes fijas tomadas con varias configuraciones de imagen a imagen. Los tipos de captura entre corchetes disponibles son:

  • Corchete de exposición automática: donde todas las imágenes tienen una cantidad de bias variado.
  • Corchete de exposición manual: donde todas las imágenes tienen una cantidad variada de velocidad de obturación (duración) e ISO.
  • Corchete de ráfaga simple: una serie de imágenes fijas tomadas en una sucesión rápida.

Nuevos controles de captura entre corchetes en iOS 8

Todos los comandos de captura entre corchetes se implementan en la clase AVCaptureStillImageOutput. Use el método CaptureStillImageBracket para obtener una serie de imágenes con la matriz de configuración especificada.

Se han implementado dos clases nuevas para controlar la configuración:

  • AVCaptureAutoExposureBracketedStillImageSettings: tiene una propiedad, ExposureTargetBias, utilizada para establecer el bias de un corchete de exposición automática.
  • AVCaptureManualExposureBracketedStillImageSettings: tiene dos propiedades, ExposureDuration y ISO, usadas para establecer la velocidad del obturador e ISO para un corchete de exposición manual.

Normas de los controles de captura entre corchetes

Qué hacer

A continuación se muestra una lista de las cosas que se deben hacer al usar los controles de captura entre corchetes en iOS 8:

  • Prepare la aplicación para la situación de captura en el peor de los casos llamando al método PrepareToCaptureStillImageBracket.
  • Supongamos que los búferes de ejemplo van a proceder del mismo grupo compartido.
  • Para liberar la memoria asignada por una llamada de preparación anterior, vuelva a llamar a PrepareToCaptureStillImageBracket y envíe una matriz de un objeto.

No

A continuación se muestra una lista de las cosas que no se deben hacer al usar los controles de captura entre corchetes en iOS 8:

  • No mezcle los tipos de configuración de captura entre corchetes en una sola captura.
  • No solicite más de MaxBracketedCaptureStillImageCount imágenes en una sola captura.

Detalles de captura entre corchetes

Se deben tener en cuenta los detalles siguientes al trabajar con la captura entre corchetes en iOS 8:

  • La configuración entre corchetes invalida temporalmente la configuración AVCaptureDevice.
  • Se omiten los ajustes de estabilización de imágenes y del flash.
  • Todas las imágenes deben usar el mismo formato de salida (jpeg, png, etc.)
  • La vista previa del vídeo puede quitar fotogramas.
  • La captura entre corchetes es compatible con todos los dispositivos compatibles con iOS 8.

Teniendo en cuenta esta información, echemos un vistazo a un ejemplo de uso de captura entre corchetes en iOS 8.

Ejemplo de captura entre corchetes

Con el código general de instalación de captura de AV en su lugar, se puede agregar un UIViewController al Storyboard de la aplicación y configurarlo como se indica a continuación:

Un UIViewController se puede agregar a las aplicaciones Storyboard y configurar como se muestra aquí ejemplo de captura de encuadre.

La vista contiene los siguientes elementos principales:

  • Un UIImageView que mostrará la fuente de vídeo.
  • Tres UIImageViews que mostrarán los resultados de la captura.
  • Un objeto UIScrollView para alojar la fuente de vídeo y las vistas de resultados.
  • Un UIButton se usa para tomar una captura entre corchetes con algunos valores preestablecidos.

Haga lo siguiente para conectar el controlador de vista para la captura entre corchetes:

  1. Agregue las siguientes instrucciones using:

    using System;
    using System.Drawing;
    using Foundation;
    using UIKit;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Linq;
    using AVFoundation;
    using CoreVideo;
    using CoreMedia;
    using CoreGraphics;
    using CoreFoundation;
    using CoreImage;
    
  2. Agregue las variables privadas siguientes:

    #region Private Variables
    private NSError Error;
    private List<UIImageView> Output = new List<UIImageView>();
    private nint OutputIndex = 0;
    #endregion
    
  3. Agregue las siguientes propiedades calculadas:

    #region Computed Properties
    public AppDelegate ThisApp {
        get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
    }
    #endregion
    
  4. Agregue el siguiente método privado para crear las vistas de imagen de salida necesarias:

    #region Private Methods
    private UIImageView BuildOutputView(nint n) {
    
        // Create a new image view controller
        var imageView = new UIImageView (new CGRect (CameraView.Frame.Width * n, 0, CameraView.Frame.Width, CameraView.Frame.Height));
    
        // Load a temp image
        imageView.Image = UIImage.FromFile ("Default-568h@2x.png");
    
        // Add a label
        UILabel label = new UILabel (new CGRect (0, 20, CameraView.Frame.Width, 24));
        label.TextColor = UIColor.White;
        label.Text = string.Format ("Bracketed Image {0}", n);
        imageView.AddSubview (label);
    
        // Add to scrolling view
        ScrollView.AddSubview (imageView);
    
        // Return new image view
        return imageView;
    }
    #endregion
    
  5. Invalide el método ViewDidLoad y agregue el código siguiente:

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
    
        // Hide no camera label
        NoCamera.Hidden = ThisApp.CameraAvailable;
    
        // Attach to camera view
        ThisApp.Recorder.DisplayView = CameraView;
    
        // Setup scrolling area
        ScrollView.ContentSize = new SizeF (CameraView.Frame.Width * 4, CameraView.Frame.Height);
    
        // Add output views
        Output.Add (BuildOutputView (1));
        Output.Add (BuildOutputView (2));
        Output.Add (BuildOutputView (3));
    
        // Create preset settings
        var Settings = new AVCaptureBracketedStillImageSettings[] {
            AVCaptureAutoExposureBracketedStillImageSettings.Create(-2.0f),
            AVCaptureAutoExposureBracketedStillImageSettings.Create(0.0f),
            AVCaptureAutoExposureBracketedStillImageSettings.Create(2.0f)
        };
    
        // Wireup capture button
        CaptureButton.TouchUpInside += (sender, e) => {
            // Reset output index
            OutputIndex = 0;
    
            // Tell the camera that we are getting ready to do a bracketed capture
            ThisApp.StillImageOutput.PrepareToCaptureStillImageBracket(ThisApp.StillImageOutput.Connections[0],Settings,async (bool ready, NSError err) => {
                // Was there an error, if so report it
                if (err!=null) {
                    Console.WriteLine("Error: {0}",err.LocalizedDescription);
                }
            });
    
            // Ask the camera to snap a bracketed capture
            ThisApp.StillImageOutput.CaptureStillImageBracket(ThisApp.StillImageOutput.Connections[0],Settings, (sampleBuffer, settings, err) =>{
                // Convert raw image stream into a Core Image Image
                var imageData = AVCaptureStillImageOutput.JpegStillToNSData(sampleBuffer);
                var image = CIImage.FromData(imageData);
    
                // Display the resulting image
                Output[OutputIndex++].Image = UIImage.FromImage(image);
    
                // IMPORTANT: You must release the buffer because AVFoundation has a fixed number
                // of buffers and will stop delivering frames if it runs out.
                sampleBuffer.Dispose();
            });
        };
    }
    
  6. Invalide el método ViewDidAppear y agregue el código siguiente:

    public override void ViewDidAppear (bool animated)
    {
        base.ViewDidAppear (animated);
    
        // Start udating the display
        if (ThisApp.CameraAvailable) {
            // Remap to this camera view
            ThisApp.Recorder.DisplayView = CameraView;
    
            ThisApp.Session.StartRunning ();
        }
    }
    
    
  7. Guarde los cambios en el código y ejecute la aplicación.

  8. Enmarque una escena y pulse el botón capturar entre corchetes:

    Enmarque una escena y pulse el botón Capture Bracket

  9. Deslice el dedo hacia la derecha a la izquierda para ver las tres imágenes tomadas por la captura entre corchetes:

    Deslice el dedo hacia la derecha a la izquierda para ver las tres imágenes tomadas por Bracketed Capture

  10. Detenga la aplicación.

El código anterior ha mostrado cómo configurar y tomar una captura entre corchetes de exposición automática en iOS 8.

Resumen

En este artículo hemos dado una introducción a los nuevos controles manuales de la cámara proporcionados por iOS 8 y hemos tratado los conceptos básicos de qué hacen y cómo funcionan. Hemos dado ejemplos de enfoque manual, exposición manual y balance de blancos manual. Por último, se ha dado un ejemplo de cómo tomar una captura entre corchetes mediante los controles manuales de la cámara descritos anteriormente