Skip to content

Instantly share code, notes, and snippets.

@steverichey
Created June 28, 2016 16:40
Show Gist options
  • Save steverichey/501661b5136d0e7d11813534468ef7cb to your computer and use it in GitHub Desktop.
Save steverichey/501661b5136d0e7d11813534468ef7cb to your computer and use it in GitHub Desktop.
Convert CSV of luminance to PNG
// 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