Contents

withBNNSTensor(_:)

Calls the given closure with a pointer to a BNNS tensor that shares memory with the pixel buffer.

Declaration

func withBNNSTensor<R>(_ body: (BNNSTensor) throws -> R) rethrows -> R

Parameters

  • body:

    A closure with a BNNSTensor parameter

Discussion

Use this function to pass image data to a BNNSGraph. For example, the following code creates a graph that calculates the mean value of an image and apply a threshold based on the mean.

let context = try BNNSGraph.makeContext {
   builder in

   let src = builder.argument(name: "source",
                              dataType: Float16.self,
                              shape: [<height, width, channels count>])

   let mean = src.mean(axes: [0, 1], keepDimensions: false)

   let thresholded = src .> mean

   let result = thresholded.cast(to: Float16.self)

   return [result]
}

Use withBNNSTensor() to pass source and destination pixel buffers to the context:

let source = vImage.PixelBuffer<vImage.Planar16F>(...)
let destination = vImage.PixelBuffer<vImage.Planar16F>(...)
source.withBNNSTensor { src in
    destination.withBNNSTensor { dst in

        var args = [dst, src]

        try! context.executeFunction(arguments: &args)
    }
}

On return, destination contains the thresholded image data.

Note that the tensor that this function creates has the shape height, width, channels count. If you appy a slice operation to a pixel buffer back tensor, the first dimension is the height and the second dimension is the width.

For example, given the following code:

   let sourcePixels: [Float] = [
       001, 002, 003, 004,     005, 006, 007, 008,     009, 010, 011, 012,
       013, 014, 015, 016,     017, 018, 019, 020,     021, 022, 023, 024,
       025, 026, 027, 028,     029, 030, 031, 032,     033, 034, 035, 036,
       037, 038, 039, 040,     041, 042, 043, 044,     045, 046, 047, 048,
       049, 050, 051, 052,     053, 054, 055, 056,     057, 058, 059, 060
   ]

   let source = vImage.PixelBuffer(pixelValues: sourcePixels,
                                   size: .init(width: 3, height: 5),
                                   pixelFormat: vImage.InterleavedFx4.self)

   let destination = vImage.PixelBuffer(size: .init(width: 2, height: 3),
                                        pixelFormat: vImage.InterleavedFx4.self)

   let context = try BNNSGraph.makeContext {
       builder in

       let src = builder.argument(name: "source",
                                  dataType: Float.self,
                                  shape: [ -1, -1, -1])

       let result = src[ 0...2,    // rows 0, 1, 2
                         1...2,    // cols 1, 2
                         0...3 ]   // channels 0, 1, 2, 3

       return [result]
   }

   source.withBNNSTensor { src in
       destination.withBNNSTensor { dst in

           var args = [dst, src]
           try! context.executeFunction(arguments: &args)
       }
   }

The slice selects rows 0, 1, and 2 and columns 1 and 2. On return, destination contains the following values:

       [
           005, 006, 007, 008,     009, 010, 011, 012,
           017, 018, 019, 020,     021, 022, 023, 024,
           029, 030, 031, 032,     033, 034, 035, 036,
       ]
  • Returns The return value, if any, of the body closure parameter.