GPUImage源码解读(十)

iOS小结(四) GPUImage加速图像处理 在ios中大量用到图像处理的app, 如果想要加速, 大体有三个办法可以选择:   Core Image framework  vImage, 在Accerlerate.framework中  GPUImage 第三方库              GPUImage 是 BradLarson 写的开源库,主要提供了一些 filter 的 shader, 外包了一层与 IOS的 UIIma 阅读详情

GPUImageVideoCamera继承自GPUImageOutput,实现了 AVCaptureVideoDataOutputSampleBufferDelegate 和 AVCaptureAudioDataOutputSampleBufferDelegate 协议。GPUImageVideoCamera可以调用相机进行视频拍摄,拍摄之后会生成帧缓存对象,我们可以使用GPUImageView显示,也可以使用GPUImageMovieWriter保存为视频文件。同时也提供了GPUImageVideoCameraDelegate 代理,方便我们自己处理CMSampleBuffer。

  • 属性列表。属性中大多数是与相机相关的相关参数。
/// The AVCaptureSession used to capture from the camera
// AVCaptureSession对象
@property(readonly, retain, nonatomic) AVCaptureSession *captureSession;

/// This enables the capture session preset to be changed on the fly
// 视频输出的质量、大小的控制参数。如:AVCaptureSessionPreset640x480
@property (readwrite, nonatomic, copy) NSString *captureSessionPreset;

/// This sets the frame rate of the camera (iOS 5 and above only)
/**
 Setting this to 0 or below will set the frame rate back to the default setting for a particular preset.
 */
// 视频的帧率
@property (readwrite) int32_t frameRate;

/// Easy way to tell which cameras are present on device
// 正在使用哪个相机 前后置
@property (readonly, getter = isFrontFacingCameraPresent) BOOL frontFacingCameraPresent;
@property (readonly, getter = isBackFacingCameraPresent) BOOL backFacingCameraPresent;

/// This enables the benchmarking mode, which logs out instantaneous and average frame times to the console
// 实时日志输出
@property(readwrite, nonatomic) BOOL runBenchmark;

/// Use this property to manage camera settings. Focus point, exposure point, etc.
// 正在使用的相机对象,方便设置参数 对焦等
@property(readonly) AVCaptureDevice *inputCamera;

/// This determines the rotation applied to the output image, based on the source material
// 输出图片的方向
@property(readwrite, nonatomic) UIInterfaceOrientation outputImageOrientation;

/// These properties determine whether or not the two camera orientations should be mirrored. By default, both are NO.
// 前置相机水平镜像
@property(readwrite, nonatomic) BOOL horizontallyMirrorFrontFacingCamera, horizontallyMirrorRearFacingCamera;

// GPUImageVideoCameraDelegate代理
@property(nonatomic, assign) id<GPUImageVideoCameraDelegate> delegate;

GPUImageVideoCamera初始化的时候需要传递视频质量以及使用哪个相机。如果直接调用 - (instancetype)init 则会使用 AVCaptureSessionPreset640x480 和 AVCaptureDevicePositionBack 来初始化。

- (id)initWithSessionPreset:(NSString *)sessionPreset cameraPosition:(AVCaptureDevicePosition)cameraPosition;
{
    if (!(self = [super init]))
    {
        return nil;
    }

     // 创建音视频处理队列 audio DISPATCH_QUEUE_PRIORITY_LOW camera  DISPATCH_QUEUE_PRIORITY_HIGH
    cameraProcessingQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
    audioProcessingQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0);

     // 创建信号量
    frameRenderingSemaphore = dispatch_semaphore_create(1);

      // 变量的初始化
    _frameRate = 0; // This will not set frame rate unless this value gets set to 1 or above
    _runBenchmark = NO;
    capturePaused = NO;
    outputRotation = kGPUImageNoRotation;
    internalRotation = kGPUImageNoRotation;
    captureAsYUV = YES;
    _preferredConversion = kColorConversion709;

    // 根据传入参数获取前后相机
    // Grab the back-facing or front-facing camera
    _inputCamera = nil;
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *device in devices)
    {
        if ([device position] == cameraPosition)
        {
            _inputCamera = device;
        }
    }

      // 获取相机失败,创建失败
    if (!_inputCamera) {
        return nil;
    }

    // Create the capture session
    _captureSession = [[AVCaptureSession alloc] init];

    [_captureSession beginConfiguration];

    // 创建video输入对象
    // Add the video input
    NSError *error = nil;
    videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_inputCamera error:&error];
    if ([_captureSession canAddInput:videoInput])
    {
        [_captureSession addInput:videoInput];
    }

    // Add the video frame output
    // 创建video输出对象
    videoOutput = [[AVCaptureVideoDataOutput alloc] init];
    [videoOutput setAlwaysDiscardsLateVideoFrames:NO];

//    if (captureAsYUV && [GPUImageContext deviceSupportsRedTextures])
    // 设置YUV的处理方式
    if (captureAsYUV && [GPUImageContext supportsFastTextureUpload])
    {
        BOOL supportsFullYUVRange = NO;
        NSArray *supportedPixelFormats = videoOutput.availableVideoCVPixelFormatTypes;
        for (NSNumber *currentPixelFormat in supportedPixelFormats)
        {
            if ([currentPixelFormat intValue] == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange)
            {
                supportsFullYUVRange = YES;
            }
        }

        //支持 full  YUV 格式
        if (supportsFullYUVRange)
        {
            // 设置kCVPixelFormatType_420YpCbCr8BiPlanarFullRange格式
            [videoOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
            isFullYUVRange = YES;
        }
        else
        {
            // 设置kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange格式
            [videoOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
            isFullYUVRange = NO;
        }
    }
    else
    {
        // 设置kCVPixelFormatType_32BGRA格式
        [videoOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
    }

    // 创建GL程序、获取属性位置
    runSynchronouslyOnVideoProcessingQueue(^{

        if (captureAsYUV)
        {
            [GPUImageContext useImageProcessingContext];
            //            if ([GPUImageContext deviceSupportsRedTextures])
            //            {
            //                yuvConversionProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:kGPUImageVertexShaderString fragmentShaderString:kGPUImageYUVVideoRangeConversionForRGFragmentShaderString];
            //            }
            //            else
            //            {
            if (isFullYUVRange)
            {
                yuvConversionProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:kGPUImageVertexShaderString fragmentShaderString:kGPUImageYUVFullRangeConversionForLAFragmentShaderString];
            }
            else
            {
                yuvConversionProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:kGPUImageVertexShaderString fragmentShaderString:kGPUImageYUVVideoRangeConversionForLAFragmentShaderString];
            }

            //            }

            if (!yuvConversionProgram.initialized)
            {
                [yuvConversionProgram addAttribute:@"position"];
                [yuvConversionProgram addAttribute:@"inputTextureCoordinate"];

                if (![yuvConversionProgram link])
                {
                    NSString *progLog = [yuvConversionProgram programLog];
                    NSLog(@"Program link log: %@", progLog);
                    NSString *fragLog = [yuvConversionProgram fragmentShaderLog];
                    NSLog(@"Fragment shader compile log: %@", fragLog);
                    NSString *vertLog = [yuvConversionProgram vertexShaderLog];
                    NSLog(@"Vertex shader compile log: %@", vertLog);
                    yuvConversionProgram = nil;
                    NSAssert(NO, @"Filter shader link failed");
                }
            }

            yuvConversionPositionAttribute = [yuvConversionProgram attributeIndex:@"position"];
            yuvConversionTextureCoordinateAttribute = [yuvConversionProgram attributeIndex:@"inputTextureCoordinate"];
            yuvConversionLuminanceTextureUniform = [yuvConversionProgram uniformIndex:@"luminanceTexture"];
            yuvConversionChrominanceTextureUniform = [yuvConversionProgram uniformIndex:@"chrominanceTexture"];
            yuvConversionMatrixUniform = [yuvConversionProgram uniformIndex:@"colorConversionMatrix"];

            [GPUImageContext setActiveShaderProgram:yuvConversionProgram];

            glEnableVertexAttribArray(yuvConversionPositionAttribute);
            glEnableVertexAttribArray(yuvConversionTextureCoordinateAttribute);
        }
    });


    // 设置AVCaptureVideoDataOutputSampleBufferDelegate代理
    [videoOutput setSampleBufferDelegate:self queue:cameraProcessingQueue];
    // 添加输出
    if ([_captureSession canAddOutput:videoOutput])
    {
        [_captureSession addOutput:videoOutput];
    }
    else
    {
        NSLog(@"Couldn't add video output");
        return nil;
    }

    // 设置视频质量
    _captureSessionPreset = sessionPreset;
    [_captureSession setSessionPreset:_captureSessionPreset];

// This will let you get 60 FPS video from the 720p preset on an iPhone 4S, but only that device and that preset
//    AVCaptureConnection *conn = [videoOutput connectionWithMediaType:AVMediaTypeVideo];
//    
//    if (conn.supportsVideoMinFrameDuration)
//        conn.videoMinFrameDuration = CMTimeMake(1,60);
//    if (conn.supportsVideoMaxFrameDuration)
//        conn.videoMaxFrameDuration = CMTimeMake(1,60);

    // 提交配置
    [_captureSession commitConfiguration];

    return self;
}
  • 其它方法。GPUImageVideoCamera方法大致分为这几类:1、添加输入输出设备;2、捕获视频;3、处理音视频;4、相机参数设置;
