欢迎光临
我们一直在努力

鸿蒙开发-想用AI把低清画面变高清?GLES神经网络超分

用 AI 让低分辨率画面变清晰——GLES 神经网络超分实战

想象一下这个场景:你做了一个画面很精美的 3D 游戏,但手机性能有限,跑不了原生高分辨率。你有两个选择:一是降低分辨率让游戏流畅运行,但画面会模糊;二是硬扛高分辨率,但帧率惨不忍睹。

有没有第三种选择?有——用神经网络超分。

简单说就是:你用低分辨率渲染(性能好),然后通过 AI 算法把画面"放大"到高分辨率。因为 AI 能够智能地补充细节,所以最终效果比传统的双线性插值好得多。这就是 XEngine 的神经网络超分(Neural Upscale)做的事情。

神经网络超分整体流程

使用 GLES 神经网络超分的完整流程如下:

#mermaid-svg-gqpPD72e7oBJFSJv{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gqpPD72e7oBJFSJv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gqpPD72e7oBJFSJv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gqpPD72e7oBJFSJv .error-icon{fill:#552222;}#mermaid-svg-gqpPD72e7oBJFSJv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gqpPD72e7oBJFSJv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gqpPD72e7oBJFSJv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gqpPD72e7oBJFSJv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gqpPD72e7oBJFSJv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gqpPD72e7oBJFSJv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gqpPD72e7oBJFSJv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gqpPD72e7oBJFSJv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gqpPD72e7oBJFSJv .marker.cross{stroke:#333333;}#mermaid-svg-gqpPD72e7oBJFSJv svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gqpPD72e7oBJFSJv p{margin:0;}#mermaid-svg-gqpPD72e7oBJFSJv .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-gqpPD72e7oBJFSJv .cluster-label text{fill:#333;}#mermaid-svg-gqpPD72e7oBJFSJv .cluster-label span{color:#333;}#mermaid-svg-gqpPD72e7oBJFSJv .cluster-label span p{background-color:transparent;}#mermaid-svg-gqpPD72e7oBJFSJv .label text,#mermaid-svg-gqpPD72e7oBJFSJv span{fill:#333;color:#333;}#mermaid-svg-gqpPD72e7oBJFSJv .node rect,#mermaid-svg-gqpPD72e7oBJFSJv .node circle,#mermaid-svg-gqpPD72e7oBJFSJv .node ellipse,#mermaid-svg-gqpPD72e7oBJFSJv .node polygon,#mermaid-svg-gqpPD72e7oBJFSJv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gqpPD72e7oBJFSJv .rough-node .label text,#mermaid-svg-gqpPD72e7oBJFSJv .node .label text,#mermaid-svg-gqpPD72e7oBJFSJv .image-shape .label,#mermaid-svg-gqpPD72e7oBJFSJv .icon-shape .label{text-anchor:middle;}#mermaid-svg-gqpPD72e7oBJFSJv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gqpPD72e7oBJFSJv .rough-node .label,#mermaid-svg-gqpPD72e7oBJFSJv .node .label,#mermaid-svg-gqpPD72e7oBJFSJv .image-shape .label,#mermaid-svg-gqpPD72e7oBJFSJv .icon-shape .label{text-align:center;}#mermaid-svg-gqpPD72e7oBJFSJv .node.clickable{cursor:pointer;}#mermaid-svg-gqpPD72e7oBJFSJv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gqpPD72e7oBJFSJv .arrowheadPath{fill:#333333;}#mermaid-svg-gqpPD72e7oBJFSJv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gqpPD72e7oBJFSJv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gqpPD72e7oBJFSJv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gqpPD72e7oBJFSJv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gqpPD72e7oBJFSJv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gqpPD72e7oBJFSJv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gqpPD72e7oBJFSJv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gqpPD72e7oBJFSJv .cluster text{fill:#333;}#mermaid-svg-gqpPD72e7oBJFSJv .cluster span{color:#333;}#mermaid-svg-gqpPD72e7oBJFSJv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gqpPD72e7oBJFSJv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gqpPD72e7oBJFSJv rect.text{fill:none;stroke-width:0;}#mermaid-svg-gqpPD72e7oBJFSJv .icon-shape,#mermaid-svg-gqpPD72e7oBJFSJv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gqpPD72e7oBJFSJv .icon-shape p,#mermaid-svg-gqpPD72e7oBJFSJv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gqpPD72e7oBJFSJv .icon-shape .label rect,#mermaid-svg-gqpPD72e7oBJFSJv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gqpPD72e7oBJFSJv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gqpPD72e7oBJFSJv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gqpPD72e7oBJFSJv :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

