2013-08-16 51 views
0

我的應用程序中有一個UICollectionView,它的單元格主要由UIImageView組成,其中包含已使用Core Image處理的圖像以減少顏色飽和度。滾動時的性能是非常糟糕的。當我描述它時,大部分時間(80%左右)都不在我的代碼中,甚至在我的堆棧中。這一切似乎都在覈心動畫代碼中。可能有人知道這可能是爲什麼?UICollectionView與使用Core Image控制的圖像的UIImageViews性能不佳

在我UICollectionViewCell小類我有這樣的事情:

UIImage *img = [self obtainImageForCell]; 
img = [img applySaturation:0.5]; 
self.imageView.image = img; 

applySaturation看起來是這樣的:

CIImage *image = [CIImage imageWithCGImage:self.CGImage]; 
CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"]; 
[filter setValue:image forKey:kCIInputImageKey]; 
[filter setValue:[NSNumber numberWithFloat:saturation] forKey:@"inputSaturation"]; 
return [UIImage imageWithCIImage:filter.outputImage]; 

我唯一的猜測是,核心動畫不與核心形象發揮出色。 Apple docs對此有所描述CIImage

儘管CIImage對象具有與其關聯的圖像數據,但它不是圖像。您可以將CIImage對象視爲圖像的「配方」。CIImage對象具有生成圖像所需的所有信息,但Core Image實際上並不會渲染圖像,除非被告知這樣做。這種「懶惰評估」方法允許Core Image儘可能高效地運行。

在動畫製作過程中最後一分鐘做這個評估可能會很棘手。

+1

您是否嘗試過一次過濾和緩存結果? –

+0

我看到相同的緩慢滾動行爲。 – openfrog

回答

2

我有完全相同的問題,通過在單元更新期間避免觸發核心圖像過濾器來解決問題。

蘋果公司關於懶惰評估/食譜的文檔是,我認爲,更有針對性的想法是你可以非常有效地將核心圖像過濾器鏈接在一起。但是,如果要顯示核心圖像過濾器鏈的結果,則需要在那裏和那裏對其進行評估,如果'then and there'在快速滾動視圖中並且篩選器處於問題需要大量處理(其中很多都是)。

你可以嘗試用GPU VS CPU處理擺弄,但我發現,運動圖像數據,並從CIImage的開銷可能會更顯著的開銷(見我的回答here

我的建議是治療這種處理方式與處理用在線圖像填充滾動視圖的方式相同 - 即異步處理,使用佔位符(例如預處理圖像),並緩存結果以供重用。

更新

在回答您的評論:當您從CIImage提取數據

適用的過濾器被應用 - 例如,用imageWithCIImage: [警告 - 這是我的推斷,我沒有測試]。

但這不是你的問題......你需要在背景線程上處理你的圖像,因爲處理過程需要時間來保持滾動。同時在滾動單元格中顯示其他內容,例如平面顏色或 - 更好 - 您將輸入到CIImage中的UIImage進行過濾。處理完成後更新單元格(檢查是否仍需要更新,到那時它可能會滾動到屏幕外)。將過濾後的圖像保存在某種持久性存儲中,以便不需要再次對其進行過濾,並在從頭開始重新處理之前,每當需要再次顯示圖像時檢查緩存。

+0

您如何建議強制過濾器立即應用? –

+0

@Jefferson先生,請參閱我的擴展回覆 – foundry

+0

我已經在使用'imageWithCIImage'。我應用飽和度的方法返回一個UIImage。當我剖析應用程序時,我的代碼不在繁重的堆棧跟蹤中;看起來Core Animation在滾動視圖滾動時必須應用圖像「recipe」。 –

0

我也有這個確切的問題 - 正確的想要去飽和一個圖像! - 過濾一次並緩存結果(即使是UIImage)也無濟於事。

正如其他人所提到的,問題在於,一個CIImage封裝了生成圖像所需的信息,但實際上並不是圖像本身。所以當滾動時,屏幕上的圖像需要動態生成,這會殺死性能。對於使用imageWithCIImage:scale:orientation:方法創建的UIImage也是如此,因此創建一次並重用它也無濟於事。

解決方案是強制CoreGraphics在將圖像保存爲UIImage之前實際渲染圖像。這給我的滾動性能帶來了巨大的改善。在你的情況下,applySaturation方法可能是這樣的:

CIImage *image = [CIImage imageWithCGImage:self.CGImage]; 
CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"]; 

[filter setValue:image forKey:kCIInputImageKey]; 
[filter setValue:[NSNumber numberWithFloat:saturation] forKey:@"inputSaturation"]; 

CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:filter.outputImage fromRect:filter.outputImage.extent]; 
UIImage *image = [UIImage imageWithCGImage:cgImage]; 
CGImageRelease(cgImage); 

return image; 

您也可以考慮緩存CIFilter和/或CIContext如果你打算使用這種方法很多,因爲這些可能是昂貴的創建。

相關問題