//添加、移除音频输入输出
/** Add audio capture to the session. Adding inputs and outputs freezes the capture session momentarily, so you
    can use this method to add the audio inputs and outputs early, if you're going to set the audioEncodingTarget
    later. Returns YES is the audio inputs and outputs were added, or NO if they had already been added.
 */
- (BOOL)addAudioInputsAndOutputs;

/** Remove the audio capture inputs and outputs from this session. Returns YES if the audio inputs and outputs
    were removed, or NO is they hadn't already been added.
 */
- (BOOL)removeAudioInputsAndOutputs;

//移除所有输入输出
/** Tear down the capture session
 */
- (void)removeInputsAndOutputs;

/// @name Manage the camera video stream

/** Start camera capturing 开始相机捕获
 */
- (void)startCameraCapture;

/** Stop camera capturing  关闭相机捕获
 */
- (void)stopCameraCapture;

/** Pause camera capturing 暂停相机捕获
 */
- (void)pauseCameraCapture;

/** Resume camera capturing 恢复相机捕获
 */
- (void)resumeCameraCapture;

// 处理视频数据
/** Process a video sample
 @param sampleBuffer Buffer to process
 */
- (void)processVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer;

// 处理音频数据
/** Process an audio sample
 @param sampleBuffer Buffer to process
 */
- (void)processAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer;

// 获取相机相关参数
/** Get the position (front, rear) of the source camera
 */
- (AVCaptureDevicePosition)cameraPosition;

/** Get the AVCaptureConnection of the source camera
 */
- (AVCaptureConnection *)videoCaptureConnection;

// 变换相机
/** This flips between the front and rear cameras
 */
- (void)rotateCamera;


// 获取平均帧率
/// @name Benchmarking

/** When benchmarking is enabled, this will keep a running average of the time from uploading, processing, and final recording or display
 */
- (CGFloat)averageFrameDurationDuringCapture;

// 重置相关基准
- (void)resetBenchmarkAverage;

//当前是前后置判断
+ (BOOL)isBackFacingCameraPresent;
+ (BOOL)isFrontFacingCameraPresent;

  • 其它主要方法,视频数据处理
