3

CMSampleBuffer을 카메라 출력에서 ​​vImage으로 변환하고 나중에 처리하려고합니다. (질문에서 고려되지 않는 메모리 관리 및 오류)CMSampleBuffer 프레임을 vImage로 변환 할 때 색상이 잘못되었습니다.

Example image of current implementation

구현 :

비디오 출력 장치를 구성 :

불행하게도, 심지어는 더 이상 편집하지 않고, 내가 버퍼에서 얻을 프레임은 잘못된 색상을 가지고

: CASampleBuffer에서 vImage 만들기
videoDataOutput = AVCaptureVideoDataOutput() 
    videoDataOutput.videoSettings = [String(kCVPixelBufferPixelFormatTypeKey): kCVPixelFormatType_32BGRA] 
    videoDataOutput.alwaysDiscardsLateVideoFrames = true 
    videoDataOutput.setSampleBufferDelegate(self, queue: captureQueue) 
    videoConnection = videoDataOutput.connection(withMediaType: AVMediaTypeVideo) 

    captureSession.sessionPreset = AVCaptureSessionPreset1280x720 

    let videoDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) 
    guard let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice) else { 
     return 
    } 

카메라로부터받은 CVPixelBuffer가있는 UIImage로 내보낼 테스트를 위해서

, 그러나 비디오 버퍼에 추가하는 동일한 결과를 갖는다 : 0

// Convert `CASampleBuffer` to `CVImageBuffer` guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } var buffer: vImage_Buffer = vImage_Buffer() buffer.data = CVPixelBufferGetBaseAddress(pixelBuffer) buffer.rowBytes = CVPixelBufferGetBytesPerRow(pixelBuffer) buffer.width = vImagePixelCount(CVPixelBufferGetWidth(pixelBuffer)) buffer.height = vImagePixelCount(CVPixelBufferGetHeight(pixelBuffer)) let vformat = vImageCVImageFormat_CreateWithCVPixelBuffer(pixelBuffer) let bitmapInfo:CGBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue | CGBitmapInfo.byteOrder32Little.rawValue) var cgFormat = vImage_CGImageFormat(bitsPerComponent: 8, bitsPerPixel: 32, colorSpace: nil, bitmapInfo: bitmapInfo, version: 0, decode: nil, renderingIntent: .defaultIntent) // Create vImage vImageBuffer_InitWithCVPixelBuffer(&buffer, &cgFormat, pixelBuffer, vformat!.takeRetainedValue(), cgColor, vImage_Flags(kvImageNoFlags)) 

있는 UIImage 버퍼로 변환.

var dstPixelBuffer: CVPixelBuffer? 

    let status = CVPixelBufferCreateWithBytes(nil, Int(buffer.width), Int(buffer.height), 
               kCVPixelFormatType_32BGRA, buffer.data, 
               Int(buffer.rowBytes), releaseCallback, 
               nil, nil, &dstPixelBuffer) 

    let destCGImage = vImageCreateCGImageFromBuffer(&buffer, &cgFormat, nil, nil, numericCast(kvImageNoFlags), nil)?.takeRetainedValue() 

    // create a UIImage 
    let exportedImage = destCGImage.flatMap { UIImage(cgImage: $0, scale: 0.0, orientation: UIImageOrientation.right) } 

    DispatchQueue.main.async { 
     self.previewView.image = exportedImage 
    } 
+0

제거 하시겠습니까? CGBitmapInfo.byteOrder32Little.rawValue' 도움? 노란색 오리가 FFFF00에서 00FF00으로 이동 했으므로 0 알파를 포함하면 바이트 스와핑 문제가 될 수 있습니다. –

+0

@RhythmicFistman 그건 재미 있어요. 나는 디폴트 순서를 유지하기 위해'byteOrder32Little'을 제거하고'CGBitmapInfo (rawValue : CGImageByteOrderInfo.orderMask.rawValue | CGImageAlphaInfo.last.rawValue)'로 변경하려고 시도했지만 결과는 모든 경우에서 똑같이 보입니다. – Dawid

+0

실행 가능한 샘플에 연결할 수 있습니까? –

답변

0

vImageBuffer_InitWithCVPixelBuffer에 대한 호출은

CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly) 
을 말할 때 (연결) 코드는 픽셀을 수정하지 않겠다고 약속 때문에 조금 장난 꾸러기 당신의 vImage_BufferCVPixelBuffer 's의 내용을 수정 수행

CGBitmapInfo을 BGRA8888로 초기화하는 올바른 방법은 알파 우선, 32 비트 리틀 엔디안입니다. 이는 명백하지 않지만 vImage_Utilities.h의 vImage_CGImageFormat에 대한 헤더 파일에 포함되어 있습니다.

내가하지 않는 무엇 10
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.first.rawValue | CGImageByteOrderInfo.order32Little.rawValue) 

cgFormat (desiredFormat가) vformat 일치해야합니다으로는 버퍼를 수정하는 설명되어 있지만 vImageBuffer_InitWithCVPixelBuffer이, 당신의 버퍼를 수정하는 것입니다 그래서 아마 당신이 먼저 데이터를 복사해야하는 이유입니다. 마지막으로

let error = vImageBuffer_InitWithCVPixelBuffer(&buffer, &cgFormat, pixelBuffer, vformat, nil, vImage_Flags(kvImageNoFlags)) 

: vformat 지금 관리 기준 인 사실을 반영하는 vImageBuffer_InitWithCVPixelBuffer에 전화를

let vformat = vImageCVImageFormat_CreateWithCVPixelBuffer(pixelBuffer).takeRetainedValue() 

    vImageCVImageFormat_SetColorSpace(vformat, 
             CGColorSpaceCreateDeviceRGB()) 

... 그리고 업데이트 :

1

이력서 이미지 형식에 색 공간을 설정하십시오 다음 라인을 제거하면 vImageBuffer_InitWithCVPixelBuffer이 해당 작업을 수행합니다.

//  buffer.data = CVPixelBufferGetBaseAddress(pixelBuffer) 
//  buffer.rowBytes = CVPixelBufferGetBytesPerRow(pixelBuffer) 
//  buffer.width = vImagePixelCount(CVPixelBufferGetWidth(pixelBuffer)) 
//  buffer.height = vImagePixelCount(CVPixelBufferGetHeight(pixelBuffer)) 

코어 비디오 픽셀 버퍼를 잠그지 않아도됩니다. headerdoc을 확인하면 "이 함수를 호출하기 전에 CVPixelBuffer를 잠글 필요가 없습니다"라는 메시지가 표시됩니다.