【问题标题】:AVCaptureStillImageOutput & UIImagePNGRepresentationAVCaptureStillImageOutput & UIImagePNGRepresentation
【发布时间】:2016-01-08 10:34:53
【问题描述】:

我在做一些我认为不应该那么困难的事情时遇到了困难,所以我想我一定是从错误的角度看待问题。 为了了解 AVCaptureStillImageOutput 和相机的工作原理,我制作了一个小应用程序。

这个应用程序能够拍照并将其保存为 PNG 文件(我不想要 JPEG)。下次启动应用程序时,它会检查文件是否存在,如果存在,则将存储在文件中的图像用作应用程序的背景视图。这个想法很简单。

问题是它不起作用。如果有人能告诉我我做错了什么,那将非常有帮助。

我希望图片以与拍摄时在显示屏上相同的方式显示为背景,但它被旋转或比例错误..等等。

这是相关代码(如果需要,我可以提供更多信息)。

viewDidLoad 方法:

override func viewDidLoad() {
    super.viewDidLoad()

    // For the photo capture:
    captureSession.sessionPreset = AVCaptureSessionPresetHigh

    // Select the appropriate capture devices:
    for device in AVCaptureDevice.devices() {
        // Make sure this particular device supports video.
        if (device.hasMediaType(AVMediaTypeVideo)) {
            // Finally check the position and confirm we've got the back camera.
            if(device.position == AVCaptureDevicePosition.Back) {
                captureDevice = device as? AVCaptureDevice
            }
        }
    }

    tapGesture = UITapGestureRecognizer(target: self, action: Selector("takePhoto"))
    self.view.addGestureRecognizer(tapGesture)

    let filePath = self.toolBox.getDocumentsDirectory().stringByAppendingPathComponent("BackGroundImage@2x.png")

    if !NSFileManager.defaultManager().fileExistsAtPath(filePath) {return}

    let bgImage = UIImage(contentsOfFile: filePath),
    bgView = UIImageView(image: bgImage)
    self.view.addSubview(bgView)
}

拍照处理方法:

func takePhoto() {
    if !captureSession.running {
        beginPhotoCaptureSession()
        return
    }

    if let videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo) {
        stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection) {
            (imageDataSampleBuffer, error) -> Void in
            if error == nil {
                var localImage = UIImage(fromSampleBuffer: imageDataSampleBuffer)
                UIGraphicsBeginImageContext(localImage!.size)
                CGContextRotateCTM (UIGraphicsGetCurrentContext(), CGFloat(M_PI_2))
                //localImage!.drawAtPoint(CGPointZero)
                localImage!.drawAtPoint(CGPoint(x: -localImage!.size.height, y: -localImage!.size.width))
                //localImage!.drawAtPoint(CGPoint(x: -localImage!.size.width, y: -localImage!.size.height))
                localImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                localImage = resizeImage(localImage!, toSize: self.view.frame.size)

                if let data = UIImagePNGRepresentation(localImage!) {
                    let bitMapName = "BackGroundImage@2x"
                    let filename = self.toolBox.getDocumentsDirectory().stringByAppendingPathComponent("\(bitMapName).png")
                    data.writeToFile(filename, atomically: true)
                    print("Picture saved: \(bitMapName)\n\(filename)")
                }
            } else {print("Error on taking a picture:\n\(error)")}
        }
    }

    captureSession.stopRunning()
    previewLayer!.removeFromSuperlayer()
}

启动AVCaptureSession的方法:

func beginPhotoCaptureSession() {
    do {let input = try AVCaptureDeviceInput(device: captureDevice)
        captureSession.addInput(input)
    } catch let error as NSError {
        // Handle any errors:
        print(error)
    }

    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    previewLayer?.frame = self.view.layer.frame
    self.view.layer.addSublayer(previewLayer!)
    captureSession.startRunning()

    stillImageOutput.outputSettings = [kCVPixelBufferPixelFormatTypeKey:Int(kCVPixelFormatType_32BGRA)]
    if captureSession.canAddOutput(stillImageOutput) {
        captureSession.addOutput(stillImageOutput)
    }
}

