Ya tengo el modelo entrenado y lo único que queda es usarlo en una app para iOS y comprobar que funciona tal y como se espera.
Para compilar el proyecto necesitas Xcode en su versión 9.3, y para llevar a cabo las pruebas debes tener un iPhone con iOS actualizado a la versión 11.0
He organizado el código en dos targets.
- El principal donde está el interfaz de usuario y la llamada a CoreML y Vision
- Un framework llamado
IncidenceKit
que tiene el modelo importado de Keras y se encarga de la clasificación de las imágenes y otras cosas
Todo lo relacionado con CoreML y el modelo está programado en dos archivos
CaptureViewController
(target principal)Visionary
(framework IncidenceKit)
Este es el código donde capturo un número del identificador y los transformo para crear una imagen como las que espera el modelo.
// El rectángulo del número
let box_rect = box.boundingBox.scaled(to: ciBikeImage.extent.size)
// Calculamos los vértices del rectangulo...
let topLeft = box.topLeft.scaled(to: imageSize)
let topRight = box.topRight.scaled(to: imageSize)
let bottomLeft = box.bottomLeft.scaled(to: imageSize)
let bottomRight = box.bottomRight.scaled(to: imageSize)
// ...y cortamos la imagen, la ponemos en blanco y negro
// y por último invertimos los colores. De esta manera
// la nueva imagen es como las del modelo de predicción
let correctedImage = ciBikeImage
.cropped(to: box_rect)
.applyingFilter("CIColorInvert")
.applyingFilter("CIPerspectiveCorrection", parameters: [
"inputTopLeft": CIVector(cgPoint: topLeft),
"inputTopRight": CIVector(cgPoint: topRight),
"inputBottomLeft": CIVector(cgPoint: bottomLeft),
"inputBottomRight": CIVector(cgPoint: bottomRight)
])
.applyingFilter("CIColorControls", parameters: [
kCIInputSaturationKey: 0,
kCIInputContrastKey: 32
])
Y aquí es donde le paso la imagen el modelo para que me de el resultado de su clasificación
public func prediction(image: CIImage) -> Int?
{
guard let buffer = self.pixelBuffer(from: image),
let output = try? self.model.prediction(image: buffer)
else
{
return nil
}
let digit = output.numero.enumerated()
.filter({ $0.element.value > 0.90 && $0.element.value <= 1.0 })
.map({ $0.element })
.sorted(by: { $0.value < $1.value })
.first
if let digit = digit, let number = Int(digit.key)
{
return number
}
return nil
}
Si tienes alguna duda o comentario que me quieras hacer lo mejor es que me busques en twitter, allí me encuentras en @fitomad