- (void)processVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer;
{
    if (capturePaused)
    {
        return;
    }

    CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
    CVImageBufferRef cameraFrame = CMSampleBufferGetImageBuffer(sampleBuffer);
    // 获取视频宽高
    int bufferWidth = (int) CVPixelBufferGetWidth(cameraFrame);
    int bufferHeight = (int) CVPixelBufferGetHeight(cameraFrame);
    CFTypeRef colorAttachments = CVBufferGetAttachment(cameraFrame, kCVImageBufferYCbCrMatrixKey, NULL);
    if (colorAttachments != NULL)
    {
        if(CFStringCompare(colorAttachments, kCVImageBufferYCbCrMatrix_ITU_R_601_4, 0) == kCFCompareEqualTo)
        {
            if (isFullYUVRange)
            {
                _preferredConversion = kColorConversion601FullRange;
            }
            else
            {
                _preferredConversion = kColorConversion601;
            }
        }
        else
        {
            _preferredConversion = kColorConversion709;
        }
    }
    else
    {
        if (isFullYUVRange)
        {
            _preferredConversion = kColorConversion601FullRange;
        }
        else
        {
            _preferredConversion = kColorConversion601;
        }
    }

    CMTime currentTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);

    [GPUImageContext useImageProcessingContext];

    // 快速YUV纹理生成
    if ([GPUImageContext supportsFastTextureUpload] && captureAsYUV)
    {
        CVOpenGLESTextureRef luminanceTextureRef = NULL;
        CVOpenGLESTextureRef chrominanceTextureRef = NULL;

//        if (captureAsYUV && [GPUImageContext deviceSupportsRedTextures])
        if (CVPixelBufferGetPlaneCount(cameraFrame) > 0) // Check for YUV planar inputs to do RGB conversion
        {
            CVPixelBufferLockBaseAddress(cameraFrame, 0);

            if ( (imageBufferWidth != bufferWidth) && (imageBufferHeight != bufferHeight) )
            {
                imageBufferWidth = bufferWidth;
                imageBufferHeight = bufferHeight;
            }

            CVReturn err;
            // Y-plane Y分量
            glActiveTexture(GL_TEXTURE4);
            if ([GPUImageContext deviceSupportsRedTextures])
            {
//                err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, coreVideoTextureCache, cameraFrame, NULL, GL_TEXTURE_2D, GL_RED_EXT, bufferWidth, bufferHeight, GL_RED_EXT, GL_UNSIGNED_BYTE, 0, &luminanceTextureRef);
                err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], cameraFrame, NULL, GL_TEXTURE_2D, GL_LUMINANCE, bufferWidth, bufferHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0, &luminanceTextureRef);
            }
            else
            {
                err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], cameraFrame, NULL, GL_TEXTURE_2D, GL_LUMINANCE, bufferWidth, bufferHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0, &luminanceTextureRef);
            }
            if (err)
            {
                NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
            }

            luminanceTexture = CVOpenGLESTextureGetName(luminanceTextureRef);
            glBindTexture(GL_TEXTURE_2D, luminanceTexture);
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

            // UV-plane  UV分量(Width/2 = Width/4 + Width/4)
            glActiveTexture(GL_TEXTURE5);
            if ([GPUImageContext deviceSupportsRedTextures])
            {
//                err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, coreVideoTextureCache, cameraFrame, NULL, GL_TEXTURE_2D, GL_RG_EXT, bufferWidth/2, bufferHeight/2, GL_RG_EXT, GL_UNSIGNED_BYTE, 1, &chrominanceTextureRef);
                err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], cameraFrame, NULL, GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, bufferWidth/2, bufferHeight/2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, &chrominanceTextureRef);
            }
            else
            {
                err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], cameraFrame, NULL, GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, bufferWidth/2, bufferHeight/2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, &chrominanceTextureRef);
            }
            if (err)
            {
                NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
            }

            chrominanceTexture = CVOpenGLESTextureGetName(chrominanceTextureRef);
            glBindTexture(GL_TEXTURE_2D, chrominanceTexture);
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

//            if (!allTargetsWantMonochromeData)
//            {
                [self convertYUVToRGBOutput];
