2013-01-22 16 views
2

我目前正在運行CPU上的代碼,對灰度級 NSImage的列和行進行求和(即只有1個samplePerPixel)。我想我會嘗試將代碼移動到GPU(如果可能的話)。我發現CoreImage過濾器CIRowAverageCIColumnAverage看起來很相似。製作一個CoreImage過濾器,而不是總和所有行像素,類似於CIRowAverage?

在蘋果文檔上寫custom Core Image filters他們的狀態,

請記住,你的代碼不能從像素積累的知識像素。編寫代碼時一個好的策略是儘可能多地從實際的內核中移動不變的計算,並將其放置在過濾器的Objective-C部分。

這提示可能無法使用濾波器內核對像素求和。如果是這樣,上述函數如何設法得到一個區域的平均值?

所以我的問題是,什麼是最好的方式來實現一個圖像的行或列的總和,以獲得像素的總值。我應該堅持CPU嗎?

回答

4

核心圖像過濾器通過一系列的縮小來執行此平均。團隊中的前任工程師描述瞭如何在this GPU Gems chapter(根據第26.2.2節「查找質心」)下爲CIAreaAverage過濾器執行此操作。

我在談論減少my answer here的類似平均值。我在iOS上需要這種功能,因此我編寫了一個片段着色器,在水平和垂直維度上將圖像縮小四倍,在像素之間進行採樣,以便在每個步驟中將16個像素平均爲一個像素。一旦圖像縮小到足夠小的尺寸,剩下的像素就會被讀出並被平均以產生單個最終值。

這種減少在GPU上執行的速度仍然非常快,我可以在iPhone 4上以〜6 ms的速度從640x480視頻幀中提取平均顏色。當然,您還可以獲得更多在Mac上玩的馬力。

您可以採取類似的方法,通過在每個步驟中只減少一個方向或另一個方向。如果您有興趣獲得像素值的總和,則需要注意GPU上使用的像素格式的精度限制。默認情況下,RGBA顏色值存儲爲8位值,但某些GPU上的OpenGL(ES)擴展可讓您能夠渲染爲16位甚至32位浮點紋理,從而擴展動態範圍。我不確定,但我相信Core Image可讓您在Mac上使用32位浮點組件。

+0

謝謝你的建議。移動到GPU是我想的竅門。我的目的是處理像素亮度有意義的科學數據(光子到達事件)。保持一切線性是非常重要的,我不樂意將這類工作卸載到GPU上,除非我確信我完全理解它是如何工作的。不幸的是,CoreImage插件似乎將所有內容都轉換爲RGB,並且有時會爲圖像添加特殊的偏移和縮放因子(對於CIGaussianBlur爲true)。也許我會在需要拋光的時候解決這個問題!我需要學習OpenGL。 –

1

FYI上CIAreaAverage過濾器,它的編碼是這樣的:

CGRect inputExtent = [self.inputImage extent]; 
CIVector *extent = [CIVector vectorWithX:inputExtent.origin.x 
             Y:inputExtent.origin.y 
             Z:inputExtent.size.width 
             W:inputExtent.size.height]; 
CIImage* inputAverage = [CIFilter filterWithName:@"CIAreaAverage" keysAndValues:@"inputImage", self.inputImage, @"inputExtent", extent, nil].outputImage; 

//CIImage* inputAverage = [self.inputImage imageByApplyingFilter:@"CIAreaMinimum" withInputParameters:@{@"inputImage" : inputImage, @"inputExtent" : extent}]; 
EAGLContext *myEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 
NSDictionary *options = @{ kCIContextWorkingColorSpace : [NSNull null] }; 
CIContext *myContext = [CIContext contextWithEAGLContext:myEAGLContext options:options]; 

size_t rowBytes = 32 ; // ARGB has 4 components 
uint8_t byteBuffer[rowBytes]; // Buffer to render into 

[myContext render:inputAverage toBitmap:byteBuffer rowBytes:rowBytes bounds:[inputAverage extent] format:kCIFormatRGBA8 colorSpace:nil]; 

const uint8_t* pixel = &byteBuffer[0]; 
float red = pixel[0]/255.0; 
float green = pixel[1]/255.0; 
float blue = pixel[2]/255.0; 
NSLog(@"%f, %f, %f\n", red, green, blue); 

輸出應該是這個樣子:

2015-05-23 15:58:20.935 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196 
2015-05-23 15:58:20.981 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196