如何在 Swift 中使用道尔顿化算法更改 UIImage 的像素值
How do I change the pixel values of UIImage with daltonization algorithm in Swift
我正在尝试更改 UIImage 的像素数据并使用新像素数据创建新图像。我一直在尝试实现下面link到Swift.
中的功能
https://galactic.ink/labs/Color-Vision/Javascript/Color.Vision.Daltonize.js
我一直遇到转换错误。
错误:无法将类型 'UInt32' 的值分配给类型 'RGBA32'
的下标
错误:无法将类型 'RGBA32' 的值转换为预期的参数类型 'UInt32'
此外,我在处理算法中使用的数据类型是 UInt32,它不包含负数,所以我想知道是否有可能在 Swift 中编写此方法。
var image = UIImage(named: "ME2.png")!
func processPixels(in image: UIImage) -> UIImage? {
guard let inputCGImage = image.cgImage else { print("unable to get cgImage")
return nil}
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: colorSpace, 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)
let pro :[Float] = [0.0, 2.02344, -2.52581, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
let a = pro[0];
let b = pro[1];
let c = pro[2];
let d = pro[3];
let e = pro[4];
let f = pro[5];
let g = pro[6];
let h = pro[7];
let i = pro[8];
var L : UInt32
var M : UInt32
var S : UInt32
var l : UInt32
var m : UInt32
var s : UInt32
var R : UInt32
var G : UInt32
var B : UInt32
var RR : UInt32
var GG : UInt32
var BB : UInt32
for y in 0 ..< inputCGImage.height {
for x in 0 ..< inputCGImage.width {
let offset = (y * inputCGImage.bytesPerRow) + (x * bytesPerPixel)
let r = pixelBuffer[offset]
let g = pixelBuffer[offset + 1]
let b = pixelBuffer[offset + 2]
let components = (r: pixelBuffer[offset], g: pixelBuffer[offset + 1], b: pixelBuffer[offset + 2])
print("[x:\(x), y:\(y)] \(components)")
//RGB To LMS matrix conversion
error: ColorPractice.playground:78:15: error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
L = (UInt32(17.8824) * r) + (UInt32(43.5161) * g) + (UInt32(4.11935) * b);
error: ColorPractice.playground:79:15: error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
M = (UInt32(3.45565) * r) + (UInt32(27.1554) * g) + (UInt32(3.86714) * b);
error: ColorPractice.playground:80:15: error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
S = (UInt32(0.0299566) * r) + (UInt32(0.184309) * g) + (UInt32(1.46709) * b);
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
L = (UInt32(17.8824) * r) + (UInt32(43.5161) * g) + (UInt32(4.11935) * b);
M = (UInt32(3.45565) * r) + (UInt32(27.1554) * g) + (UInt32(3.86714) * b);
S = (UInt32(0.0299566) * r) + (UInt32(0.184309) * g) + (UInt32(1.46709) * b);
//Simulate Color Blindness
error: ColorPractice.playground:86:36: error: no exact matches in call to initializer
l = (UInt32(a) * L) + (UInt32(b) * M) + (UInt32(c) * S);
error: ColorPractice.playground:88:18: error: no exact matches in call to initializer
s = (UInt32(g) * L) + (UInt32(h) * M) + (UInt32(i) * S);
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
l = (UInt32(a) * L) + (UInt32(b) * M) + (UInt32(c) * S);
m = (UInt32(d) * L) + (UInt32(e) * M) + (UInt32(f) * S);
s = (UInt32(g) * L) + (UInt32(h) * M) + (UInt32(i) * S);
//LMS to RGB matrix conversion
R = (UInt32(0.0809444479) * l) + (UInt32(0.130504409) * m) + (UInt32(0.116721066) * s);
G = (UInt32(0.0102485335) * l) + (UInt32(0.0540193266) * m) + (UInt32(0.113614708) * s);
B = (UInt32(0.000365296938) * l) + (UInt32(0.00412161469) * m) + (UInt32(0.693511405) * s);
//Isolate invisible colors to color vision deficiency (calculate error matrix)
error: ColorPractice.playground:98:17: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
R = r - R;
^
error: ColorPractice.playground:99:17: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
G = g - G;
^
error: ColorPractice.playground:100:17: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
B = b - B;
^
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
R = r - R;
G = g - G;
B = b - B;
//Shift colors towards visible spectrum (apply error modifications)
RR = (UInt32(0.0) * R) + (UInt32(0.0) * G) + (UInt32(0.0) * B);
GG = (UInt32(0.7) * R) + (UInt32(1.0) * G) + (UInt32(0.0) * B);
BB = (UInt32(0.7) * R) + (UInt32(0.0) * G) + (UInt32(1.0) * B);
//Add compensation to original values
error: ColorPractice.playground:108:22: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
R = RR + r;
^
error: ColorPractice.playground:109:22: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
G = GG + g;
^
error: ColorPractice.playground:110:22: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
B = BB + b;
^
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
R = RR + r;
G = GG + g;
B = BB + b;
//Keep values in range
if(R < 0) {R = 0}
if(R > 255) {R = 255}
if(G < 0 ) {G = 0}
if(G > 255) {G = 255}
if (B < 0) {B = 0}
if (B > 255) {B = 255}
//Resassign Pixels in Array
error: ColorPractice.playground:123:37: error: cannot assign value of type 'UInt32' to subscript of type 'RGBA32'
pixelBuffer[offset] = R >> 0;
~~^~~~
error: ColorPractice.playground:124:41: error: cannot assign value of type 'UInt32' to subscript of type 'RGBA32'
pixelBuffer[offset + 1] = G >> 0;
~~^~~~
error: ColorPractice.playground:125:41: error: cannot assign value of type 'UInt32' to subscript of type 'RGBA32'
pixelBuffer[offset + 2] = B >> 0;
~~^~~~
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pixelBuffer[offset] = R >> 0;
pixelBuffer[offset + 1] = G >> 0;
pixelBuffer[offset + 2] = B >> 0;
}
}
let outputCGImage = context.makeImage()!
let outputImage = UIImage(cgImage: outputCGImage, scale: image.scale, orientation: image.imageOrientation)
return outputImage
}
struct RGBA32: Equatable {
private 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) {
let red = UInt32(red)
let green = UInt32(green)
let blue = UInt32(blue)
let alpha = UInt32(alpha)
color = (red << 24) | (green << 16) | (blue << 8) | (alpha << 0)
}
static let red = RGBA32(red: 255, green: 0, blue: 0, alpha: 255)
static let green = RGBA32(red: 0, green: 255, blue: 0, alpha: 255)
static let blue = RGBA32(red: 0, green: 0, blue: 255, alpha: 255)
static let white = RGBA32(red: 255, green: 255, blue: 255, alpha: 255)
static let black = RGBA32(red: 0, green: 0, blue: 0, alpha: 255)
static let magenta = RGBA32(red: 255, green: 0, blue: 255, alpha: 255)
static let yellow = RGBA32(red: 255, green: 255, blue: 0, alpha: 255)
static let cyan = RGBA32(red: 0, green: 255, blue: 255, alpha: 255)
static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
static func ==(lhs: RGBA32, rhs: RGBA32) -> Bool {
return lhs.color == rhs.color
}
}
你定义了
pixelBuffer = buffer.bindMemory(to: RGBA32.self...
但是后来,在您的其余代码中,您似乎认为 pixelBuffer
中的每个 offset
都是 UInt8。它不是。这是一个 RGBA32!
比如你说:
let r = pixelBuffer[offset]
let g = pixelBuffer[offset + 1]
let b = pixelBuffer[offset + 2]
这似乎暗示您认为 r
、g
和 b
是 数字 (例如 UInt8 值)。他们不是。您将 pixelBuffer
绑定到 RGBA32,因此 pixelBuffer
中的每个 offset
都是一个 RGBA32。这就是内存绑定的意思。
在我看来,你所有的错误都源于那个错误的想法。
如果您的目标是获取 pixelBuffer
中第 nth 像素的红色、绿色、蓝色和 alpha 分量,这些分别是 pixelBuffer[n].redComponent
、pixelBuffer[n].greenComponent
、pixelBuffer[n].blueComponent
和 pixelBuffer[n].alphaComponent
。
即便如此,您也无法将组件直接乘以 UInt32,因为您无法将 UInt32 乘以 UInt8;但你会更接近完成一些有用的事情。
我正在尝试更改 UIImage 的像素数据并使用新像素数据创建新图像。我一直在尝试实现下面link到Swift.
中的功能https://galactic.ink/labs/Color-Vision/Javascript/Color.Vision.Daltonize.js
我一直遇到转换错误。
错误:无法将类型 'UInt32' 的值分配给类型 'RGBA32'
的下标错误:无法将类型 'RGBA32' 的值转换为预期的参数类型 'UInt32'
此外,我在处理算法中使用的数据类型是 UInt32,它不包含负数,所以我想知道是否有可能在 Swift 中编写此方法。
var image = UIImage(named: "ME2.png")!
func processPixels(in image: UIImage) -> UIImage? {
guard let inputCGImage = image.cgImage else { print("unable to get cgImage")
return nil}
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: colorSpace, 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)
let pro :[Float] = [0.0, 2.02344, -2.52581, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
let a = pro[0];
let b = pro[1];
let c = pro[2];
let d = pro[3];
let e = pro[4];
let f = pro[5];
let g = pro[6];
let h = pro[7];
let i = pro[8];
var L : UInt32
var M : UInt32
var S : UInt32
var l : UInt32
var m : UInt32
var s : UInt32
var R : UInt32
var G : UInt32
var B : UInt32
var RR : UInt32
var GG : UInt32
var BB : UInt32
for y in 0 ..< inputCGImage.height {
for x in 0 ..< inputCGImage.width {
let offset = (y * inputCGImage.bytesPerRow) + (x * bytesPerPixel)
let r = pixelBuffer[offset]
let g = pixelBuffer[offset + 1]
let b = pixelBuffer[offset + 2]
let components = (r: pixelBuffer[offset], g: pixelBuffer[offset + 1], b: pixelBuffer[offset + 2])
print("[x:\(x), y:\(y)] \(components)")
//RGB To LMS matrix conversion
error: ColorPractice.playground:78:15: error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
L = (UInt32(17.8824) * r) + (UInt32(43.5161) * g) + (UInt32(4.11935) * b);
error: ColorPractice.playground:79:15: error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
M = (UInt32(3.45565) * r) + (UInt32(27.1554) * g) + (UInt32(3.86714) * b);
error: ColorPractice.playground:80:15: error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
S = (UInt32(0.0299566) * r) + (UInt32(0.184309) * g) + (UInt32(1.46709) * b);
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
L = (UInt32(17.8824) * r) + (UInt32(43.5161) * g) + (UInt32(4.11935) * b);
M = (UInt32(3.45565) * r) + (UInt32(27.1554) * g) + (UInt32(3.86714) * b);
S = (UInt32(0.0299566) * r) + (UInt32(0.184309) * g) + (UInt32(1.46709) * b);
//Simulate Color Blindness
error: ColorPractice.playground:86:36: error: no exact matches in call to initializer
l = (UInt32(a) * L) + (UInt32(b) * M) + (UInt32(c) * S);
error: ColorPractice.playground:88:18: error: no exact matches in call to initializer
s = (UInt32(g) * L) + (UInt32(h) * M) + (UInt32(i) * S);
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
l = (UInt32(a) * L) + (UInt32(b) * M) + (UInt32(c) * S);
m = (UInt32(d) * L) + (UInt32(e) * M) + (UInt32(f) * S);
s = (UInt32(g) * L) + (UInt32(h) * M) + (UInt32(i) * S);
//LMS to RGB matrix conversion
R = (UInt32(0.0809444479) * l) + (UInt32(0.130504409) * m) + (UInt32(0.116721066) * s);
G = (UInt32(0.0102485335) * l) + (UInt32(0.0540193266) * m) + (UInt32(0.113614708) * s);
B = (UInt32(0.000365296938) * l) + (UInt32(0.00412161469) * m) + (UInt32(0.693511405) * s);
//Isolate invisible colors to color vision deficiency (calculate error matrix)
error: ColorPractice.playground:98:17: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
R = r - R;
^
error: ColorPractice.playground:99:17: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
G = g - G;
^
error: ColorPractice.playground:100:17: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
B = b - B;
^
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
R = r - R;
G = g - G;
B = b - B;
//Shift colors towards visible spectrum (apply error modifications)
RR = (UInt32(0.0) * R) + (UInt32(0.0) * G) + (UInt32(0.0) * B);
GG = (UInt32(0.7) * R) + (UInt32(1.0) * G) + (UInt32(0.0) * B);
BB = (UInt32(0.7) * R) + (UInt32(0.0) * G) + (UInt32(1.0) * B);
//Add compensation to original values
error: ColorPractice.playground:108:22: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
R = RR + r;
^
error: ColorPractice.playground:109:22: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
G = GG + g;
^
error: ColorPractice.playground:110:22: error: cannot convert value of type 'RGBA32' to expected argument type 'UInt32'
B = BB + b;
^
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
R = RR + r;
G = GG + g;
B = BB + b;
//Keep values in range
if(R < 0) {R = 0}
if(R > 255) {R = 255}
if(G < 0 ) {G = 0}
if(G > 255) {G = 255}
if (B < 0) {B = 0}
if (B > 255) {B = 255}
//Resassign Pixels in Array
error: ColorPractice.playground:123:37: error: cannot assign value of type 'UInt32' to subscript of type 'RGBA32'
pixelBuffer[offset] = R >> 0;
~~^~~~
error: ColorPractice.playground:124:41: error: cannot assign value of type 'UInt32' to subscript of type 'RGBA32'
pixelBuffer[offset + 1] = G >> 0;
~~^~~~
error: ColorPractice.playground:125:41: error: cannot assign value of type 'UInt32' to subscript of type 'RGBA32'
pixelBuffer[offset + 2] = B >> 0;
~~^~~~
~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pixelBuffer[offset] = R >> 0;
pixelBuffer[offset + 1] = G >> 0;
pixelBuffer[offset + 2] = B >> 0;
}
}
let outputCGImage = context.makeImage()!
let outputImage = UIImage(cgImage: outputCGImage, scale: image.scale, orientation: image.imageOrientation)
return outputImage
}
struct RGBA32: Equatable {
private 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) {
let red = UInt32(red)
let green = UInt32(green)
let blue = UInt32(blue)
let alpha = UInt32(alpha)
color = (red << 24) | (green << 16) | (blue << 8) | (alpha << 0)
}
static let red = RGBA32(red: 255, green: 0, blue: 0, alpha: 255)
static let green = RGBA32(red: 0, green: 255, blue: 0, alpha: 255)
static let blue = RGBA32(red: 0, green: 0, blue: 255, alpha: 255)
static let white = RGBA32(red: 255, green: 255, blue: 255, alpha: 255)
static let black = RGBA32(red: 0, green: 0, blue: 0, alpha: 255)
static let magenta = RGBA32(red: 255, green: 0, blue: 255, alpha: 255)
static let yellow = RGBA32(red: 255, green: 255, blue: 0, alpha: 255)
static let cyan = RGBA32(red: 0, green: 255, blue: 255, alpha: 255)
static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
static func ==(lhs: RGBA32, rhs: RGBA32) -> Bool {
return lhs.color == rhs.color
}
}
你定义了
pixelBuffer = buffer.bindMemory(to: RGBA32.self...
但是后来,在您的其余代码中,您似乎认为 pixelBuffer
中的每个 offset
都是 UInt8。它不是。这是一个 RGBA32!
比如你说:
let r = pixelBuffer[offset]
let g = pixelBuffer[offset + 1]
let b = pixelBuffer[offset + 2]
这似乎暗示您认为 r
、g
和 b
是 数字 (例如 UInt8 值)。他们不是。您将 pixelBuffer
绑定到 RGBA32,因此 pixelBuffer
中的每个 offset
都是一个 RGBA32。这就是内存绑定的意思。
在我看来,你所有的错误都源于那个错误的想法。
如果您的目标是获取 pixelBuffer
中第 nth 像素的红色、绿色、蓝色和 alpha 分量,这些分别是 pixelBuffer[n].redComponent
、pixelBuffer[n].greenComponent
、pixelBuffer[n].blueComponent
和 pixelBuffer[n].alphaComponent
。
即便如此,您也无法将组件直接乘以 UInt32,因为您无法将 UInt32 乘以 UInt8;但你会更接近完成一些有用的事情。