Я работаю над простым шумоподавляющим POC в SwiftUI, где хочу:
- Загрузить входное изображение
- Примените модель CoreML (шумоподавление) к входному изображению
- Отображение выходного изображения
У меня есть что-то работающее на основе десятков исходных кодов, которые я нашел в Интернете. Основываясь на том, что я читал, модель CoreML (по крайней мере, та, которую я использую) принимает CVPixelBuffer и выводит также CVPixelBuffer. Итак, моя идея заключалась в следующем:
- Преобразуйте входной UIImage в CVPixelBuffer
- Примените модель CoreML к CVPixelBuffer
- Преобразуйте вновь созданный CVPixelBuffer в UIImage
(Обратите внимание, что я читал, что, используя структуру Vision, можно вводить CGImage непосредственно в модель. Я попробую этот подход, как только ознакомлюсь с тем, чего я пытаюсь достичь здесь, поскольку я думаю, что это хорошее упражнение.)
Для начала я хотел пропустить шаг (2), чтобы сосредоточиться на проблеме преобразования. В приведенном ниже коде я пытался добиться:
- Преобразуйте входной UIImage в CVPixelBuffer
- Преобразуйте CVPixelBuffer в UIImage
Я не разработчик Swift или Objective-C, поэтому почти уверен, что сделал по крайней мере несколько ошибок. Я нашел этот код довольно сложным, и мне было интересно, есть ли лучший / простой способ сделать то же самое?
func convert(input: UIImage) -> UIImage? {
// Input CGImage
guard let cgInput = input.cgImage else {
return nil
}
// Image size
let width = cgInput.width
let height = cgInput.height
let region = CGRect(x: 0, y: 0, width: width, height: height)
// Attributes needed to create the CVPixelBuffer
let attributes = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue,
kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue]
// Create the input CVPixelBuffer
var pbInput:CVPixelBuffer? = nil
let status = CVPixelBufferCreate(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_32ARGB,
attributes as CFDictionary,
&pbInput)
// Sanity check
if status != kCVReturnSuccess {
return nil
}
// Fill the input CVPixelBuffer with the content of the input CGImage
CVPixelBufferLockBaseAddress(pbInput!, CVPixelBufferLockFlags(rawValue: 0))
guard let context = CGContext(data: CVPixelBufferGetBaseAddress(pbInput!),
width: width,
height: height,
bitsPerComponent: cgInput.bitsPerComponent,
bytesPerRow: cgInput.bytesPerRow,
space: cgInput.colorSpace!,
bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue) else {
return nil
}
context.draw(cgInput, in: region)
CVPixelBufferUnlockBaseAddress(pbInput!, CVPixelBufferLockFlags(rawValue: 0))
// Create the output CGImage
let ciOutput = CIImage(cvPixelBuffer: pbInput!)
let temporaryContext = CIContext(options: nil)
guard let cgOutput = temporaryContext.createCGImage(ciOutput, from: region) else {
return nil
}
// Create and return the output UIImage
return UIImage(cgImage: cgOutput)
}
Когда я использовал этот код в своем проекте SwiftUI, входные и выходные изображения выглядели одинаково, но не были идентичными. Я думаю, что у входного изображения была связанная с ним палитра (профиль ColorSync), которая была потеряна во время преобразования. Я предполагал, что должен был использовать cgInput.colorSpace
во время создания CGContext, но казалось, что использование CGColorSpace(name: CGColorSpace.sRGB)!
работает лучше. Может кто-нибудь объяснить мне это?
Спасибо за вашу помощь.