欢迎来到天天文库
浏览记录
ID:47105267
大小:26.60 KB
页数:6页
时间:2019-08-04
《ios 实时滤镜》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
iOS编程高性能之路-GPU着色器实现实时滤镜作为智能机照相和摄像功能无疑是其重要的功能,从比较早期使用实时滤镜的path到后期迎头赶上的instagram,他们出彩了滤镜效果和流畅的性能无疑给软件增色不少,而其中最大的功臣就要归功于opengles2.x之后引入的着色器了。Ka&lYYPI~zX3nP取得照相时的图片数据加入FrameworkAVFoundation8nsZw,;k_GuVp:p_session=[[AVCaptureSessionalloc]init];nZ=F_]tvk;_videoOutput=[[[AVCaptureVideoDataOutputalloc]init]autorelease];rK>[Ly8[J1/b15Guif([_sessioncanAddOutput:_videoOutput]){wzTEg=i5[_sessionaddOutput:_videoOutput];Miy|50aa}Vyn4T1Iv/CnMTM~[_videoOutputsetSampleBufferDelegate:selfqueue:videoCaptureQueue];Dc6M"z+Y!bEfWII`S[_sessionstartRunning];X&uT!qFd)$az(f)2]U/HbDT[});)z!#A}Y=@PoXj(d...PZ~}c0^i<}k:]WK]F[kYflz)nI,9^iK7拿到sbuf之后我们就可以通过以下的方法来获取图片的首地址^2P(l>f/~iFAICVPixelBufferRefpixelBuffer=CMSampleBufferGetImageBuffer(sampleBuffer);EUOw^&V`~qJW$CVPixelBufferLockBaseAddress(pixelBuffer,0);:E`vx[J&3bsRAHtintlen=CVPixelBufferGetDataSize(pixelBuffer);m='0PX#EmsiIWVt!$UInt8*pixel=(UInt8*)CVPixelBufferGetBaseAddress(pixelBuffer);R.0vn|yhxNBFO_render(pixel,len)//滤镜函数ZV8mcxki<^2&80这样其实就可以简单的实现照相时候的实时滤镜,当然作为高性能的标题,肯定实现不会这么简单,大家可以尝试一下这个方法的效果,我之前尝试的时候原本60帧左右的摄像,对rgb某个单通道操作影响不大,但是一旦操作到三个通道,降帧就很明显,更不用说在摄像时同时还要录音了。这时我们要解决这个问题就需要我们下一节来认识着色器。认识着色器用过opengl的同学对着色器应该不会陌生,但对与iOS终端设备的开发者,对于图形图像有着深入了解的人不多,本人也只是个初学者,对于opengles2.x才引入的着色器也是初步认识,WWDC的专题讲座有一节就是讲opengles的新特性的结合AVFoundation那一节我们还是可以学到不少东西的。opengles的着色器有.fsh和.vsh两个文件这两个文件在被编译和链接后就可以产生可执行程序与GPU交互 .vsh是顶点shader用与顶点计算可以理解控制顶点的位置在这个文件中我们通常会传入当前顶点的位置,和纹理的坐标例如attributevec4position;attributevec4inputTextureCoordinate;varyingvec2textureCoordinate;precisionmediumpfloat;uniformfloatoverTurn;voidmain(){gl_Position=position;if(overTurn>0.0){textureCoordinate=vec2(inputTextureCoordinate.x,overTurn-inputTextureCoordinate.y);}elsetextureCoordinate=vec2(inputTextureCoordinate.x,inputTextureCoordinate.y);}attribute外部传入vsh文件的变量每帧的渲染的可变参数变化率高用于定义每个点varying用于vsh和fsh之间相互传递的参数precisionmediumpfloat定义中等精度的浮点数uniform外部传入vsh文件的变量变化率较低对于可能在整个渲染过程没有改变只是个常量在main()当overTurn大于0的时候函数里面做的事情就是将纹理y轴反转.fsh是片段shader在这里面我可以对于每一个像素点进行重新计算从而达到我们滤镜效果varyinghighpvec2textureCoordinate;precisionmediumpfloat;uniformsampler2DvideoFrame;vec4memoryRender(vec4color){floatgray;gray=color.r*0.3+color.g*0.59+color.b*0.11;color.r=gray; color.g=gray;color.b=gray;color.r+=color.r*1.5;color.g=color.g*2.0;if(color.r>255.0)color.r=255.0;if(color.g>255.0)color.g=255.0;returncolor;}voidmain(){vec4pixelColor;pixelColor=texture2D(videoFrame,textureCoordinate);gl_FragColor=memoryRender(pixelColor);}varyinghighpvec2textureCoordinate就是从vsh中传过来了纹理坐标uniformsampler2DvideoFrame是我们真正的纹理贴图texture2D(videoFrame,textureCoordinate)将纹理中的每个像素点颜色取出到pixelColor我们可以用memoryRender(pixelColor)将我们取到像素点重新加工总结:对于着色器的编程并不是很困难,完全是C的语法但是debug比较麻烦,对于类型的约束也很严格必须是相同类型的才能进行算术运算。我们理解了这两个文件之后就可以发挥我们的想象对纹理图片做出各种的处理。了解如何编写着色器之后我们就要在下篇开始了解如何把AVFoundation中取到的图片帧来与我们的着色器结合,从来绘制出高性能的滤镜。实时滤镜实现在了解了如何添加滤镜(http://blog.sina.com.cn/s/blog_7011f21c0101afz4.html)和着色器(http://blog.sina.com.cn/s/blog_7011f21c0101akez.html)下一步我们就可以来真正的实现实时滤镜效果了。 上节我们讲到在fsh里面有Sample2D这一个类型,其实这个就是我们需要的纹理,有了这个纹理我们就可以随意操纵这个纹理里面的像素点,那用他来产生滤镜效果也是轻而易举的事情了。所以首先要做的就是对原来的接收帧数据做改造,不是让他直接变成bitmap而是让他变成纹理,为此我们需要引入OpenGLESview(这个我们可以从opengles的模板工程里面取出来)。我们拿到回调中的数据CVImageBufferRefpixBuf=CMSampleBufferGetImageBuffer(sbuf);再利用以下代码就可以转成texture渲染在openglview上glGenTextures(1,&videoFrameTexture);glBindTexture(GL_TEXTURE_2D,videoFrameTexture);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//Thisisnecessaryfornon-power-of-twotexturesglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);//UsingBGRAextensiontopullinvideoframedatadirectlyglTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,bufferWidth,bufferHeight,0,GL_BGRA,GL_UNSIGNED_BYTE,CVPixelBufferGetBaseAddress(cameraFrame));通过从opengles模板中的shader加载函数我们就可以在上一篇所将的vshfsh中对像素点进行修改。这时我们可以看到操作三通道,四通道都是轻而易举没有降帧。当然对与高阶的滤镜效果我们可以自己生成噪点纹理或是其他效果的纹理做叠加,这个是我之前自己创建的油画纹理,原理很简单就是在当前像素某个范围内随机找出一个点用这个点的颜色来替换当前点从而造成一种扩散的效果intw=320;inth=460;intrange=6;UInt8*pixels=malloc(sizeof(UInt8)*w*h*4);intpixOff=0;intwOff=0;for(inty=0;y
此文档下载收益归作者所有
举报原因
联系方式
详细说明
内容无法转码请点击此处