10 行代码搞定“热成像”【shader风格化】

可莉
• 阅读 744

作者:这是上帝的杰作

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

10 行代码搞定“热成像”【shader风格化】

===

已经过去的 2020 是一个不怎么顺遂的一年,出入公共场所都需要体温监测,而人流量密集的商场,一般会采用热成像技术来快速测量体温。那么今天我们就来说说如何让一张普通图片变成具有热成像的效果。

最终效果如下:

10 行代码搞定“热成像”【shader风格化】 最终效果

从本文中你可以了解到:

  1. 发光的基本原理,如何给图片施加不同颜色的光

  2. 图片模糊的原理,如何用高斯模糊解决重影问题

  3. colorRamp是什么?texture2D的一些高级用法,如何使用colorRamp改变图片的色彩风格

  4. 如何结合以上技术实现热成像效果

本文不再过多赘述webglAPI的使用。只关注片段着色器,下面给出最基本的一个着色器:

precision mediump float;

在第一部分变量生命中中我们从web层传入了一系列变量,现在看可能有点云里雾里别着急,我们后面会逐个提到,在main函数中我们获取了纹理信息,并把图片呈现出来:

10 行代码搞定“热成像”【shader风格化】

发光效果(Glow)

在GLSL中颜色用一个四维向量表示:

vec4 color = vec4(0,0,1.0,0.5,1.0);
  • 四个分量分别表示RGBA是个通道

  • 如果要取出比如rgb构成一个三维向量,可以简写成color.rgb

  • 颜色值范围在[0,1]之间,对应web常用的颜色区间[0,255]

我们要介绍的第一个效果是发光,发光简单来说就是让图片变量。最原始的想法就是把颜色值变大:

void main () {

和我们期待的一样果然变量了:

10 行代码搞定“热成像”【shader风格化】

但能否不仅仅想让图片发白光,而是可以发任意颜色的光?很自然地我们想到让color乘以另一个color:

....

10 行代码搞定“热成像”【shader风格化】

图片的确如我们所想,画面变红了,但是却变暗了,这是由于在 vec3(1.0,0.0,0.5,); 的绿通道值为0,向量相乘后,原本图片中的绿通道信息全部丢失,变为0,(读者不妨验证一下变黑幅度大的区域,是否就是原来比较绿的区域)

为此我们需要使用加和而不是乘积的形式:

color.rgb += vec3(1.0,0.0,0.5)*color.rgb;

10 行代码搞定“热成像”【shader风格化】

最后我们将颜色和强度替换成我们,传入的变量,发光的效果就实现了:

.... 

10 行代码搞定“热成像”【shader风格化】

模糊(Blur)

接下来我们来讲第二种效果模糊,核心思路也很简单,如果一个像素点的颜色信息掺杂了周围点的颜色信息,那么图片就会模糊。

为此我们选择讲像素点上下左右四个点的信息融合:

.....

10 行代码搞定“热成像”【shader风格化】

为了让效果更佳,我们引入权重体系,让原本的点在结果中贡献最大设权重为4,正方向的点权重为2,45度方向的点权重为1:

 vec4 color = 4.0*texture2D (u_texture0, uv);

正当我们满心欢喜第把step改成我们传入的变量u_blurIntensity(控制模糊强度时)悲剧发生了:

10 行代码搞定“热成像”【shader风格化】

这是因为我们虽然加上了权重,但点的影响值却没有随 step 的怎大而递减,举个例子:就是当步幅为 0.001 和 0.1 时正上方的点贡献都是 2(而实际上 0.001 要比 0.1 有更大的权重,因为它更接近原始点)。

所以当step增大时很明显就会出现重影。

为此我们参考高斯模糊,引入一个指数函数:

10 行代码搞定“热成像”【shader风格化】

该函数随着传入的x的增大而减小,于是我们改造上述代码:

  • 将取值点由3*3增加到了8*8;

  • 采用递减的指数函数:exp(-(x * x)/(2.0* bhqp * bhqp));

  • 控制了偏移的范围(float(iy - halfIterations)*0.00390625);

  • float Blur_Gauss (float bhqp, float x) {

10 行代码搞定“热成像”【shader风格化】

负片(negative)

这个可能是本文最简单的一个效果,就是让图片呈现出负片的效果,代码如下:

color.rgb = abs(u_negativeAmount - color.rgb);

10 行代码搞定“热成像”【shader风格化】

colorRamp

colorRamp 简单理解就是色卡,就是下面这种:

10 行代码搞定“热成像”【shader风格化】

在进一步说明 colorRamp 前,我们先想想如何把图片变成黑白?

最直接的想法就是把R,G,B三个通道的颜色取平均:

......

其实这件事也可以用ColorRamp实现,我们想找一个由黑到白的色表,传入着色器作为u_texture1。

10 行代码搞定“热成像”【shader风格化】

纹理最左侧的点x坐标就是0,最右侧的点x坐标就是1,因此黑白效果的代码可以写成:

......  

这里浮点素P记录了原始图片(u_texture0)的信息,同时它制定了规则,输出的颜色是R,G,B三个通道值取平均的结果。

当然一个黑白效果不必如此大费周章,生产环境中ColorRamp更加缤纷,下面我们依旧使用(color.r+color.g+color.b)/3.0作为取色规则,来看看一些coloRamp的效果:

10 行代码搞定“热成像”【shader风格化】

当然我们不会局限于一种规则,为此我们使用u_r,u_g,u_b分别控制红绿蓝三色通道权重:

......  

我们一上图中第二种纹理为例,实现效果如下:

10 行代码搞定“热成像”【shader风格化】

最总我们使用下面这个风格的colorRamp:

10 行代码搞定“热成像”【shader风格化】

最后就是见证奇迹的是时刻了,我们把上面所过的效果合起来(发光=>colorRamp=>负片=>模糊):

10 行代码搞定“热成像”【shader风格化】

最终效果

10 行代码搞定“热成像”【shader风格化】

当然这个 shader 也可用在真人身上,比如封面图。其中 blurIntensity 越大风格越卡通,大家可以自己实践一下。

10 行代码搞定“热成像”【shader风格化】 最近很常用的一张表情包

-- END --

进技术交流群,扫码添加我的微信:Byte-Flow

10 行代码搞定“热成像”【shader风格化】

获取视频教程和源码

推荐:

利用 OpenGL ES 给视频播放器做个字符画滤镜

字节流动 OpenGL ES 技术交流群来啦

Android OpenGL 渲染图像读取哪家强?

FFmpeg + OpenGL ES 实现 3D 全景播放器

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

Android OpenGL ES 从入门到精通系统性学习教程

OpenGL ES 实现动态(水波纹)涟漪效果

觉得不错,点个在看呗~

10 行代码搞定“热成像”【shader风格化】

本文分享自微信公众号 - 字节流动(google_developer)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
2年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
ES6 新增的数组的方法
给定一个数组letlist\//wu:武力zhi:智力{id:1,name:'张飞',wu:97,zhi:10},{id:2,name:'诸葛亮',wu:55,zhi:99},{id:3,name:'赵云',wu:97,zhi:66},{id:4,na
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
1个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这