我希望AVCaptureVideoDataOutput中的整个图像的平均像素值,我正在捕捉图像并循环通过像素来对它们求和. 我想知道是否有更有效的方法来执行GPU / openGL,因为这是一个可并行化的图像处理任务
我想知道是否有更有效的方法来执行GPU / openGL,因为这是一个可并行化的图像处理任务. (也许是一个沉重的高斯模糊,并读取中心像素值?)
一个特定的要求是使用高水平的平均值来获得高精度结果.请注意下面的CGFloat结果.
目前swift 2代码:
编辑:添加了CIAreaAverage的实现,如Simon所示.它由useGPU bool分隔.
func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) { var redmean:CGFloat = 0.0; var greenmean:CGFloat = 0.0; var bluemean:CGFloat = 0.0; if (useGPU) { let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) let cameraImage = CIImage(CVPixelBuffer: pixelBuffer!) let filter = CIFilter(name: "CIAreaAverage") filter!.setValue(cameraImage, forKey: kCIInputImageKey) let outputImage = filter!.valueForKey(kCIOutputImageKey) as! CIImage! let ctx = CIContext(options:nil) let cgImage = ctx.createCGImage(outputImage, fromRect:outputImage.extent) let rawData:NSData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage))! let pixels = UnsafePointer<UInt8>(rawData.bytes) let bytes = UnsafeBufferPointer<UInt8>(start:pixels, count:rawData.length) var BGRA_index = 0 for pixel in UnsafeBufferPointer(start: bytes.baseAddress, count: bytes.count) { switch BGRA_index { case 0: bluemean = CGFloat (pixel) case 1: greenmean = CGFloat (pixel) case 2: redmean = CGFloat (pixel) case 3: break default: break } BGRA_index++ } } else { let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) CVPixelBufferLockBaseAddress(imageBuffer!, 0) let baseAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer!, 0) let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!) let width = CVPixelBufferGetWidth(imageBuffer!) let height = CVPixelBufferGetHeight(imageBuffer!) let colorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue).rawValue | CGBitmapInfo.ByteOrder32Little.rawValue let context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, bitmapInfo) let imageRef = CGBitmapContextCreateImage(context) CVPixelBufferUnlockBaseAddress(imageBuffer!, 0) let data:NSData = CGDataProviderCopyData(CGImageGetDataProvider(imageRef))! let pixels = UnsafePointer<UInt8>(data.bytes) let bytes = UnsafeBufferPointer<UInt8>(start:pixels, count:data.length) var redsum:CGFloat = 0 var greensum:CGFloat = 0 var bluesum:CGFloat = 0 var BGRA_index = 0 for pixel in UnsafeBufferPointer(start: bytes.baseAddress, count: bytes.count) { switch BGRA_index { case 0: bluesum += CGFloat (pixel) case 1: greensum += CGFloat (pixel) case 2: redsum += CGFloat (pixel) case 3: //alphasum += UInt64(pixel) break default: break } BGRA_index += 1 if BGRA_index == 4 { BGRA_index = 0 } } redmean = redsum / CGFloat(bytes.count) greenmean = greensum / CGFloat(bytes.count) bluemean = bluesum / CGFloat(bytes.count) } print("R:\(redmean) G:\(greenmean) B:\(bluemean)")CIAreaAverage过滤器性能不佳的问题和原因是缺少输入范围的定义.
因此,滤镜的输出与输入图像的大小相同,因此您可以在完整的图像上循环而不是1×1像素的图像.因此,执行所需的时间与初始版本相同.
如CIAreaAverage的文档中所述,您可以指定inputExtent参数.
如何在swift中完成这个问题可以在类似问题的this answer中找到:
let cameraImage = CIImage(CVPixelBuffer: pixelBuffer!) let extent = cameraImage.extent let inputExtent = CIVector(x: extent.origin.x, y: extent.origin.y, z: extent.size.width, w: extent.size.height) let filter = CIFilter(name: "CIAreaAverage", withInputParameters: [kCIInputImageKey: cameraImage, kCIInputExtentKey: inputExtent])! let outputImage = filter.outputImage!
如果要挤出更高的性能,可以确保重用CIContext,而不是为每个捕获的帧重新创建它.