UIImage to MLMultiArray

MLBoy
3 min readJan 12, 2023

--

When you want to run a CoreML model whose input is TensorType

CoreML models with ImageType input can use CIImage, CGImage, and PixelBuffer as inputs, but CoreML models with TensorType input require MLMultiArray as input.

How to convert from UIImage to MLMultiArray when you want to use image input for such model.

Method

It can be converted with the following UIImageExtension.

// Usage:
// let mlMultiArray:MLMultiArray = uiImage.mlMultiArray()
//
// or if you need preprocess ...
// let preProcessedMlMultiArray:MLMultiArray = uiImage.mlMultiArray(scale: 127.5, rBias: -1, gBias: -1, bBias: -1)
//
// or if you have gray scale image ...
// let grayScaleMlMultiArray:MLMultiArray = uiImage.mlMultiArrayGrayScale()
extension UIImage {

func mlMultiArray(scale preprocessScale:Double=255, rBias preprocessRBias:Double=0, gBias preprocessGBias:Double=0, bBias preprocessBBias:Double=0) -> MLMultiArray {
let imagePixel = self.getPixelRgb(scale: preprocessScale, rBias: preprocessRBias, gBias: preprocessGBias, bBias: preprocessBBias)
let size = self.size
let imagePointer : UnsafePointer<Double> = UnsafePointer(imagePixel)
let mlArray = try! MLMultiArray(shape: [3, NSNumber(value: Float(size.width)), NSNumber(value: Float(size.height))], dataType: MLMultiArrayDataType.double)
mlArray.dataPointer.initializeMemory(as: Double.self, from: imagePointer, count: imagePixel.count)
return mlArray
}

func mlMultiArrayGrayScale(scale preprocessScale:Double=255,bias preprocessBias:Double=0) -> MLMultiArray {
let imagePixel = self.getPixelGrayScale(scale: preprocessScale, bias: preprocessBias)
let size = self.size
let imagePointer : UnsafePointer<Double> = UnsafePointer(imagePixel)
let mlArray = try! MLMultiArray(shape: [1, NSNumber(value: Float(size.width)), NSNumber(value: Float(size.height))], dataType: MLMultiArrayDataType.double)
mlArray.dataPointer.initializeMemory(as: Double.self, from: imagePointer, count: imagePixel.count)
return mlArray
}

func getPixelRgb(scale preprocessScale:Double=255, rBias preprocessRBias:Double=0, gBias preprocessGBias:Double=0, bBias preprocessBBias:Double=0) -> [Double]
{
guard let cgImage = self.cgImage else {
return []
}
let bytesPerRow = cgImage.bytesPerRow
let width = cgImage.width
let height = cgImage.height
let bytesPerPixel = 4
let pixelData = cgImage.dataProvider!.data! as Data

var r_buf : [Double] = []
var g_buf : [Double] = []
var b_buf : [Double] = []

for j in 0..<height {
for i in 0..<width {
let pixelInfo = bytesPerRow * j + i * bytesPerPixel
let r = Double(pixelData[pixelInfo])
let g = Double(pixelData[pixelInfo+1])
let b = Double(pixelData[pixelInfo+2])
r_buf.append(Double(r/preprocessScale)+preprocessRBias)
g_buf.append(Double(g/preprocessScale)+preprocessGBias)
b_buf.append(Double(b/preprocessScale)+preprocessBBias)
}
}
return ((b_buf + g_buf) + r_buf)
}

func getPixelGrayScale(scale preprocessScale:Double=255, bias preprocessBias:Double=0) -> [Double]
{
guard let cgImage = self.cgImage else {
return []
}
let bytesPerRow = cgImage.bytesPerRow
let width = cgImage.width
let height = cgImage.height
let bytesPerPixel = 2
let pixelData = cgImage.dataProvider!.data! as Data

var buf : [Double] = []

for j in 0..<height {
for i in 0..<width {
let pixelInfo = bytesPerRow * j + i * bytesPerPixel
let v = Double(pixelData[pixelInfo])
buf.append(Double(v/preprocessScale)+preprocessBias)
}
}
return buf
}

}

Check if the conversion is done properly

You can check if the conversion is properly done by inversely converting the MLMultiArray converted using CoreMLHelpers to UIImage.

// scale = 255
let resultUIImage = mlMultiArray.cgImage(min: 0, max: 1, channel: nil)
// scale = 255 bias = -1
let resultUIImage = preProcessedMlMultiArray.cgImage(min: -1, max: 1, channel: nil)
// min and max are range of preprocessed value

🐣

I’m a freelance engineer.
Work consultation
Please feel free to contact us with a brief development description.
rockyshikoku@gmail.com

I am making an app that uses Core ML and ARKit.
We send machine learning / AR related information.

GitHub

Twitter
Medium

--

--

MLBoy
MLBoy

Responses (1)