2016-06-30 3 views
9

私のアプリにカスタムカメラを実装したい。だから、AVCaptureDeviceを使ってこのカメラを作っています。iOSのAVCaptureDeviceの出力でGrayScaleを設定する

今、カスタムカメラにグレーアウトプットを表示したいとします。だから私はsetWhiteBalanceModeLockedWithDeviceWhiteBalanceGains:AVCaptureWhiteBalanceGainsを使ってこれを得ようとしています。私はこれにAVCamManual: Extending AVCam to Use Manual Captureを使用しています。

- (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); 
    } 
} 

しかし、そのために、私はRGBゲインがだから私はMAXとMINの値をチェックするため、このメソッドを作成しています1〜4の間の値渡すために持っている必要があります。

- (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; 
} 

また、RGBゲイン静的値を渡すようなさまざまな効果を得ようとしています。私のカスタムカメラに:(ピクセル= 0.30078125fの*のR + 0.5859375f * G + 0.11328125f * B式)

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

は今、私はこのグレースケールを設定します。私はこの式のためにこれを試しました。

- (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; 
} 

のでにはどうすれ 4から1の間で、この値を渡すことができますか..?

これを比較する方法や規模はありますか?

お願いします。

+2

ホワイトバランスを調整しても、カラー画像は白黒画像に変換されません。これを行うには、別のAPIを見つける必要があります。たとえば、[vImageMatrixMultiply_ARGB8888](https://developer.apple.com/library/ios/documentation/Performance/Reference/vImage_transform/index.html#//apple_ref/c/func/vImageMatrixMultiply_ARGB8888) – Mats

+0

@Mats:ありがとう.. !!より理解しやすいようにサンプルコードを入力してください。 –

+1

多分、これは、http://stackoverflow.com/questions/21207099/、質問に役立ちます。 – Mats

答えて

5

CoreImageは、GPUを使用して画像を調整するための多数のフィルタを提供し、カメラのフィードまたはビデオファイルからビデオデータを効率的に使用できます。

これを行う方法を示す記事がobjc.ioにあります。例はObjective-Cですが、その説明は十分に明確にする必要があります。

基本的な手順は以下のとおりです。

  1. OpenGLES2を使用するように構成され、EAGLContextを作成します。
  2. レンダリングされた出力を表示するにはGLKViewを作成し、EAGLContextを使用します。
  3. 同じEAGLContextを使用してCIContextを作成します。
  4. CIColorMonochromeCoreImage filterを使用してCIFilterを作成します。
  5. AVCaptureSessionAVCaptureVideoDataOutputで作成します。
  6. AVCaptureVideoDataOutputDelegateメソッドでCMSampleBufferCIImageに変換します。 CIFilterを画像に適用します。フィルタリングされた画像をCIImageContextに描画します。

このパイプラインは、ビデオピクセルバッファが(カメラからディスプレイへの)GPU上にとどまることを保証し、CPUへのデータの移動を防ぎ、リアルタイムパフォーマンスを維持します。

フィルタリングされたビデオを保存するには、AVAssetWriterを実装し、フィルタリングが行われる同じAVCaptureVideoDataOutputDelegateにサンプルバッファを追加します。

ここは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パーフェクトなソリューション。ありがとうルーク。 :)私はこれを私のアプリに実装しました。しかし、 'glView.display()'行にクラッシュすることがあります。 –

+0

GLKViewビューを使用してイメージをキャプチャする方法はありますか? –

+1

異なるスレッドでフィルタまたはコンテキストを変更すると、クラッシュが発生する可能性があります。これを回避する安全な方法は、メインスレッド上ですべての作業を実行することです(これを表示するために例を更新しました)。リソースを大量に消費するフィルタ(ぼかしなど)を使用しないように注意してください。また、メインスレッドで余分な作業をしてください。実際には、複雑なトピックですが、主スレッドをブロックしないように複数のスレッドを使用することをお勧めします。興味があれば、OpenGLを使ったマルチスレッドのAppleのドキュメントを見てください。 –

関連する問題