You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用OpenGL将24位Bayer tiles数据传入GPU(C# OpenTK场景)

实现方案

纹理上传格式选择

你之前用的Luminance是OpenGL旧兼容模式下的单通道8位格式,完全不匹配你每Bayer采样点3字节的24位raw场景,首先废弃该方案。

推荐直接上传原始byte[]数组,不需要CPU端做额外的int拼接操作,完全规避额外开销,代码如下:

// 临时修改解压对齐为1,避免非4倍数行宽出现像素错位
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
GL.BindTexture(TextureTarget.Texture2D, this.handle);
// 内部格式用Rgb8ui,每个纹理元素对应3个无符号字节,和你的输入完全匹配
GL.TexImage2D(
    TextureTarget.Texture2D, 
    0, 
    PixelInternalFormat.Rgb8ui, 
    rawWidth, 
    rawHeight, 
    0, 
    PixelFormat.RgbInteger, 
    PixelType.UnsignedByte, 
    imageBuffer
);
// 纹理必须用邻近过滤,禁止线性过滤,否则会破坏raw采样点的原始值
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
GL.BindTexture(TextureTarget.Texture2D, 0);
// 恢复默认4字节对齐,避免影响后续其他纹理操作
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4);

其中rawWidth和rawHeight是你Bayer raw图像的原始宽高。

片段着色器处理逻辑

你需要用整数采样器usampler2D采样该纹理,先完成去马赛克,再做色调映射,示例代码如下:

#version 330 core
out vec4 FragColor;
uniform usampler2D bayerRawTex;
// 根据你的相机Bayer排列修改,可选值RGGB/GRBG/GBRG/BGGR,这里以RGGB为例
const int BAYER_TYPE = 0;

// 24位raw值转归一化HDR浮点
float rawToHdr(uvec3 rawVal) {
    uint rawUint = (rawVal.r << 16) | (rawVal.g << 8) | rawVal.b;
    return float(rawUint) / 16777215.0f; // 2^24 - 1
}

// 去马赛克实现,可根据需求替换为更高精度的算法
vec3 demosaic(ivec2 pos) {
    int xOff = pos.x % 2;
    int yOff = pos.y % 2;
    float currVal = rawToHdr(texelFetch(bayerRawTex, pos, 0).rgb);
    vec3 rgb = vec3(0.0f);

    // RGGB排列的通道判断逻辑,其他排列修改判断条件即可
    if (yOff == 0) {
        rgb.r = xOff == 0 ? currVal : rawToHdr(texelFetch(bayerRawTex, pos + ivec2(-1, 0), 0).rgb);
        rgb.g = xOff == 1 ? currVal : rawToHdr(texelFetch(bayerRawTex, pos + ivec2(1, 0), 0).rgb);
        rgb.b = rawToHdr(texelFetch(bayerRawTex, pos + ivec2(1, 1), 0).rgb);
    } else {
        rgb.g = xOff == 0 ? currVal : rawToHdr(texelFetch(bayerRawTex, pos + ivec2(-1, 0), 0).rgb);
        rgb.b = xOff == 1 ? currVal : rawToHdr(texelFetch(bayerRawTex, pos + ivec2(1, 0), 0).rgb);
        rgb.r = rawToHdr(texelFetch(bayerRawTex, pos + ivec2(-1, -1), 0).rgb);
    }
    return rgb;
}

// 色调映射,可替换为ACES等更优方案
vec3 toneMap(vec3 hdrCol) {
    // Reinhard色调映射+伽马校正
    hdrCol = hdrCol / (hdrCol + vec3(1.0f));
    return pow(hdrCol, vec3(1.0f/2.2f));
}

void main() {
    ivec2 texPos = ivec2(gl_FragCoord.xy);
    vec3 hdrRgb = demosaic(texPos);
    FragColor = vec4(toneMap(hdrRgb), 1.0f);
}

可选CPU端拼接int方案

如果你一定要在CPU端把3字节拼接为int存入int[]数组,上传时使用如下配置即可:

GL.TexImage2D(
    TextureTarget.Texture2D, 
    0, 
    PixelInternalFormat.R32UI, 
    rawWidth, 
    rawHeight, 
    0, 
    PixelFormat.RedInteger, 
    PixelType.UnsignedInt, 
    intBuffer
);

采样时直接读取uint值转换即可,该方案会增加CPU端的拼接开销,无特殊需求不推荐使用。

内容的提问来源于stack exchange,提问作者user17556291

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 03:15:01