鸿蒙开发-想用AI把低清画面变高清?GLES神经网络超分
想象一下这个场景你做了一个画面很精美的 3D 游戏但手机性能有限跑不了原生高分辨率。你有两个选择一是降低分辨率让游戏流畅运行但画面会模糊二是硬扛高分辨率但帧率惨不忍睹。有没有第三种选择有——用神经网络超分。简单说就是你用低分辨率渲染性能好然后通过 AI 算法把画面放大到高分辨率。因为 AI 能够智能地补充细节所以最终效果比传统的双线性插值好得多。这就是 XEngine 的神经网络超分Neural Upscale做的事情。神经网络超分整体流程使用 GLES 神经网络超分的完整流程如下否是检查设备支持支持神经网络超分?退出创建 OH_NativeBuffer 纹理绑定输出帧缓冲设置输入参数设置 NativeBuffer Handle 必填设置裁剪窗口 可选设置锐化度 可选执行超分渲染输出高分辨率画面使用前的准备跟其他 XEngine 特性一样你得先确认设备支持这个能力constGLubyte*extensionsHMS_XEG_GetString(XEG_EXTENSIONS);if(strstr((constchar*)extensions,XEG_neural_upscale)NULL){return;// 不支持神经网络超分}注意这个特性推荐的超分倍率是 1.0 到 1.5 倍。也就是说你可以把 720p 的画面超分到 1080p但不建议直接从 480p 超到 1080p倍率太大效果会差。神经网络超分需要哪些输入神经网络超分需要一个关键的输入由OH_NativeBuffer创建的纹理。为什么呢因为 AI 推理需要用到底层的硬件加速而OH_NativeBuffer提供了高效的内存共享机制让 GPU 和 AI 加速器都能访问同一块内存。除了纹理本身你还需要把纹理关联的OH_NativeBufferhandle 告诉超分算法。这是神经网络超分和普通 GPU 超分的一个重要区别。第一步设置输入参数通过HMS_XEG_NeuralUpscaleParameter函数来设置参数。这个函数有两个参数pname是参数名param是参数值的指针。设置 OH_NativeBuffer handle必填这是神经网络超分最关键的参数。你必须把输入纹理对应的OH_NativeBufferhandle 设置进去// nativeBufferHandle 是与输入纹理关联的 OH_NativeBuffer handleHMS_XEG_NeuralUpscaleParameter(XEG_NEURAL_UPSCALE_INPUT_HANDLE,nativeBufferHandle);XEG_NEURAL_UPSCALE_INPUT_HANDLE的值是0x4U。这个参数是必选的如果不设置超分渲染会产生未定义行为效果不对或者直接崩溃。需要注意的是你传入的 handle 必须和后面HMS_XEG_RenderNeuralUpscale函数传入的inputTexture是对应关系——也就是说这个 handle 对应的OH_NativeBuffer就是用来创建那个纹理的。设置裁剪窗口可选你可以通过XEG_NEURAL_UPSCALE_SCISSOR来指定对输入图像的采样区域GLuint scissor[4]{100,100,800,600};// x, y, width, heightHMS_XEG_NeuralUpscaleParameter(XEG_NEURAL_UPSCALE_SCISSOR,scissor);XEG_NEURAL_UPSCALE_SCISSOR的值是0x1U。传入的是长度为 4 的无符号整数数组依次为裁剪窗口左下角的 x、y 坐标和窗口的宽高。这个参数有什么用呢如果你只想对画面的某个区域做超分比如游戏主画面不包括 UI就可以用裁剪窗口来指定。如果不设置默认是整个输入纹理。设置锐化度可选超分之后的画面可能会有点软你可以通过XEG_NEURAL_UPSCALE_SHARPNESS来调节锐化程度GLfloat sharpness0.3f;// 取值范围 [0, 1]默认 0.2HMS_XEG_NeuralUpscaleParameter(XEG_NEURAL_UPSCALE_SHARPNESS,sharpness);XEG_NEURAL_UPSCALE_SHARPNESS的值是0x2U。值越大锐化效果越强默认是 0.2。但要注意锐化值不是越大越好。太大了会出现振铃效应——物体边缘会出现亮边或者噪点。建议从默认值 0.2 开始慢慢调。不同风格的画面需要的锐化值不一样写实风格的游戏可能 0.2 就够了卡通风格的可能需要 0.4-0.5。第二步执行超分渲染参数设好之后调用HMS_XEG_RenderNeuralUpscale来执行超分HMS_XEG_RenderNeuralUpscale(inputTexture);inputTexture是超分的输入纹理它有几个严格的要求纹理类型必须是GL_TEXTURE_2DmipLevels 必须是 1纹理的宽度必须在[448, 1728]范围内。太小或者太大都可能引起 AI 推理结果错误纹理必须是由OH_NativeBuffer创建的超分的结果会直接渲染到当前绑定的帧缓冲上。所以你需要在调用之前确保正确绑定了输出目标。完整的使用示例把上面的步骤串起来// 1. 检查支持constGLubyte*extensionsHMS_XEG_GetString(XEG_EXTENSIONS);if(strstr((constchar*)extensions,XEG_neural_upscale)NULL){return;}// 2. 假设你已经用 OH_NativeBuffer 创建了一个纹理// inputTexture 是纹理 IDnativeBufferHandle 是对应的 handle// 3. 绑定输出帧缓冲超分结果会渲染到这里glBindFramebuffer(GL_FRAMEBUFFER,outputFBO);// 4. 设置必选参数OH_NativeBuffer handleHMS_XEG_NeuralUpscaleParameter(XEG_NEURAL_UPSCALE_INPUT_HANDLE,nativeBufferHandle);// 5. 设置可选参数锐化度GLfloat sharpness0.3f;HMS_XEG_NeuralUpscaleParameter(XEG_NEURAL_UPSCALE_SHARPNESS,sharpness);// 6. 执行超分HMS_XEG_RenderNeuralUpscale(inputTexture);// 7. 超分完成outputFBO 里的颜色附件就是超分后的结果两种超分方案对比下面是神经网络超分和空域 GPU 超分的对比是否超分方案选择神经网络超分空域 GPU 超分AI 推理算法画质更好需要 OH_NativeBuffer推荐倍率 1.0-1.5传统图像处理速度更快普通纹理即可无明确倍率限制选择建议追求画质?和传统超分Spatial Upscale的区别你可能会问XEngine 不是还有个空域 GPU 超分吗它和神经网络超分有什么区别简单来说空域 GPU 超分Spatial Upscale用传统的图像处理算法比如锐化、边缘增强来放大画面。速度快但效果一般。神经网络超分Neural Upscale用 AI 模型来放大画面。速度稍慢但效果好得多能补充更多细节。选择哪个取决于你的需求如果对性能要求极高、对画质要求不那么苛刻用 GPU 超分如果希望画面尽可能清晰用神经网络超分。另外神经网络超分有一个限制输入纹理必须由OH_NativeBuffer创建而 GPU 超分没有这个要求。这是由 AI 推理的硬件加速机制决定的。注意事项输入宽度限制纹理宽度必须在[448, 1728]范围内。超出这个范围可能导致 AI 推理出错。OH_NativeBuffer 是必须的神经网络超分的输入纹理必须由OH_NativeBuffer创建并且你需要在调用超分之前把对应的 handle 设置好。推荐超分倍率1.0 到 1.5 倍。超过 1.5 倍效果会明显下降。锐化度要适度从 0.2 开始调不要一上来就设很高。神经网络超分是一个用少量性能开销换取明显画质提升的好东西。特别是对于那些需要在中低端设备上运行的游戏用 720p 渲染然后超分到 1080p既流畅又清晰用户体验会好很多。