Anonymous
Использование vImageFloodFill_ARGB8888 в iOS для создания заливки Flood для UIImage
Сообщение
Anonymous » 09 май 2024, 18:14
Я отредактировал сообщение, добавив изображение результатов. Я также отредактировал блок кода. чтобы показать, что я использую, это основано непосредственно на документации Apple для этого.
Используя платформу Accelerate, которую я, если честно, не совсем понимаю, я пытаюсь создать заливку для UIImage. У меня есть расширение UIImage, но результат, который я получаю, непредсказуем, если изображение представляет собой что-либо. Если UIImage представляет собой одноцветное изображение, в котором каждый пиксель идентичен, результат будет таким, как ожидалось, но если я возьму изображение из фотопленки и попытаюсь запустить FloodFill, то получу путаницу.
Это код, с которым я работаю:
Код: Выделить всё
import Accelerate
import Accelerate.vImage
import Foundation
import CoreGraphics
extension UIImage {
func floodFill(seedPoint: CGPoint, replacementColor: UIColor) -> UIImage? {
guard var buffer = self.toVImage() else {
return nil
}
guard var maskBuffer = createMaskBuffer(width: Int(buffer.width), height: Int(buffer.height)) else {
return nil
}
let replacementRGBA = replacementColor.toRGBA()
var cgImageFormatPlanarF = vImage_CGImageFormat(
bitsPerComponent: 32,
bitsPerPixel: 32,
colorSpace: CGColorSpaceCreateDeviceGray(),
bitmapInfo: CGBitmapInfo(
rawValue: kCGBitmapByteOrder32Host.rawValue |
CGBitmapInfo.floatComponents.rawValue |
CGImageAlphaInfo.none.rawValue),
renderingIntent: .defaultIntent)!
let bufferPlanarF = try! vImage.PixelBuffer(
cgImage: self.cgImage!,
cgImageFormat: &cgImageFormatPlanarF)
bufferPlanarF.colorThreshold(
0.5,
destination: bufferPlanarF)
let bufferRGB8 = vImage.PixelBuffer(
planarBuffers: [bufferPlanarF, bufferPlanarF, bufferPlanarF, bufferPlanarF])
// Create a contiguous memory block for RGBA components
var rgbaComponents: [UInt8] = [replacementRGBA.0, replacementRGBA.1, replacementRGBA.2, replacementRGBA.3]
bufferRGB8.withUnsafePointerToVImageBuffer { src in
vImageFloodFill_ARGB8888(src, nil,
UInt(seedPoint.x), UInt(seedPoint.y),
&rgbaComponents, 8, 0)
}
let cgImageFormatRGB8 = vImage_CGImageFormat(
bitsPerComponent: 8,
bitsPerPixel: 8 * 4,
colorSpace: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(
rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue),
renderingIntent: .defaultIntent)!
guard let result = bufferRGB8.makeCGImage(cgImageFormat: cgImageFormatRGB8) else{
return nil
}
return UIImage(cgImage: result)
}
private func toVImage() -> vImage_Buffer? {
guard let cgImage = self.cgImage else {
return nil
}
guard let colorSpace = cgImage.colorSpace else {
return nil
}
var format = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 8 * 4,
colorSpace: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue))!
var buffer = vImage_Buffer()
let error = vImageBuffer_InitWithCGImage(&buffer, &format, nil, cgImage, vImage_Flags(kvImageNoFlags))
guard error == kvImageNoError else {
print("Error creating vImage buffer: \(error)")
return nil
}
return buffer
}
private func vImageToCGImage(buffer: vImage_Buffer) -> CGImage? {
guard let context = CGContext(data: buffer.data,
width: Int(buffer.width),
height: Int(buffer.height),
bitsPerComponent: 8,
bytesPerRow: buffer.rowBytes,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).rawValue) else {
return nil
}
return context.makeImage()
}
private func createMaskBuffer(width: Int, height: Int) -> vImage_Buffer? {
let bytesPerPixel = 4
let bytesPerRow = width * bytesPerPixel
let byteCount = bytesPerRow * height
let maskData = UnsafeMutablePointer.allocate(capacity: byteCount)
var maskBuffer = vImage_Buffer(data: maskData, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow)
memset(maskBuffer.data, 0, byteCount)
return maskBuffer
}
}
extension UIColor {
func toRGBA() -> (UInt8, UInt8, UInt8, UInt8) {
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
return (UInt8(red * 255), UInt8(green * 255), UInt8(blue * 255), UInt8(alpha * 255))
}
}
Я попробовал несколько подходов к передаче цвета замены. Я пытаюсь сделать что-то невозможное?
Функция заливки vImageFloodFill_ARGB8888 не предназначена для настоящей заливки, а предназначена только для заполнения пустых изображений.
Подробнее здесь:
https://stackoverflow.com/questions/784 ... -a-uiimage
1715267646
Anonymous
[img]https://i.sstatic.net/AJJ641N8.png[/img] Я отредактировал сообщение, добавив изображение результатов. Я также отредактировал блок кода. чтобы показать, что я использую, это основано непосредственно на документации Apple для этого. Используя платформу Accelerate, которую я, если честно, не совсем понимаю, я пытаюсь создать заливку для UIImage. У меня есть расширение UIImage, но результат, который я получаю, непредсказуем, если изображение представляет собой что-либо. Если UIImage представляет собой одноцветное изображение, в котором каждый пиксель идентичен, результат будет таким, как ожидалось, но если я возьму изображение из фотопленки и попытаюсь запустить FloodFill, то получу путаницу. Это код, с которым я работаю: [code]import Accelerate import Accelerate.vImage import Foundation import CoreGraphics extension UIImage { func floodFill(seedPoint: CGPoint, replacementColor: UIColor) -> UIImage? { guard var buffer = self.toVImage() else { return nil } guard var maskBuffer = createMaskBuffer(width: Int(buffer.width), height: Int(buffer.height)) else { return nil } let replacementRGBA = replacementColor.toRGBA() var cgImageFormatPlanarF = vImage_CGImageFormat( bitsPerComponent: 32, bitsPerPixel: 32, colorSpace: CGColorSpaceCreateDeviceGray(), bitmapInfo: CGBitmapInfo( rawValue: kCGBitmapByteOrder32Host.rawValue | CGBitmapInfo.floatComponents.rawValue | CGImageAlphaInfo.none.rawValue), renderingIntent: .defaultIntent)! let bufferPlanarF = try! vImage.PixelBuffer( cgImage: self.cgImage!, cgImageFormat: &cgImageFormatPlanarF) bufferPlanarF.colorThreshold( 0.5, destination: bufferPlanarF) let bufferRGB8 = vImage.PixelBuffer( planarBuffers: [bufferPlanarF, bufferPlanarF, bufferPlanarF, bufferPlanarF]) // Create a contiguous memory block for RGBA components var rgbaComponents: [UInt8] = [replacementRGBA.0, replacementRGBA.1, replacementRGBA.2, replacementRGBA.3] bufferRGB8.withUnsafePointerToVImageBuffer { src in vImageFloodFill_ARGB8888(src, nil, UInt(seedPoint.x), UInt(seedPoint.y), &rgbaComponents, 8, 0) } let cgImageFormatRGB8 = vImage_CGImageFormat( bitsPerComponent: 8, bitsPerPixel: 8 * 4, colorSpace: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo( rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue), renderingIntent: .defaultIntent)! guard let result = bufferRGB8.makeCGImage(cgImageFormat: cgImageFormatRGB8) else{ return nil } return UIImage(cgImage: result) } private func toVImage() -> vImage_Buffer? { guard let cgImage = self.cgImage else { return nil } guard let colorSpace = cgImage.colorSpace else { return nil } var format = vImage_CGImageFormat(bitsPerComponent: 8, bitsPerPixel: 8 * 4, colorSpace: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue))! var buffer = vImage_Buffer() let error = vImageBuffer_InitWithCGImage(&buffer, &format, nil, cgImage, vImage_Flags(kvImageNoFlags)) guard error == kvImageNoError else { print("Error creating vImage buffer: \(error)") return nil } return buffer } private func vImageToCGImage(buffer: vImage_Buffer) -> CGImage? { guard let context = CGContext(data: buffer.data, width: Int(buffer.width), height: Int(buffer.height), bitsPerComponent: 8, bytesPerRow: buffer.rowBytes, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).rawValue) else { return nil } return context.makeImage() } private func createMaskBuffer(width: Int, height: Int) -> vImage_Buffer? { let bytesPerPixel = 4 let bytesPerRow = width * bytesPerPixel let byteCount = bytesPerRow * height let maskData = UnsafeMutablePointer.allocate(capacity: byteCount) var maskBuffer = vImage_Buffer(data: maskData, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow) memset(maskBuffer.data, 0, byteCount) return maskBuffer } } extension UIColor { func toRGBA() -> (UInt8, UInt8, UInt8, UInt8) { var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0 getRed(&red, green: &green, blue: &blue, alpha: &alpha) return (UInt8(red * 255), UInt8(green * 255), UInt8(blue * 255), UInt8(alpha * 255)) } } [/code] Я попробовал несколько подходов к передаче цвета замены. Я пытаюсь сделать что-то невозможное? Функция заливки vImageFloodFill_ARGB8888 не предназначена для настоящей заливки, а предназначена только для заполнения пустых изображений. Подробнее здесь: [url]https://stackoverflow.com/questions/78451785/using-vimagefloodfill-argb8888-on-ios-to-create-a-flood-fill-for-a-uiimage[/url]