Возникли проблемы с входным изображением с моделью классификации изображений iOS Swift TensorFlowLite?

Я пытался добавить классификатор распознавания растений в свое приложение через облачную модель машинного обучения Firebase, и я подошел близко - проблема в том, что я почти уверен, что где-то испортил ввод для данных изображения по пути. Мой классификатор производит бессмысленные вероятности / результаты на основе вывода этого классификатора, и я тестировал тот же классификатор с помощью скрипта Python, который дает мне точные результаты.

Вход для модели требует изображения 224x224 с 3 каналами с масштабированием до 0,1. Я сделал все это, но не могу понять CGImage через Camera / ImagePicker. Вот фрагмент кода, который обрабатывает ввод изображения:

if let imageData = info[.originalImage] as? UIImage {
            DispatchQueue.main.async {

                let resizedImage = imageData.scaledImage(with: CGSize(width:224, height:224))

                let ciImage = CIImage(image: resizedImage!)
                let CGcontext = CIContext(options: nil)

                let image : CGImage = CGcontext.createCGImage(ciImage!, from: ciImage!.extent)!

                guard let context = CGContext(
                    data: nil,
                    width: image.width, height: image.height,
                    bitsPerComponent: 8, bytesPerRow: image.width * 4,
                    space: CGColorSpaceCreateDeviceRGB(),
                    bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue
                ) else {
                    return
                }

                context.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height))
                guard let imageData = context.data else { return }

                print("Image data showing as: \(imageData)")
                var inputData = Data()
                do {
                    for row in 0 ..< 224 {
                        for col in 0 ..< 224 {
                            let offset = 4 * (row * context.width + col)
                            // (Ignore offset 0, the unused alpha channel)
                            let red = imageData.load(fromByteOffset: offset+1, as: UInt8.self)
                            let green = imageData.load(fromByteOffset: offset+2, as: UInt8.self)
                            let blue = imageData.load(fromByteOffset: offset+3, as: UInt8.self)

                            // Normalize channel values to [0.0, 1.0].
                            var normalizedRed = Float32(red) / 255.0
                            var normalizedGreen = Float32(green) / 255.0
                            var normalizedBlue = Float32(blue) / 255.0

                            // Append normalized values to Data object in RGB order.
                            let elementSize = MemoryLayout.size(ofValue: normalizedRed)

                            var bytes = [UInt8](repeating: 0, count: elementSize)
                            memcpy(&bytes, &normalizedRed, elementSize)
                            inputData.append(&bytes, count: elementSize)
                            memcpy(&bytes, &normalizedGreen, elementSize)
                            inputData.append(&bytes, count: elementSize)
                            memcpy(&bytes, &normalizedBlue, elementSize)
                            inputData.append(&bytes, count: elementSize)

                        }
                    }
                    print("Successfully added inputData")
                    self.parent.invokeInterpreter(inputData: inputData)

                } catch let error {
                    print("Failed to add input: \(error)")
                }
            }
        }

После этого я обрабатываю inputData следующим образом:

    func invokeInterpreter(inputData: Data) {
    do {
    var interpreter = try Interpreter(modelPath: ProfileUserData.sharedUserData.modelPath)
    var labels: [String] = []
        
        try interpreter.allocateTensors()
        try interpreter.copy(inputData, toInputAt: 0)
        try interpreter.invoke()
        
        let output = try interpreter.output(at: 0)
        
            switch output.dataType {
            case .uInt8:
              guard let quantization = output.quantizationParameters else {
                print("No results returned because the quantization values for the output tensor are nil.")
                return
              }
              let quantizedResults = [UInt8](output.data)
              let results = quantizedResults.map {
                quantization.scale * Float(Int($0) - quantization.zeroPoint)
              }
                
                let sum = results.reduce(0, +)
                print("Sum of all dequantized results is: \(sum)")
                print("Count of dequantized results is: \(results.indices.count)")
                
                let filename = "plantLabels"
                let fileExtension = "csv"
                guard let labelPath = Bundle.main.url(forResource: filename, withExtension: fileExtension) else {
                    print("Labels file not found in bundle. Please check labels file.")
                    return
                }
                
                do {
                      let contents = try String(contentsOf: labelPath, encoding: .utf8)
                    labels = contents.components(separatedBy: .newlines)
                    print("Count of label rows is: \(labels.indices.count)")
                    } catch {
                      fatalError("Labels file named \(filename).\(fileExtension) cannot be read. Please add a " +
                                   "valid labels file and try again.")
                    }
                
                let zippedResults = zip(labels.indices, results)
                 
                 // Sort the zipped results by confidence value in descending order.
                 let sortedResults = zippedResults.sorted { $0.1 > $1.1 }.prefix(3)
                
                 print("Printing sortedResults: \(sortedResults)")
            case .float32:
              print("Output tensor data type [Float32] is unsupported for this model.")
            default:
              print("Output tensor data type \(output.dataType) is unsupported for this model.")
              return
            }
    } catch {
        //Error with interpreter
        print("Error with running interpreter: \(error.localizedDescription)")
    }
}

Какое отношение этот вопрос имеет к Firebase? Firebase - это множество разных продуктов - есть ли у вас проблемы с Firebase или как обрабатывать данные CGImage?

Jay 06.04.2021 21:30

Firebase содержит сам классификатор изображений - я добавил этот тег на случай, если возникнут проблемы с вызовом / вызовом классификатора при размещении в Firebase.

neddyflanders7 06.04.2021 22:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
22
0

Другие вопросы по теме