我们正在尝试使UIImage
以便它可以正确传递到 CoreML 模型中。
我们从每个像素检索 RGB 值的方法是首先初始化一个[CGFloat]
数组称为rawData
每个像素的值,这样就有一个红色、绿色、蓝色和 alpha 值的位置。在bitmapInfo
,我们从原始 UIimage 本身获取原始像素值并进行操作。这用于填充bitmapInfo
参数输入context
, a CGContext
多变的。我们稍后将使用context
变量为draw
a CGImage
稍后将转换标准化CGImage
回到一个UIImage
.
使用嵌套的 for 循环迭代x
and y
坐标,所有颜色中的最小和最大像素颜色值(通过CGFloat
的原始数据数组)跨所有像素被发现。
设置一个绑定变量来终止for循环,否则会出现超出范围的错误。
range
表示可能的 RGB 值的范围(即最大颜色值与最小颜色值之间的差值)。
使用方程标准化每个像素值:
A = Image
curPixel = current pixel (R,G, B or Alpha)
NormalizedPixel = (curPixel-minPixel(A))/range
以及上面类似设计的嵌套 for 循环来解析数组rawData
并根据此标准化修改每个像素的颜色。
我们的大部分代码来自:
- UIImage 到 UIColor 像素颜色数组 https://stackoverflow.com/questions/38163523/uiimage-to-uicolor-array-of-pixel-colors
- 更改 UIImage 中某些像素的颜色 https://stackoverflow.com/questions/31661023/change-color-of-certain-pixels-in-a-uiimage
- https://gist.github.com/pimpapare/e8187d82a3976b851fc12fe4f8965789 https://gist.github.com/pimpapare/e8187d82a3976b851fc12fe4f8965789
We use CGFloat
代替UInt8
因为归一化像素值应该是 0 到 1 之间的实数,而不是 0 或 1。
func normalize() -> UIImage?{
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let cgImage = cgImage else {
return nil
}
let width = Int(size.width)
let height = Int(size.height)
var rawData = [CGFloat](repeating: 0, count: width * height * 4)
let bytesPerPixel = 4
let bytesPerRow = bytesPerPixel * width
let bytesPerComponent = 8
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue & CGBitmapInfo.alphaInfoMask.rawValue
let context = CGContext(data: &rawData,
width: width,
height: height,
bitsPerComponent: bytesPerComponent,
bytesPerRow: bytesPerRow,
space: colorSpace,
bitmapInfo: bitmapInfo)
let drawingRect = CGRect(origin: .zero, size: CGSize(width: width, height: height))
context?.draw(cgImage, in: drawingRect)
let bound = rawData.count
//find minimum and maximum
var minPixel: CGFloat = 1.0
var maxPixel: CGFloat = 0.0
for x in 0..<width {
for y in 0..<height {
let byteIndex = (bytesPerRow * x) + y * bytesPerPixel
if(byteIndex > bound - 4){
break
}
minPixel = min(CGFloat(rawData[byteIndex]), minPixel)
minPixel = min(CGFloat(rawData[byteIndex + 1]), minPixel)
minPixel = min(CGFloat(rawData[byteIndex + 2]), minPixel)
minPixel = min(CGFloat(rawData[byteIndex + 3]), minPixel)
maxPixel = max(CGFloat(rawData[byteIndex]), maxPixel)
maxPixel = max(CGFloat(rawData[byteIndex + 1]), maxPixel)
maxPixel = max(CGFloat(rawData[byteIndex + 2]), maxPixel)
maxPixel = max(CGFloat(rawData[byteIndex + 3]), maxPixel)
}
}
let range = maxPixel - minPixel
print("minPixel: \(minPixel)")
print("maxPixel : \(maxPixel)")
print("range: \(range)")
for x in 0..<width {
for y in 0..<height {
let byteIndex = (bytesPerRow * x) + y * bytesPerPixel
if(byteIndex > bound - 4){
break
}
rawData[byteIndex] = (CGFloat(rawData[byteIndex]) - minPixel) / range
rawData[byteIndex+1] = (CGFloat(rawData[byteIndex+1]) - minPixel) / range
rawData[byteIndex+2] = (CGFloat(rawData[byteIndex+2]) - minPixel) / range
rawData[byteIndex+3] = (CGFloat(rawData[byteIndex+3]) - minPixel) / range
}
}
let cgImage0 = context!.makeImage()
return UIImage.init(cgImage: cgImage0!)
}
标准化之前,我们期望像素值范围为 0 - 255,标准化之后,像素值范围为 0 - 1。
归一化公式能够将像素值归一化为 0 到 1 之间的值。但是当我们尝试打印出归一化之前的像素值(只需在循环像素值时添加打印语句)以验证我们获得的原始像素值是否正确时,我们发现这些值的范围超出了范围。例如,像素值为 3.506e+305(大于 255)。我们认为一开始就得到了错误的原始像素值。
我们对 Swift 中的图像处理不熟悉,并且不确定整个规范化过程是否正确。任何帮助,将不胜感激!