시각 효과를 만들고 장치 카메라를 통해 캡처 한 비디오 프레임에 적용하는 대학의 과제가 있습니다. 현재 이미지 및 디스플레이를 가져올 수 있지만 픽셀 색상 값을 변경할 수는 없습니다.Swift에서 픽셀 단위로 이미지에 시각 효과 적용
샘플 버퍼를 imageRef 변수로 변환하고 UIImage로 변환하면 모든 것이 정상입니다.
그러나이 이미지를 가져 오려면이 색상 값을 픽셀 단위로 변경하고 싶습니다.이 예제에서는 음수 색상으로 변경합니다 (CIFilter를 사용할 수 없기 때문에 더 복잡한 작업을해야합니다).하지만 주석 처리 된 나쁜 액세스로 인해 추락했습니다. 당신은 아무 권한이없는 곳 newPixels UnsafeMutablePointer가 RawPointer 년에 지어졌으며 0000 포인트 메모리 및 내 의견으로는 할당되지 않은 메모리 공간을 가리키는으로 초기화하기 때문에
import UIKit
import AVFoundation
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
let captureSession = AVCaptureSession()
var previewLayer : AVCaptureVideoPreviewLayer?
var captureDevice : AVCaptureDevice?
@IBOutlet weak var cameraView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
captureSession.sessionPreset = AVCaptureSessionPresetMedium
let devices = AVCaptureDevice.devices()
for device in devices {
if device.hasMediaType(AVMediaTypeVideo) && device.position == AVCaptureDevicePosition.Back {
if let device = device as? AVCaptureDevice {
captureDevice = device
beginSession()
break
}
}
}
}
func focusTo(value : Float) {
if let device = captureDevice {
if(device.lockForConfiguration(nil)) {
device.setFocusModeLockedWithLensPosition(value) {
(time) in
}
device.unlockForConfiguration()
}
}
}
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
var touchPercent = Float(touches.anyObject().locationInView(view).x/320)
focusTo(touchPercent)
}
override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) {
var touchPercent = Float(touches.anyObject().locationInView(view).x/320)
focusTo(touchPercent)
}
func beginSession() {
configureDevice()
var error : NSError?
captureSession.addInput(AVCaptureDeviceInput(device: captureDevice, error: &error))
if error != nil {
println("error: \(error?.localizedDescription)")
}
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer?.frame = view.layer.frame
//view.layer.addSublayer(previewLayer)
let output = AVCaptureVideoDataOutput()
let cameraQueue = dispatch_queue_create("cameraQueue", DISPATCH_QUEUE_SERIAL)
output.setSampleBufferDelegate(self, queue: cameraQueue)
output.videoSettings = [kCVPixelBufferPixelFormatTypeKey: kCVPixelFormatType_32BGRA]
captureSession.addOutput(output)
captureSession.startRunning()
}
func configureDevice() {
if let device = captureDevice {
device.lockForConfiguration(nil)
device.focusMode = .Locked
device.unlockForConfiguration()
}
}
// MARK : - AVCaptureVideoDataOutputSampleBufferDelegate
func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {
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()
var bitmapInfo = CGBitmapInfo.fromRaw(CGImageAlphaInfo.PremultipliedFirst.toRaw())! | CGBitmapInfo.ByteOrder32Little
let context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, bitmapInfo)
let imageRef = CGBitmapContextCreateImage(context)
CVPixelBufferUnlockBaseAddress(imageBuffer, 0)
let data = CGDataProviderCopyData(CGImageGetDataProvider(imageRef)) as NSData
let pixels = data.bytes
var newPixels = UnsafeMutablePointer<UInt8>()
//for index in stride(from: 0, to: data.length, by: 4) {
/*newPixels[index] = 255 - pixels[index]
newPixels[index + 1] = 255 - pixels[index + 1]
newPixels[index + 2] = 255 - pixels[index + 2]
newPixels[index + 3] = 255 - pixels[index + 3]*/
//}
bitmapInfo = CGImageGetBitmapInfo(imageRef)
let provider = CGDataProviderCreateWithData(nil, newPixels, UInt(data.length), nil)
let newImageRef = CGImageCreate(width, height, CGImageGetBitsPerComponent(imageRef), CGImageGetBitsPerPixel(imageRef), bytesPerRow, colorSpace, bitmapInfo, provider, nil, false, kCGRenderingIntentDefault)
let image = UIImage(CGImage: newImageRef, scale: 1, orientation: .Right)
dispatch_async(dispatch_get_main_queue()) {
self.cameraView.image = image
}
}
}
이것이 분명한 경우 사과드립니다. 그러나이 경우 'captureOutput' 함수가 어떻게 트리거됩니까? – Ian
원래 게시물 (첫 번째 행의 클래스 정의)에서 볼 수있는 뷰가 AVCaptureVideoDataOutputSampleBufferDelegate 여야합니다. 그런 다음 뷰는 서비스가 시작되고 버퍼에 데이터가있는 경우 함수를 트리거합니다. – KZD76
아! 감사. 나는 그것을 놓쳤다. 왜 내가'videoDataOutput.setSampleBufferDelegate (self, queue : sessionQueue) '를 non-self가되도록 조정해야하는지 궁금 해서요 – Ian