6

I'm trying to work with Brad Larson's splendid GPUImage framework, and I'm struggling to process the cornerArray returned by the GPUImageHarrisCornerDetectionFilter.

The corners are returned as an array of GLFloat in an UnsafeMutablePointer - and I would like to convert that to an array of CGPoint

I've tried allocating space for the memory

var cornerPointer = UnsafeMutablePointer<GLfloat>.alloc(Int(cornersDetected) * 2)

but the data doesn't seem to make any sense - either zero or 1E-32

I found what looked like the perfect answer how to loop through elements of array of <UnsafeMutablePointer> in Swift and tried

filter.cornersDetectedBlock = {(cornerArray:UnsafeMutablePointer<GLfloat>, cornersDetected:UInt, frameTime:CMTime) in
        crosshairGenerator.renderCrosshairsFromArray(cornerArray, count:cornersDetected, frameTime:frameTime)

    for floatData in UnsafeBufferPointer(start: cornerArray, count: cornersDetected)
    {
        println("\(floatData)")
    }

but the compiler didn't like the UnsafeBufferPointer - so I changed it to UnsafeMutablePointer, but it didn't like the argument list.

I'm sure this is nice and simple, and it sounds like something other people must have had to do - so what's the solution?

Community
  • 1
  • 1
Russell
  • 5,436
  • 2
  • 19
  • 27

3 Answers3

6

The UnsafeMutablePointer<GLfloat> type translated from C can have its elements accessed via a subscript, just like a normal array. To achieve your goal of converting these to CGPoints, I'd use the following code:

filter.cornersDetectedBlock = { (cornerArray:UnsafeMutablePointer<GLfloat>, cornersDetected:UInt, frameTime:CMTime) in
    var points = [CGPoint]()
    for index in 0..<Int(cornersDetected) {
       points.append(CGPoint(x:CGFloat(cornerArray[index * 2]), y:CGFloat(cornerArray[(index * 2) + 1])))
    }
    // Do something with these points
}

The memory backing cornerArray is allocated immediately before the callback is triggered, and deallocated immediately after it. Unless you copy these values over in the middle of the block, as I do above, I'm afraid that you'll leave yourself open to some nasty bugs. It's also easier to convert to the correct format at that point, anyway.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
3

I have found a solution - and it's simple. The answer was here https://gist.github.com/kirsteins/6d6e96380db677169831

var dataArray = Array(UnsafeBufferPointer(start: cornerArray, count: Int(cornersDetected) * 2))
Russell
  • 5,436
  • 2
  • 19
  • 27
  • 1
    I'm not entirely sure this is safe in this case. The backing memory for `cornerArray` is manually allocated right before this block is called, and manually freed immediately after. I believe that if you do this, you'll encounter memory corruption bugs. I've provided an answer that shows how to safely copy these values over into the format you want. – Brad Larson Feb 10 '16 at 20:19
  • 2
    This is the fastest method and is safe, according to Apple’s documentation: “However, initializing another collection with an UnsafeBufferPointer instance copies the instances out of the referenced memory and into the new collection” – Wil Shipley Sep 02 '17 at 03:31
-1

Try this :

     var cornerPointer = UnsafeMutablePointer<GLfloat>.alloc(Int(cornersDetected) * 2)

    filter.cornersDetectedBlock = {(cornerArray:UnsafeMutablePointer<GLfloat>, cornersDetected:UInt, frameTime:CMTime) in
        crosshairGenerator.renderCrosshairsFromArray(cornerArray, count:cornersDetected, frameTime:frameTime)

    for i in 0...cornersDetected
    {
        print("\(cornerPointer[i])")
    }
Aruna Mudnoor
  • 4,795
  • 14
  • 16
  • I'm not sure I understand this. cornersDetected is only defined within the closure, so you can't use it before the cornersDetectedBlock. Other than the incorrect ordering of the code, I don't see anything different from what I already have – Russell Feb 10 '16 at 17:36