3

Je suis en train de convertir CMSampleBuffer de la sortie de la caméra à vImage et plus tard appliquer un traitement. Malheureusement, même sans autre montage, cadre que je reçois de tampon a mauvaises couleurs:CMSampleBuffer cadre converti en vImage a mauvaises couleurs

Example image of current implementation

Mise en œuvre (gestion de la mémoire et les erreurs ne sont pas considérés en question):

Configuration d'un périphérique de sortie vidéo:

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 
    } 

Création vImage de CASampleBuffer reçu de la caméra:

// 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)) 

Conversion tampon UIImage:

Pour des raisons de tests CVPixelBuffer est exportée vers UIImage, mais en ajoutant à un tampon vidéo a le même résultat.

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

La suppression de '| CGBitmapInfo.byteOrder32Little.rawValue' aide? Votre canard jaune est passé de FFFF00 à 00FF00, de sorte que _could_ soit un problème d'échange d'octets, si vous incluez un alpha zéro. –

+0

@RhythmicFistman c'est intéressant. J'ai essayé de supprimer 'byteOrder32Little' et aussi de changer' CGBitmapInfo (rawValue: CGImageByteOrderInfo.orderMask.rawValue | CGImageAlphaInfo.last.rawValue) 'pour garder l'ordre par défaut, mais le résultat semble exactement le même dans tous les cas. – Dawid

+0

Pouvez-vous lier à un échantillon exécutable? –

Répondre

0

L'appel à vImageBuffer_InitWithCVPixelBuffer effectue la modification de vos vImage_Buffer et CVPixelBuffer « contenu s, ce qui est un peu méchant parce que dans votre (lié) code que vous promets de ne pas modifier les pixels quand vous dites

CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly) 

la bonne façon pour initialiser le CGBitmapInfo pour BGRA8888 est alpha première, 32bit peu endian, qui est non évidente, mais couvert dans le fichier d'en-tête pour vImage_CGImageFormat dans vImage_Utilities.h:

let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.first.rawValue | CGImageByteOrderInfo.order32Little.rawValue) 

Ce que je ne comprends pas pourquoi vImageBuffer_InitWithCVPixelBuffer modifie votre tampon, comme cgFormat (desiredFormat) doit correspondre vformat, bien qu'il soit documenté de modifier la mémoire tampon, alors peut-être vous devez copier les données d'abord.

1

Essayez de régler l'image de votre espace couleur CV Format:

let vformat = vImageCVImageFormat_CreateWithCVPixelBuffer(pixelBuffer).takeRetainedValue() 

    vImageCVImageFormat_SetColorSpace(vformat, 
             CGColorSpaceCreateDeviceRGB()) 

... et mettre à jour votre appel à vImageBuffer_InitWithCVPixelBuffer pour refléter le fait vformat est maintenant une référence gérée:

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

Enfin , vous pouvez supprimer les lignes suivantes, vImageBuffer_InitWithCVPixelBuffer fait ce travail pour vous:

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

Notez que vous n'avez pas besoin de verrouiller le tampon de pixels Core Video, si vous vérifiez le headerdoc, il est dit "Il n'est pas nécessaire de verrouiller le CVPixelBuffer avant d'appeler cette fonction".