在实验室颜色空间中创建像素缓冲区
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在实验室颜色空间中创建像素缓冲区相关的知识,希望对你有一定的参考价值。
我正在实现一个类似于ios中photoshop的魔棒工具的颜色选择工具。
我已经让它在RGB工作,但为了使它更准确我想让它在LAB色彩空间中工作。
它目前的工作方式是它采用UIImage,创建该图像的CGImage版本。然后它在RGB colourspace中创建一个CGContext,在该上下文中绘制CGImage,获取上下文数据,然后将其绑定到使用struct RGBA32的像素缓冲区。
let colorSpace = CGColorSpaceCreateDeviceRGB()
let width = inputCGImage.width
let height = inputCGImage.height
let bytesPerPixel = 4
let bitsPerComponent = 8
let bytesPerRow = bytesPerPixel * width
let bitmapInfo = RGBA32.bitmapInfo
guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colspace, bitmapInfo: bitmapInfo) else {
print("unable to create context")
return nil
}
context.draw(inputCGImage, in: CGRect(x: 0, y: 0, width: width, height: height))
guard let buffer = context.data else {
print("unable to get context data")
return nil
}
let pixelBuffer = buffer.bindMemory(to: RGBA32.self, capacity: width * height)
struct RGBA32: Equatable {
var color: UInt32
var redComponent: UInt8 {
return UInt8((color >> 24) & 255)
}
var greenComponent: UInt8 {
return UInt8((color >> 16) & 255)
}
var blueComponent: UInt8 {
return UInt8((color >> 8) & 255)
}
var alphaComponent: UInt8 {
return UInt8((color >> 0) & 255)
}
init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) {
color = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0)
}
static let clear = RGBA32(red: 0, green: 0, blue: 0, alpha: 0)
static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
static func ==(lhs: RGBA32, rhs: RGBA32) -> Bool {
return lhs.color == rhs.color
}
}
然后使用该像素缓冲区使用非常简单的欧几里德距离快速将颜色值与所选像素进行比较,如此处所述。
https://en.wikipedia.org/wiki/Color_difference
正如我所说的那样,但是为了获得更准确的结果,我希望它能够工作的是CIE Lab Color space。
最初我尝试在检查时将每个像素转换为LAB颜色,然后使用CIE94比较,如上面的色差链接所述。它工作但很慢,我猜是因为它必须在检查之前将一百万像素(或左右)转换为LAB颜色。
然后让我感到震惊的是,为了使它快速工作,最好将像素缓冲区存储在LAB颜色空间中(它不用于其他任何东西)。
所以我创建了一个类似的结构LABA32
struct LABA32:Equatable {
var colour: UInt32
var lComponent: UInt8 {
return UInt8((colour >> 24) & 255)
}
var aComponent: UInt8 {
return UInt8((colour >> 16) & 255)
}
var bComponent: UInt8 {
return UInt8((colour >> 8) & 255)
}
var alphaComponent: UInt8 {
return UInt8((colour >> 0) & 255)
}
init(lComponent: UInt8, aComponent: UInt8, bComponent: UInt8, alphaComponent: UInt8) {
colour = (UInt32(lComponent) << 24) | (UInt32(aComponent) << 16) | (UInt32(bComponent) << 8) | (UInt32(alphaComponent) << 0)
}
static let clear = LABA32(lComponent: 0, aComponent: 0, bComponent: 0, alphaComponent: 0)
static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
static func ==(lhs: LABA32, rhs: LAB32) -> Bool {
return lhs.colour == rhs.colour
}
我可能错了,但理论上如果我在具有LAB颜色空间而不是设备RGB的上下文中绘制CGImage,它应该将数据映射到这个新结构。
我遇到的问题实际上是创建颜色空间(更不用说测试这个理论是否真的有效)。
要创建LAB colourspace,我正在尝试使用此构造函数
CGColorSpace(labWhitePoint: <UnsafePointer<CGFloat>!>, blackPoint: <UnsafePointer<CGFloat>!>, range: <UnsafePointer<CGFloat>!>)
根据苹果文档
white Point:一个由3个数字组成的数组,用于指定CIE 1931 XYZ空间中漫反射白点的三刺激值。黑点:由3个数字组成的数组,用于指定扩散黑点在CIE 1931 XYZ空间中的三刺激值。 range:一个包含4个数字的数组,用于指定颜色空间的a *和b *组件的有效值范围。 a *组件表示从绿色到红色的值,b *组件表示从蓝色到黄色的值。
所以我创建了3个CGFloats阵列
var whitePoint:[CGFloat] = [0.95947,1,1.08883]
var blackPoint:[CGFloat] = [0,0,0]
var range:[CGFloat] = [-127,127,-127,127]
然后我尝试构建颜色空间
let colorSpace = CGColorSpace(labWhitePoint: &whitePoint, blackPoint: &blackPoint, range: &range)
问题是我不断收到错误“不支持的色彩空间”所以我必须做一些完全错误的事情。我花了很多时间寻找其他人试图构建LAB色彩空间,但似乎没有任何相关性,甚至试图找到Objective-C版本。
那么我如何才能正确创建LAB色彩空间呢?
谢谢。
重要提示:iOS不支持与设备无关或通用的颜色空间。 iOS应用程序必须使用设备颜色空间。
所以,如果你想在LAB中工作,我想你必须手动进行转换。
以上是关于在实验室颜色空间中创建像素缓冲区的主要内容,如果未能解决你的问题,请参考以下文章
如何在opengl es 3+中获取我的离屏帧缓冲区内的底层对象的像素颜色?