我有一个包含数百万个元素(7201 x 7201 数据点)的数组,我将数据转换为灰度图像。
var imagePixels = heights.map { terrainToColorScale($0.height, gradient: .Linear) }
let _ = writeImageToFile(imagePixels, height: latStrides, width: lonStrides, imgColorSpace: .BW, to: imageURL, as: .png)
这段代码大约需要 11 秒才能完成(CPU=2.3Ghz 8-Core i9),但如果可能的话,我希望获得更好的性能。代码当前在单个线程中运行。
简单地将我的heights
数组分成块(比如 100 个块)并为每个块运行一个任务组并获得一个不错的改进吗?或者我是否正在考虑进入金属和着色器(我对金属的了解为零!!)以获得更好的结果?
只是为了感兴趣,生成的典型图像是......(图像被下采样,因为太大而无法在此处上传。)
更新:添加与terrainToColorScale
基本上相关的代码,对于线性转换,它将采用地形高度(通常为 0...9000)并将其缩放以返回 0...255 之间的值我也有非线性实现(未在下面显示) 这将为主要是低/高地形海拔的数据集显示更多细节。
let terrainLowerCutOff: Double = 0.0 // Mean Sea Level
let terrainUpperCutOff: Double = 9000.0 // Value in meters, just higher that Everest
func terrainToColorScale(_ elev: Double, lowerCutOff: Double = terrainLowerCutOff, upperCutOff: Double = terrainUpperCutOff, gradient: ImageColorGradient = .Linear) -> UInt8 {
switch gradient {
case .Linear:
return linearColorScale(elev, lowerCutOff: lowerCutOff, upperCutOff: upperCutOff)
case .LinearInverse:
return linearInverseColorScale(elev, lowerCutOff: lowerCutOff, upperCutOff: upperCutOff)
case .CurveEmphasiseLows:
return reciprocalPowerColorScale(elev, lowerCutOff: lowerCutOff, upperCutOff: upperCutOff)
case .CurveEmphasiseLowsInverse:
return reciprocalInversePowerColorScale(elev, lowerCutOff: lowerCutOff, upperCutOff: upperCutOff)
case .CurveEmphasiseHighs:
return powerColorScale(elev, lowerCutOff: lowerCutOff, upperCutOff: upperCutOff)
case .CurveEmphasiseHighsInverse:
return powerInverseColorScale(elev, lowerCutOff: lowerCutOff, upperCutOff: upperCutOff)
}
}
fileprivate func linearColorScale(_ value: Double, lowerCutOff: Double, upperCutOff: Double) -> UInt8 {
return UInt8( 255 * normaliseColorScale(value, lowerCutOff: lowerCutOff, upperCutOff: upperCutOff) )
}
fileprivate func normaliseColorScale(_ value: Double, lowerCutOff: Double, upperCutOff: Double) -> Double {
switch value {
case _ where value <= lowerCutOff :
return 0.0
case _ where value >= upperCutOff :
return 1.0
default :
return (value - lowerCutOff) / (upperCutOff - lowerCutOff)
}
}