作为一个例子,这里是一张使用应用程序拍摄的照片:

现在这是我重新启动应用程序时得到的背景:

如果工作正常,两张图片会很相似。

【问题讨论】:

  • “问题是它不起作用。”嗯,这是什么意思?
  • 这意味着它没有做我想要的。这在以下句子中进行了解释:“我希望图片以与拍摄时在显示屏上相同的方式显示为背景”。
  • 好的,但是你还没有说它在做什么(屏幕截图、崩溃信息等)。见How to Askminimal reproducible example
  • 它没有崩溃,应用程序在技术上可以正常工作,但我得到的背景不是我想要的。如果有帮助,我可以提供 2 个屏幕截图。
  • 我添加了两张截图,以清楚地显示我想要的和我得到的之间的区别。

标签: ios swift avcapture uiimagepngrepresentation avcaptureoutput


【解决方案1】:

我在屏幕截图中看不到旋转。但是当您在function takePhoto 中绘制它时,比例是一个与您的代码相关的问题。你可以试试

func takePhoto() {
    if !captureSession.running {
        beginPhotoCaptureSession()
        return
    }
    if let videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo) {
        stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection) {
            (imageDataSampleBuffer, error) -> Void in
            if error == nil {
               if let data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer) {
                    let bitMapName = "BackGroundImage@2x"
                    let filename = self.toolBox.getDocumentsDirectory().stringByAppendingPathComponent("\(bitMapName).png")
                    data.writeToFile(filename, atomically: true)
                    print("Picture saved: \(bitMapName)\n\(filename)")
                }
            } else {print("Error on taking a picture:\n\(error)")}
        }
    }

    captureSession.stopRunning()
    previewLayer!.removeFromSuperlayer()
}

【讨论】:

  • 感谢您的建议。你是对的,我已经解决了轮换问题。但是您的代码使用 JPEG 格式,这不是我想要的,正如我在我想使用 PNG 的问题中提到的那样。
  • 由于丢失,我认为这不是一个好的解决方案,我更喜欢从一开始就使用 PNG。这实际上是我创建这个测试应用程序的原因,如果我对 JPEG 没问题,我原来的问题确实有效。
  • 使用 PNG 的另一个原因是我还需要透明度。
  • 我同意,因为我没有看到任何错误,也知道我对这类问题没有太多经验,所以我决定写一篇文章(和一个测试应用程序),想有人else 可能能够快速发现故障点。
  • 您为什么不首先采用 PNG 表示 localImage .. 或者您需要在检索图像之前对图像进行一些调整?
【解决方案2】:

对于那些可能在某一时刻遇到相同问题的人,我在下面发布了我在代码中修复的内容以使其正常工作。可能仍需要一些改进来支持所有可能的方向,但一开始就可以。

    if let videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo) {
        stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection) {
            (imageDataSampleBuffer, error) -> Void in
            if error == nil {
                var localImage = UIImage(fromSampleBuffer: imageDataSampleBuffer)
                var imageSize = CGSize(width: UIScreen.mainScreen().bounds.height * UIScreen.mainScreen().scale,
                    height: UIScreen.mainScreen().bounds.width * UIScreen.mainScreen().scale)
                localImage = resizeImage(localImage!, toSize: imageSize)

                imageSize = CGSize(width: imageSize.height, height: imageSize.width)
                UIGraphicsBeginImageContext(imageSize)
                CGContextRotateCTM (UIGraphicsGetCurrentContext(), CGFloat(M_PI_2))
                localImage!.drawAtPoint(CGPoint(x: 0.0, y: -imageSize.width))
                localImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()

                if let data = UIImagePNGRepresentation(localImage!) {
                    data.writeToFile(self.bmpFilePath, atomically: true)
                }
            } else {print("Error on taking a picture:\n\(error)")}
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    • 2014-10-08
    • 2015-05-04
    • 2012-08-05
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    相关资源
    最近更新 更多