Created
June 28, 2016 16:40
-
-
Save steverichey/501661b5136d0e7d11813534468ef7cb to your computer and use it in GitHub Desktop.
Convert CSV of luminance to PNG
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// swiftlint:disable line_length | |
// swiftlint:disable variable_name | |
import Foundation | |
import Cocoa | |
struct PixelData { | |
var a: UInt8 = 255 | |
var r: UInt8 | |
var g: UInt8 | |
var b: UInt8 | |
} | |
func getContents(ofFile file: String) -> String? { | |
do { | |
return try String(contentsOfFile: file) | |
} catch { | |
return nil | |
} | |
} | |
func imageFromBitmap(pixels: [PixelData], width: Int, height: Int) -> NSImage { | |
let bitsPerComponent = 8 | |
let bitsPerPixel = 32 | |
let colorSpace = CGColorSpaceCreateDeviceRGB() | |
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue) | |
assert(pixels.count == Int(width * height)) | |
var data = pixels | |
let providerRef = CGDataProviderCreateWithCFData( | |
NSData(bytes: &data, length: data.count * sizeof(PixelData)) | |
) | |
let cgim = CGImageCreate( | |
width, height, bitsPerComponent, bitsPerPixel, | |
width * sizeof(PixelData), colorSpace, bitmapInfo, providerRef, | |
nil, true, .RenderingIntentDefault | |
) | |
return NSImage(CGImage: cgim!, size: NSSize(width: width, height: height)) | |
} | |
func sum(values: [Double]) -> Double { | |
return values.reduce(0, combine: +) | |
} | |
func sq(value: Double) -> Double { | |
return pow(value, 2) | |
} | |
func mean(values: [Double]) -> Double { | |
return sum(values) / Double(values.count) | |
} | |
func stdev(values: [Double]) -> Double { | |
let count = Double(values.count) | |
let mean = sum(values) / count | |
let meanSquare = values.map { sq($0 - mean) } | |
return sqrt(sum(meanSquare) / count) | |
} | |
func normalize(value: Double, mean: Double, stdev: Double) -> Double { | |
return (value - mean) / stdev | |
} | |
func normalize(values: [Double]) -> [Double] { | |
let m = mean(values) | |
let s = stdev(values) | |
return values.map { normalize($0, mean: m, stdev: s) } | |
} | |
func coerce(value: Double, min: Double, max: Double) -> Double { | |
return value < min ? min : value > max ? max : value | |
} | |
let formatter = NSNumberFormatter() | |
func stringToDouble(x: String) -> Double { | |
return formatter.numberFromString(x)?.doubleValue ?? -1 | |
} | |
if Process.arguments.count < 2 { | |
print("requires CSV path argument") | |
exit(1) | |
} | |
guard let csvContents = getContents(ofFile: Process.arguments[1]) else { | |
print("failed to find file") | |
exit(1) | |
} | |
let csvSplitByLine = csvContents.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) | |
let csvOneDimensionalArray = csvSplitByLine.reduce([]) { array, line in | |
array + line.componentsSeparatedByString(",").map { stringToDouble($0) } | |
} | |
let csvTwoDimensionalArray = csvSplitByLine.map { | |
$0.componentsSeparatedByString(",") | |
} | |
let targetWidth = csvTwoDimensionalArray[0].count | |
let targetHeight = csvTwoDimensionalArray.count | |
guard let max = csvOneDimensionalArray.maxElement() else { | |
print("could not determine max element in input values") | |
exit(1) | |
} | |
let csvMean = mean(csvOneDimensionalArray) | |
let csvStdDev = stdev(csvOneDimensionalArray) | |
let normalized = normalize(csvOneDimensionalArray) | |
let normMean = mean(normalized) | |
let normStdDev = stdev(normalized) | |
print("Data Statistics:\n\tMax: \(max)\n\tWidth: \(targetWidth)\n\tHeight: \(targetHeight)\n\tMean: \(csvMean)\n\tStdev: \(csvStdDev)\n\tNormalized Mean: \(normMean)\n\tNormalized Stddev: \(normStdDev)") | |
let length: Int = 200 | |
let blackPixel = PixelData(a: 255, r: 0, g: 0, b: 0) | |
var pixelData = [PixelData](count: Int(targetWidth * targetHeight), repeatedValue: blackPixel) | |
for i in 0...pixelData.count { | |
if i > csvOneDimensionalArray.count - 1 { | |
break | |
} | |
let value = csvOneDimensionalArray[i] | |
if value >= 0 { | |
let norm = normalized[i] / -1 | |
let scaled = coerce(floor(128 + norm * 128), min: 0, max: 255) | |
let color = UInt8(scaled) | |
pixelData[i] = PixelData(a: 255, r: color, g: color, b: color) | |
} | |
} | |
var image = imageFromBitmap(pixelData, width: targetWidth, height: targetHeight) | |
let tifImageRep = image.TIFFRepresentation | |
let pngImageRep = NSBitmapImageRep(data: tifImageRep!)!.representationUsingType(.NSPNGFileType, properties: [:])! | |
pngImageRep.writeToFile("test.png", atomically: true) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment