2017-06-09 42 views
11

Nowy framework CoreML firmy Apple ma funkcję przewidywania, która ma CVPixelBuffer. Aby dokonać klasyfikacji UIImage, należy dokonać konwersji między tymi dwoma.Jak przekonwertować UIImage do CVPixelBuffer

kod konwersji dostałem od inżyniera 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)) 

To rozwiązanie jest w szybki i jest na skali szarości. Zmiany, które należy wprowadzić w zależności od typu obrazu, to:

  • Linia 5 | kCVPixelFormatType_OneComponent8 do innego OSType (dla RGB)
  • Linia 8 | colorSpace do innego CGColorSpace (CGColorSpaceCreateDeviceRGB dla RGB)
  • Linia 9 | bitsPerComponent do liczby bitów na piksel pamięci (32 dla RGB)
  • Linia 9 | bitmapInfo do niezerową CGBitmapInfo własności (kCGBitmapByteOrderDefault jest domyślnym)
+0

myślę 'CVPixelBuffer' to tylko konwencja dla obrazów z kamery, są też 'ciImage',' cgImage' dostępny – WeiJay

+0

Dlaczego nie używać Vision Framework? Możesz (1) zainicjować obiekt 'VNCoreMLModel', a następnie (2)' VNCoreMLRequest' za pomocą procedury obsługi zakończenia, a następnie użyć (3) 'VNImageRequestHandler' - który może przyjąć adres URL' CIImage' lub plik. Wyniki są zbiorem obiektów 'VNClassificationObservation'. Teraz oczywiście, jeśli chcesz przekonwertować 'UIImage' na' CVPixelBuffer' - którego tak naprawdę ** nigdzie nie powiedziałeś ** wewnątrz ** twojego pytania, które nie zawierało pytania :-) - ty można po prostu wyszukać w Internecie i znaleźć to: https://gist.github.com/cieslak/743f9321834c5a40597afa1634a48343 – dfd

+0

@dfd Tak, chciałem przekonwertować 'UIImage' na' CVPixelBuffer' na potrzeby używania CoreML model, ale łaskawie udało mi się rozwiązać ten problem przez inżyniera Apple w WWDC z powyższym kodem. Biorąc pod uwagę, że kilka osób na konferencji miało ten sam problem, doszedłem do wniosku, że podzielę się rozwiązaniem, które osiąga cel znacznie prostszy niż rozwiązanie Github. Dzięki za sugestie! – Ryan

Odpowiedz

14

Można przyjrzeć się tym tutorialu https://www.hackingwithswift.com/whats-new-in-ios-11, kod jest w 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 
}