2017-06-09 3 views
11

Le nouveau framework CoreML d'Apple a une fonction de prédiction qui prend un CVPixelBuffer. Afin de classer un UIImage une conversion doit être faite entre les deux.Comment convertir un UIImage en un CVPixelBuffer

code de conversion, je suis d'un ingénieur d'Apple:

1 // image has been defined earlier 
2 
3  var pixelbuffer: CVPixelBuffer? = nil 
4 
5  CVPixelBufferCreate(kCFAllocatorDefault, Int(image.size.width), Int(image.size.height), kCVPixelFormatType_OneComponent8, nil, &pixelbuffer) 
6  CVPixelBufferLockBaseAddress(pixelbuffer!, CVPixelBufferLockFlags(rawValue:0)) 
7 
8  let colorspace = CGColorSpaceCreateDeviceGray() 
9  let bitmapContext = CGContext(data: CVPixelBufferGetBaseAddress(pixelbuffer!), width: Int(image.size.width), height: Int(image.size.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelbuffer!), space: colorspace, bitmapInfo: 0)! 
10 
11 bitmapContext.draw(image.cgImage!, in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)) 

Cette solution est rapide et est pour une image en niveaux de gris. Les modifications qui doivent être apportées en fonction du type d'image sont les suivantes:

  • Ligne 5 | kCVPixelFormatType_OneComponent8 à l'autre OSType (kCVPixelFormatType_32ARGB pour RGB)
  • Ligne 8 | colorSpace à l'autre (CGColorSpaceCreateDeviceRGB pour RGB)
  • Ligne 9 | bitsPerComponent au nombre de bits par pixel de mémoire (32 pour RGB)
  • Ligne 9 | bitmapInfo à une propriété CGBitmapInfo non nulle (kCGBitmapByteOrderDefault est la valeur par défaut)
+0

Je pense que 'CVPixelBuffer' est juste une convention pour les images à partir de la caméra, il y a aussi 'ciImage',' cgImage' disponible – WeiJay

+0

Pourquoi ne pas utiliser Vision Framework? Vous pouvez (1) initialiser un objet 'VNCoreMLModel', puis un (2)' VNCoreMLRequest' avec un gestionnaire de complétion, puis utiliser un (3) 'VNImageRequestHandler' - qui peut prendre un' CIImage' ou une URL de fichier. Les résultats sont une collection d'objets 'VNClassificationObservation'. Maintenant, bien sûr, si vous voulez convertir un 'UIImage' en un' CVPixelBuffer' - ce que vous ** n'avez vraiment pas dit ** à l'intérieur ** de votre question qui n'avait pas de question :-) - vous peut simplement rechercher l'Internet pour cela et trouver ceci: https://gist.github.com/cieslak/743f9321834c5a40597afa1634a48343 – dfd

+0

@dfd Oui, donc je voulais convertir un 'UIImage' en un' CVPixelBuffer' dans le but d'utiliser un CoreML modèle, mais j'ai gentiment résolu ce problème par un ingénieur d'Apple à la WWDC avec le code ci-dessus. Étant donné que plusieurs autres personnes à la conférence ont eu le même problème, j'ai pensé que je partagerais la solution qui atteint son but avec beaucoup plus de simplicité que cette solution de github. Merci pour les suggestions si! – Ryan

Répondre

14

Vous pouvez jeter un oeil à ce tutoriel https://www.hackingwithswift.com/whats-new-in-ios-11, le code est à Swift 4

func buffer(from image: UIImage) -> CVPixelBuffer? { 
    let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary 
    var pixelBuffer : CVPixelBuffer? 
    let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(image.size.width), Int(image.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer) 
    guard (status == kCVReturnSuccess) else { 
    return nil 
    } 

    CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) 
    let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!) 

    let rgbColorSpace = CGColorSpaceCreateDeviceRGB() 
    let context = CGContext(data: pixelData, width: Int(image.size.width), height: Int(image.size.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue) 

    context?.translateBy(x: 0, y: image.size.height) 
    context?.scaleBy(x: 1.0, y: -1.0) 

    UIGraphicsPushContext(context!) 
    image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)) 
    UIGraphicsPopContext() 
    CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) 

    return pixelBuffer 
}