检查设备支持

支持神经网络超分?

退出

创建 OH_NativeBuffer 纹理

绑定输出帧缓冲

设置输入参数

设置 NativeBuffer Handle 必填

设置裁剪窗口 可选

设置锐化度 可选

执行超分渲染

输出高分辨率画面

使用前的准备

跟其他 XEngine 特性一样,你得先确认设备支持这个能力:

const GLubyte* extensions = HMS_XEG_GetString(XEG_EXTENSIONS);
if (strstr((const char*)extensions, "XEG_neural_upscale") == NULL) {
return; // 不支持神经网络超分
}

注意,这个特性推荐的超分倍率是 1.0 到 1.5 倍。也就是说,你可以把 720p 的画面超分到 1080p,但不建议直接从 480p 超到 1080p(倍率太大效果会差)。

神经网络超分需要哪些输入

神经网络超分需要一个关键的输入:由 OH_NativeBuffer 创建的纹理。为什么呢?因为 AI 推理需要用到底层的硬件加速,而 OH_NativeBuffer 提供了高效的内存共享机制,让 GPU 和 AI 加速器都能访问同一块内存。

除了纹理本身,你还需要把纹理关联的 OH_NativeBuffer handle 告诉超分算法。这是神经网络超分和普通 GPU 超分的一个重要区别。

第一步:设置输入参数

通过 HMS_XEG_NeuralUpscaleParameter 函数来设置参数。这个函数有两个参数:pname 是参数名,param 是参数值的指针。

设置 OH_NativeBuffer handle(必填)

这是神经网络超分最关键的参数。你必须把输入纹理对应的 OH_NativeBuffer handle 设置进去:

// nativeBufferHandle 是与输入纹理关联的 OH_NativeBuffer handle
HMS_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, height
HMS_XEG_NeuralUpscaleParameter(XEG_NEURAL_UPSCALE_SCISSOR, scissor);

XEG_NEURAL_UPSCALE_SCISSOR 的值是 0x1U。传入的是长度为 4 的无符号整数数组,依次为裁剪窗口左下角的 x、y 坐标和窗口的宽高。

这个参数有什么用呢?如果你只想对画面的某个区域做超分(比如游戏主画面,不包括 UI),就可以用裁剪窗口来指定。如果不设置,默认是整个输入纹理。

设置锐化度(可选)

超分之后的画面可能会有点"软",你可以通过 XEG_NEURAL_UPSCALE_SHARPNESS 来调节锐化程度:

