0

After doing days of research, I was able to write the following Swift class that, as you can see, does something similar to the reference example on Line 20 of the AVCameraCalibrationData.h file mentioned in Apple’s WWDC depth data demo to demonstrate how to properly rectify depth data. It compiles fine, but with a deprecation warning denoted by a comment:

class Undistorter : NSObject {
    
    var result: CGPoint!
    
    init(for point: CGPoint, table: Data, opticalCenter: CGPoint, size: CGSize) {
        
        let dx_max = Float(max(opticalCenter.x, size.width - opticalCenter.x))
        let dy_max = Float(max(opticalCenter.y, size.width - opticalCenter.y))
        let max_rad = sqrt(pow(dx_max,2) - pow(dy_max, 2))
        
        let vx = Float(point.x - opticalCenter.x)
        let vy = Float(point.y - opticalCenter.y)
        
        let r = sqrt(pow(vx, 2) - pow(vy, 2))
        
        // deprecation warning: “'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R instead”
        let mag: Float = table.withUnsafeBytes({ (tableValues: UnsafePointer<Float>) in
            
            let count = table.count / MemoryLayout<Float>.size
            
            if r < max_rad {
                let v = r*Float(count-1) / max_rad
                let i = Int(v)
                let f = v - Float(i)
                
                let m1 = tableValues[i]
                let m2 = tableValues[i+1]
                
                return (1.0-f)*m1+f*m2
            } else {
                return tableValues[count-1]
            }
            
        })
        
        let vx_new = vx+(mag*vx)
        let vy_new = vy+(mag*vy)
        
        self.result = CGPoint(
            x: opticalCenter.x + CGFloat(vx_new),
            y: opticalCenter.y + CGFloat(vy_new)
        )
        
    }
}

Although this is a pretty common warning with a lot of examples in existence, I haven't found any examples of answers to the problem that fit this use case — all the examples that currently exist of people trying to get it to work involve networking contexts, and attempting to modify this code to add the fixes in those locations in end up introducing errors. For example, on attempt to use this fix:

let mag: Float = table.withUnsafeBytes { $0.load(as: Float) in // 6 errors introduced

So if there’s any way to fix this without introducing errors, I’d like to know.

Update: it actually does work; see my answer to my own question.

realkstrawn93
  • 722
  • 1
  • 6
  • 13

2 Answers2

0

Turns out it was simply a matter of adding one extra line:

let mag: Float = table.withUnsafeBytes {

    let tableValues = $0.load(as: [Float].self)

Now it compiles without incident.

Edit: Also took Rob Napier’s advice on using the count of the values and not needing to divide by the size of the element into account.

realkstrawn93
  • 722
  • 1
  • 6
  • 13
  • You're now making a copy of the data; is that ok for this use case? Sorry, for the typo: it's `baseAddress` not `basePointer`. – Rob Napier Nov 27 '21 at 00:56
-1

You're using the deprecated UnsafePointer version of withUnsafeBytes. The new version passes UnsafeBufferPointer. So instead of this:

let mag: Float = table.withUnsafeBytes({ (tableValues: UnsafePointer<Float>) in

you mean this:

let mag: Float = table.withUnsafeBytes({ (tableValues: UnsafeBufferPointer<Float>) in

Instead of:

let count = table.count / MemoryLayout<Float>.size

(which was never legal, because you cannot access table inside of table.withUnsafeBytes), you now want:

let count = tableValues.count

There's no need to divide by the size of the element.

And instead of tableValues, you'll use tableValues.baseAddress!. Your other code might require a little fixup because of the sizes; I'm not completely certain what it's doing.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • “Not completely certain what it’s doing” — that would be why Apple placed a commented out Objective-C version of exactly this [here](https://github.com/xybp888/iOS-SDKs/blob/master/iPhoneOS13.0.sdk/System/Library/Frameworks/AVFoundation.framework/Headers/AVCameraCalibrationData.h), correct? Ended up solving my own problem anyway, see above. – realkstrawn93 Nov 27 '21 at 00:47
  • 1
    I don't know what this comment means. I just wasn't clear what the `m1` and `m2` assignments are trying to do and whether that requires changing the offsets. Fixed the `basePointer` typo; it's `baseAddress`. – Rob Napier Nov 27 '21 at 00:57
  • The `m1` and `m2` assignments correspond to the `mag_1` and `mag_2` assignments in Apple’s commented-out reference implementation where they’re specifically denoted with the `// Linear interpolation` comment on Line 154 of AVCalibrationData.h. You’d know what these assignments are trying to do if you just looked there. – realkstrawn93 Nov 27 '21 at 01:34