Skip to content

Commit fdaed49

Browse files
author
Chris Greening
committed
Use vDSP
1 parent 3263729 commit fdaed49

3 files changed

Lines changed: 37 additions & 43 deletions

File tree

IrProCapture/Camera/ImageProcessor.swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Foundation
22
import CoreImage
33
import CoreImage.CIFilterBuiltins
44
import AppKit
5+
import Accelerate
56

67
extension CIImage {
78
// To be honest - not completely sure what's going on here - but trial and error has produced this code...
@@ -75,14 +76,15 @@ extension CIImage {
7576
static func fromTemperatures(temperatures: [Float], minTemp: Float, maxTemp: Float, width: Int, height: Int, scale: Float, colorMap: ColorMap) -> CIImage? {
7677
var pixelData = [UInt8](repeating: 0, count: width * height * 4)
7778
let range = max(maxTemp - minTemp, 1.0)
78-
79+
let scaledTemperatures = vDSP.multiply(255.0 / range, vDSP.add(-minTemp, temperatures))
80+
var dstIndex = 0
7981
for index in 0..<width*height {
80-
let temp = temperatures[index]
81-
let scaled = UInt8(255.0 * (temp - minTemp) / range)
82-
pixelData[index * 4] = scaled
83-
pixelData[index * 4 + 1] = scaled
84-
pixelData[index * 4 + 2] = scaled
85-
pixelData[index * 4 + 3] = 255
82+
let temp = UInt8(scaledTemperatures[index])
83+
pixelData[dstIndex] = temp
84+
pixelData[dstIndex + 1] = temp
85+
pixelData[dstIndex + 2] = temp
86+
pixelData[dstIndex + 3] = 255
87+
dstIndex += 4
8688
}
8789
let bytesPerRow = width * 4
8890
let colorSpace = CGColorSpaceCreateDeviceRGB()

IrProCapture/Camera/TemperatureProcessor.swift

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import Foundation
2+
import Accelerate
3+
24

35
struct TemperatureResult {
46
let temperatures: [Float]
@@ -20,57 +22,47 @@ struct HistogramPoint: Identifiable {
2022
class TemperatureProcessor {
2123
private let width: Int = 256
2224
private let height: Int = 192
23-
24-
@inline(__always)
25-
func convertTemp<T: BinaryInteger>(raw: T) -> Float {
26-
return Float(raw) / 64.0 - 273.2
27-
}
28-
29-
func computeHistogram(values: [Float], min: Float, max: Float, bins: Int) -> [HistogramPoint] {
30-
var histogram = [Int](repeating: 0, count: bins)
3125

32-
// Ensure values are within the specified range
26+
func computeHistogram(values: [Float], min: Float, max: Float, bins: Int) -> [HistogramPoint] {
3327
let range = max - min
34-
let binWidth = range / Float(bins)
28+
let binWidth = range / Float(bins - 1)
3529
if (binWidth == 0) {
3630
return []
3731
}
38-
39-
// Iterate through each value
40-
for value in values {
41-
// Skip values that are outside the given range
42-
if value < min || value > max {
43-
continue
44-
}
45-
46-
// Find the appropriate bin for the value
47-
let binIndex = Int((value - min) / binWidth)
48-
49-
// Make sure binIndex is within bounds
50-
if binIndex >= 0 && binIndex < bins {
51-
histogram[binIndex] += 1
52-
}
53-
}
54-
32+
// work out which bin each value falls in
33+
let binIndexes = vDSP.multiply(1/binWidth, vDSP.add(-min, values))
34+
// accumulate the histogram
35+
var histogram = [Int](repeating: 0, count: bins)
36+
binIndexes.forEach { histogram[Int($0)] += 1 }
37+
// results for charting
5538
return histogram.enumerated().map { (index, element) in
5639
HistogramPoint(x: Float(index) * binWidth + min, y: element)
5740
}
5841
}
5942

60-
func getTemperatures(from buffer: UnsafePointer<UInt16>, bytesPerRow: Int, startingAtRow: Int = 192) -> TemperatureResult {
61-
var temperatures = [Float](repeating: 0, count: width * height)
62-
var dstIndex = 0
43+
func getTemperatures(from buffer: UnsafeMutablePointer<UInt16>, bytesPerRow: Int, startingAtRow: Int = 192) -> TemperatureResult {
6344

64-
// Process the temperature data
45+
// Step 1 - get the bytes into the right order
46+
var swappedValues = [UInt16](repeating: 0, count: width * height)
47+
var dstIndex = 0
6548
for row in startingAtRow..<(startingAtRow + height) {
66-
for column in 0..<width {
67-
let index = row * bytesPerRow / MemoryLayout<UInt16>.size + column
68-
let value = buffer[index].byteSwapped
69-
temperatures[dstIndex] = convertTemp(raw: value)
49+
var srcIndex = row * bytesPerRow / MemoryLayout<UInt16>.size
50+
for _ in 0..<width {
51+
let value = buffer[srcIndex].byteSwapped
52+
swappedValues[dstIndex] = value
7053
dstIndex += 1
54+
srcIndex += 1
7155
}
7256
}
73-
57+
// Step 2: Convert UInt16 to Float
58+
var temperatures = [Float](repeating: 0, count: width * height)
59+
vDSP_vfltu16(swappedValues, 1, &temperatures, 1, vDSP_Length(width*height))
60+
61+
// Step 3: Apply conversion: `(raw / 64.0) - 273.2`
62+
let scale: Float = 1.0 / 64.0
63+
let offset: Float = -273.2
64+
temperatures = vDSP.add(offset, vDSP.multiply(scale, temperatures))
65+
7466
// Calculate statistics
7567
let minValue = temperatures.min() ?? 0.0
7668
let maxElement = temperatures.enumerated().max(by: { $0.element < $1.element })

0 commit comments

Comments
 (0)