GPUImage作為iOS相當老牌的圖片處理三方庫已經有些日子了(2013年發布第一個版本),至今甚至感覺要離我們慢慢遠去(2015年更新了最后一個release)。可能現在分享這個稍微有點晚,再加上落影大神早已發布過此類文章,但是還是想從自己的角度來分享一下對其的理解和想法。
本文集所有內容皆為原創,嚴禁轉載。
? ? ? ? 第一篇有提到想試著翻譯一下GitHub中GPUImage的說明文檔來化解當時剛接觸時給我留下的不會用的痛,結果發現網上已有挺多大神完成了一字不差的翻譯工作。那我就選擇從其中挑選重點,以個人理解來解釋說明文檔重點部分的意思。
Overview? ? ? ??
GPUImage可以對圖片、攝像頭實時影像、視頻添加通過GPU加速的濾鏡和圖像處理效果。
與iOS5.0上的CoreImage框架比較,GPUImage的優勢:可以自定義濾鏡(通過自定義glsl語句來實現);不足:沒有人臉檢測等此類先進技術(話說現在已經相對不先進了吧。。)。
如果需要對圖片或者視頻進行大量計算,那么GPU實現可以說是首選,iPhone4上比較快了100倍。
使用GPU處理圖像需要編寫大量代碼才可實現,作者就先寫了一篇demo(http://www.sunsetlakesoftware.com/2010/10/22/gpu-accelerated-video-processing-mac-and-ios)。之后發現其實之間有很多可模版化的內容,再結合具體使用,最后開發出了GPUImage。意思就是使用GPUImage可以實現基于OpenGLES2.0的GPU處理圖像工作并且基本不需涉及OpenGLES2.0的api。
Technical requirements
iOS5+,ARC,有攝像頭,...現在已經不存在不滿足要求的吧。
General architecture
這個在第一篇當中已經大致說明我自己的理解,此處就照本翻譯。
GPUImage是通過OpenGL ES 2.0著色器實現圖片和視頻的處理計算,所以會比CPU更快。并且!在使用過程中不需要涉及復雜的OpenGLES2.0的api,而是提供封裝好的OC實現的類和方法即可實現圖片或視頻的多步驟處理操作、并能導出處理完成的結果。
視頻或圖片載入后會以GPUImageOutput的一種子類為類型的資源對象存在。GPUImage具備的資源類有:GPUImageVideoCamera、GPUImageStillCamera、GPUImagePicture、GPUImageMovie(我記得還有一種:GPUImageRawDataInput。具體使用之后細說)。資源對象會把圖片或視頻載入到紋理(OpenGLES中的一種存儲圖片信息的具體對象),并且把這些紋理傳入具體的處理流程。
在整個處理流程鏈中的濾鏡或者說除了輸入源之后的對象,都需要遵循GPUImageInput協議,只有這樣才能拿到上一個步驟處理完成的紋理進行相應處理。這些對象會經過預先設置好的所有目標對象中,并且處理過程中可以有多個分支的存在,即有多個下一步驟的路徑。
總結:通過GPUImage可以創建一個濾鏡鏈,鏈中可以有多個分支,載入所需輸入源后經過每個步驟的處理可得到一個或者多個結果。
Performing common tasks(挑重點)
Filtering live video
通過CustomShader.fsh(glsl語句構成)文件作為參數生成的自定義濾鏡customFilter可以作為一個目標(target)添加到從攝像頭獲取到的實時影像幀對象上。最終,這些經過濾鏡處理后的幀內容會顯示在一個繼承自UIView并且可以把紋理顯示出來的視圖(GPUImageView,其實最終是通過它的layer,即CAEAGLLayer對象來展示)上。
接下來提到了一個重點:GPUImageView的fillMode屬性。源碼中該屬性的每個枚舉都有簡短的解釋:1.kGPUImageFillModeStretch, ?// Stretch to fill the full view, which may distort the image outside of its normal aspect ratio。拉伸內容至填滿整個視圖,可能會照成圖片被不等比拉伸至變形。
2.kGPUImageFillModePreserveAspectRatio,? ? ? ? ? // Maintains the aspect ratio of the source image, adding bars of the specified background color。保持顯示圖片的原比例,在未鋪滿區域顯示設置的背景顏色。
3.kGPUImageFillModePreserveAspectRatioAndFill? ? // Maintains the aspect ratio of the source image, zooming in on its center to fill the view。保持顯示圖片的原比例,等比放大填充整個視圖并居中顯示。
這個fillMode在我實際項目中給我帶來了一些困擾。所以這里就先簡單翻譯,想在之后單獨針對GPUImageView的文章中詳細說明。
如果想在通過GPUImage錄制視頻時也把聲音錄進去,那么可以設置GPUImageVideoCamera對象的audioEncodingTarget屬性。
Capturing and filtering a still photo
這里提到的一點是:在某些設備上是支持不到2048或者更高像素的攝像頭圖片捕捉,原因是這些設備對紋理大小有相應的限制,翻開源碼,可以從繼承自GPUImageOutput的五個資源類中發現,初始化資源將信息寫入紋理時,會做一次資源文件大小的判斷。因為對應生成的紋理對象是根據資源文件大小來生成的,所以如果過大,則會使用當前設備所支持的最大紋理大小來進行生成。紋理既然作為一個編輯過程中實時存儲數據信息的對象,它也是會占據相應內存的,并且在處理過程中,如果紋理過大,或者說紋理中待處理的信息過多,也會給GPU帶來壓力。所以即使在使用GPUImage對圖片或者視頻進行處理的過程中,同樣需要注意處理資源的大小問題。
Processing a still image
對一張靜態圖片進行濾鏡或者其他效果處理可以說是GPUImage的基礎入門操作(我是這么認為)。
1.使用GPUImagePicture的初始化方法,可以將一張靜態圖片載入到紋理中。不過GPUImagePicture的初始化方法有好幾個,具體區別同樣之后再細說。
2.可以通過繼承自GPUImageFilter的類的對象調用imageFromCurrentFramebuffer方法得到處理后的圖片。但如果要使用這種方法導出圖片,則必須要在GPUImagePicture對象執行processImage方法之前執行濾鏡對象的useNextFrameForImageCapture方法,否則按照GPUImage的源碼來看注定會crash,控制臺的提示“Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?”。
3.另一種導出處理圖片的方法是調用濾鏡對象的imageByFilteringImage方法,入參為UIImage對象。
Writing a custom filter
GPUImage相比CoreImage另一個大優勢在于可以自定義濾鏡,通過glsl語言(OpenGL Shading Language,十分類似C語言的OpenGL著色器語言)實現。GPUImage庫中的絕大多數濾鏡都是通過自定義的glsl語句進行對片段著色器操作,之前也有說過,因為大多數濾鏡只改變紋理內容,并不會涉及到如何貼圖,或者說如何展示紋理。
Filtering and re-encoding a movie
視頻文件通過GPUImageMovie類載入,GPUImageMovieWriter類導出。需要注意的點有:
1.記錄,或者說處理完成后,需要將GPUImageMovieWriter對象從上一個target(一般都為GPUImageFilter對象)中移除,并且調用自身的finishRecording方法。
2.如果在記錄完成前壞了,那之前的處理導出內容也沒了。
Interacting with OpenGL ES
通過GPUImage的GPUImageTextureOutput和GPUImageTextureInput類,可以從OpenGLES中導入或者導出紋理。使用這種方式的過程中要注意,待處理的紋理需要通過類似共享群組的東西在GPUImage自身的OpenGLES的context和其他context之間實現共享。
Built-in filters
GPUImage庫中提供125種左右的內建濾鏡。
這個我記得網上已經有大神對文檔中有說明的濾鏡做了詳細的翻譯,之后會針對比較常用或者特殊的濾鏡做詳細說明,此處就不翻譯了。
Sample applications
又想起第一次接觸GPUImage時,不看文檔直接download,run,完了完全不知道每個demo的具體實現內容。所以建議初學者在接觸到新的三方庫或者源碼時,不要急著run,先看看文檔或者源碼注釋,可能會更好上手。
1.SimpleImageFilter:對一張靜態圖片進行濾鏡操作,保存到disk。
2.SimpleVideoFilter:馬賽克錄像,滑桿可調整馬賽克顆粒大小。
3.SimpleVideoFileFilter:對disk中的視頻文件進行虛化處理,并保存為另一個視頻文件。
4.MultiViewFilterExample:攝像頭實時濾鏡效果,多個濾鏡疊加,并且其中兩個是自定義濾鏡。
5.FilterShowcase:GPUImage內建濾鏡的全部展示,這個demo中的判斷語句優點復雜。
6.BenchmarkSuite:GPUImage與基于CPU實現的圖片處理效果以及CoreImage做的處理效率比較。
7.CubeExample:說明GPUImage與OpenGLES渲染的相互關系。給攝像頭獲取到的每一幀內容加上sepia(烏賊色效果?)的濾鏡并且顯示在一個立方體的表面,可以用手機旋轉立方體。立方體被渲染成一個texture-backed(沒懂)的frambuffer對象,再反饋給GPUImage進行馬賽克處理后顯示。
7.ColorObjectTracking:待解釋。