//            }

            int rotatedImageBufferWidth = bufferWidth, rotatedImageBufferHeight = bufferHeight;

            if (GPUImageRotationSwapsWidthAndHeight(internalRotation))
            {
                rotatedImageBufferWidth = bufferHeight;
                rotatedImageBufferHeight = bufferWidth;
            }

            [self updateTargetsForVideoCameraUsingCacheTextureAtWidth:rotatedImageBufferWidth height:rotatedImageBufferHeight time:currentTime];

            CVPixelBufferUnlockBaseAddress(cameraFrame, 0);
            CFRelease(luminanceTextureRef);
            CFRelease(chrominanceTextureRef);
        }
        else
        {
            // TODO: Mesh this with the output framebuffer structure

//            CVPixelBufferLockBaseAddress(cameraFrame, 0);
//            
//            CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], cameraFrame, NULL, GL_TEXTURE_2D, GL_RGBA, bufferWidth, bufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0, &texture);
//            
//            if (!texture || err) {
//                NSLog(@"Camera CVOpenGLESTextureCacheCreateTextureFromImage failed (error: %d)", err);
//                NSAssert(NO, @"Camera failure");
//                return;
//            }
//            
//            outputTexture = CVOpenGLESTextureGetName(texture);
//            //        glBindTexture(CVOpenGLESTextureGetTarget(texture), outputTexture);
//            glBindTexture(GL_TEXTURE_2D, outputTexture);
//            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//            
//            [self updateTargetsForVideoCameraUsingCacheTextureAtWidth:bufferWidth height:bufferHeight time:currentTime];
//
//            CVPixelBufferUnlockBaseAddress(cameraFrame, 0);
//            CFRelease(texture);
//
//            outputTexture = 0;
        }

        // 帧率
        if (_runBenchmark)
        {
            numberOfFramesCaptured++;
            if (numberOfFramesCaptured > INITIALFRAMESTOIGNOREFORBENCHMARK)
            {
                CFAbsoluteTime currentFrameTime = (CFAbsoluteTimeGetCurrent() - startTime);
                totalFrameTimeDuringCapture += currentFrameTime;
                NSLog(@"Average frame time : %f ms", [self averageFrameDurationDuringCapture]);
                NSLog(@"Current frame time : %f ms", 1000.0 * currentFrameTime);
            }
        }
    }
    else
    {
        // 锁定基地址
        CVPixelBufferLockBaseAddress(cameraFrame, 0);
        // 获取每行的字节宽度(width * 4)
        int bytesPerRow = (int) CVPixelBufferGetBytesPerRow(cameraFrame);
        // 获取帧缓存
        outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:CGSizeMake(bytesPerRow / 4, bufferHeight) onlyTexture:YES];
        [outputFramebuffer activateFramebuffer];

        // 激活纹理
        glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);

        //        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bufferWidth, bufferHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddress(cameraFrame));

         // BGRA转RGBA
        // Using BGRA extension to pull in video frame data directly
        // The use of bytesPerRow / 4 accounts for a display glitch present in preview video frames when using the photo preset on the camera
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bytesPerRow / 4, bufferHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddress(cameraFrame));

        [self updateTargetsForVideoCameraUsingCacheTextureAtWidth:bytesPerRow / 4 height:bufferHeight time:currentTime];

        CVPixelBufferUnlockBaseAddress(cameraFrame, 0);

        // 更新帧率
        if (_runBenchmark)
        {
            numberOfFramesCaptured++;
            if (numberOfFramesCaptured > INITIALFRAMESTOIGNOREFORBENCHMARK)
            {
                CFAbsoluteTime currentFrameTime = (CFAbsoluteTimeGetCurrent() - startTime);
                totalFrameTimeDuringCapture += currentFrameTime;
            }
        }
    }  
}
  • 音频数据处理 由于 processAudioSampleBuffer 直接交给audioEncodingTarget(GPUImageMovieWriter)处理AudioBuffer。因此,录制视频的时候如果需要加入声音需要设置audioEncodingTarget。否则,录制出的视频就没有声音,声音处理后面在 GPUImageMovieWriter中详细 说明.
遗传算法驱动吃豆人进化:从零构建AI游戏智能体 遗传算法是一种模拟自然选择过程的优化技术,其核心原理是通过选择、交叉和变异等操作,在解空间中迭代搜索最优解。该技术为解决复杂优化问题提供了强大工具,尤其在游戏AI、机器人控制和参数调优等场景中价值显著。在游戏AI领域,遗传算法常被用于训练智能体自主决策,例如在经典游戏《吃豆人》中,通过定义智能体的“基因”(如神经网络权重)和“适应度”(如游戏得分),可以引导其进化出躲避幽灵、高效吃豆等策略。本项目结合Pygame框架与神经网络,构建了一个完整的遗传算法训练沙盒,详细展示了如何通过适应度函数设计和参数调优,实 阅读详情

相关推荐

【SABRE 3D, SABRE 3DxT,LAM设备】2025年9月12日-生产期间维护用的双重隔离

生产期间维护用的双重隔离。该程序用于准备将一个或多个双工位设置为维护状态,同时SABRE 3D/3DxT/3D Scimitar保持生产运行。其目的是在不中断生产的情况下将双工位与运行中的设备隔离。

weixin_46735260的博客 574

YUV 与 颜色空间转换

