一、布景
你是否从前想要给你的相片增加一些特殊作用,让它们愈加引人注目?或许你是否对那些充溢艺术感的滤镜相片羡慕不已,但却以为它们需求专业的图画处理技巧?今日,我将向你提醒一个令人惊奇的事实——图片加滤镜竟如此简略!
滤镜是一种强大而又简略的工具,它能够改变图片的色彩、亮度、对比度和纹路等特性,让你的相片锋芒毕露。
在本文中,我将向你展现怎么简略运用滤镜特点为你的图片增加味道。让我们一同揭开图片加滤镜的奥秘面纱,开掘那些隐藏在简略代码背后的冷艳作用。让你的相片勃发重生,让你的创造力在滤镜的法力下绽放!让我们开始吧!
了解ios的朋友,如果说到滤镜,那么第一时间就会想到 GPUImage, 的确很好用,不过这个库已经太久不更新维护。
于是乎我这边根据Swift + Metal
制造一款全新的滤镜库,这边在编写的时候,当然也有借鉴GPUImage
许多滤镜算法,再次感谢大神!!!
- 先贴链接地址:github.com/yangKJ/Harb…
Animated | Still | Mix |
---|---|---|
话不多说,先简略介绍滤镜库 Harbeth 支撑功用:
- 支撑ios体系和macOS体系;
- 支撑运算符函数式操作;
- 支撑多种形式数据源 UIImage, CIImage, CGImage, CMSampleBuffer, CVPixelBuffer
- 支撑运用体系 MetalPerformanceShaders 滤镜和兼容 CoreImage 滤镜;
- 支撑快速规划滤镜;
- 支撑兼并多种滤镜作用;
- 支撑输出源的快速扩展;
- 支撑相机采集特效 和 视频增加滤镜特效;
- 支撑已有视频增加滤镜并导出;
大致计算下来,这边目前也已经拥有超150
多种内置滤镜供给运用,而且这边也支撑兼容体系CoreImage
,这样一算那滤镜就太多了!
实现计划
该库首要分为以下几个板块,根底模块、Metal内核滤镜模块、CoreImage滤镜模块、视频滤镜模块
根底模块又首要分为以下部分:
- Core: 该模块首要处理装备Metal信息,和CoreImage兼容转化;
- Extensions: 该模块首要处理各类型资源和MTLTexture互相转化办法;
- Matrix: 该模块首要包括矩阵相关,常用矩阵卷积内核和常用色彩矩阵;
-
Outputs: 该模块首要包括对外转化,
BoxxIO
快速向源增加过滤器; - Setup: 该模块首要包括装备信息,该库运用的小工具等;
怎么运用
- 代码彻底能够做到零侵入对图画注入滤镜功用,然后显现在UIImageView控件;
- 原始代码:
lazy var ImageView: UIImageView = {
let imageView = UIImageView(image: originImage)
imageView.layer.borderColor = R.color("background2")?.cgColor
imageView.layer.borderWidth = 0.5
return imageView
}()
ImageView.image = originImage
图画增加滤镜
- 注入滤镜代码:
let filter1 = C7ColorMatrix4x4(matrix: Matrix4x4.Color.sepia)
let filter2 = C7Granularity(grain: 0.8)
let filter3 = C7SoulOut(soul: 0.7)
let filters = [filter1, filter2, filter3]
简略运用`Outputable`
ImageView.image = try? originImage.makeGroup(filters: filters)
指定图画数据源
- 能够高性能在这些数据源快速增加过滤器,例如:NSImage、UIImage、CIImage、CGImage、CMSampleBuffer, CVPixelBuffer;
- 其间CMSampleBuffer首要为相机采集回来的缓冲数据,CVPixelBuffer则能够简略用于播映视频增加滤镜;
也可数据源形式运用
let dest = BoxxIO.init(element: originImage, filters: filters)
// 同步处理
ImageView.image = try? dest.output()
异步处理
// 异步处理
dest.transmitOutput(success: { [weak self] image in
DispatchQueue.main.async {
self?.ImageView.image = image
}
})
运算符
或许运算符操作
ImageView.image = originImage -->>> filters
甚至不定参数运用
ImageView.image = originImage.filtering(filter, filter2, filter3)
总之这么多种计划,怎么运用就看你的心情了!!!
怎么规划滤镜
这边彻底选用协议方法,用于自定义各种滤镜;
滤镜类型
- 首要包括以下几种类型滤镜;
public enum Modifier {
/// 根据`MTLComputeCommandEncoder`并行计算编码器,可直接生成图片
case compute(kernel: String)
/// 根据`MTLRenderCommandEncoder`烘托 3D 编码器,需配合`MTKView`方能显现
case render(vertex: String, fragment: String)
/// 根据`MTLBlitCommandEncoder`位图复制编码器,拷贝纹路一起也能生成贴图
case blit
/// 根据`CoreImage`,直接生成图片
case coreimage(CIName: String)
/// 根据`MetalPerformanceShaders`着色器
case mps(performance: MPSUnaryImageKernel)
}
首要包括下面几个协议,
- C7FilterPorotocal: 根底协议,包括滤镜类型
Modifier
、参数因子、其他输入源、以及修正尺度巨细; - ComputeFiltering: 该协议首要用于根据内核形式,传递特殊参数因子;
- CoreImageFiltering: 该协议首要用于根据CoreImage,兼容运用体系CoreImage滤镜;
- RenderFiltering: 该协议首要作用于根据片元着色器和顶点着色器;
根底 C7FilterProtocal 协议:
public protocol C7FilterProtocol {
/// 编码器类型和对应的函数名
///
/// 计算需求对应的`kernel`函数名
/// 烘托需求一个`vertex`着色器函数名和一个`fragment`着色器函数名
var modifier: Modifier { get }
/// 制造缓冲区
/// 设置修正参数因子,需求转化为`Float`。
var factors: [Float] { get }
/// 多输入源扩展
/// 包括 `MTLTexture` 的数组
var otherInputTextures: C7InputTextures { get }
/// 改变输出图画的巨细
func outputSize(input size:C7Size) -> C7Size
}
规划滤镜
- 遵从协议
C7FilterProtocal
- 装备额外的所需纹路
- 装备传递参数因子,仅支撑
Float
类型 - 编写根据并行计算的核函数着色器
- 简略运用,由于我这边规划的是根据并行计算管道,所以能够直接生成图片
根据内核形式的查找滤镜
kernel void C7LookupTable(texture2d<half, access::write> outputTexture [[texture(0)]],
texture2d<half, access::read> inputTexture [[texture(1)]],
texture2d<half, access::sample> lookupTexture [[texture(2)]],
constant float *intensity [[buffer(0)]],
uint2 grid [[thread_position_in_grid]]) {
const half4 inColor = inputTexture.read(grid);
const half blueColor = inColor.b * 63.0h; // 蓝色部分[0, 63] 共64种
half2 quad1;
quad1.y = floor(floor(blueColor) / 8.0h);
quad1.x = floor(blueColor) - (quad1.y * 8.0h);
half2 quad2;
quad2.y = floor(ceil(blueColor) / 8.0h);
quad2.x = ceil(blueColor) - (quad2.y * 8.0h);
const float A = 0.125;
const float B = 0.5 / 512.0;
const float C = 0.125 - 1.0 / 512.0;
float2 texPos1; // 计算色彩(r,b,g)在第一个正方形中对应位置
texPos1.x = A * quad1.x + B + C * inColor.r;
texPos1.y = A * quad1.y + B + C * inColor.g;
float2 texPos2;
texPos2.x = A * quad2.x + B + C * inColor.r;
texPos2.y = A * quad2.y + B + C * inColor.g;
constexpr sampler quadSampler(mag_filter::linear, min_filter::linear);
const half4 newColor1 = lookupTexture.sample(quadSampler, texPos1);
const half4 newColor2 = lookupTexture.sample(quadSampler, texPos2);
const half4 newColor = mix(newColor1, newColor2, fract(blueColor));
const half4 outColor = half4(mix(inColor, half4(newColor.rgb, inColor.a), half(*intensity)));
outputTexture.write(outColor, grid);
}
展现图
- 给部分作用展现
色相交融 | 透明度交融 | 亮度交融 |
---|---|---|
总结
本文对于怎么运用Harbth滤镜库做了简略介绍,和怎么规划滤镜等等;
欢迎我们来运用该结构,然后指正修正亦或许我们有什么需求也可提出来,后续渐渐补充完善;
也欢迎大神来帮助运用优化此库,再次感谢!!!
对于怎么运用和规划原理先简略介绍出来,关于后续功用和优化再渐渐介绍!
觉得有帮助的铁子,就给我点个星支撑一哈,谢谢铁子们~
本文滤镜结构传送门 Harbeth 地址。
有什么问题也能够直接联络我,邮箱 yangkj310@gmail.com