首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >“热成像”风格的效果是怎么实现的?(内附源码)

“热成像”风格的效果是怎么实现的?(内附源码)

作者头像
字节流动
发布2023-10-12 15:51:42
发布2023-10-12 15:51:42
1.2K0
举报
文章被收录于专栏:字节流动字节流动

之前转载过知乎上面的一篇文章:

作者:这是上帝的杰作 链接:https://zhuanlan.zhihu.com/p/344110917

文章详细讲解了 Shader 实现“热成像”效果的思路,但是并没有给出完整的实现代码,后台有读者多次催促,希望我能实现下并给出完整的代码,于是,今天晚上就花了一点时间简单实现了下这个效果。

按照那篇文章的思路,主要步骤是:模糊->发光->亮度分级->替换颜色 ,其中发光这一步不大重要。

可以观察到“热成像”效果的颜色也就是蓝色(冷)和红色(热)组合的几种颜色,然后对颜色做一个排序,并根据亮度等级替换对应的颜色。

至于做模糊,其实就是为了增加层次感而已,可以对比下面的两幅图,左边的是没有做模糊的“热成像效果”。

根据“热成像”的色谱创建一个颜色查找数组:

代码语言:javascript
复制
vec3 colorLevels[9] = vec3[9](
    vec3(234.0,51.0,61.0),
    vec3(235.0,70.0,105.0),
    vec3(178.0,119.0,37.0),
    vec3(247.0,206.0,70.0),
    vec3(149.0,232.0,71.0),
    vec3(103.0,200.0,250.0),
    vec3(68.0,132.0,245.0),
    vec3(40.0,3.0,143.0),
    vec3(18.0,5.0,62.0)
);

接下来将 rgb 转换为灰度值,我们将灰度值分为 9 个 level ,然后根据当前灰度值,选择相应的颜色。

代码语言:javascript
复制
    float lum = dot(color.rgb, vec3(0.3, 0.59, 0.11));
    lum = 1.0 - lum;
    float d = 1.0 / 9.0;//将灰度值分为 9 个 level
    int i = int(lum / d);
    i = clamp(i, 0, 8);

    fragColor = vec4(colorLevels[i]/255.0, 1.0);

最终的效果如下:

完整实现代码:

代码语言:javascript
复制
vec3 colorLevels[9] = vec3[9](
    vec3(234.0,51.0,61.0),
    vec3(235.0,70.0,105.0),
    vec3(178.0,119.0,37.0),
    vec3(247.0,206.0,70.0),
    vec3(149.0,232.0,71.0),
    vec3(103.0,200.0,250.0),
    vec3(68.0,132.0,245.0),
    vec3(40.0,3.0,143.0),
    vec3(18.0,5.0,62.0)
);

float blur_gauss(float bhqp, float x) {
  return exp (-(x * x) / (2.0 * bhqp * bhqp));
}

vec4 blur(vec2 uv, sampler2D source, float Intensity) {
  const int iterations = 4;
  int halfIterations = iterations / 2;
  float sigmaX = 0.1 + Intensity * 0.5;
  float sigmaY = sigmaX;
  float total = 0.0;
  vec4 ret = vec4 (0., 0., 0., 0.);
  float step = 0.00390625;
  for (int iy = 0; iy < iterations; ++iy) {
    float fy = blur_gauss(sigmaY, float (iy - halfIterations));
    float offsety = float (iy - halfIterations) * step;
    for (int ix = 0; ix < iterations; ++ix) {
      float fx = blur_gauss(sigmaX, float (ix - halfIterations));
      float offsetx = float (ix - halfIterations) * step;
      total += fx * fy;
      vec4 a = texture2D (source, uv + vec2 (offsetx, offsety));
      a.rgb *= a.a;
      ret += a * fx * fy;
    }
  }
  return ret / total;
}


void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;

    //vec4 color = texture2D(iChannel0, uv);
    vec4 color = blur(uv, iChannel0, 3.0);//模糊

    color.rgb += vec3(1.0,0.0,0.5)*color.rgb*0.2;//发光

    float lum = dot(color.rgb, vec3(0.3, 0.59, 0.11));
    lum = 1.0 - lum;
    float d = 1.0 / 9.0;
    int i = int(lum / d);
    i = clamp(i, 0, 8);

    fragColor = vec4(colorLevels[i]/255.0, 1.0);
}

参考文章:

https://zhuanlan.zhihu.com/p/344110917

获取相关资料和源码

推荐:

Android FFmpeg 实现带滤镜的微信小视频录制功能

全网最全的 Android 音视频和 OpenGL ES 干货,都在这了

一文掌握 YUV 图像的基本处理

抖音传送带特效是怎么实现的?

所有你想要的图片转场效果,都在这了

面试官:如何利用 Shader 实现 RGBA 到 NV21 图像格式转换?

我用 OpenGL ES 给小姐姐做了几个抖音滤镜

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 字节流动 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档