Swift:将字节数组转换为CIImage

时间:2018-07-17 02:05:26

标签: swift macos rest http ciimage

我正在寻找一种将字节数组转换为CIIimage的方法,以便可以将其输入到ML模型中进行分类。我使用的是REST HTTP服务器,在其中我以有效负载作为映像向服务器发送POST请求。服务器接收到的图像字节需要进行处理,并转换为MAC OS的CIImage格式,以便可以将其送入接受模型VNImageRequestHandler(ciImage: <ciimage>)的ML模型中。

有人可以举个例子迅速做到这一点吗?

VNImageRequestHandler : NSObject

let data = Data(bytes) let imgHandler = VNImageRequestHandler(ciImage: data) 上面的数据变量需要大小写为CIImage类型。

在HTTP服务器端,我正在接收图像的字节,如下所示: imageData = request.body.bytes

1 个答案:

答案 0 :(得分:1)

使用此方法将字节数组转换为CGImage。您必须确保您的字节是rgba 32位像素原始字节。

func byteArrayToCGImage(raw: UnsafeMutablePointer<UInt8>, // Your byte array
                        w: Int, // your image's width
                        h: Int // your image's height
    ) -> CGImage! {

    // 4 bytes(rgba channels) for each pixel
    let bytesPerPixel: Int = 4
    // (8 bits per each channel)
    let bitsPerComponent: Int = 8

    let bitsPerPixel = bytesPerPixel * bitsPerComponent;
    // channels in each row (width)
    let bytesPerRow: Int = w * bytesPerPixel;

    let cfData = CFDataCreate(nil, raw, w * h * bytesPerPixel)
    let cgDataProvider = CGDataProvider.init(data: cfData!)!

    let deviceColorSpace = CGColorSpaceCreateDeviceRGB()

    let image: CGImage! = CGImage.init(width: w,
                                       height: h,
                                       bitsPerComponent: bitsPerComponent,
                                       bitsPerPixel: bitsPerPixel,
                                       bytesPerRow: bytesPerRow,
                                       space: deviceColorSpace,
                                       bitmapInfo: [],
                                       provider: cgDataProvider,
                                       decode: nil,
                                       shouldInterpolate: true,
                                       intent: CGColorRenderingIntent.defaultIntent)



    return image;
}

使用此方法,您可以像这样转换为CIImage。

let cgimage = byteArrayToCGImage(raw: <#Pointer to Your byte array#> ,
                                 w: <#your image's width#>,
                                 h: <#your image's height#>)
if cgimage != nil {
    let ciImage = CIImage.init(cgImage: cgimage)
}

根据注释,您的数据可能是RGB原始字节,而不是RGBA。在这种情况下,您将不得不分配新的缓冲区,手动为每个alpha通道放置255,然后将该缓冲区传递给方法。

已更新为将32位RGB转换为32位RGBA

func convertTo32bitsRGBA(from32bitsRGB pointer: UnsafeMutablePointer<UInt8>!,
                         width: Int,
                         height: Int) -> UnsafeMutablePointer<UInt8> {

    let pixelCount = width * height
    let memorySize = pixelCount * 4
    let newBuffer = malloc(memorySize).bindMemory(to: UInt8.self, capacity: width * height)

    var i = 0;
    while(i < pixelCount) {
        let oldBufferIndex = i * 3;
        let newBufferIndex = i * 4;

        // red channel
        newBuffer.advanced(by: newBufferIndex).pointee = pointer.advanced(by: oldBufferIndex).pointee
        // green channel
        newBuffer.advanced(by: newBufferIndex + 1).pointee = pointer.advanced(by: oldBufferIndex + 1).pointee
        // blue channel
        newBuffer.advanced(by: newBufferIndex + 2).pointee = pointer.advanced(by: oldBufferIndex + 2).pointee
        // alpha channel
        newBuffer.advanced(by: newBufferIndex + 3).pointee = 0xff;

        // &+ is used for little performance gain
        i = i &+ 1;
    }


    return newBuffer;
}

您可以使用rgb图像缓冲区调用以下转换器方法

let newImageBuffer = convertTo32bitsRGBA(from32bitsRGB: <#Your RGB image buffer#>,
                    width: <#Your image pixel row count or width#>,
                    height: <#Your image pixel column count or height#>)

但是请记住,像在C,C ++或Objective-C中一样,您有责任释放此方法返回的内存分配。这些是内存不由编译器管理的指针。

您可以使用简单的功能进行释放。

newImageBuffer.deallocate();

释放后,您不得访问被释放的内存。如果这样做,您将得到BAD_ACCESS_EXC(操作系统为访问您不拥有的内存而抛出的访问异常)。