GPUImage 是强大的图像处理库,基于其架构可以很简单的搭建起图像,视频采集,处理的应用。但如果要把其加入到一个成熟的商业系统中,则比较麻烦,需要修改已有的图像处理框架适应GPUImage的框架。
本博介绍一种简单的方法,直接把已有系统中的raw数据导入GPUImage的filter中,再读取回已有系统。
上代码:
- 先加入头文件:
#import <GPUImage/GPUImage.h>
- 在已有类中加入,GPUImage filter对象,GPUImageRawDataOutput是必须的,其他filter根据自己需要选择:在已有类中加入,GPUImage filter对象,GPUImageRawDataOutput是必须的,其他filter根据自己需要选择:
GPUImageBilateralFilter *_bilateralFilter;
GPUImageRawDataOutput *_rawdataOutput;
- 在已有类中加入,两个属性,semaphore用于主程序和gpuimage处理同步,rawBytesForImage用于gpuimage返回raw数据:
@property (nonatomic, strong) dispatch_semaphore_t semaphore;
@property (nonatomic) GLubyte *rawBytesForImage;
- 已有类初始化时,初始化GPUImage对象:
//setup:
_rawBytesForImage = (unsigned char*)malloc(1280*720*4);
_semaphore = dispatch_semaphore_create(0);
_rawdataOutput = [[GPUImageRawDataOutput alloc] initWithImageSize:CGSizeMake(1280.0,720.0) resultsInBGRAFormat:YES];
_bilateralFilter = [[GPUImageBilateralFilter alloc] init];
[_bilateralFilter setDistanceNormalizationFactor:(5)];
[_bilateralFilter addTarget:_rawdataOutput];
__weak GPUImageRawDataOutput *weakOutput = _rawdataOutput;
__weak typeof(self) ws = self;
__unsafe_unretained GPUImageRawDataOutput *_rawDataOutputFilter = _rawdataOutput;
[_rawdataOutput setNewFrameAvailableBlock:^{
__strong GPUImageRawDataOutput *strongOutput = weakOutput;
[_rawDataOutputFilter lockFramebufferForReading];
GLubyte *data = [_rawDataOutputFilter rawBytesForImage];
memcpy(ws.rawBytesForImage, data, 1280*720*4);
CGSize bufSize = [_rawDataOutputFilter maximumOutputSize];
[_rawDataOutputFilter unlockFramebufferAfterReading];
dispatch_semaphore_signal(ws.semaphore);
[_rawDataOutputFilter setImageSize:CGSizeMake(1280.0,720.0)];
}];
- 在已有类的图像处理函数中,调用GPUImage filter处理sampleBuffer中的数据,sampleBuffer是CMSampleBufferRef类型数据
CVImageBufferRef videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(videoFrame, 0);
uint8_t *baseAddress = (uint8_t *) CVPixelBufferGetBaseAddress(videoFrame);
size_t stride = CVPixelBufferGetBytesPerRow(videoFrame);
size_t width = CVPixelBufferGetWidth(videoFrame);
size_t height = CVPixelBufferGetHeight(videoFrame);
[GPUImageContext useImageProcessingContext];
GPUImageFramebuffer *outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:CGSizeMake(stride / 4, height) onlyTexture:YES];
[outputFramebuffer activateFramebuffer];
glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, stride / 4, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddress(videoFrame));
CVPixelBufferUnlockBaseAddress(videoFrame, 0);
CMTime time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
//simulate GPUImage call
[_bilateralFilter setInputSize:CGSizeMake(width, height) atIndex:0];
[_bilateralFilter setInputFramebuffer:outputFramebuffer atIndex:0];
[_bilateralFilter newFrameReadyAtTime:time atIndex:0];
size_t size = 1280*720*4;
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
memcpy(baseAddress, self.rawBytesForImage, size);
CVPixelBufferUnlockBaseAddress(videoFrame, 0);
最后重点:PC上数据从CPU导入GPU真是耗费CPU啊,尤其是在有独立显卡的机器上,GPU处理节约的时间还不够内存导入导出的。