gpt4 book ai didi

ios - 快速将图像转换为二进制

转载 作者:搜寻专家 更新时间:2023-10-31 08:22:07 24 4
gpt4 key购买 nike

我想将图像转换为二进制黑白图像,此时我正在使用普通嵌套循环遍历像素(存储在 UnsafeMutableBufferPointer 中),将每个 RGB 与平均值进行比较并将其设置为黑色或白色。

这看起来真的很慢,我确信有一种内置的方式可以使用 gpu 或经过很好的优化。如果您可以提供代码示例或链接,那就太好了。

for var y in 0..<height {
for var x in 0..<width{
//Pixel is small class i made for 8 bit access and comparison
if (Buffer[x+y*width] < AVRRGB) {
Buffer[x+y*width] = Pixel(RGB: 0x000000FF)
} else{
Buffer[x+y*width] = Pixel(RGB: 0xFFFFFFFF)
}
}
}

最佳答案

一些观察:

  1. 确保您在发布版本(或关闭优化)的设备上进行测试。仅此一项就使它更快。在 iPhone 7+ 上,它将 1920 x 1080 像素彩色图像转换为灰度图像的时间从 1.7 秒减少到不到 0.1 秒。

  2. 您可能希望使用 DispatchQueue.concurrentPerform 并发处理像素。在我的 iPhone 7+ 上,速度大约是原来的两倍。

根据我的经验,Core Image 过滤器并没有快多少,但如果您需要更快,可以考虑使用 vImage 或 Metal。但是除非您要处理非常大的图像,否则使用优化的(可能并发的)简单 Swift 代码的响应时间可能就足够了。

一个不相关的观察:

  1. 另外,我不确定您的黑白转换是如何进行的,但通常您会想要计算 relative luminance颜色像素(例如 0.2126 * 红色 + 0.7152 * 绿色 + 0.0722 * 蓝色)。当然,当将彩色图像转换为灰度图像时,您会执行类似的操作以获得更接近人眼所见内容的图像,如果转换为黑白图像,我个人也会执行类似的操作。

仅供引用,我的 Swift 3/4 颜色到灰度例程如下所示:

func blackAndWhite(image: UIImage, completion: @escaping (UIImage?) -> Void) {
DispatchQueue.global(qos: .userInitiated).async {
// get information about image

let imageref = image.cgImage!
let width = imageref.width
let height = imageref.height

// create new bitmap context

let bitsPerComponent = 8
let bytesPerPixel = 4
let bytesPerRow = width * bytesPerPixel
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = Pixel.bitmapInfo
let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)!

// draw image to context

let rect = CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height))
context.draw(imageref, in: rect)

// manipulate binary data

guard let buffer = context.data else {
print("unable to get context data")
completion(nil)
return
}

let pixels = buffer.bindMemory(to: Pixel.self, capacity: width * height)

DispatchQueue.concurrentPerform(iterations: height) { row in
for col in 0 ..< width {
let offset = Int(row * width + col)

let red = Float(pixels[offset].red)
let green = Float(pixels[offset].green)
let blue = Float(pixels[offset].blue)
let alpha = pixels[offset].alpha
let luminance = UInt8(0.2126 * red + 0.7152 * green + 0.0722 * blue)
pixels[offset] = Pixel(red: luminance, green: luminance, blue: luminance, alpha: alpha)
}
}

// return the image

let outputImage = context.makeImage()!
completion(UIImage(cgImage: outputImage, scale: image.scale, orientation: image.imageOrientation))
}
}

struct Pixel: Equatable {
private var rgba: UInt32

var red: UInt8 {
return UInt8((rgba >> 24) & 255)
}

var green: UInt8 {
return UInt8((rgba >> 16) & 255)
}

var blue: UInt8 {
return UInt8((rgba >> 8) & 255)
}

var alpha: UInt8 {
return UInt8((rgba >> 0) & 255)
}

init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) {
rgba = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0)
}

static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue

static func ==(lhs: Pixel, rhs: Pixel) -> Bool {
return lhs.rgba == rhs.rgba
}
}

显然,如果您想将其转换为绝对黑白,则相应地调整算法,但这说明了并发图像缓冲区操作例程。


虽然上面的速度相当快(同样,在优化的发布版本中),但使用 vImage 甚至更快。以下内容改编自Converting Color Images to Grayscale :

func grayscale(of image: UIImage) -> UIImage? {
guard var source = sourceBuffer(for: image) else { return nil }

defer { free(source.data) }

var destination = destinationBuffer(for: source)

// Declare the three coefficients that model the eye's sensitivity
// to color.
let redCoefficient: Float = 0.2126
let greenCoefficient: Float = 0.7152
let blueCoefficient: Float = 0.0722

// Create a 1D matrix containing the three luma coefficients that
// specify the color-to-grayscale conversion.
let divisor: Int32 = 0x1000
let fDivisor = Float(divisor)

var coefficients = [
Int16(redCoefficient * fDivisor),
Int16(greenCoefficient * fDivisor),
Int16(blueCoefficient * fDivisor)
]

// Use the matrix of coefficients to compute the scalar luminance by
// returning the dot product of each RGB pixel and the coefficients
// matrix.
let preBias: [Int16] = [0, 0, 0, 0]
let postBias: Int32 = 0

let result = vImageMatrixMultiply_ARGB8888ToPlanar8(
&source,
&destination,
&coefficients,
divisor,
preBias,
postBias,
vImage_Flags(kvImageNoFlags))

guard result == kvImageNoError else { return nil }

defer { free(destination.data) }

// Create a 1-channel, 8-bit grayscale format that's used to
// generate a displayable image.
var monoFormat = vImage_CGImageFormat(
bitsPerComponent: 8,
bitsPerPixel: 8,
colorSpace: Unmanaged.passRetained(CGColorSpaceCreateDeviceGray()),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
version: 0,
decode: nil,
renderingIntent: .defaultIntent)

// Create a Core Graphics image from the grayscale destination buffer.
let cgImage = vImageCreateCGImageFromBuffer(&destination,
&monoFormat,
nil,
nil,
vImage_Flags(kvImageNoFlags),
nil)?.takeRetainedValue()
return cgImage.map { UIImage(cgImage: $0) }
}


func sourceBuffer(for image: UIImage) -> vImage_Buffer? {
guard let cgImage = image.cgImage else { return nil }

let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).union(.byteOrder32Big)

var format = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: Unmanaged.passRetained(CGColorSpaceCreateDeviceRGB()),
bitmapInfo: bitmapInfo,
version: 0,
decode: nil,
renderingIntent: .defaultIntent)

var sourceImageBuffer = vImage_Buffer()
vImageBuffer_InitWithCGImage(&sourceImageBuffer,
&format,
nil,
cgImage,
vImage_Flags(kvImageNoFlags))

return sourceImageBuffer

func destinationBuffer(for sourceBuffer: vImage_Buffer) -> vImage_Buffer {
var destinationBuffer = vImage_Buffer()

vImageBuffer_Init(&destinationBuffer,
sourceBuffer.height,
sourceBuffer.width,
8,
vImage_Flags(kvImageNoFlags))

return destinationBuffer
}

关于ios - 快速将图像转换为二进制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45154391/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com