iosswiftimage-processingcvpixelbuffer

Get pixel value from CVPixelBufferRef in Swift


How can I get the RGB (or any other format) pixel value from a CVPixelBufferRef? Ive tried many approaches but no success yet.

func captureOutput(captureOutput: AVCaptureOutput!,
                   didOutputSampleBuffer sampleBuffer: CMSampleBuffer!,
                   fromConnection connection: AVCaptureConnection!) {
  let pixelBuffer: CVPixelBufferRef = CMSampleBufferGetImageBuffer(sampleBuffer)!
                CVPixelBufferLockBaseAddress(pixelBuffer, 0)
  let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer)

  //Get individual pixel values here

  CVPixelBufferUnlockBaseAddress(pixelBuffer, 0)
}

Solution

  • baseAddress is an unsafe mutable pointer or more precisely a UnsafeMutablePointer<Void>. You can easily access the memory once you have converted the pointer away from Void to a more specific type:

    // Convert the base address to a safe pointer of the appropriate type
    let byteBuffer = UnsafeMutablePointer<UInt8>(baseAddress)
    
    // read the data (returns value of type UInt8)
    let firstByte = byteBuffer[0]
    
    // write data
    byteBuffer[3] = 90
    

    Make sure you use the correct type (8, 16 or 32 bit unsigned int). It depends on the video format. Most likely it's 8 bit.

    Update on buffer formats:

    You can specify the format when you initialize the AVCaptureVideoDataOutput instance. You basically have the choice of:

    If you're interested in the color values and speed (or rather maximum frame rate) is not an issue, then go for the simpler BGRA format. Otherwise take one of the more efficient native video formats.

    If you have two planes, you must get the base address of the desired plane (see video format example):

    Video format example

    let pixelBuffer: CVPixelBufferRef = CMSampleBufferGetImageBuffer(sampleBuffer)!
    CVPixelBufferLockBaseAddress(pixelBuffer, 0)
    let baseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)
    let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0)
    let byteBuffer = UnsafeMutablePointer<UInt8>(baseAddress)
    
    // Get luma value for pixel (43, 17)
    let luma = byteBuffer[17 * bytesPerRow + 43]
    
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0)
    

    BGRA example

    let pixelBuffer: CVPixelBufferRef = CMSampleBufferGetImageBuffer(sampleBuffer)!
    CVPixelBufferLockBaseAddress(pixelBuffer, 0)
    let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer)
    let int32PerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
    let int32Buffer = UnsafeMutablePointer<UInt32>(baseAddress)
    
    // Get BGRA value for pixel (43, 17)
    let luma = int32Buffer[17 * int32PerRow + 43]
    
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0)