GLfloat sharpness = 0.3f; // 取值范围 [0, 1],默认 0.2
HMS_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_2D
  • mipLevels 必须是 1
  • 纹理的宽度必须在 [448, 1728] 范围内。太小或者太大都可能引起 AI 推理结果错误
  • 纹理必须是由 OH_NativeBuffer 创建的
  • 超分的结果会直接渲染到当前绑定的帧缓冲上。所以你需要在调用之前确保正确绑定了输出目标。

    完整的使用示例

    把上面的步骤串起来:

    // 1. 检查支持
    const GLubyte* extensions = HMS_XEG_GetString(XEG_EXTENSIONS);
    if (strstr((const char*)extensions, "XEG_neural_upscale") == NULL) {
    return;
    }

    // 2. 假设你已经用 OH_NativeBuffer 创建了一个纹理
    // inputTexture 是纹理 ID,nativeBufferHandle 是对应的 handle

    // 3. 绑定输出帧缓冲(超分结果会渲染到这里)
    glBindFramebuffer(GL_FRAMEBUFFER, outputFBO);

    // 4. 设置必选参数:OH_NativeBuffer handle
    HMS_XEG_NeuralUpscaleParameter(XEG_NEURAL_UPSCALE_INPUT_HANDLE, &nativeBufferHandle);

    // 5. 设置可选参数:锐化度
    GLfloat sharpness = 0.3f;
    HMS_XEG_NeuralUpscaleParameter(XEG_NEURAL_UPSCALE_SHARPNESS, &sharpness);

    // 6. 执行超分
    HMS_XEG_RenderNeuralUpscale(inputTexture);

    // 7. 超分完成,outputFBO 里的颜色附件就是超分后的结果

    两种超分方案对比

    下面是神经网络超分和空域 GPU 超分的对比:

    #mermaid-svg-GKcrTZOwbPGuldjd{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GKcrTZOwbPGuldjd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GKcrTZOwbPGuldjd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GKcrTZOwbPGuldjd .error-icon{fill:#552222;}#mermaid-svg-GKcrTZOwbPGuldjd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GKcrTZOwbPGuldjd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GKcrTZOwbPGuldjd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GKcrTZOwbPGuldjd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GKcrTZOwbPGuldjd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GKcrTZOwbPGuldjd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GKcrTZOwbPGuldjd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GKcrTZOwbPGuldjd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GKcrTZOwbPGuldjd .marker.cross{stroke:#333333;}#mermaid-svg-GKcrTZOwbPGuldjd svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GKcrTZOwbPGuldjd p{margin:0;}#mermaid-svg-GKcrTZOwbPGuldjd .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-GKcrTZOwbPGuldjd .cluster-label text{fill:#333;}#mermaid-svg-GKcrTZOwbPGuldjd .cluster-label span{color:#333;}#mermaid-svg-GKcrTZOwbPGuldjd .cluster-label span p{background-color:transparent;}#mermaid-svg-GKcrTZOwbPGuldjd .label text,#mermaid-svg-GKcrTZOwbPGuldjd span{fill:#333;color:#333;}#mermaid-svg-GKcrTZOwbPGuldjd .node rect,#mermaid-svg-GKcrTZOwbPGuldjd .node circle,#mermaid-svg-GKcrTZOwbPGuldjd .node ellipse,#mermaid-svg-GKcrTZOwbPGuldjd .node polygon,#mermaid-svg-GKcrTZOwbPGuldjd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GKcrTZOwbPGuldjd .rough-node .label text,#mermaid-svg-GKcrTZOwbPGuldjd .node .label text,#mermaid-svg-GKcrTZOwbPGuldjd .image-shape .label,#mermaid-svg-GKcrTZOwbPGuldjd .icon-shape .label{text-anchor:middle;}#mermaid-svg-GKcrTZOwbPGuldjd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GKcrTZOwbPGuldjd .rough-node .label,#mermaid-svg-GKcrTZOwbPGuldjd .node .label,#mermaid-svg-GKcrTZOwbPGuldjd .image-shape .label,#mermaid-svg-GKcrTZOwbPGuldjd .icon-shape .label{text-align:center;}#mermaid-svg-GKcrTZOwbPGuldjd .node.clickable{cursor:pointer;}#mermaid-svg-GKcrTZOwbPGuldjd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GKcrTZOwbPGuldjd .arrowheadPath{fill:#333333;}#mermaid-svg-GKcrTZOwbPGuldjd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GKcrTZOwbPGuldjd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GKcrTZOwbPGuldjd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GKcrTZOwbPGuldjd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GKcrTZOwbPGuldjd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GKcrTZOwbPGuldjd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GKcrTZOwbPGuldjd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GKcrTZOwbPGuldjd .cluster text{fill:#333;}#mermaid-svg-GKcrTZOwbPGuldjd .cluster span{color:#333;}#mermaid-svg-GKcrTZOwbPGuldjd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GKcrTZOwbPGuldjd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GKcrTZOwbPGuldjd rect.text{fill:none;stroke-width:0;}#mermaid-svg-GKcrTZOwbPGuldjd .icon-shape,#mermaid-svg-GKcrTZOwbPGuldjd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GKcrTZOwbPGuldjd .icon-shape p,#mermaid-svg-GKcrTZOwbPGuldjd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GKcrTZOwbPGuldjd .icon-shape .label rect,#mermaid-svg-GKcrTZOwbPGuldjd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GKcrTZOwbPGuldjd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GKcrTZOwbPGuldjd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GKcrTZOwbPGuldjd :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    超分方案选择

    神经网络超分

    空域 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,既流畅又清晰,用户体验会好很多。

    赞(0)
    未经允许不得转载:171主机测评 » 鸿蒙开发-想用AI把低清画面变高清?GLES神经网络超分
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址