2016-06-30 37 views
9

Desidero implementare una telecamera personalizzata nella mia app. Quindi, sto creando questa fotocamera usando AVCaptureDevice.Impostare GrayScale su Output di AVCaptureDevice in iOS

Ora voglio mostrare solo l'uscita grigia nella mia fotocamera personalizzata. Quindi sto cercando di ottenere questo utilizzando setWhiteBalanceModeLockedWithDeviceWhiteBalanceGains: e AVCaptureWhiteBalanceGains. Sto usando AVCamManual: Extending AVCam to Use Manual Capture per questo.

- (void)setWhiteBalanceGains:(AVCaptureWhiteBalanceGains)gains 
{ 
    NSError *error = nil; 

    if ([videoDevice lockForConfiguration:&error]) { 
     AVCaptureWhiteBalanceGains normalizedGains = [self normalizedGains:gains]; // Conversion can yield out-of-bound values, cap to limits 
     [videoDevice setWhiteBalanceModeLockedWithDeviceWhiteBalanceGains:normalizedGains completionHandler:nil]; 
     [videoDevice unlockForConfiguration]; 
    } 
    else { 
     NSLog(@"Could not lock device for configuration: %@", error); 
    } 
} 

Ma per questo, devo avere per passare RGB valori di guadagno tra 1 a 4. Così sto creando questo metodo per il controllo dei valori MAX e MIN.

- (AVCaptureWhiteBalanceGains)normalizedGains:(AVCaptureWhiteBalanceGains) gains 
{ 
    AVCaptureWhiteBalanceGains g = gains; 

    g.redGain = MAX(1.0, g.redGain); 
    g.greenGain = MAX(1.0, g.greenGain); 
    g.blueGain = MAX(1.0, g.blueGain); 

    g.redGain = MIN(videoDevice.maxWhiteBalanceGain, g.redGain); 
    g.greenGain = MIN(videoDevice.maxWhiteBalanceGain, g.greenGain); 
    g.blueGain = MIN(videoDevice.maxWhiteBalanceGain, g.blueGain); 

    return g; 
} 

Anche io sto cercando di ottenere effetti diversi come il passaggio di valori statici di guadagno RGB.

- (AVCaptureWhiteBalanceGains)normalizedGains:(AVCaptureWhiteBalanceGains) gains 
{ 
    AVCaptureWhiteBalanceGains g = gains; 
    g.redGain = 3; 
    g.greenGain = 2; 
    g.blueGain = 1; 
    return g; 
} 

Ora, voglio impostare questa scala di grigi (Formula: Pixel = 0.30078125f * R + G + 0.5859375f * 0.11328125f * B) sulla mia macchina fotografica personalizzato. Ho provato questo per questa formula.

- (AVCaptureWhiteBalanceGains)normalizedGains:(AVCaptureWhiteBalanceGains) gains 
{ 
    AVCaptureWhiteBalanceGains g = gains; 

    g.redGain = g.redGain * 0.30078125; 
    g.greenGain = g.greenGain * 0.5859375; 
    g.blueGain = g.blueGain * 0.11328125; 

    float grayScale = g.redGain + g.greenGain + g.blueGain; 

    g.redGain = MAX(1.0, grayScale); 
    g.greenGain = MAX(1.0, grayScale); 
    g.blueGain = MAX(1.0, grayScale); 

    g.redGain = MIN(videoDevice.maxWhiteBalanceGain, g.redGain); 
    g.greenGain = MIN(videoDevice.maxWhiteBalanceGain, g.greenGain); 
    g.blueGain = MIN(videoDevice.maxWhiteBalanceGain, g.blueGain); 

    return g; 
} 

Così Come posso passare questo valore tra 1 a 4 ..?

C'è qualche modo o scala per confrontare queste cose ..?

Qualsiasi aiuto sarebbe apprezzato.

+2

La regolazione del bilanciamento del bianco non trasformerà un'immagine a colori in un'immagine in bianco e nero. Devi trovare un'altra API per farlo. Ad esempio [vImageMatrixMultiply_ARGB8888] (https://developer.apple.com/library/ios/documentation/Performance/Reference/vImage_transform/index.html#//apple_ref/c/func/vImageMatrixMultiply_ARGB8888) – Mats

+0

@Mats: Sì, grazie .. !! Si prega di fornire qualsiasi codice di esempio per una migliore comprensione. –

+1

Forse questo, http://stackoverflow.com/questions/21207099/, la domanda aiuta. – Mats

risposta

5

CoreImage fornisce una serie di filtri per la regolazione delle immagini utilizzando la GPU e può essere utilizzato in modo efficiente con i dati video, da un feed della telecamera o da un file video.

C'è un articolo su objc.io che mostra come procedere. Gli esempi sono in Objective-C ma la spiegazione dovrebbe essere abbastanza chiara da seguire.