BT601 和 BT709由于在处理相机实时图像数据时,需要将相机采集的YUV数据转换为RGB,根据GPUImage的源码看到是有三种转换矩阵用于将YUV数据转换成RGB数据,分别是//BT.601,whichisthestandardforSDTV. GLfloatkColorConversion601Default[]={ 1.164,1.16...

音视频开发进阶 1514

电力市场小白必看:手把手教你用Matlab实现市场出清电价计算(附完整代码)

本文为电力市场初学者提供了使用Matlab计算市场出清电价的完整指南。通过Yalmip和Matpower工具包,详细讲解了从环境配置到模型构建、求解及结果分析的整个过程,帮助读者快速掌握节点电价计算的核心技术。

weixin_30379531的博客 73

Metal 案例06:视频文件渲染

本案例的目的在于理解本地视频文件渲染的过程 整体的效果图如下 整体的流程图如下 主要分为三部分 viewDidLoad函数:绘制前的准备工作 MTKViewDelegate协议:视频文件渲染 Metal着色文件:处理顶点数据,以及将YUV转换为RGB格式显示 准备工作 在此之前还需要作一些准备 创建OC与C共用的.h文件 AVassetreader工具类 共用文件 主要包含以下内容 顶点数据结构体 //顶点数据结构 typedef struct { //顶点坐标(x,y,z,w)

lin1109221208的博客 1197

一文读懂世界模型(World Model):AI的“数字大脑”,通往AGI的核心基石

世界模型正成为AI领域的关键技术,它让AI在虚拟环境中模拟物理世界规律并预测行动后果,从而减少现实试错成本。2018年Ha和Schmidhuber提出的VAE+RNN架构奠定基础,2022年后自监督学习推动快速发展。当前世界模型分为潜空间、生成式、强化学习和对象中心四大流派,已在机器人、自动驾驶、工业仿真等领域落地应用。尽管面临长时序预测误差等挑战,未来将向多模态建模、大模型融合等方向发展,成为实现具身智能和通用人工智能的核心基石。

m0_38116472的博客 805

STM32的DMA模块及Protues仿真实验

(一)DMA简介      DMA(Direct Memory Access,直接存储器访问), 用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可 供其它操作使用。      STM32F407共有两个 DMA 控制器,总共有 16 个数据流(每个控制器 8 个),每一个 DMA 控制器都用于管理 一个或多

weixin_45930204的博客 2850

AdMob接入踩坑记

转载自: http://blog.youkuaiyun.com/d744784681/article/details/60574700 首先列出参考文档:admob官方参考链接 我是cocos2d-x v3.9的工程,在按照官方文档接入之后,出现一堆编译错误例如: [plain] view plain copy Undefined symbo

沸腾的泪水的专栏 3522

Fast-LIO2代码解析 古月居

FAST-LIO,FAST-LIO2与FASTER-LIO - 古月居FAST-LIO2代码解析(一) - 古月居FAST-LIO2代码解析(二) - 古月居FAST-LIO2代码解析(三) - 古月居FAST-LIO2代码解析(四) - 古月居FAST-LIO2代码解析(五) - 古月居FAST-LIO2代码解析(六) - 古月居

li4692625的博客 2784

LYOpenGLView

Shader.fsh/******************************************/varying highp vec2 texCoordVarying; // 接收从顶点着色器过来的顶点颜色数precision mediump float; // 设置工作精度 uniform sampler2D SamplerY; // 纹理采样器uniform ...

weixin_33705053的博客 175

【推荐100个unity插件】在unity快速生成3D人物自然姿势和动作,且支持按图像生成姿势—— Pose AI

PoseAI是一款基于肌肉的智能动画创作工具,通过神经网络和逆运动学技术实现自然姿势生成。主要功能包括:自动/手动角色设置、神经控制装备、姿态估计与预览等。工具支持从2D图像生成3D姿势,并能在编辑器中实时预览动画效果。其神经网络架构采用前馈网络与ResNet结合的方式,通过多层全连接和ReLU激活函数处理输入数据。PoseAI简化了动画制作流程,提供高效的姿势创作解决方案,适用于Unity游戏开发。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 1361

【大语言模型 21】语言模型训练目标:MLM vs CLM vs GLM对比分析

