美文网首页图像处理
GPUImage Filter链(2)技术实现

GPUImage Filter链(2)技术实现

作者: 南风无影 | 来源:发表于2017-02-21 14:35 被阅读373次

    我要实现把(CVPixelBufferRef)pixel_buffer摄像头采集的数据,通过_rawDataInputFilter _rawDataOutputFilter加入到filter链, 再把数据传回来,实现接入第三方的filter。

    init初始化
    self.Process = [[ProcessPixelBuffer alloc]init];
    
    转化接口:
    CVPixelBufferRef output = NULL;
    [self.Process processWithCVPixelBuffer:pixel_buffer];
    output = pixel_buffer; //output转化后输出的数据
    

    转化工具processWithCVPixelBuffer代码:

    processWithCVPixelBuffer.m
    
    #import "ProcessPixelBuffer.h"
    #import "YFGPUImageCameraBeautyFilters.h"
    
    @interface ProcessPixelBuffer (){
        GPUImageFilter                  *_beautityFilter;
        GPUImageRawDataInput *_rawDataInputFilter;
        CVPixelBufferRef imageBuffer;
    
    }
    @property (nonatomic, strong) dispatch_semaphore_t semaphore;
    
    @end
    
    @implementation ProcessPixelBuffer
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            
            _semaphore = dispatch_semaphore_create(0);
    
            _rawDataInputFilter = [[GPUImageRawDataInput alloc] initWithBytes:nil size:CGSizeMake(0, 0)];
            
    
             _beautityFilter = [[GPUImageFilter alloc] initWithFragmentShaderFromString:kGPUImageBeautifyFragmentShaderString_Level_5];
            
            __weak typeof(self) ws = self;
            
            [_beautityFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
                GPUImageFramebuffer *imageFramebuffer = output.framebufferForOutput;
                glFinish();
                
                imageBuffer = [imageFramebuffer getRenderTarget];
                
                dispatch_semaphore_signal(ws.semaphore);
                
            }];
    
            [_rawDataInputFilter addTarget:_beautityFilter];
    
        }
        return self;
    }
    
    - (void)processWithCVPixelBuffer:(CVPixelBufferRef)pixelBuffer{
        
        CVPixelBufferLockBaseAddress(pixelBuffer, 0);
        
        //从 CVImageBufferRef 取得影像的细部信息
        uint8_t *base;
        size_t width, height, bytesPerRow, size;
        base = CVPixelBufferGetBaseAddress(pixelBuffer);
        width = CVPixelBufferGetWidth(pixelBuffer);
        height = CVPixelBufferGetHeight(pixelBuffer);
        bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
        
        [_rawDataInputFilter updateDataFromBytes:base size:CGSizeMake(bytesPerRow/4, height)];
        [_rawDataInputFilter processData];
        
        dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
        
        CVPixelBufferLockBaseAddress(imageBuffer, 0);
        
        uint8_t *data = CVPixelBufferGetBaseAddress(imageBuffer);
        size = CVPixelBufferGetDataSize(imageBuffer);
    
        memcpy(base,data,size);
        
        CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
        CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
    }
    
    -(void)dealloc{
        [_beautityFilter removeAllTargets];
    }
    @end
    
    
    
    
    processWithCVPixelBuffer.h
    
    
    #import <Foundation/Foundation.h>
    #import <CoreVideo/CoreVideo.h>
    
    @interface ProcessPixelBuffer : NSObject
    
    - (void)processWithCVPixelBuffer:(CVPixelBufferRef)pixelBuffer;
    
    @end
    
    修改GPUImage源码:
    GPUImageRawDataInput.m
    
    - (void)uploadBytes:(GLubyte *)bytesToUpload;
    {
        [GPUImageContext useImageProcessingContext];
    
        // TODO: This probably isn't right, and will need to be corrected
        outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:uploadedImageSize textureOptions:self.outputTextureOptions onlyTexture:YES];
        
        glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);
    //  glTexImage2D(GL_TEXTURE_2D, 0, _pixelFormat, (int)uploadedImageSize.width, (int)uploadedImageSize.height, 0, (GLint)_pixelFormat, (GLenum)_pixelType, bytesToUpload); //gongjia mask
    +    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)uploadedImageSize.width, (int)uploadedImageSize.height, 0, (GLint)GL_BGRA, (GLenum)_pixelType, bytesToUpload); //gongjia add
    }
    
    - (void)processData;
    {
        if (dispatch_semaphore_wait(dataUpdateSemaphore, DISPATCH_TIME_NOW) != 0)
        {
            return;
        }
        
        runAsynchronouslyOnVideoProcessingQueue(^{
      +      [GPUImageContext useImageProcessingContext]; //gongjia add
            CGSize pixelSizeOfImage = [self outputImageSize];
    
    GPUImageFrameBuffer.m新增
    // modified by gongjia
    - (CVPixelBufferRef)getRenderTarget {
        return renderTarget;
    }
    
    GPUImageFrameBuffer.h新增
    - (CVPixelBufferRef)getRenderTarget;
    

    这样改ProcessPixelBuffer.m还是有问题,进不去析构函数,原因就出在那个setFrameProcessingCompletionBlock上,这个坑前面遇到过,会造成cycle
    所以要用weak;
    __weak typeof(self) ws = self;

    #import "ProcessPixelBuffer.h"
    #import "YFGPUImageCameraBeautyFilters.h"
    
    @interface ProcessPixelBuffer (){
        GPUImageFilter                  *_beautityFilter;
        GPUImageRawDataInput *_rawDataInputFilter;
    }
    @property (nonatomic, strong) dispatch_semaphore_t semaphore;
    @property (nonatomic) CVPixelBufferRef imageBuffer;
    
    @end
    
    @implementation ProcessPixelBuffer
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            
            _semaphore = dispatch_semaphore_create(0);
    
            _rawDataInputFilter = [[GPUImageRawDataInput alloc] initWithBytes:nil size:CGSizeMake(0, 0)];
            
    
             _beautityFilter = [[GPUImageFilter alloc] initWithFragmentShaderFromString:kGPUImageBeautifyFragmentShaderString_Level_5];
            
            __weak typeof(self) ws = self;
            
            [_beautityFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
                GPUImageFramebuffer *imageFramebuffer = output.framebufferForOutput;
                glFinish();
                
                ws.imageBuffer = [imageFramebuffer getRenderTarget];
                
                dispatch_semaphore_signal(ws.semaphore);
                
            }];
    
            [_rawDataInputFilter addTarget:_beautityFilter];
    
        }
        return self;
    }
    
    - (void)processWithCVPixelBuffer:(CVPixelBufferRef)pixelBuffer{
        
        CVPixelBufferLockBaseAddress(pixelBuffer, 0);
        
        //从 CVImageBufferRef 取得影像的细部信息
        uint8_t *base;
        size_t width, height, bytesPerRow, size;
        base = CVPixelBufferGetBaseAddress(pixelBuffer);
        width = CVPixelBufferGetWidth(pixelBuffer);
        height = CVPixelBufferGetHeight(pixelBuffer);
        bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
        
        [_rawDataInputFilter updateDataFromBytes:base size:CGSizeMake(bytesPerRow/4, height)];
        [_rawDataInputFilter processData];
        
        dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
        
        CVPixelBufferLockBaseAddress(self.imageBuffer, 0);
        
        uint8_t *data = CVPixelBufferGetBaseAddress(self.imageBuffer);
        size = CVPixelBufferGetDataSize(self.imageBuffer);
    
        memcpy(base,data,size);
        
        CVPixelBufferUnlockBaseAddress(self.imageBuffer, 0);
        CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
    }
    
    -(void)dealloc{
        [_beautityFilter removeAllTargets];
    }
    @end
    
    

    参考的是GPUImageHistogramEqualizationFilter.m源码

    - (id)initWithHistogramType:(GPUImageHistogramType)newHistogramType
    {
        if (!(self = [super init]))
        {
            return nil;
        }
        
        histogramFilter = [[GPUImageHistogramFilter alloc] initWithHistogramType:newHistogramType];
        [self addFilter:histogramFilter];
        
        GLubyte dummyInput[4 * 256]; // NB: No way to initialise GPUImageRawDataInput without providing bytes
    
        //实现协议GPUImageInput,可以接受响应链的图像信息,并且以二进制的格式返回数据;
        rawDataInputFilter = [[GPUImageRawDataInput alloc] initWithBytes:dummyInput size:CGSizeMake(256.0, 1.0) pixelFormat:GPUPixelFormatBGRA type:GPUPixelTypeUByte];
    
        //继承GPUImageOutput类,可以接受二进制数据,按照特定的颜色格式,把数据转成图像并传入响应链
        rawDataOutputFilter = [[GPUImageRawDataOutput alloc] initWithImageSize:CGSizeMake(256.0, 3.0) resultsInBGRAFormat:YES];
        
        __unsafe_unretained GPUImageRawDataOutput *_rawDataOutputFilter = rawDataOutputFilter;
        __unsafe_unretained GPUImageRawDataInput *_rawDataInputFilter = rawDataInputFilter;
        [rawDataOutputFilter setNewFrameAvailableBlock:^{
            
            unsigned int histogramBins[3][256];
            
            [_rawDataOutputFilter lockFramebufferForReading];
    
            //属性: 二进制数据的指针;
            GLubyte *data  = [_rawDataOutputFilter rawBytesForImage];
            data += [_rawDataOutputFilter bytesPerRowInOutput];
    
            histogramBins[0][0] = *data++;
            histogramBins[1][0] = *data++;
            histogramBins[2][0] = *data++;
            data++;
            
            for (unsigned int x = 1; x < 256; x++) {
                histogramBins[0][x] = histogramBins[0][x-1] + *data++;
                histogramBins[1][x] = histogramBins[1][x-1] + *data++;
                histogramBins[2][x] = histogramBins[2][x-1] + *data++;
                data++;
            }
            
            [_rawDataOutputFilter unlockFramebufferAfterReading];
    
            GLubyte colorMapping[4 * 256];
            GLubyte *_colorMapping = colorMapping;
            
            for (unsigned int x = 0; x < 256; x++) {
                *_colorMapping++ = (GLubyte) (((histogramBins[0][x] - histogramBins[0][0]) * 255) / histogramBins[0][255]);
                *_colorMapping++ = (GLubyte) (((histogramBins[1][x] - histogramBins[1][0]) * 255) / histogramBins[1][255]);
                *_colorMapping++ = (GLubyte) (((histogramBins[2][x] - histogramBins[2][0]) * 255) / histogramBins[2][255]);
                *_colorMapping++ = 255;
            }
            
            _colorMapping = colorMapping;
            [_rawDataInputFilter updateDataFromBytes:_colorMapping size:CGSizeMake(256.0, 1.0)];
            [_rawDataInputFilter processData];
        }];
        [histogramFilter addTarget:rawDataOutputFilter];
        
        NSString *fragmentShader = nil;
        switch (newHistogramType) {
            case kGPUImageHistogramRed:
                fragmentShader = kGPUImageRedHistogramEqualizationFragmentShaderString;
                break;
            case kGPUImageHistogramGreen:
                fragmentShader = kGPUImageGreenHistogramEqualizationFragmentShaderString;
                break;
            case kGPUImageHistogramBlue:
                fragmentShader = kGPUImageBlueHistogramEqualizationFragmentShaderString;
                break;
            default:
            case kGPUImageHistogramRGB:
                fragmentShader = kGPUImageRGBHistogramEqualizationFragmentShaderString;
                break;
            case kGPUImageHistogramLuminance:
                fragmentShader = kGPUImageLuminanceHistogramEqualizationFragmentShaderString;
                break;
        }
        GPUImageFilter *equalizationFilter = [[GPUImageTwoInputFilter alloc] initWithFragmentShaderFromString:fragmentShader];
        [rawDataInputFilter addTarget:equalizationFilter atTextureLocation:1];
        
        [self addFilter:equalizationFilter];
        
        self.initialFilters = [NSArray arrayWithObjects:histogramFilter, equalizationFilter, nil];
        self.terminalFilter = equalizationFilter;
        
        self.downsamplingFactor = 16;
        
        return self;
    }
    
    

    相关文章

      网友评论

        本文标题:GPUImage Filter链(2)技术实现

        本文链接:https://www.haomeiwen.com/subject/kidewttx.html