I passaggi fondamentali sono:

  1. Creare un EAGLContext, configurato per utilizzare OpenGLES2.
  2. Creare un GLKView per visualizzare l'output reso, utilizzando EAGLContext.
  3. Creare un CIContext, utilizzando lo stesso EAGLContext.
  4. Creare un CIFilter utilizzando un CIColorMonochromeCoreImage filter.
  5. Creare un AVCaptureSession con un AVCaptureVideoDataOutput.
  6. Nel metodo AVCaptureVideoDataOutputDelegate, convertire CMSampleBuffer in CIImage. Applica lo CIFilter all'immagine. Disegna l'immagine filtrata su CIImageContext.

Questa pipeline garantisce che i buffer dei pixel video rimangano sulla GPU (dalla telecamera alla visualizzazione) ed eviti di spostare i dati nella CPU, per mantenere le prestazioni in tempo reale.

Per salvare il video filtrato, implementare un AVAssetWriter e aggiungere il buffer di esempio nello stesso AVCaptureVideoDataOutputDelegate in cui è stato effettuato il filtro.

Ecco un esempio in Swift.

Example on GitHub.

import UIKit 
import GLKit 
import AVFoundation 

private let rotationTransform = CGAffineTransformMakeRotation(CGFloat(-M_PI * 0.5)) 

class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate { 

    private var context: CIContext! 
    private var targetRect: CGRect! 
    private var session: AVCaptureSession! 
    private var filter: CIFilter! 

    @IBOutlet var glView: GLKView! 

    override func prefersStatusBarHidden() -> Bool { 
     return true 
    } 

    override func viewDidAppear(animated: Bool) { 
     super.viewDidAppear(animated) 

     let whiteColor = CIColor(
      red: 1.0, 
      green: 1.0, 
      blue: 1.0 
     ) 

     filter = CIFilter(
      name: "CIColorMonochrome", 
      withInputParameters: [ 
       "inputColor" : whiteColor, 
       "inputIntensity" : 1.0 
      ] 
     ) 

     // GL context 

     let glContext = EAGLContext(
      API: .OpenGLES2 
     ) 

     glView.context = glContext 
     glView.enableSetNeedsDisplay = false 

     context = CIContext(
      EAGLContext: glContext, 
      options: [ 
       kCIContextOutputColorSpace: NSNull(), 
       kCIContextWorkingColorSpace: NSNull(), 
      ] 
     ) 

     let screenSize = UIScreen.mainScreen().bounds.size 
     let screenScale = UIScreen.mainScreen().scale 

     targetRect = CGRect(
      x: 0, 
      y: 0, 
      width: screenSize.width * screenScale, 
      height: screenSize.height * screenScale 
     ) 

     // Setup capture session. 

     let cameraDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) 

     let videoInput = try? AVCaptureDeviceInput(
      device: cameraDevice 
     ) 

     let videoOutput = AVCaptureVideoDataOutput() 
     videoOutput.setSampleBufferDelegate(self, queue: dispatch_get_main_queue()) 

     session = AVCaptureSession() 
     session.beginConfiguration() 
     session.addInput(videoInput) 
     session.addOutput(videoOutput) 
     session.commitConfiguration() 
     session.startRunning() 
    } 

    func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) { 

     guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { 
      return 
     } 

     let originalImage = CIImage(
      CVPixelBuffer: pixelBuffer, 
      options: [ 
       kCIImageColorSpace: NSNull() 
      ] 
     ) 

     let rotatedImage = originalImage.imageByApplyingTransform(rotationTransform) 

     filter.setValue(rotatedImage, forKey: kCIInputImageKey) 

     guard let filteredImage = filter.outputImage else { 
      return 
     } 

     context.drawImage(filteredImage, inRect: targetRect, fromRect: filteredImage.extent) 

     glView.display() 
    } 

    func captureOutput(captureOutput: AVCaptureOutput!, didDropSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) { 
     let seconds = CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) 
     print("dropped sample buffer: \(seconds)") 
    } 
} 
+0

Yesss Soluzioni perfette. Grazie Luca. :) L'ho implementato nella mia app. Ma a volte si blocca sulla linea 'glView.display()'. –

+0

Come posso acquisire un'immagine usando la vista GLKView? –

+1

Gli arresti anomali potrebbero essere causati dalla modifica del filtro o del contesto su thread diversi. Un modo sicuro per ovviare a questo problema è eseguire tutto il lavoro sul thread principale (ho aggiornato l'esempio per mostrarlo). Fai solo attenzione a non utilizzare un filtro che utilizza molte risorse (ad es. Sfocatura), oppure fai troppo lavoro extra sul thread principale. In pratica, probabilmente si desidera utilizzare più thread per evitare di bloccare il thread principale, sebbene questo sia un argomento complesso. Se interessati, consulta la documentazione Apple per il multithreading con OpenGL. –