本文深入对比分析三种主流语言模型训练目标:掩码语言模型(MLM)、因果语言模型(CLM)和双空白填充(GLM)。通过数学推导、代码实现和实验对比,揭示不同训练目标的工作机制、适用场景和性能差异,为选择合适的预训练策略提供科学指导。

熵数实验室 1174

iOS播放与编辑HDR视频

在iPhone12发布后,支持使用Dolby Vision来录制HDR视频。至此,升级到iOS14.1系统后,已经支持录制、播放、编辑和导出HDR视频。

徐福记456 2360

电源完整性分析:PDN阻抗与去耦电容设计——目标阻抗计算与电容选型深度实战

摘要:随着嵌入式处理器主频突破 GHz、多核架构普及,电源完整性(Power Integrity, PI)已成为高速 PCB 设计中不可忽视的关键环节。本文从 PDN(电源分配网络)阻抗模型出发,系统讲解目标阻抗计算方法、去耦电容选型策略、反谐振抑制技术,并结合 STM32F4 核心板的完整设计实例,提供一套可落地的电源完整性工程实践方案。电源完整性设计是一项系统工程,需要从目标阻抗计算电容选型反谐振抑制PCB 布局目标阻抗是设计的起点,由电源电压、纹波要求和瞬态电流决定去耦电容。

从事移动开发八年,csdn博客专家,阿里云特邀专家,华为云云享专家,高级网络信息安全工程师,大数据工程师(高级),python技术开发(高级),HarmonyOS 应用开发者高级认证,现在某学校任教。 1万+

GPUImage 源码分析

GPUImage源码解读 介绍 GitHub - cats-oss/android-gpuimage: Android filters based on OpenGL (idea from GPUImage for iOS) 做图片或者视频滤镜渲染,离不开 OpenGL,而在移动平台上最令人熟知的就是 GitHub - BradLarson/GPUImage2: GPUImage 2 is ...

crazy_jack 2173

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

iOS GPUImage研究总结

关于GPUImage 这里直接引用官方描述:GPUImage是使用GPU处理图像的、他可以对图片、实时画面、视频进行处理。他允许你自定义滤镜、支持iOS4.0。然而,目前缺乏核心形象的一些更高级的功能,比如面部检测。

Quinn's blog ! I'm glad to be here! 1万+

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

iOS GPUImage源码解读

前言 GPUImage是iOS上一个基于OpenGL进行图像处理的开源框架,内置大量滤镜,架构灵活,可以在其基础上很轻松地实现各种图像处理功能。本文主要向大家分享一下项目的核心架构、源码解读及使用心得。 GPUImage有哪些特性 丰富的输入组件 摄像头、图片、视频、OpenGL纹理、二进制数据、UIElement(UIView, CALayer) 大量现成的内置滤镜(4大类) 1). 颜...

majiakun1的专栏 3613

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

打造自己的GPUImage

学习路线与方法 本人16年,因直播的需要,开始接触GPUImage、然后学习OpenGL ES;OpenGL ES的门槛比较高,如果没有人带,入门就比较费劲;很长一段时间,大概有半年,有时明明觉得看的都懂了,过一段时间又会忘记,或者在实际应用中就整个垮掉; 在iOS的日常开发中,由于我自工作以来接触到的App都是直播类或者相机类产品,所以对图像知识有所了解,但又一知半解,难以深入,后来在开发的过...

Quinn's blog ! I'm glad to be here! 994

iOS开发——GPUImage源码解析

一、基本概念 GPUImage:一个开源的、基于openGL的图片或视频的处理框架,其本身内置了多达120多种常见的滤镜效果,并且支持照相机和摄像机的实时滤镜,并且能够自定义图像滤镜。同时也很方便在原有基础上加入自己的滤镜Filter,所有滤镜是基于opengl shader(着色器)实现的,所以滤镜效果图像处理是在GPU上实现的,处理效率比较高,在iPhone6及其以上手机,可以做到实时流...

weixin_30240349的博客 378

GPUImage源码解析 -- OpenGL ES基础

https://www.jianshu.com/p/9a4a8d972d5e GPUImage是一个开源的图像处理工具,它基于OpenGL ES实现,Git地址为:https://github.com/BradLarson/GPUImage。GPUImage最大的好处是它提供了一套非常好的图像处理架构,并且提供了各种PhotoShop中常见的滤镜的着色器。使用者只需要通过对这些滤镜的组合,...

