実現したいこと・発生している問題
現在、AVFoundationを利用したカメラ機能を開発しております。
iPhone標準のカメラアプリにある、露出調整(明るさ調整)と同等の機能を実装したいと考えているのですが、
実装したものだと露出を上げるほどに被写体がブレる(かくつくような動き)ようになります。
「露出を変更する = シャッタースピードが変わる」という認識でいます。
その影響で被写体がブレる現象が発生していると考えているのですが、iPhone標準のカメラではブレる現象が発生しません。
質問内容
どような実装を行えば、被写体がブレる現象を抑えられますでしょうか?
「露出を上げすぎないことで対応するしかない」、「ISO感度と組み合わせて実装する」など、何かアドバイスなどあればご回答をお願いしたいです。
補足情報(FW/ツールのバージョンなど)
- 開発環境:Xcode11.2.1
- 言語 :Swift5
- 端末 :iPhoneX、iPadPro11インチ
参考にしたサイトなど
Swiftでカメラアプリを作成する(1)
AVCamManual: Extending AVCam to Use Manual Capture API
z-hao-wang / ios-pro-camera
該当のソースコード
【露出調整箇所抜粋】
以下はAppleのサンプルソースを元に実装。
「case 1」配下で露出調整を行なっているのですが、ここの処理に問題があると想定しております。
Swift
1// MARK: - Slider Action 2@IBAction func changeSlider(_ sender: UISlider) { 3 4 let tag: Int = sender.tag 5 do { 6 try currentDevice!.lockForConfiguration() 7 defer { currentDevice!.unlockForConfiguration() } 8 9 // 露出、または ISO感度を設定 10 switch tag { 11 case 1: 12 // 露出調整 13 let p = Float64(pow(sender.value, kExposureDurationPower)) // Apply power function to expand slider's low-end range 14 let minDurationSeconds = Float64(max(CMTimeGetSeconds(currentDevice!.activeFormat.minExposureDuration), kExposureMinimumDuration)) 15 let maxDurationSeconds = Float64(CMTimeGetSeconds(currentDevice!.activeFormat.maxExposureDuration)) 16 let newDurationSeconds = Float64(p * (maxDurationSeconds - minDurationSeconds)) + minDurationSeconds // Scale from 0-1 slider range to actual duration 17 18 currentDevice!.setExposureModeCustom(duration: CMTimeMakeWithSeconds( newDurationSeconds, preferredTimescale: 1000*1000*1000 ), 19 iso: AVCaptureDevice.currentISO, 20 completionHandler: nil) 21 22 case 2: 23 // ISO感度調整 24 currentDevice!.setExposureModeCustom(duration: AVCaptureDevice.currentExposureDuration, 25 iso: sender.value, 26 completionHandler: nil) 27 default: 28 break 29 } 30 } catch { 31 print("(error.localizedDescription)") 32 } 33}
【処理全体】
Swift
1import UIKit 2import AVFoundation 3 4class ViewController: UIViewController { 5 6@IBOutlet weak var cameraView: UIView! // プレビュー配置先のView 7var captureSession = AVCaptureSession() // セッション管理用 8var mainCamera: AVCaptureDevice? // メインカメラ用 9var innerCamera: AVCaptureDevice? // インカメラ用意 10var currentDevice: AVCaptureDevice? // 現在利用中のカメラ用 11var photoOutput : AVCapturePhotoOutput? // キャプチャーの出力データを受け付けるオブジェクト 12var cameraPreviewLayer : AVCaptureVideoPreviewLayer?// プレビュー表示用のレイヤ 13 14@IBOutlet weak var brightnessSlider: UISlider! // 露出用スライダー 15@IBOutlet weak var isoSlider: UISlider! // ISO感度用スライダー 16 17// 露出制御時用の定数 18let kExposureDurationPower : Float = 4 // Higher numbers will give the slider more sensitivity at shorter durations 19let kExposureMinimumDuration: Float64 = 1.0/2000 // Limit exposure duration to a useful range 20 21 22 23// MARK: - Life Cycle 24override func viewDidLoad() { 25 super.viewDidLoad() 26 27 // カメラ周り設定 28 self.setupCaptureSession() 29 self.setupDevice() 30 self.setupInputOutput() 31 self.setupPreviewLayer() 32 self.captureSession.startRunning() 33 34 // スライダー初期設定 35 self.setupSlider() 36} 37 38// スライダー初期設定 39func setupSlider() { 40 41 // 露出用スライダー設定 42 brightnessSlider.minimumValue = 0.0 43 brightnessSlider.maximumValue = 1.0 44 self.brightnessSlider.value = 0.5 45 46 // ISO感度用スライダー設定 47 isoSlider.minimumValue = Float(currentDevice!.activeFormat.minISO) 48 isoSlider.maximumValue = Float(currentDevice!.activeFormat.maxISO) 49 self.isoSlider.value = (isoSlider.minimumValue + isoSlider.maximumValue) / 2 50} 51 52 53// MARK: - Camera Setting 54// カメラの画質の設定 55func setupCaptureSession() { 56 captureSession.sessionPreset = AVCaptureSession.Preset.photo 57} 58 59// デバイスの設定 60func setupDevice() { 61 // カメラデバイスのプロパティ設定 62 let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], 63 mediaType: AVMediaType.video, 64 position: AVCaptureDevice.Position.unspecified) 65 // カメラデバイスの取得 66 let devices = deviceDiscoverySession.devices 67 for device in devices { 68 if device.position == AVCaptureDevice.Position.back { 69 mainCamera = device 70 } else if device.position == AVCaptureDevice.Position.front { 71 innerCamera = device 72 } 73 } 74 75 // 起動時のカメラを設定 76 currentDevice = mainCamera 77 78 // 露出とISO感度の初期値設定 79 do { 80 try mainCamera!.lockForConfiguration() 81 defer { mainCamera!.unlockForConfiguration() } 82 mainCamera!.exposureMode = .custom 83 mainCamera!.setExposureModeCustom(duration: AVCaptureDevice.currentExposureDuration, iso: AVCaptureDevice.currentISO, completionHandler: nil) 84 } catch { 85 print("(error.localizedDescription)") 86 } 87} 88 89// 入出力データの設定 90func setupInputOutput() { 91 do { 92 // 入力を初期化 93 let captureDeviceInput = try AVCaptureDeviceInput(device: currentDevice!) 94 captureSession.addInput(captureDeviceInput) 95 96 // 出力を初期化 97 photoOutput = AVCapturePhotoOutput() 98 photoOutput!.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey : AVVideoCodecType.jpeg])], 99 completionHandler: nil) 100 captureSession.addOutput(photoOutput!) 101 } catch { 102 print(error) 103 } 104} 105 106// カメラプレビュー用のレイヤを設定 107func setupPreviewLayer() { 108 // プレビューレイヤを初期化 109 self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 110 self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill 111 self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait 112 self.cameraPreviewLayer?.frame = view.frame 113 114 self.cameraPreviewLayer?.frame = self.cameraView.bounds 115 self.cameraView.layer.insertSublayer(self.cameraPreviewLayer!, at: 0) 116} 117 118 119// MARK: - Slider Action 120@IBAction func changeSlider(_ sender: UISlider) { 121 122 let tag: Int = sender.tag 123 do { 124 try currentDevice!.lockForConfiguration() 125 defer { currentDevice!.unlockForConfiguration() } 126 127 // 露出、または ISO感度を設定 128 switch tag { 129 case 1: 130 let p = Float64(pow(sender.value, kExposureDurationPower)) // Apply power function to expand slider's low-end range 131 let minDurationSeconds = Float64(max(CMTimeGetSeconds(currentDevice!.activeFormat.minExposureDuration), kExposureMinimumDuration)) 132 let maxDurationSeconds = Float64(CMTimeGetSeconds(currentDevice!.activeFormat.maxExposureDuration)) 133 let newDurationSeconds = Float64(p * (maxDurationSeconds - minDurationSeconds)) + minDurationSeconds // Scale from 0-1 slider range to actual duration 134 135 currentDevice!.setExposureModeCustom(duration: CMTimeMakeWithSeconds( newDurationSeconds, preferredTimescale: 1000*1000*1000 ), 136 iso: AVCaptureDevice.currentISO, 137 completionHandler: nil) 138 139 case 2: 140 currentDevice!.setExposureModeCustom(duration: AVCaptureDevice.currentExposureDuration, 141 iso: sender.value, 142 completionHandler: nil) 143 default: 144 break 145 } 146 } catch { 147 print("(error.localizedDescription)") 148 } 149} 150} 151
2020.06.22追記
発生している現象をGIFにしてみました。
露出を上げる前は問題なくカメラプレビューが表示されますが、
露出を上げると、カメラプレビュー自体がブレるような動きになってしまいます。
※iPhoneの標準カメラアプリではこの様な現象は発生しないため、何か特殊な処理が必要なのでしょうか。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。