Brad Larson
http://www.sunsetlakesoftware.com
GPUImage 框架是一个基于 BSD 许可的 iOS 库,它允许您将 GPU 加速的滤镜和其他效果应用到图像、实时相机视频和电影中。与 Core Image(iOS 5.0 的一部分)相比,GPUImage 允许您编写自己的自定义滤镜,支持部署到 iOS 4.0,并且具有更简单的接口。然而,它目前缺少 Core Image 的一些更高级功能,比如面部检测。
对于处理图像或实时视频帧这类大规模并行操作,GPU 相较于 CPU 拥有一些显著的性能优势。iPhone 4 上,一个简单的图像滤镜在 GPU 上的执行速度可以比等效的基于 CPU 的滤镜快 100 多倍。
但是,在 GPU 上运行自定义滤镜需要编写大量的代码来设置和维护渲染目标 OpenGL ES 2.0。我创建了一个示例项目来做这件事
http://www.sunsetlakesoftware.com/2010/10/22/gpu-accelerated-video-processing-mac-and-ios
并且发现创建时必须编写大量的代码。因此,我汇集了这个框架,它封装了许多您在处理图像和视频时可能遇到的任务,并且确保您无需关心 OpenGL ES 2.0 的底层实现。
在初始基准测试中,该框架在处理视频时显著优于 Core Image,iPhone 4 上仅用 2.5 毫秒将相机帧上传、应用棕褐色滤镜和显示,而 Core Image 进行相同操作需要 149 毫秒。基于 CPU 的处理需要 460 毫秒,这使得 GPUImage 在此硬件上比 Core Image 快 60 倍,比 CPU 编程快 184 倍。在 iPhone 4S 上,GPUImage 比 Core Image 快 13 倍,比 CPU 编程快 102 倍。
BSD 样式,完整的许可证可在框架的 License.txt 中找到。
GPUImage使用OpenGL ES 2.0着色器以比在CPU绑定例程中更快的方式执行图像和视频处理。然而,它通过简化的Objective-C接口隐藏了与OpenGL ES API交互的复杂性。这个接口让您定义图像和视频的输入源,按链附加过滤器,并将处理后图像或视频发送到屏幕,到UIImage,或到磁盘上的电影。
图像或视频帧从源对象上传,这些对象是GPUImageOutput的子类。它们包括GPUImageVideoCamera(来自iOS相机的实时视频)、GPUImageStillCamera(使用相机拍照)、GPUImagePicture(静态图像)和GPUImageMovie(电影)。源对象将静态图像帧上传到OpenGL ES作为纹理,然后将这些纹理转交给处理链中的下一个对象。
链中的过滤器和后续元素遵守GPUImageInput协议,这使得它们可以从链中的前一个链接接收提供的或处理的纹理并对它进行处理。链中再一步的对象被视为目标,可以通过向单个输出或过滤器添加多个目标来分支处理。
例如,一个从相机获取实时视频、将其转换为棕褐色并显示在屏幕上的应用程序将设置如下类似的链
GPUImageVideoCamera -> GPUImageSepiaFilter -> GPUImageView
文档由头注释使用appledoc生成。要生成文档,切换到Xcode中的“文档”方案。您应确保“APPLEDOC_PATH”(一个用户定义的构建设置)指向appledoc二进制文件,它可以在Github或通过Homebrew获取。它还将构建并安装一个.docset文件,您可以使用您喜欢的文档工具查看该文件。
目前有125个内置过滤器,分为以下类别
GPUImageBrightnessFilter:调整图像亮度
GPUImageExposureFilter:调整图像曝光
GPUImageContrastFilter:调整图像对比度
GPUImageSaturationFilter:调整图像饱和度
GPUImageGammaFilter:调整图像伽玛值
GPUImageLevelsFilter:类似Photoshop的级别调整。min、max、minOut和maxOut参数范围在[0, 1]的浮点数。如果您有来自Photoshop的范围在[0, 255]的参数,您必须首先将它们转换为范围[0, 1]。gamma/mid参数为float >= 0。这与Photoshop中的值匹配。如果您想要将级别应用于RGB以及单独的通道,您需要使用这个过滤器两次 - 首先用于单独的通道,然后用于所有通道。
GPUImageColorMatrixFilter:通过应用矩阵来转换图像的颜色
GPUImageRGBFilter:调整图像的RGB通道
GPUImageHueFilter:调整图像的色调
GPUImageToneCurveFilter:根据每个颜色通道的样条曲线调整图像的颜色
GPUImageHighlightShadowFilter:调整图像的阴影和高光
GPUImageLookupFilter:使用RGB颜色查找图像重新映射图像中的颜色。首先,使用您喜欢的照片编辑应用程序将查找.png从GPUImage/framework/Resources应用到查找.png。为了正确工作,每个像素的颜色必须不依赖于其他像素(例如,模糊将不起作用)。如果您需要更复杂的过滤器,您可以创建所需的任何数量的查找表。一旦准备就绪,使用您新的查找.png文件作为GPUImageLookupFilter的第二个输入。
GPUImageAmatorkaFilter:基于Amatorka的Photoshop动作的滤镜:[http://amatorka.deviantart.com/art/Amatorka-Action-2-121069631](http://amatorka.deviantart.com/art/Amatorka-Action-2-121069631)。如果您想使用此效果,您必须将GPUImage Resources文件夹中的lookup_amatorka.png添加到您的应用程序包中。
GPUImageMissEtikateFilter:基于Miss Etikate的Photoshop动作的滤镜:[http://miss-etikate.deviantart.com/art/Photoshop-Action-15-120151961](http://miss-etikate.deviantart.com/art/Photoshop-Action-15-120151961)。如果您想使用此效果,您必须将GPUImage Resources文件夹中的lookup_miss_etikate.png添加到您的应用程序包中。
GPUImageSoftEleganceFilter:另一个基于查找的颜色重映射滤波器。如果您想使用此效果,您必须将GPUImage Resources文件夹中的lookup_soft_elegance_1.png和lookup_soft_elegance_2.png添加到您的应用程序包中。
GPUImageColorInvertFilter:反转图像的颜色
GPUImageGrayscaleFilter:将图像转换为灰度(饱和度滤镜的略快实现,无法调整颜色贡献)
GPUImageMonochromeFilter:根据每个像素的亮度将图像转换为单色版本
GPUImageFalseColorFilter:使用图像的亮度在两个用户指定的颜色之间混合
GPUImageHazeFilter:用于添加或去除雾气(类似于UV滤镜)
GPUImageSepiaFilter:简单的棕褐色滤镜
GPUImageOpacityFilter:调整输入图像的alpha通道
GPUImageSolidColorGenerator:输出一个具有纯色的图像。您需要使用-fouseProcessingAtSize来定义图像大小。
GPUImageLuminanceThresholdFilter:亮度超过阈值的像素将显示为白色,低于阈值的像素将显示为黑色。
GPUImageAdaptiveThresholdFilter:确定像素周围的局部亮度,如果像素亮度低于该局部亮度则将其变黑,如果高于则变白。这在不同照明条件下提取文本时可能很有用。
GPUImageAverageLuminanceThresholdFilter:该阈值根据场景的平均亮度不断调整进行阈值操作。
GPUImageHistogramFilter:分析输入图像,并根据每个颜色值出现的频率创建输出直方图。该过滤器的输出是一个3像素高、256像素宽的图像,其中中心(垂直)像素包含对应于各种颜色值出现频率的像素。每个颜色值占据256宽度中的一个位置,从左边的0到右边的255。可以为单个颜色通道(kGPUImageHistogramRed、kGPUImageHistogramGreen、kGPUImageHistogramBlue)、图像亮度(kGPUImageHistogramLuminance)或三个颜色通道同时(kGPUImageHistogramRGB)生成此直方图。
GPUImageHistogramGenerator:这是一个特殊过滤器,其主要目的是与GPUImageHistogramFilter一起使用。它生成GPUImageHistogramFilter生成的颜色直方图的输出表示,但可以被重新用于显示其他类型的值。它接收一个图像,并查看中心(垂直)像素。然后它在一个输出纹理中使用单独的彩色图表绘制RGB组件的数值。您可能需要强制设置为这个过滤器的大小,以便使其输出可见。
GPUImageAverageColor:处理输入图像并确定场景的平均颜色,通过平均图像中每个像素的RGBA组件。使用裁剪过程在GPU上逐级下采样源图像,然后在CPU上进行简短的平均值计算。该过滤器的输出没有意义,但您需要设置colorAverageProcessingFinishedBlock属性,将一个块作为输入四个颜色组件和帧时间,对其执行操作。
GPUImageLuminosity:与GPUImageAverageColor类似,将图像还原为其平均亮度。您需要设置luminosityProcessingFinishedBlock以处理该过滤器的输出,该过滤器仅返回一个亮度和帧时间。
GPUImageChromaKeyFilter:对于图像中的给定颜色,将alpha通道设置为0。与GPUImageChromaKeyBlendFilter类似,但它不需要为匹配的颜色混合第二个图像,而只是将给定颜色透明。
GPUImageTransformFilter:这是对图像应用任意2D或3D变换
GPUImageCropFilter:这是将图像裁剪到特定区域,然后将该区域传递到滤镜的下一阶段的操作
GPUImageLanczosResamplingFilter:允许您使用Lanczos重采样方法上采样或下采样图像,其质量明显优于标准的线性或三线性插值。只需使用-forceProcessingAtSize:来设置滤镜的目标输出分辨率,图像将为了新的大小而进行重采样。
GPUImageSharpenFilter:锐化图像
GPUImageUnsharpMaskFilter:应用一个锐化蒙版
GPUImageFastBlurFilter:对图像进行硬件加速的9次高斯模糊
GPUImageSingleComponentFastBlurFilter:GPUImageFastBlurFilter的修改版,仅对红色部分操作
GPUImageGaussianBlurFilter:一个更通用的9x9高斯模糊滤镜
GPUImageSingleComponentGaussianBlurFilter:修改后的GPUImageGaussianBlurFilter,仅对红色部分操作
GPUImageGaussianSelectiveBlurFilter:一种高斯模糊,在圆形区域内保持焦点
GPUImageGaussianBlurPositionFilter:GPUImageGaussianSelectiveBlurFilter的逆过程,仅对特定圆内的区域应用模糊
GPUImageMedianFilter:从一个3x3区域内取出三个颜色分量中值
GPUImageBilateralFilter:双边模糊,尝试模糊相似的颜色值,同时保留锐利的边缘
GPUImageTiltShiftFilter:模拟倾斜移轴镜头效果
GPUImageBoxBlurFilter:图像硬件加速的9点框模糊
GPUImage3x3ConvolutionFilter:对图像执行3x3卷积核运算
GPUImageSobelEdgeDetectionFilter:Sobel边缘检测,边缘以白色高亮显示
GPUImagePrewittEdgeDetectionFilter:Prewitt边缘检测,边缘以白色高亮显示
GPUImageThresholdEdgeDetectionFilter:执行Sobel边缘检测,但应用阈值而不是给出渐变的强度值
GPUImageCannyEdgeDetectionFilter:使用完整的Canny过程来突出显示单像素宽的边缘
GPUImageHarrisCornerDetectionFilter:在输入图像上运行Harris角检测算法,并生成一个白色像素点表示角点,其他部分为黑色的图像。可以设置cornersDetectedBlock,在此回调中将提供角落列表(在归一化的0..1 X, Y坐标中),以便您执行任何其他操作。
GPUImageNobleCornerDetectionFilter:在Harris角检测器上运行Noble变体。它的工作方式与上面所述Harris检测器相同。
GPUImageShiTomasiCornerDetectionFilter:运行Shi-Tomasi特征检测器。它的工作方式与上面所述Harris检测器相同。
GPUImageNonMaximumSuppressionFilter:当前仅作为Harris角点检测滤镜的一部分使用,它将对每个像素周围的一个1像素盒子进行采样,并确定中心像素的红色通道是否是该区域的最高值。如果是,则保持不变;如果不是,则所有颜色通道都将设置为0。
GPUImageXYDerivativeFilter:是Harris角点检测滤镜中的内部组件,它计算这个像素左右像素之间的平方差异以及上下像素之间的平方差异,以及这两个差异的乘积。
GPUImageCrosshairGenerator:在图像上绘制一系列的十字线,常用于识别机器视觉特征。它不会接收标准图像,而是在-Content:count:方法中接收一系列点,该方法负责实际的绘制。您需要强制此滤镜以所需的部分大小渲染。
GPUImageDilationFilter:执行图像膨胀操作,在此操作中,矩形邻域中红色通道的最大强度用于此像素的强度。初始时指定矩形区域的半径,范围为1-4像素。这旨在与灰度图像一起使用,并扩展明亮区域。
GPUImageRGBDilationFilter:与GPUImageDilationFilter相同,只不过它作用于所有颜色通道,而不仅仅是红色通道。
GPUImageErosionFilter:执行图像腐蚀操作,在此操作中,_rectangle区域的红色通道最小强度用于此像素的强度。初始时指定矩形区域的半径,范围为1-4像素。这旨在与灰度图像一起使用,并扩展黑暗区域。
GPUImageRGBErosionFilter:与GPUImageErosionFilter相同,只不过它作用于所有颜色通道,而不仅仅是红色通道。
GPUImageOpeningFilter:对图像的红色通道进行腐蚀,接着进行相同半径的膨胀。初始时设置半径,范围为1-4像素。此过滤器可过滤掉较小的明亮区域。
GPUImageRGBOpeningFilter:与GPUImageOpeningFilter相同,只不过它作用于所有颜色通道,而不仅仅是红色通道。
GPUImageClosingFilter:对图像的红色通道进行膨胀,然后进行相同半径的腐蚀。初始时设置半径,范围为1-4像素。此过滤器可过滤掉较小的黑暗区域。
GPUImageRGBClosingFilter:与GPUImageClosingFilter相同,只不过它作用于所有颜色通道,而不仅仅是红色通道。
GPUImageLocalBinaryPatternFilter:比较8个周围像素和中心像素的红色通道强度,并将比较结果编码成位串作为此像素强度。最低有效位是右上角的比较,逆时针结束,最高有效位是右边的比较。
GPUImageLowPassFilter:对传入的视频帧应用低通滤波器。这基本上是将前面累积的加权滚动平均值与当前传入的帧相加。此功能可用于去噪视频、添加运动模糊或创建高通滤波器。
GPUImageHighPassFilter:对传入的视频帧应用高通滤波器。这是低通滤波器的逆运算,显示当前帧与前面加权滚动平均值的差异。这对运动检测最有用。
GPUImageMotionDetector:这是一个基于高通滤波器的运动检测器。您设置运动检测块,在每一帧输入时,它将给出场景中任何检测到的运动的质心(在归一化的X,Y坐标中)以及场景的运动强度。
GPUImageHoughTransformLineDetector:使用霍夫变换到并行坐标空间来检测图像中的线条。这种方法完全基于布拉格科技大学Graph@FIT研究小组开发的PC线条过程,并在其出版物中进行了描述:M. Dubská, J. Havel, and A. Herout. 实时使用并行坐标和OpenGL检测线条。SCCG 2011会议论文集,斯洛伐克布拉迪斯拉发,p. 7 (http://medusa.fit.vutbr.cz/public/data/papers/2011-SCCG-Dubska-Real-Time-Line-Detection-Using-PC-and-OpenGL.pdf) 和 M. Dubská, J. Havel, and A. Herout. PClines — 使用并行坐标的线条检测。2011 IEEE计算机视觉和模式识别会议(CVPR),p. 1489- 1494 (http://medusa.fit.vutbr.cz/public/data/papers/2011-CVPR-Dubska-PClines.pdf)。
GPUImageLineGenerator:一个辅助类,用于生成可以叠加到场景中的线条。这些线条的颜色可以通过-setLineColorRed:green:blue进行调整
GPUImageMotionBlurFilter:对一个图像应用方向性运动模糊
GPUImageZoomBlurFilter:对一个图像应用方向性运动模糊
GPUImageChromaKeyBlendFilter:选择性地用第二个图像替换第一张图像中的颜色
GPUImageDissolveBlendFilter:应用两个图像的溶解叠加
GPUImageMultiplyBlendFilter:应用两个图像的乘法叠加
GPUImageAddBlendFilter:应用两个图像的加法叠加
GPUImageSubtractBlendFilter:应用两个图像的减法叠加
GPUImageDivideBlendFilter:应用两个图像的除法叠加
GPUImageOverlayBlendFilter:应用两个图像的叠加叠加
GPUImageDarkenBlendFilter:通过取两个图像之间每个颜色成分的最小值来混合两个图像
GPUImageLightenBlendFilter:通过取两个图像之间每个颜色成分的最大值来混合两个图像
GPUImageColorBurnBlendFilter:对两个图像应用色彩渐变增强叠加
GPUImageColorDodgeBlendFilter:将两个图像进行颜色 dodge 混合
GPUImageScreenBlendFilter:将两个图像进行 screen 混合
GPUImageExclusionBlendFilter:将两个图像进行排除混合
GPUImageDifferenceBlendFilter:将两个图像进行差异混合
GPUImageHardLightBlendFilter:将两个图像进行强光混合
GPUImageSoftLightBlendFilter:将两个图像进行柔光混合
GPUImageAlphaBlendFilter:根据第二图像的 alpha 通道,将第二图像混合到第一图像上
GPUImageSourceOverBlendFilter:将两个图像进行源覆盖混合
GPUImageColorBurnBlendFilter:对两个图像应用色彩渐变增强叠加
GPUImageColorDodgeBlendFilter:将两个图像进行颜色 dodge 混合
GPUImageNormalBlendFilter:将两个图像进行正常混合
GPUImageColorBlendFilter:将两个图像进行颜色混合
GPUImageHueBlendFilter:将两个图像进行色调混合
GPUImageSaturationBlendFilter:将两个图像进行饱和度混合
GPUImageLuminosityBlendFilter:将两个图像进行亮度混合
GPUImageLinearBurnBlendFilter:将两个图像进行线性燃烧混合
GPUImagePoissonBlendFilter:将两个图像进行泊松混合
GPUImageMaskFilter:使用另一图像对图像进行遮罩
GPUImagePixellateFilter:对图像或视频应用像素化效果
GPUImagePolarPixellateFilter:基于极坐标而不是笛卡尔坐标,对图像或视频应用像素化效果
GPUImagePolkaDotFilter:将图像分割成规则网格中的彩色点
GPUImageHalftoneFilter:对图像应用网点效果,类似于报纸印刷
GPUImageCrosshatchFilter:将图像转换为黑白网状图案
GPUImageSketchFilter:将视频转换为类似于素描的效果。这仅仅是将索布尔的边缘检测滤波器应用在颜色上,并进行了颜色反转
GPUImageThresholdSketchFilter:与素描滤波器相同,只是边缘被阈值为灰度值而不是灰度
GPUImageToonFilter:使用索布尔的边缘检测来围绕对象放置黑色边框,然后量化图像中存在的颜色,以给图像带来卡通般的质感。
GPUImageSmoothToonFilter:该滤镜使用类似于GPUImageToonFilter的过程,只是在调色带效果之前先使用高斯模糊来平滑噪声。
GPUImageEmbossFilter:在图像上应用浮雕效果。
GPUImagePosterizeFilter:将颜色动态范围减少到指定的步数,导致图像呈现类似卡通的简单着色。
GPUImageSwirlFilter:在图像上创建漩涡扭曲。
GPUImageBulgeDistortionFilter:在图像上创建隆起扭曲。
GPUImagePinchDistortionFilter:在图像上创建挤压扭曲。
GPUImageStretchDistortionFilter:在图像上创建拉伸扭曲。
GPUImageSphereRefractionFilter:模拟通过玻璃球体的折射。
GPUImageGlassSphereFilter:与GPUImageSphereRefractionFilter相同,但图像没有倒置,并且玻璃边缘有一些霜化。
GPUImageVignetteFilter:执行暗角效果,使图像边缘变淡。
GPUImageKuwaharaFilter:Kuwahara图像抽象,源自Kyprianidis等人发表的“GPU Pro”系列中的出版物“在GPU上的各向异性Kuwahara滤波”。这会产生类似油画的图像,但计算成本极高,因此在iPad 2上渲染一帧可能需要几秒钟。这最适合用于静态图像。
GPUImageKuwaharaRadius3Filter:Kuwahara滤镜的修改版本,优化用于仅覆盖三个像素的半径。
GPUImagePerlinNoiseFilter:生成满屏的Perlin噪声。
GPUImageCGAColorspaceFilter:模拟CGA显示器的颜色空间。
GPUImageMosaicFilter:该滤镜使用输入的瓦片集,瓦片必须按亮度级别递增。它查看输入图像,并根据该瓦片的亮度将每个显示瓦片替换为输入瓦片。最初是为了复制其他应用中看到的ASCII视频滤波器,但瓦片集可以是任何东西。
GPUImageJFAVoronoiFilter:生成Voronoi图,供后续阶段使用。
GPUImageVoronoiConsumerFilter:接收Voronoi图,并使用该图来过滤传入的图像。
您还可以轻松使用C语言风格的OpenGL着色语言编写自己的自定义过滤器,详情见下文。
一旦您有了框架的最新源代码,将其添加到您的应用程序中相当简单。首先,将GPUImage.xcodeproj文件拖放到您的Xcode项目中以嵌入框架。接下来,转到您的应用程序的目标,并将GPUImage添加为Target依赖项。最后,您将从GPUImage框架的产品文件夹中拖动libGPUImage.a库到应用程序目标的Link Binary With Libraries构建阶段。
GPUImage需要将几个其他框架链接到您的应用程序中,因此您需要将以下内容作为链接库添加到应用程序目标中
您还需要找到框架头文件,因此请在进行项目的构建设置时将 Header Search Paths 设置为从您的应用程序到GPUImage源目录中的 framework/ 子目录的相对路径。请将此头搜索路径设置为递归。
要使用应用程序中的GPUImage类,只需使用以下方式包含核心框架头文件
#import "GPUImage.h"
备注:如果您在尝试使用Interface Builder构建界面时遇到“未知类GPUImageView”或类似错误,您可能需要将-ObjC添加到项目的构建设置中的Other Linker Flags。
另外,如果您需要将其部署到iOS 4.x,当前版本的Xcode(4.3)似乎要求您在最终应用程序中对Core Video框架进行弱链接。否则,当您创建上传到App Store或用于ad hoc分发的存档时,您会看到崩溃信息“找不到符号:_CVOpenGLESTextureCacheCreate”。要完成此操作,转到项目的构建阶段标签,展开Link Binary With Libraries组,并在列表中找到CoreVideo.framework。将列表右侧的设置从Required更改为Optional。
此外,这是一个启用了ARC的框架,因此如果您想在手动引用计数的应用程序中使用它,目标为iOS 4.x,您还需要将-fobjc-arc添加到Other Linker Flags。
如果您不想将项目作为依赖项包含在应用程序的Xcode项目中,您可以构建iOS模拟器或设备的通用静态库。为此,请在命令行中运行build.sh
。生成的库和头文件将位于build/Release-iphone
。您也可以通过修改build.sh
中的IOSSDK_VER
变量来更改iOS SDK的版本(所有可用版本都可以使用xcodebuild -showsdks
找到)。
要过滤iOS设备的摄像头实时视频,您可以使用如下代码
GPUImageVideoCamera *videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:AVCaptureDevicePositionBack];
videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
GPUImageFilter *customFilter = [[GPUImageFilter alloc] initWithFragmentShaderFromFile:@"CustomShader"];
GPUImageView *filteredVideoView = [[GPUImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, viewWidth, viewHeight)];
// Add the view somewhere so it's visible
[videoCamera addTarget:customFilter];
[customFilter addTarget:filteredVideoView];
[videoCamera startCameraCapture];
此操作设置了一个来自iOS设备后置摄像头的视频源,使用预设尝试捕捉640x480的分辨率。该视频采用竖直模式捕捉,在此模式下,水平左置的摄像头需要将其视频帧在显示之前旋转。然后使用来自CustomShader.fsh文件的代码,设置一个自定义过滤器作为摄像头视频帧的目标。最终,这些经过过滤的视频帧通过一个能够展示从该数据处理流程中得到的OpenGL ES纹理的UIView子类在屏幕上显示。
可以通过设置GPUImageView的fillMode属性来改变GPUImageView的填充模式,这样如果源视频的宽高比与视图不同,视频将被拉伸、居中带黑边,或者缩放填充。
对于需要输入多个图像的混合过滤器和其他滤波器,您可以创建多个输出并将单个过滤器作为这两个输出的目标。输出作为目标添加的顺序将会影响输入图像的混合或其他处理的顺序。
另外,如果您希望在录制电影时启用麦克风音频捕捉,您需要将相机音频编码目标设置为您电影编写器,如下所示
videoCamera.audioEncodingTarget = movieWriter;
要捕捉和过滤静态照片,可以使用和过滤视频类似的过程。您使用的是GPUImageStillCamera而不是GPUImageVideoCamera。
stillCamera = [[GPUImageStillCamera alloc] init];
stillCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
filter = [[GPUImageGammaFilter alloc] init];
[stillCamera addTarget:filter];
GPUImageView *filterView = (GPUImageView *)self.view;
[filter addTarget:filterView];
[stillCamera startCameraCapture];
这将提供静态相机的实时过滤预览视频流。注意,此预览视频仅在iOS 4.3及以上版本提供,所以如果您希望使用此功能,可能需要设置该版本为您的部署目标。
当您想要捕捉一张照片时,您可以使用如下回调块
[stillCamera capturePhotoProcessedUpToFilter:filter withCompletionHandler:^(UIImage *processedImage, NSError *error){
NSData *dataForPNGFile = UIImageJPEGRepresentation(processedImage, 0.8);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSError *error2 = nil;
if (![dataForPNGFile writeToFile:[documentsDirectory stringByAppendingPathComponent:@"FilteredPhoto.jpg"] options:NSAtomicWrite error:&error2])
{
return;
}
}];
以上代码捕捉了一个全尺寸的照片,该照片经过与预览视图中相同的过滤器链处理,并将其作为JPEG文件保存在应用文档目录中。
请注意,该框架目前无法处理超过2048像素宽或高的图像(iPhone 4S、iPad 2或Retina iPad之前的旧设备),这是由于纹理大小限制导致的。这意味着iPhone 4(其摄像头输出大于此大小的静态照片)将无法捕捉这类照片。正在实施一种平铺机制来解决这个问题。其他所有设备都应能使用此方法捕捉和过滤图像。
有几种方法可以处理静态图像并创建结果。您可以通过创建一个静态图像源对象并手动创建一个过滤器链来实现这一点。
UIImage *inputImage = [UIImage imageNamed:@"Lambeau.jpg"];
GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:inputImage];
GPUImageSepiaFilter *stillImageFilter = [[GPUImageSepiaFilter alloc] init];
[stillImageSource addTarget:stillImageFilter];
[stillImageSource processImage];
UIImage *currentFilteredVideoFrame = [stillImageFilter imageFromCurrentlyProcessedOutput];
对于希望将单个过滤器应用于图像的情况,您可以简单地执行以下操作
GPUImageSepiaFilter *stillImageFilter2 = [[GPUImageSepiaFilter alloc] init];
UIImage *quickFilteredImage = [stillImageFilter2 imageByFilteringImage:inputImage];
相比于iOS上的Core Image(截至iOS 5.0),该框架一个显著优势是能够编写自己的自定义图像和视频处理过滤器。这些过滤器作为OpenGL ES 2.0片段着色器提供,使用类似C的OpenGL着色语言编写。
自定义过滤器可以使用如下代码初始化
GPUImageFilter *customFilter = [[GPUImageFilter alloc] initWithFragmentShaderFromFile:@"CustomShader"];
其中用于片段着色器的扩展名为.fsh。另外,您可以使用-initWithFragmentShaderFromString:初始化器将片段着色器作为一个字符串提供,如果您不希望将片段着色器打包到应用包中。
片段着色器在过滤阶段为要渲染的每个像素执行计算。它们使用OpenGL着色语言(GLSL)进行此操作,这是一种类似于C语言,并添加了特定于2-D和3-D图形的语言。以下是一个调色法过滤器片段着色器的示例:
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
void main()
{
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
lowp vec4 outputColor;
outputColor.r = (textureColor.r * 0.393) + (textureColor.g * 0.769) + (textureColor.b * 0.189);
outputColor.g = (textureColor.r * 0.349) + (textureColor.g * 0.686) + (textureColor.b * 0.168);
outputColor.b = (textureColor.r * 0.272) + (textureColor.g * 0.534) + (textureColor.b * 0.131);
outputColor.a = 1.0;
gl_FragColor = outputColor;
}
为了在GPUImage框架中使用图像过滤器,需要前两行代码,这些代码接受纹理坐标变量(对于纹理中的当前坐标,归一化为1.0)和输入图像纹理统一变量(对于实际的输入图像帧纹理)。
着色器的其余部分将从这个传入选定的纹理中的像素位置获取颜色,以生成棕褐色色调的方式对其进行处理,并将该像素颜色写入以便在下一个处理阶段的流水线中使用。
将片段着色器添加到您的Xcode项目时,有一点需要注意:Xcode认为它们是源代码文件。为了解决这个问题,您需要手动将着色器从编译源文件阶段移动到复制最终资源阶段,以便使着色器包含在您的应用程序包中。
可以通过GPUImageMovie类将电影加载到框架中,进行过滤,然后使用GPUImageMovieWriter写入。GPUImageMovieWriter的速度也足够快,可以从iPhone 4的摄像头实时录制640x480的视频,因此可以直接将过滤的视频源输入到其中。目前,GPUImageMovieWriter可以在iPhone 4上以至少20 FPS的速率录制满720p的视频,在iPhone 4S上以30 FPS录制720p和1080p视频(以及在新iPad上)。
以下是如何加载示例电影,将其通过像素化过滤器处理,然后将结果记录到磁盘作为480 x 640 h.264电影的示例:
movieFile = [[GPUImageMovie alloc] initWithURL:sampleURL];
pixellateFilter = [[GPUImagePixellateFilter alloc] init];
[movieFile addTarget:pixellateFilter];
NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Movie.m4v"];
unlink([pathToMovie UTF8String]);
NSURL *movieURL = [NSURL fileURLWithPath:pathToMovie];
movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(480.0, 640.0)];
[pixellateFilter addTarget:movieWriter];
movieWriter.shouldPassthroughAudio = YES;
movieFile.audioEncodingTarget = movieWriter;
[movieFile enableSynchronizedEncodingUsingMovieWriter:movieWriter];
[movieWriter startRecording];
[movieFile startProcessing];
一旦录制完成,您需要从过滤链中删除电影录制器,并关闭以下代码的录制:
[pixellateFilter removeTarget:movieWriter];
[movieWriter finishRecording];
电影在完成之前的任何时间点都无法使用,所以如果在这一点被中断,录制将会丢失。
通过使用GPUImageTextureOutput和GPUImageTextureInput类,GPUImage既可以导出也可以导入OpenGL ES中的纹理。这允许您从渲染到具有绑定纹理的帧缓冲对象中的OpenGL ES场景中记录电影,或者过滤视频或图像,然后将其作为纹理输入到OpenGL ES中以便在场景中显示。
使用这种方法时有一点需要注意:在这些过程中使用的纹理必须在GPUImage的OpenGL ES上下文和任何其他上下文之间通过共享组或在类似的方式下共享。
框架资源中包含了几个示例应用程序。大多数与iPhone和iPad类设备兼容。它们旨在展示框架的各个方面,并且在框架开发期间应该用作API的最佳示例。这些包括:
在应用程序启动时将捆绑的JPEG图像加载到应用程序中,对其应用过滤器,然后将结果渲染到屏幕上。此外,该示例还展示了两种接受图像、过滤它并将其保存到磁盘的方法。
对实时视频流应用像素化滤镜,并通过 UISlider 控件调整实时视频中的像素大小。
从磁盘加载一个电影文件,对它应用锐化蒙版滤镜,并将过滤结果重新编码为另一部电影。
从一个单一摄像头输入中,为摄像头应用实时滤镜生成四个视图。一个是直通的摄像头视频,一个是预设的棕褐色调,另外两个是基于着色器程序的定制滤镜。
这展示了 GPUImage 提供的所有滤镜。
这是用来通过测试对 CPU 密集型程序和 Core Image 的性能来测试整体框架性能的。涉及静态图像和视频的基准测试将针对所有三者运行,并在应用程序中显示结果。
这展示了 GPUImage 与 OpenGL ES 渲染交互的能力。从摄像头捕获帧,在它们上应用棕褐色滤镜,然后将它们喂入一个纹理,这个纹理被应用于立方体的表面,这个立方体可以用手指旋转。这个立方体反过来被渲染到纹理缓冲区对象上,而这个纹理被送回 GPUImage,在它之前应用一个像素化滤镜,最后渲染到屏幕上。
换句话说,该应用程序的过程是:摄像头 -> 棕褐色滤镜 -> 立方体 -> 像素化滤镜 -> 显示。
这是从 http://www.sunsetlakesoftware.com/2010/10/22/gpu-accelerated-video-processing-mac-and-ios 中的 ColorTracking 示例移植过来并在 GPUImage 上应用版本的示例,这个应用程序使用场景中的颜色来跟踪来自实时摄像头流的物体。你可以切换的四个视图包括原始摄像头输入、带有与颜色阈值匹配的像素的白色摄像头输入、编码为通过的阈值测试像素位置的分析视频,以及最后带有跟踪所选颜色的点的实时视频流。屏幕上的点击改变跟踪的颜色以匹配你手指下的颜色。屏幕上的点击和拖动使颜色阈值更加宽容。这在第二种颜色阈值视图上尤为明显。
目前,在最后一步中,颜色的平均值处理全部在 CPU 上完成,因此这部分非常慢。