11import Foundation
2+ import Accelerate
3+
24
35struct TemperatureResult {
46 let temperatures : [ Float ]
@@ -20,57 +22,47 @@ struct HistogramPoint: Identifiable {
2022class 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