mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
@inline(__always) does not imply inlinable, which means that it effectively does nothing in the context of the Accelerate overlay. I have replaced all of these with @inlinable where that can be done as a one-line change. Functions that switch over open enums and more complex API (DCT, DFT, FFT) will require more sophisticated corrections, which we can undertake in later commits. For now, they have been rolled back to simply being normal public API.
750 lines
31 KiB
Swift
750 lines
31 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension vDSP {
|
|
|
|
// MARK: One-dimensional convolution
|
|
|
|
/// Returns one-dimensional convolution, single-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter kernel: Single-precision convolution kernel.
|
|
/// - Returns: Convolution result.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U>(_ vector: T,
|
|
withKernel kernel: U) -> [Float]
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
T.Element == Float, U.Element == Float {
|
|
|
|
let n = vector.count - kernel.count
|
|
|
|
let result = Array<Float>(unsafeUninitializedCapacity: n) {
|
|
buffer, initializedCount in
|
|
|
|
convolve(vector,
|
|
withKernel: kernel,
|
|
result: &buffer)
|
|
|
|
initializedCount = n
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// One-dimensional convolution, single-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter kernel: Single-precision convolution kernel.
|
|
/// - Parameter result: Destination vector.
|
|
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U, V>(_ vector: T,
|
|
withKernel kernel: U,
|
|
result: inout V)
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
T.Element == Float, U.Element == Float, V.Element == Float {
|
|
|
|
let n = result.count
|
|
precondition(vector.count >= n + kernel.count - 1,
|
|
"Source vector count must be at least the sum of the result and kernel counts, minus one.")
|
|
|
|
result.withUnsafeMutableBufferPointer { dest in
|
|
vector.withUnsafeBufferPointer { src in
|
|
kernel.withUnsafeBufferPointer { k in
|
|
vDSP_conv(src.baseAddress!, 1,
|
|
k.baseAddress!.advanced(by: kernel.count - 1), -1,
|
|
dest.baseAddress!, 1,
|
|
vDSP_Length(n),
|
|
vDSP_Length(kernel.count))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns one-dimensional convolution, double-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter kernel: Double-precision convolution kernel.
|
|
/// - Returns: Convolution result.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U>(_ vector: T,
|
|
withKernel kernel: U) -> [Double]
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
T.Element == Double, U.Element == Double {
|
|
|
|
let n = vector.count - kernel.count
|
|
|
|
let result = Array<Double>(unsafeUninitializedCapacity: n) {
|
|
buffer, initializedCount in
|
|
|
|
convolve(vector,
|
|
withKernel: kernel,
|
|
result: &buffer)
|
|
|
|
initializedCount = n
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// One-dimensional convolution, double-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter kernel: Double-precision convolution kernel.
|
|
/// - Parameter result: Destination vector.
|
|
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U, V>(_ vector: T,
|
|
withKernel kernel: U,
|
|
result: inout V)
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
T.Element == Double, U.Element == Double, V.Element == Double {
|
|
|
|
let n = result.count
|
|
precondition(vector.count >= n + kernel.count - 1,
|
|
"Source vector count must be at least the sum of the result and kernel counts, minus one.")
|
|
|
|
result.withUnsafeMutableBufferPointer { dest in
|
|
vector.withUnsafeBufferPointer { src in
|
|
kernel.withUnsafeBufferPointer { k in
|
|
vDSP_convD(src.baseAddress!, 1,
|
|
k.baseAddress!.advanced(by: kernel.count - 1), -1,
|
|
dest.baseAddress!, 1,
|
|
vDSP_Length(n),
|
|
vDSP_Length(kernel.count))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: One-dimensional correlation
|
|
|
|
/// Returns one-dimensional correlation, single-precision.
|
|
///
|
|
/// - Parameter vector: The vector to correlate.
|
|
/// - Parameter kernel: Single-precision convolution kernel.
|
|
/// - Returns: Correlation result.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func correlate<T, U>(_ vector: T,
|
|
withKernel kernel: U) -> [Float]
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
T.Element == Float, U.Element == Float {
|
|
|
|
let n = vector.count - kernel.count
|
|
|
|
let result = Array<Float>(unsafeUninitializedCapacity: n) {
|
|
buffer, initializedCount in
|
|
|
|
correlate(vector,
|
|
withKernel: kernel,
|
|
result: &buffer)
|
|
|
|
initializedCount = n
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// One-dimensional correlation, single-precision.
|
|
///
|
|
/// - Parameter vector: The vector to correlate.
|
|
/// - Parameter kernel: Single-precision convolution kernel.
|
|
/// - Parameter result: Destination vector.
|
|
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func correlate<T, U, V>(_ vector: T,
|
|
withKernel kernel: U,
|
|
result: inout V)
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
T.Element == Float, U.Element == Float, V.Element == Float {
|
|
|
|
let n = result.count
|
|
precondition(vector.count >= n + kernel.count - 1,
|
|
"Source vector count must be at least the sum of the result and kernel counts, minus one.")
|
|
|
|
result.withUnsafeMutableBufferPointer { dest in
|
|
vector.withUnsafeBufferPointer { src in
|
|
kernel.withUnsafeBufferPointer { k in
|
|
vDSP_conv(src.baseAddress!, 1,
|
|
k.baseAddress!, 1,
|
|
dest.baseAddress!, 1,
|
|
vDSP_Length(n),
|
|
vDSP_Length(kernel.count))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns one-dimensional correlation, double-precision.
|
|
///
|
|
/// - Parameter vector: The vector to correlate.
|
|
/// - Parameter kernel: Single-precision convolution kernel.
|
|
/// - Returns: Correlation result.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func correlate<T, U>(_ vector: T,
|
|
withKernel kernel: U) -> [Double]
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
T.Element == Double, U.Element == Double {
|
|
|
|
let n = vector.count - kernel.count
|
|
|
|
let result = Array<Double>(unsafeUninitializedCapacity: n) {
|
|
buffer, initializedCount in
|
|
|
|
correlate(vector,
|
|
withKernel: kernel,
|
|
result: &buffer)
|
|
|
|
initializedCount = n
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// One-dimensional correlation, double-precision.
|
|
///
|
|
/// - Parameter vector: The vector to correlate.
|
|
/// - Parameter kernel: Single-precision convolution kernel.
|
|
/// - Parameter result: Destination vector.
|
|
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func correlate<T, U, V>(_ vector: T,
|
|
withKernel kernel: U,
|
|
result: inout V)
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
T.Element == Double, U.Element == Double, V.Element == Double {
|
|
|
|
let n = result.count
|
|
precondition(vector.count >= n + kernel.count - 1,
|
|
"Source vector count must be at least the sum of the result and kernel counts, minus one.")
|
|
|
|
result.withUnsafeMutableBufferPointer { dest in
|
|
vector.withUnsafeBufferPointer { src in
|
|
kernel.withUnsafeBufferPointer { k in
|
|
vDSP_convD(src.baseAddress!, 1,
|
|
k.baseAddress!, 1,
|
|
dest.baseAddress!, 1,
|
|
vDSP_Length(n),
|
|
vDSP_Length(kernel.count))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
extension vDSP {
|
|
|
|
// MARK: Two-dimensional convolution
|
|
|
|
/// Returns two-dimensional convolution with a 3 x 3 kernel; single-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Single-precision 3x3 convolution kernel.
|
|
/// - Returns: Convolution result.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
with3x3Kernel kernel: U) -> [Float]
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
T.Element == Float, U.Element == Float {
|
|
|
|
let result = Array<Float>(unsafeUninitializedCapacity: vector.count) {
|
|
buffer, initializedCount in
|
|
|
|
convolve(vector,
|
|
rowCount: rowCount, columnCount: columnCount,
|
|
with3x3Kernel: kernel,
|
|
result: &buffer)
|
|
|
|
initializedCount = vector.count
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// Two-dimensional convolution with a 3 x 3 kernel; single-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Single-precision 3x3 convolution kernel.
|
|
/// - Parameter result: Destination vector.
|
|
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U, V>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
with3x3Kernel kernel: U,
|
|
result: inout V)
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
T.Element == Float, U.Element == Float, V.Element == Float {
|
|
|
|
precondition(rowCount >= 3,
|
|
"Row count must be greater than or equal to 3.")
|
|
|
|
precondition(columnCount >= 4,
|
|
"Column count must be even and greater than or equal to 4")
|
|
|
|
precondition(rowCount * columnCount == vector.count,
|
|
"Row count `x` column count must equal source vector count.")
|
|
|
|
precondition(kernel.count == 9,
|
|
"Kernel must contain 9 elements.")
|
|
|
|
result.withUnsafeMutableBufferPointer { dest in
|
|
vector.withUnsafeBufferPointer { src in
|
|
kernel.withUnsafeBufferPointer { k in
|
|
vDSP_f3x3(src.baseAddress!,
|
|
vDSP_Length(rowCount), vDSP_Length(columnCount),
|
|
k.baseAddress!,
|
|
dest.baseAddress!)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns two-dimensional convolution with a 3 x 3 kernel; double-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Double-precision 3x3 convolution kernel.
|
|
/// - Returns: Convolution result.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
with3x3Kernel kernel: U) -> [Double]
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
T.Element == Double, U.Element == Double {
|
|
|
|
let result = Array<Double>(unsafeUninitializedCapacity: vector.count) {
|
|
buffer, initializedCount in
|
|
|
|
convolve(vector,
|
|
rowCount: rowCount, columnCount: columnCount,
|
|
with3x3Kernel: kernel,
|
|
result: &buffer)
|
|
|
|
initializedCount = vector.count
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// Two-dimensional convolution with a 3 x 3 kernel; double-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Double-precision 3x3 convolution kernel.
|
|
/// - Parameter result: Destination vector.
|
|
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U, V>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
with3x3Kernel kernel: U,
|
|
result: inout V)
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
T.Element == Double, U.Element == Double, V.Element == Double {
|
|
|
|
precondition(rowCount >= 3,
|
|
"Row count must be greater than or equal to 3.")
|
|
|
|
precondition(columnCount >= 4,
|
|
"Column count must be even and greater than or equal to 4")
|
|
|
|
precondition(rowCount * columnCount == vector.count,
|
|
"Row count `x` column count must equal source vector count.")
|
|
|
|
precondition(kernel.count == 9,
|
|
"Kernel must contain 9 elements.")
|
|
|
|
result.withUnsafeMutableBufferPointer { dest in
|
|
vector.withUnsafeBufferPointer { src in
|
|
kernel.withUnsafeBufferPointer { k in
|
|
vDSP_f3x3D(src.baseAddress!,
|
|
vDSP_Length(rowCount), vDSP_Length(columnCount),
|
|
k.baseAddress!,
|
|
dest.baseAddress!)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns two-dimensional convolution with a 5 x 5 kernel; single-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Single-precision 5x5 convolution kernel.
|
|
/// - Returns: Convolution result.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
with5x5Kernel kernel: U) -> [Float]
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
T.Element == Float, U.Element == Float {
|
|
|
|
let result = Array<Float>(unsafeUninitializedCapacity: vector.count) {
|
|
buffer, initializedCount in
|
|
|
|
convolve(vector,
|
|
rowCount: rowCount, columnCount: columnCount,
|
|
with5x5Kernel: kernel,
|
|
result: &buffer)
|
|
|
|
initializedCount = vector.count
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// Two-dimensional convolution with a 5 x 5 kernel; single-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Single-precision 5x5 convolution kernel.
|
|
/// - Parameter result: Destination vector.
|
|
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U, V>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
with5x5Kernel kernel: U,
|
|
result: inout V)
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
T.Element == Float, U.Element == Float, V.Element == Float {
|
|
|
|
precondition(rowCount >= 3,
|
|
"Row count must be greater than or equal to 3.")
|
|
|
|
precondition(columnCount >= 4,
|
|
"Column count must be even and greater than or equal to 4")
|
|
|
|
precondition(rowCount * columnCount == vector.count,
|
|
"Row count `x` column count must equal source vector count.")
|
|
|
|
precondition(kernel.count == 25,
|
|
"Kernel must contain 25 elements.")
|
|
|
|
result.withUnsafeMutableBufferPointer { dest in
|
|
vector.withUnsafeBufferPointer { src in
|
|
kernel.withUnsafeBufferPointer { k in
|
|
vDSP_f5x5(src.baseAddress!,
|
|
vDSP_Length(rowCount), vDSP_Length(columnCount),
|
|
k.baseAddress!,
|
|
dest.baseAddress!)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns two-dimensional convolution with a 5 x 5 kernel; double-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Double-precision 3x3 convolution kernel.
|
|
/// - Returns: Convolution result.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
with5x5Kernel kernel: U) -> [Double]
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
T.Element == Double, U.Element == Double {
|
|
|
|
let result = Array<Double>(unsafeUninitializedCapacity: vector.count) {
|
|
buffer, initializedCount in
|
|
|
|
convolve(vector,
|
|
rowCount: rowCount, columnCount: columnCount,
|
|
with5x5Kernel: kernel,
|
|
result: &buffer)
|
|
|
|
initializedCount = vector.count
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// Two-dimensional convolution with a 5 x 5 kernel; double-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Double-precision 5x5 convolution kernel.
|
|
/// - Parameter result: Destination vector.
|
|
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U, V>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
with5x5Kernel kernel: U,
|
|
result: inout V)
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
T.Element == Double, U.Element == Double, V.Element == Double {
|
|
|
|
precondition(rowCount >= 3,
|
|
"Row count must be greater than or equal to 3.")
|
|
|
|
precondition(columnCount >= 4,
|
|
"Column count must be even and greater than or equal to 4")
|
|
|
|
precondition(rowCount * columnCount == vector.count,
|
|
"Row count `x` column count must equal source vector count.")
|
|
|
|
precondition(kernel.count == 25,
|
|
"Kernel must contain 25 elements.")
|
|
|
|
result.withUnsafeMutableBufferPointer { dest in
|
|
vector.withUnsafeBufferPointer { src in
|
|
kernel.withUnsafeBufferPointer { k in
|
|
vDSP_f5x5D(src.baseAddress!,
|
|
vDSP_Length(rowCount), vDSP_Length(columnCount),
|
|
k.baseAddress!,
|
|
dest.baseAddress!)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns two-dimensional convolution with arbitrarily sized kernel; single-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Single-precision convolution kernel.
|
|
/// - Parameter kernelRowCount: The number of rows in the kernel.
|
|
/// - Parameter kernelColumnCount: The number of columns in the kernel.
|
|
/// - Returns: Convolution result.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
withKernel kernel: U,
|
|
kernelRowCount: Int, kernelColumnCount: Int) -> [Float]
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
T.Element == Float, U.Element == Float {
|
|
|
|
let result = Array<Float>(unsafeUninitializedCapacity: vector.count) {
|
|
buffer, initializedCount in
|
|
|
|
convolve(vector,
|
|
rowCount: rowCount, columnCount: columnCount,
|
|
withKernel: kernel,
|
|
kernelRowCount: kernelRowCount, kernelColumnCount: kernelColumnCount,
|
|
result: &buffer)
|
|
|
|
initializedCount = vector.count
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// Two-dimensional convolution with arbitrarily sized kernel; single-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Single-precision convolution kernel.
|
|
/// - Parameter kernelRowCount: The number of rows in the kernel.
|
|
/// - Parameter kernelColumnCount: The number of columns in the kernel.
|
|
/// - Parameter result: Destination vector.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U, V>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
withKernel kernel: U,
|
|
kernelRowCount: Int, kernelColumnCount: Int,
|
|
result: inout V)
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
T.Element == Float, U.Element == Float, V.Element == Float {
|
|
|
|
precondition(rowCount >= 3,
|
|
"Row count must be greater than or equal to 3.")
|
|
|
|
precondition(columnCount >= 4,
|
|
"Column count must be even and greater than or equal to 4")
|
|
|
|
precondition(rowCount * columnCount == vector.count,
|
|
"Row count `x` column count must equal source vector count.")
|
|
|
|
precondition(kernelRowCount % 2 == 1,
|
|
"Kernel row count must be odd.")
|
|
|
|
precondition(kernelColumnCount % 2 == 1,
|
|
"Kernel column count must be odd.")
|
|
|
|
result.withUnsafeMutableBufferPointer { dest in
|
|
vector.withUnsafeBufferPointer { src in
|
|
kernel.withUnsafeBufferPointer { k in
|
|
vDSP_imgfir(src.baseAddress!,
|
|
vDSP_Length(rowCount), vDSP_Length(columnCount),
|
|
k.baseAddress!,
|
|
dest.baseAddress!,
|
|
vDSP_Length(kernelRowCount), vDSP_Length(kernelColumnCount))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns two-dimensional convolution with arbitrarily sized kernel; double-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Single-precision convolution kernel.
|
|
/// - Parameter kernelRowCount: The number of rows in the kernel.
|
|
/// - Parameter kernelColumnCount: The number of columns in the kernel.
|
|
/// - Returns: Convolution result.
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
withKernel kernel: U,
|
|
kernelRowCount: Int, kernelColumnCount: Int) -> [Double]
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
T.Element == Double, U.Element == Double {
|
|
|
|
let result = Array<Double>(unsafeUninitializedCapacity: vector.count) {
|
|
buffer, initializedCount in
|
|
|
|
convolve(vector,
|
|
rowCount: rowCount, columnCount: columnCount,
|
|
withKernel: kernel,
|
|
kernelRowCount: kernelRowCount, kernelColumnCount: kernelColumnCount,
|
|
result: &buffer)
|
|
|
|
initializedCount = vector.count
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/// Two-dimensional convolution with arbitrarily sized kernel; double-precision.
|
|
///
|
|
/// - Parameter vector: The vector to convolve.
|
|
/// - Parameter rowCount: The number of rows in the input vector.
|
|
/// - Parameter columnCount: The number of columns in the input vector.
|
|
/// - Parameter kernel: Double-precision convolution kernel.
|
|
/// - Parameter kernelRowCount: The number of rows in the kernel.
|
|
/// - Parameter kernelColumnCount: The number of columns in the kernel.
|
|
/// - Parameter result: Destination vector.
|
|
|
|
@inlinable
|
|
@available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *)
|
|
public static func convolve<T, U, V>(_ vector: T,
|
|
rowCount: Int, columnCount: Int,
|
|
withKernel kernel: U,
|
|
kernelRowCount: Int, kernelColumnCount: Int,
|
|
result: inout V)
|
|
where
|
|
T: AccelerateBuffer,
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
T.Element == Double, U.Element == Double, V.Element == Double {
|
|
|
|
precondition(rowCount >= 3,
|
|
"Row count must be greater than or equal to 3.")
|
|
|
|
precondition(columnCount >= 4,
|
|
"Column count must be even and greater than or equal to 4")
|
|
|
|
precondition(rowCount * columnCount == vector.count,
|
|
"Row count `x` column count must equal source vector count.")
|
|
|
|
precondition(kernelRowCount % 2 == 1,
|
|
"Kernel row count must be odd.")
|
|
|
|
precondition(kernelColumnCount % 2 == 1,
|
|
"Kernel column count must be odd.")
|
|
|
|
result.withUnsafeMutableBufferPointer { dest in
|
|
vector.withUnsafeBufferPointer { src in
|
|
kernel.withUnsafeBufferPointer { k in
|
|
vDSP_imgfirD(src.baseAddress!,
|
|
vDSP_Length(rowCount), vDSP_Length(columnCount),
|
|
k.baseAddress!,
|
|
dest.baseAddress!,
|
|
vDSP_Length(kernelRowCount), vDSP_Length(kernelColumnCount))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|