前提・実現したいこと
カメラからのキャプチャ画像に何かしらの操作をして、その画像をUIImageViewで表示したいです。
発生している問題・エラーメッセージ[編集]
キャプチャ画像→ピクセルデータ配列→何かしらの処理→UIImageという処理をしたいのですが、
メソッド内で作成したUIImagを返り値で別の変数に代入した際、タイミングによって代入先の画像が壊れています。
具体的には、以下のソースコード内の
(1)の部分でreturnした場合は、正常に画像が渡され表示できます。
(2)の部分でreturnした場合は、異常な画像データが渡されてしまいます。
該当のソースコード[編集]
swift
1class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate { 2 3 @IBOutlet var previewView: UIImageView! 4 5 var session = AVCaptureSession() 6 var videoOutput = AVCaptureVideoDataOutput() 7 8 var images:[UIImage] = [] 9 10 var count: Int = 0 11 12 override func viewDidLoad() { 13 super.viewDidLoad() 14 15 if session.isRunning { 16 return 17 } 18 19 images.removeAll() 20 21 setupInputOutput() 22 23 self.session.startRunning() 24 } 25 26 override func didReceiveMemoryWarning() { 27 super.didReceiveMemoryWarning() 28 } 29 30 func setupInputOutput() { 31 32 session.sessionPreset = AVCaptureSession.Preset.medium 33 34 do { 35 let device = AVCaptureDevice.default( 36 AVCaptureDevice.DeviceType.builtInWideAngleCamera, 37 for: AVMediaType.video, 38 position: AVCaptureDevice.Position.back 39 ) 40 device?.activeVideoMinFrameDuration = CMTimeMake(1, 30) 41 42 let input = try! AVCaptureDeviceInput(device: device!) 43 if session.canAddInput(input) { 44 session.addInput(input) 45 } else { 46 print("Can't add input to session") 47 return 48 } 49 } catch let error as NSError { 50 print("no camera (error)") 51 return 52 } 53 54 videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as AnyHashable : Int(kCVPixelFormatType_32BGRA)] as! [String : Any] 55 videoOutput.alwaysDiscardsLateVideoFrames = true 56 videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main) 57 if session.canAddOutput(videoOutput) { 58 session.addOutput(videoOutput) 59 } else { 60 print("Can't add output to session") 61 return 62 } 63 } 64 65 func setPreviewLayer() { 66 let previewLayer = AVCaptureVideoPreviewLayer(session: session) 67 guard let videoLayer: AVCaptureVideoPreviewLayer = previewLayer else { 68 print("Can't create preview layer.") 69 return 70 } 71 72 videoLayer.frame = previewView.bounds 73 videoLayer.masksToBounds = true 74 videoLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill 75 previewView.layer.addSublayer(videoLayer) 76 } 77 78 func captureOutput(_ captureOutput: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 79 let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! 80 // イメージバッファのロック 81 CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0)) 82 83 self.imageFromSampleBuffer(sampleBuffer: sampleBuffer) 84 85 CVPixelBufferUnlockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0)) 86 87 DispatchQueue.main.async { 88 self.previewView.image = image 89 } 90 } 91 92 func imageFromSampleBuffer(sampleBuffer :CMSampleBuffer) -> UIImage { 93 let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! 94 95 // 画像情報を取得 96 let base = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0)! 97 let bytesPerRow = UInt(CVPixelBufferGetBytesPerRow(imageBuffer)) 98 let width = UInt(CVPixelBufferGetWidth(imageBuffer)) 99 let height = UInt(CVPixelBufferGetHeight(imageBuffer)) 100 101 // ビットマップコンテキスト作成 102 let colorSpace = CGColorSpaceCreateDeviceRGB() 103 let bitsPerCompornent = 8 104 let bitmapInfo = CGBitmapInfo(rawValue: (CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue) as UInt32) 105 let newContext = CGContext(data: base, width: Int(width), height: Int(height), bitsPerComponent: Int(bitsPerCompornent), bytesPerRow: Int(bytesPerRow), space: colorSpace, bitmapInfo: bitmapInfo.rawValue)! as CGContext 106 107 // 画像作成 108 let imageRef = newContext.makeImage()! 109 110 // (1)ここでimgを返すとキャプチャした画像が正常に表示される 111 //let img = UIImage(cgImage: imageRef, scale: 1.0, orientation: UIImageOrientation.right) 112 //return img 113 114 let data = imageRef.dataProvider!.data 115 let length = CFDataGetLength(data) 116 var rawData = [UInt8](repeating: 0, count: length) 117 CFDataGetBytes(data, CFRange(location: 0, length: length), &rawData) 118 119 let provider = CGDataProvider(dataInfo: nil,data: &rawData, size: length,releaseData: releaseData) 120 let bitsPerPixel = imageRef.bitsPerPixel 121 let cgImage = CGImage(width: Int(width), height: Int(height), bitsPerComponent: bitsPerCompornent, bitsPerPixel: bitsPerPixel, bytesPerRow:Int(bytesPerRow), space: colorSpace, bitmapInfo: bitmapInfo, provider: provider!, decode: nil, shouldInterpolate: false, intent: .defaultIntent) 122 123 let editedimage = UIImage(cgImage:cgImage!, scale:1.0, orientation:UIImageOrientation.right) 124 125 // (2)ここで返すと画像が異常になる。 126 return editedimage 127 } 128} 129
補足情報(FW/ツールのバージョンなど)
xcode Version 9.4.1
Swift4.0
回答1件
あなたの回答
tips
プレビュー