Contents

vImagePiecewisePolynomial_Planar8toPlanarF(_:_:_:_:_:_:_:)

Applies a set of piecewise polynomials to transform an 8-bit planar image to a 32-bit planar image.

Declaration

func vImagePiecewisePolynomial_Planar8toPlanarF(_ src: UnsafePointer<vImage_Buffer>, _ dest: UnsafePointer<vImage_Buffer>, _ coefficients: UnsafeMutablePointer<UnsafePointer<Float>?>, _ boundaries: UnsafePointer<Float>, _ order: UInt32, _ log2segments: UInt32, _ flags: vImage_Flags) -> vImage_Error

Parameters

  • src:

    The source vImage buffer.

  • dest:

    A pointer to the destination vImage buffer structure. You’re responsible for filling out the height, width, and rowBytes fields of this structure, and for allocating a data buffer of the appropriate size. On return, the data buffer this structure points to contains the destination image data. When you no longer need the data buffer, deallocate the memory to prevent memory leaks.

  • coefficients:

    A pointer to an array of polynomial coefficient arrays. Each polynomial coefficient array contains the coefficients for one polynomial. A polynomial of order R has R+1 coefficients, and all of the polynomials in this array must have the same order.

    Order the coefficients from the zeroth-order term to the highest order term. For example, the function evaluates the coefficients [0.5, 0.6, 0.7] as 0.5 * x⁰ + 0.6 * x¹ + 0.7 * x².

  • boundaries:

    A pointer to an array of boundary values, in increasing order, that separates adjacent ranges of pixel values. The first boundary value is the lowest in the range and the function clips input values lower than this to this value. The last boundary value is the highest in the range and the function clips input values higher than this to this value. The boundary values between the first and last separate the subranges from each other.

  • order:

    The order of the polynomials.

  • log2segments:

    The number of polynomials to represent as a base-2 logarithm. If you pass a noninteger power-of-two number of polynomials, round up to the next integer power of two, and repeat the last polynomial the appropriate number of times.

  • flags:

    The options to use when performing the operation. If your code implements its own tiling or its own multithreading, pass Kvimagedonottile; otherwise, pass Kvimagenoflags.

Return Value

kvImageNoError; otherwise, one of the error codes in Data Types and Constants.

Discussion

You can approximate many different correction functions by carefully choosing the polynomials and the ranges of input values they operate on. For example, the sample code project Applying tone curve adjustments to images demonstrates how to apply tone curve adjustments to images using polynomial transforms.

The following code defines two sets of polynomial coefficients, coefficients0 as [0.0, 0.5, 0.0] and coefficients1 as [0.0, 0.0, 1.0]. The boundaries array, [0, 0.5, 1], specifies that the vImagePiecewisePolynomial_Planar8toPlanarF(_:_:_:_:_:_:_:) function applies coefficients0 to source pixels less than 0.5, and applies coefficients1 to other pixels.

Note that the boundaries array contains three elements that define two ranges: 0..<0.5 and 0.5...1. The order value equals the number of coefficients in each segment minus one.

let source = vImage.PixelBuffer<vImage.Planar8>(
    pixelValues: [0, 0.2, 0.4, 0.6, 0.8, 1].map { Pixel_8($0 * 255) },
    size: vImage.Size(width: 6, height: 1))

let destination = vImage.PixelBuffer<vImage.PlanarF>(
    size: source.size)

let coefficients0: [Float] = [0.0, 0.5, 0.0] // 0.0 * x⁰ + 0.5 * x¹ + 0.0 * x²
let coefficients1: [Float] = [0.0, 0.0, 1.0] // 0.0 * x⁰ + 0.0 * x¹ + 1.0 * x²

let boundaries: [Float] = [0, 0.5, 1]

let order = UInt32(2)

let log2segments = UInt32(1)

coefficients0.withUnsafeBufferPointer { coefficients0Ptr in
    coefficients1.withUnsafeBufferPointer { coefficients1Ptr in
        source.withUnsafePointerToVImageBuffer { src in
            destination.withUnsafePointerToVImageBuffer { dest in
                
                var coeffs = [ coefficients0Ptr.baseAddress,
                               coefficients1Ptr.baseAddress ]
                
                vImagePiecewisePolynomial_Planar8toPlanarF(
                    src,
                    dest,
                    &coeffs,
                    boundaries,
                    order,
                    log2segments,
                    vImage_Flags(kvImageNoFlags))
            }
        }
    }
}

On return, the destination buffer contains the values [0.0, 0.1, 0.2, 0.36, 0.64, 1.0]. This is equivalent to the following scalar code:

let result = source.array.map {
    let x = Float($0) / 255
    let coefficients = x < 0.5 ? coefficients0 : coefficients1
    return coefficients[0] * pow(x, 0) +
           coefficients[1] * pow(x, 1) +
           coefficients[2] * pow(x, 2)
}

For best performance, choose a single higher-order polynomial over many lower-order polynomials. However, this function uses single-precision arithmetic, and large high-order coefficients may cause rounding errors.

See Also

Applying a polynomial