iOSのカメラというかAVFoundationにはAdobeのLightroomアプリのようにホワイトバランスやシャッタースピードなどをカスタマイズするAPIがあります。

ドキュメントを読んでみて難しい部分があったので整理しておこうと思います。

Lightroom

LightroomのiPhone版では撮影時に微調整しながら撮影できます。

↑の矢印部分をタップしてプロに切り替える(元々はAuto)と、シャッタースピードやISO感度、ホワイトバランスを調整するコントロールが現れます。ここで色々いじると設定を変えられるわけですね。

iOSでの実装

ベース部分

AVFoundationAVCapturePhotoOutputを使います。よくあるコードなので特に解説しませんが、こんな感じになりますよね。

deviceの設定をするconfigureDeviceというfunctionが最後にあります。今はオートフォーカスを有効にすることしかしていませんが、ここで色々設定を変更していきます。

 1import UIKit
 2import AVFoundation
 3
 4class CameraViewController: AppViewController {
 5
 6    let captureSession = AVCaptureSession()
 7    var photoOutput : AVCapturePhotoOutput!
 8
 9    override func viewDidLoad() {
10        super.viewDidLoad()
11        configure()
12    }
13
14    override func viewWillAppear(_ animated: Bool) {
15        captureSession.startRunning()
16        super.viewWillAppear(animated)
17    }
18
19    override func viewWillDisappear(_ animated: Bool) {
20        captureSession.stopRunning()
21        super.viewWillDisappear(animated)
22    }
23
24    private func getDevice() -> AVCaptureDevice? {
25        let discoverSession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera, .builtInTelephotoCamera, .builtInWideAngleCamera], mediaType: .video, position: .back)
26        return discoverSession.devices.first
27    }
28
29    private func configure() {
30        if let device = getDevice() {
31            do {
32                try device.lockForConfiguration()
33                self.configureDevice(device: device)
34                device.unlockForConfiguration()
35            } catch { print("error") }
36
37            do {
38                let input = try AVCaptureDeviceInput(device: device)
39                captureSession.addInput(input)
40            } catch { print("error") }
41
42
43            photoOutput = AVCapturePhotoOutput()
44            if captureSession.canAddOutput(photoOutput) {
45                captureSession.addOutput(photoOutput)
46
47                let captureVideoLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session: captureSession)
48                captureVideoLayer.frame = self.imageView.bounds
49                captureVideoLayer.videoGravity = .resizeAspectFill
50                self.imageView.layer.addSublayer(captureVideoLayer)
51            }
52        }
53    }
54
55    func configureDevice(device: AVCaptureDevice) {
56        if device.isFocusModeSupported(.continuousAutoFocus) {
57            device.focusMode = .continuousAutoFocus
58        }
59
60        // その他設定
61    }
62}

シャッタースピードとISO

AVCaptureDevicesetExposureModeCustomを使います。

先程のconfigureDeviceに追記するとして、たとえばシャッタースピードを1/400、ISOを800にするのであれば↓のように設定できます。

1let shutterSpeed = CMTimeMake(1, 400)
2device.setExposureModeCustom(duration: shutterSpeed, iso: 800, completionHandler: nil)

ホワイトバランス

ホワイトバランスのほうは少々厄介でして、iOS側のAPIはWhiteBlanceGainsというstructを使用します。

Lightroomのアプリにおけるホワイトバランスの設定は「蛍光灯」や「昼光」など、色温度ベースとなっています。そこで色温度などからWhiteBalanceGainsに変換する必要があります。

1let k = 6000 // 色温度
2let tint = -5 // -150.0〜+ 150.0の範囲のホワイトバランスの色合い値
3let values = AVCaptureDevice.WhiteBalanceTemperatureAndTintValues(temperature: k, tint: tint)
4let gains = device.deviceWhiteBalanceGains(for: values)
5device.setWhiteBalanceModeLocked(with: gains, completionHandler: nil)

まず、AVCaptureDevice.WhiteBalanceTemperatureAndTintValuesを色温度と色合いの値を使って初期化し、それを元にWhiteBalanceGainsにします。次にsetWhiteBalanceModeLockedによりホワイトバランスを設定します。

こちらは色温度だけでなくtintValueの影響もあるので欲しい設定にするには微調整が必要そう。

ともかくこれでよくやりそうな設定は変更できました。