「这是我参与2022初次更文应战的第3天,活动详情查看:2022初次更文应战」
本文正在参与「金石计划 . 分割6万现金大奖」
本案例的目的是理解如何用Metal完成3×3卷积矩阵作用滤镜,取像素点周边九个区域半径点像素rgb值进行矩阵运算获取新的rgb值;
现在有如下几款卷积核供运用,
- default:空卷积核
- identity:原始卷积核
- edgedetect:边际检测卷积核
- embossment:浮雕滤波器卷积核
- embossment45:45度的浮雕滤波器卷积核
- morphological:腐蚀卷积核
- laplance:拉普拉斯算子,边际检测算子
- sharpen:锐化卷积核
- sobel:边际提取卷积核,求梯度比较常用
Demo
- HarbethDemo地址
实操代码
// 锐化卷积作用滤镜
let filter = C7ConvolutionMatrix3x3(convolutionType: .sharpen(iterations: 2))
// 计划1:
let dest = BoxxIO.init(element: originImage, filter: filter)
ImageView.image = try? dest.output()
dest.filters.forEach {
NSLog("%@", "\($0.parameterDescription)")
}
// 计划2:
ImageView.image = try? originImage.make(filter: filter)
// 计划3:
ImageView.image = originImage ->> filter
完成原理
- 过滤器
这款滤镜选用并行计算编码器规划.compute(kernel: "C7ConvolutionMatrix3x3")
,参数因子[Float(convolutionPixel)]
对外开放参数
-
convolutionPixel
: 卷积像素
/// 3 x 3卷积
public struct C7ConvolutionMatrix3x3: C7FilterProtocol {
public enum ConvolutionType {
case `default`
case identity
case edgedetect
case embossment
case embossment45
case morphological
case sobel(orientation: Bool)
case laplance(iterations: Float)
case sharpen(iterations: Float)
case custom(Matrix3x3)
}
/// Convolution pixels, default 1
public var convolutionPixel: Int = 1
private var matrix: Matrix3x3
public var modifier: Modifier {
return .compute(kernel: "C7ConvolutionMatrix3x3")
}
public var factors: [Float] {
return [Float(convolutionPixel)]
}
public func setupSpecialFactors(for encoder: MTLCommandEncoder, index: Int) {
guard let computeEncoder = encoder as? MTLComputeCommandEncoder else { return }
var factor = matrix.to_factor()
computeEncoder.setBytes(&factor, length: Matrix3x3.size, index: index + 1)
}
public init(matrix: Matrix3x3) {
self.matrix = matrix
}
public init(convolutionType: ConvolutionType) {
self.init(matrix: convolutionType.matrix)
}
public mutating func updateConvolutionType(_ convolutionType: ConvolutionType) {
self.matrix = convolutionType.matrix
}
public mutating func updateMatrix3x3(_ matrix: Matrix3x3) {
self.matrix = matrix
}
}
extension C7ConvolutionMatrix3x3.ConvolutionType {
var matrix: Matrix3x3 {
switch self {
case .identity:
return Matrix3x3.Kernel.identity
case .edgedetect:
return Matrix3x3.Kernel.edgedetect
case .embossment:
return Matrix3x3.Kernel.embossment
case .embossment45:
return Matrix3x3.Kernel.embossment45
case .morphological:
return Matrix3x3.Kernel.morphological
case .sobel(let orientation):
return Matrix3x3.Kernel.sobel(orientation)
case .laplance(let iterations):
return Matrix3x3.Kernel.laplance(iterations)
case .sharpen(let iterations):
return Matrix3x3.Kernel.sharpen(iterations)
case .custom(let matrix3x3):
return matrix3x3
default:
return Matrix3x3.Kernel.`default`
}
}
}
- 着色器
取像素点周边九个区域半径点像素,然后归一化处理,然后取出每个像素对应rgb,再进行卷积矩阵运算得到卷积之后的rgb值,生成新的像素色彩;
kernel void C7ConvolutionMatrix3x3(texture2d<half, access::write> outputTexture [[texture(0)]],
texture2d<half, access::sample> inputTexture [[texture(1)]],
constant float *pixel [[buffer(0)]],
constant float3x3 *matrix3x3 [[buffer(1)]],
uint2 grid [[thread_position_in_grid]]) {
constexpr sampler quadSampler(mag_filter::linear, min_filter::linear);
const float x = float(grid.x);
const float y = float(grid.y);
const float w = float(inputTexture.get_width());
const float h = float(inputTexture.get_height());
const float l = float(x - *pixel);
const float r = float(x + *pixel);
const float t = float(y - *pixel);
const float b = float(y + *pixel);
// Normalization
const float2 m11Coordinate = float2(l / w, t / h);
const float2 m12Coordinate = float2(x / w, t / h);
const float2 m13Coordinate = float2(r / w, t / h);
const float2 m21Coordinate = float2(l / w, y / h);
const float2 m22Coordinate = float2(x / w, y / h);
const float2 m23Coordinate = float2(r / w, y / h);
const float2 m31Coordinate = float2(l / w, b / h);
const float2 m32Coordinate = float2(x / w, b / h);
const float2 m33Coordinate = float2(r / w, b / h);
const half4 centerColor = inputTexture.sample(quadSampler, m22Coordinate);
const half3 m11Color = inputTexture.sample(quadSampler, m11Coordinate).rgb;
const half3 m12Color = inputTexture.sample(quadSampler, m12Coordinate).rgb;
const half3 m13Color = inputTexture.sample(quadSampler, m13Coordinate).rgb;
const half3 m21Color = inputTexture.sample(quadSampler, m21Coordinate).rgb;
const half3 m22Color = centerColor.rgb;
const half3 m23Color = inputTexture.sample(quadSampler, m23Coordinate).rgb;
const half3 m31Color = inputTexture.sample(quadSampler, m31Coordinate).rgb;
const half3 m32Color = inputTexture.sample(quadSampler, m32Coordinate).rgb;
const half3 m33Color = inputTexture.sample(quadSampler, m33Coordinate).rgb;
const float3x3 matrix = (*matrix3x3);
half3 resultColor = half3(0.0h);
resultColor += m11Color * (matrix[0][0]) + m12Color * (matrix[0][1]) + m13Color * (matrix[0][2]);
resultColor += m21Color * (matrix[1][0]) + m22Color * (matrix[1][1]) + m23Color * (matrix[1][2]);
resultColor += m31Color * (matrix[2][0]) + m32Color * (matrix[2][1]) + m33Color * (matrix[2][2]);
const half4 outColor = half4(resultColor, centerColor.a);
outputTexture.write(outColor, grid);
}
其他卷积核
extension Matrix3x3 {
/// 常见 3x3 矩阵卷积内核,考线性代数时间
/// Common 3x3 matrix convolution kernel
public struct Kernel { }
}
extension Matrix3x3.Kernel {
/// 原始矩阵,空卷积核
/// The original matrix, the empty convolution kernel
public static let `default` = Matrix3x3(values: [
0.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 0.0,
])
public static let identity = Matrix3x3(values: [
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
])
/// 边际检测矩阵
/// Edge detection matrix
public static let edgedetect = Matrix3x3(values: [
-1.0, -1.0, -1.0,
-1.0, 8.0, -1.0,
-1.0, -1.0, -1.0,
])
/// 浮雕矩阵
/// Anaglyph matrix
public static let embossment = Matrix3x3(values: [
-2.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 2.0,
])
/// 45度的浮雕滤波器
/// A 45 degree emboss filter
public static let embossment45 = Matrix3x3(values: [
-1.0, -1.0, 0.0,
-1.0, 0.0, 1.0,
0.0, 1.0, 1.0,
])
/// 腐蚀矩阵
/// Matrix erosion
public static let morphological = Matrix3x3(values: [
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
])
/// 拉普拉斯算子,边际检测算子
/// Laplace operator, edge detection operator
public static func laplance(_ iterations: Float) -> Matrix3x3 {
let xxx = iterations
return Matrix3x3(values: [
0.0, -1.0, 0.0,
-1.0, xxx, -1.0,
0.0, -1.0, 0.0,
])
}
/// 锐化矩阵
/// Sharpening matrix
public static func sharpen(_ iterations: Float) -> Matrix3x3 {
let cc = (8 * iterations + 1)
let xx = (-iterations)
return Matrix3x3(values: [
xx, xx, xx,
xx, cc, xx,
xx, xx, xx,
])
}
/// Sobel矩阵图像边际提取,求梯度比较常用
/// Sobel matrix image edge extraction, gradient is more commonly used
public static func sobel(_ orientation: Bool) -> Matrix3x3 {
if orientation {
return Matrix3x3(values: [
-1.0, 0.0, 1.0,
-2.0, 0.0, 2.0,
-1.0, 0.0, 1.0,
])
} else {
return Matrix3x3(values: [
-1.0, -2.0, -1.0,
0.0, 0.0, 0.0,
1.0, 2.0, 1.0,
])
}
}
/// BT.601, which is the standard for SDTV.
public static let to601 = Matrix3x3(values: [
1.164, 1.164, 1.164,
0.000, -0.392, 2.017,
1.596, -0.813, 0.000,
])
/// BT.601 full range (ref: http://www.equasys.de/colorconversion.html)
public static let to601FullRange = Matrix3x3(values: [
1.0, 1.000, 1.000,
0.0, -0.343, 1.765,
1.4, -0.711, 0.000,
])
/// BT.709, which is the standard for HDTV.
public static let to709 = Matrix3x3(values: [
1.164, 1.164, 1.164,
0.000, -0.213, 2.112,
1.793, -0.533, 0.000,
])
}
作用图
- 常见核卷积图
边际检测矩阵 | 浮雕矩阵 | 45度的浮雕滤波器 |
---|---|---|
锐化矩阵 | 拉普拉斯算子 | Sobel矩阵图像边际提取 |
Harbeth功能清单
- 支撑ios体系和macOS体系
- 支撑运算符函数式操作
- 支撑多种模式数据源 UIImage, CIImage, CGImage, CMSampleBuffer, CVPixelBuffer.
- 支撑快速规划滤镜
- 支撑兼并多种滤镜作用
- 支撑输出源的快速扩展
- 支撑相机收集特效
- 支撑视频添加滤镜特效
- 支撑矩阵卷积
- 支撑运用体系 MetalPerformanceShaders.
- 支撑兼容 CoreImage.
- 滤镜部分大致分为以下几个模块:
- Blend:图像融合技能
- Blur:含糊作用
- Pixel:图像的根本像素色彩处理
- Effect:作用处理
- Lookup:查找表过滤器
- Matrix: 矩阵卷积滤波器
- Shape:图像形状大小相关
- Visual: 视觉动态特效
- MPS: 体系 MetalPerformanceShaders.
最后
- 关于3×3矩阵卷积作用滤镜介绍与规划到此为止吧。
- 渐渐再补充其他相关滤镜,喜爱就给我点个星吧。
-
滤镜Demo地址,现在包括
100+
种滤镜,一起也支撑CoreImage混合运用。 - 再附上一个开发加速库KJCategoriesDemo地址
- 再附上一个网络根底库RxNetworksDemo地址
- 喜爱的老板们能够点个星,谢谢各位老板!!!
✌️.