u010029439的博客 538

GPUImage源码分析与使用(一)

有丰富的输入组件,可以处理图片、纹理、视频、二进制数据、UIElement(UIView、CALayer),可以使用GPUImage拍照、处理纹理图片、给视频或拍摄中的视频添加滤镜、添加水印可以使用UIElement。支持对大图进行处理,GPU的纹理限制是4096*4096,对于超出限制的图片,GPUImage会压缩处理导致损失图片质量,CoreImage会把图片拆解成小图处理。可以传入字符串类型,也可以传入文件类型,比如以.vsh/.fsh/.glsl等为后缀等命名的文件。

程序猿老樊的博客 1123

OpenGL之GPUImage源码分析

在相机数据采集中,还有一些小的细节问题,比如相机前置与后置摄像头的左右镜像翻转问题。在前面讲到过,GPUImage 的纹理坐标原点是位于左上角的,所以使用 TEXTURE_NO_ROTATION 的纹理坐标实质上是将图像进行了上下翻转,两次调用TEXTURE_NO_ROTATION纹理坐标时,又将图像复原了,这也就可以解释为什么滤镜个数为偶数时,需要使用 mGLTextureFlipBuffer 纹理坐标将图像再进行一次翻转,而 mGLTextureBuffer 纹理坐标不需要了。

程序猿老樊的博客 776

GPUImage 源码解析

GPUImage 实现链式编程的原理 链式编程的开始,所有的数据源都继承自 GPUImageOutput 链式编程的过程,所有的 filter 都继承自 GPUImageFilter , GPUImageFilter 继承自 GPUImageOutput 并且GPUImageFilter 遵守 GPUImageInput 协议; 所以所有的filter都可以作为输入源和输出; GPUImage...

Coder 501

Swift项目中添加GPUImage

环境 Swift 3.1 (swiftlang-802.0.53 clang-802.0.42) Xcode 8.3.2 (8E2002) iOS: 10.3.2 步骤 打开Xcode,新建一个Swift项目,使用Single View Application 模板,起名为GPUImageDemo 打开工程根目录,新建Submodules/GPUImage目录 下载GPUImage源码 将源码中的f

sojlu的博客 1287

GPUImage源码解读(一)

导读: 系列文章会从结构到使用,细化到每一个变量, 使用方法全有对应 DEMO.也会有相对应的技术点扩展如(AVFoundation,OpenGL shader,CAEAGLLayer)等,目前是 Objective-C 版本的,后面会有Swift版本. GPUImage-Objective-C 官方源码 GPUImage-Swift 官方源码 GPUImage-Objective-C 添...

Philm_iOS的博客 802

美颜重磅技术之GPUImage源码分析

说到基于GPU的图像处理和实时滤镜,大家肯定会想到鼎鼎大名的GPUImage,这个项目确实为后续开发提供了很多方便,基本的图像处理工具一应俱全。但是学习借鉴GPUImage的项目结构,可以为我们提供不小的帮助。 GPUImage项目结构 GPUImage的项目结构其实很简单,Android版本就更是简陋,结构如下: 一堆滤镜(shader以及配套设置参数的代码) FilterGroup(利用FB...

欢迎关注公众号:【码农突围】,公号后台回复9999,可以获取一份500页的LeetCode刷题笔记。 2056

IOS OpenGL ES GPUImage 图像透明混合 GPUImageAlphaBlendFilter

目录GPUImage 共 125 个滤镜, 分为四类GPUImageAlphaBlendFilter 属于 GPUImage 图像混合模式相关,用于图像 透明混合。shader 源码如下: 二.效果演示 使用 GPUImageAlphaBlendFilter ****,****源图和目标图如下:使用 GPUImageAlphaBlendFilter 效果如下:OpenGL ES Demo 下载地址 : IOS OpenGL ES GPUImage 图像透明混合 GPUImageAlphaBlendFilt

猿说编程 436
上一篇: GPUImage源码解读(九)
下一篇: Swift可选类型(Optional)的介绍和使用场景
Philm_iOS
博客等级 码龄8年 74粉丝 53原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值