0

My Objective is to extract 300x300 pixel frame from a CVImageBuffer (camera stream) and convert it in to a UInt Byte Array. Technically the array size should be 90,000. However I'm getting a much more larger value. Any help would much appreciate to spot the mistake.

Method that convert the Image buffer to UIImage

 func getImageFromSampleBuffer(image_buffer : CVImageBuffer?) -> UIImage?
  {
    if let imageBuffer = image_buffer {
        // Lock the base address of the pixel buffer
        CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags.readOnly);


        // Get the number of bytes per row for the pixel buffer
        let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);

        // Get the number of bytes per row for the pixel buffer
        let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
        // Get the pixel buffer width and height
        let width = CVPixelBufferGetWidth(imageBuffer);
        let height = CVPixelBufferGetHeight(imageBuffer);

        // Create a device-dependent RGB color space
        let colorSpace = CGColorSpaceCreateDeviceRGB();

        // Create a bitmap graphics context with the sample buffer data
        var bitmapInfo: UInt32 = CGBitmapInfo.byteOrder32Little.rawValue
        bitmapInfo |= CGImageAlphaInfo.premultipliedFirst.rawValue & CGBitmapInfo.alphaInfoMask.rawValue
        //let bitmapInfo: UInt32 = CGBitmapInfo.alphaInfoMask.rawValue
        let context = CGContext.init(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)
        // Create a Quartz image from the pixel data in the bitmap graphics context
        let quartzImage = context?.makeImage();
        // Unlock the pixel buffer
        CVPixelBufferUnlockBaseAddress(imageBuffer, CVPixelBufferLockFlags.readOnly);

        // Create an image object from the Quartz image
        let image = UIImage.init(cgImage: quartzImage!);

        return (image);
    }
   return nil
  }

}

Extension that convert the image dat in to UInt8 Array

 extension Data {
   func toByteArray() -> [UInt8]? {
    var byteData = [UInt8](repeating:0, count: self.count)
    self.copyBytes(to: &byteData, count: self.count)
    return byteData
   }
 }

Usage of the Code

    let image = getImageFromSampleBuffer(image_buffer: imageBuffer)

   //Issue*******
    if let byteArrayOfImage = image.copy(newSize: CGSize(width: 300, height: 300))?.pngData()?.toByteArray(){

       print(byteArrayOfImage.count) // Technically should print 90,000. However it prints a large value
    }

What am i missing here

danu
  • 1,079
  • 5
  • 16
  • 48
  • pngData() function does not return pixel data. It returns data of a PNG file including PNG file header and compressed pixel data which is a completely different thing than you expect. And as mentioned in other answer if your image has size 300x300 it does not mean it should have 90000 bytes anyway because 1 pixel will most likely take 4 bytes in uncompressed format (if this is RGBA). – Leszek Szary Jul 19 '21 at 12:32

1 Answers1

1

Your expectation Technically the array size should be 90,000 may be wrong.

  1. If your CVPixelBuffer's format is BRGA or other 4-channel type, then the array size will be w*h*4=360,000, where w*4 or, more general, w*channel_count is the row stride.

  2. CVPixelBuffer is usually aligned by 16 bytes: https://developer.apple.com/documentation/corevideo/kcvpixelbufferbytesperrowalignmentkey?language=objc So the real row stride may be even more than w*channel_count.

You should check the value bytesPerRow to understand your whole problem.

olha
  • 2,132
  • 1
  • 18
  • 39
  • Superb answer, however if u look at the code, i convert the CVImageBuffer to an UIImage and from there only im attempting to convert the 300x300 image to an UInt array. Why would my array still gives me a high dense value – danu Jul 19 '21 at 14:12
  • Also if i can get the pixel format to kCVPixelFormatType_8Indexed I guess then the problem is solved maybe ?? – danu Jul 19 '21 at 14:31
  • Please update your question with the exact value of `// Technically should print 90,000. However it prints a large value` – olha Jul 19 '21 at 15:56
  • Also, please specify the value of `bytesPerRow ` – olha Jul 19 '21 at 15:57