【视觉基础篇】17 # 如何使用后期处理通道增强图像效果?

简介: 【视觉基础篇】17 # 如何使用后期处理通道增强图像效果?

说明

【跟月影学可视化】学习笔记。



为什么需要后期处理通道?

由于 GPU 是并行渲染的,所以在着色器的执行中,每个像素的着色都是同时进行的,彼此独立的,不能共享信息,就不能获得某一个像素坐标周围坐标点的颜色信息,也不能获得要渲染图像的全局信息。



什么是后期处理通道?

所谓后期处理通道,是指将渲染出来的图像作为纹理输入给新着色器处理,是一种二次加工的手段。可以从纹理中获取任意 uv 坐标下的像素信息,也就相当于可以获取任意位置的像素信息。



后期处理通道的一般过程

  1. 将数据送入缓冲区
  2. 然后执行 WebGLProgram
  3. 将输出的结果再作为纹理,送入另一个 WebGLProgram 进行处理
  4. 最后输出结果


6ce12747eeda402499d62c147b63ee43.png




如何用后期处理通道实现 Blur 滤镜?

下面实现一个绘制随机三角形图案的着色器,然后使用后期处理通道对它进行高斯模糊。

这是没有进行高斯模糊的效果:


e86a822cd7a747ddb9c310cc517ed214.png

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>如何用后期处理通道实现 Blur 滤镜</title>
        <style>
            canvas {
                border: 1px dashed salmon;
            }
        </style>
    </head>
    <body>
        <canvas width="512" height="512"></canvas>
        <script src="./common/lib/gl-renderer.js"></script>
        <script>
            const vertex = `
                attribute vec2 a_vertexPosition;
                attribute vec2 uv;
                varying vec2 vUv;
                void main() {
                    gl_PointSize = 1.0;
                    vUv = uv;
                    gl_Position = vec4(a_vertexPosition, 1, 1);
                }
            `;
            const fragment = `
                #ifdef GL_ES
                precision highp float;
                #endif
                float line_distance(in vec2 st, in vec2 a, in vec2 b) {
                    vec3 ab = vec3(b - a, 0);
                    vec3 p = vec3(st - a, 0);
                    float l = length(ab);
                    return cross(p, normalize(ab)).z;
                }
                float seg_distance(in vec2 st, in vec2 a, in vec2 b) {
                    vec3 ab = vec3(b - a, 0);
                    vec3 p = vec3(st - a, 0);
                    float l = length(ab);
                    float d = abs(cross(p, normalize(ab)).z);
                    float proj = dot(p, ab) / l;
                    if(proj >= 0.0 && proj <= l) return d;
                    return min(distance(st, a), distance(st, b));
                }
                float triangle_distance(in vec2 st, in vec2 a, in vec2 b, in vec2 c) {
                    float d1 = line_distance(st, a, b);
                    float d2 = line_distance(st, b, c);
                    float d3 = line_distance(st, c, a);
                    if(d1 >= 0.0 && d2 >= 0.0 && d3 >= 0.0 || d1 <= 0.0 && d2 <= 0.0 && d3 <= 0.0) {
                        return -min(abs(d1), min(abs(d2), abs(d3))); // 内部距离为负
                    }
                    return min(seg_distance(st, a, b), min(seg_distance(st, b, c), seg_distance(st, c, a))); // 外部为正
                }
                float random (vec2 st) {
                    return fract(sin(dot(st.xy, vec2(12.9898,78.233)))*43758.5453123);
                }
                vec3 hsb2rgb(vec3 c){
                    vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), 6.0)-3.0)-1.0, 0.0, 1.0);
                    rgb = rgb * rgb * (3.0 - 2.0 * rgb);
                    return c.z * mix(vec3(1.0), rgb, c.y);
                }
                varying vec2 vUv;
                void main() {
                    vec2 st = vUv;
                    st *= 10.0;
                    vec2 i_st = floor(st);
                    vec2 f_st = 2.0 * fract(st) - vec2(1);
                    float r = random(i_st);
                    float sign = 2.0 * step(0.5, r) - 1.0;
                    float d = triangle_distance(f_st, vec2(-1), vec2(1), sign * vec2(1, -1));
                    gl_FragColor.rgb = (smoothstep(-0.85, -0.8, d) - smoothstep(0.0, 0.05, d)) * hsb2rgb(vec3(r + 1.2, 0.5, r));
                    gl_FragColor.a = 1.0;
                }
            `;
      // 通过blurFragment,能将第一次渲染后生成的纹理 tMap 内容给显示出来。
            const blurFragment = `
                #ifdef GL_ES
                precision highp float;
                #endif
                varying vec2 vUv;
                uniform sampler2D tMap;
                uniform int axis;
                void main() {
                    vec4 color = texture2D(tMap, vUv);
                    // 高斯矩阵的权重值
                    float weight[5];
                    weight[0] = 0.227027;
                    weight[1] = 0.1945946;
                    weight[2] = 0.1216216;
                    weight[3] = 0.054054;
                    weight[4] = 0.016216;
                    // 每一个相邻像素的坐标间隔,这里的512可以用实际的Canvas像素宽代替
                    float tex_offset = 1.0 / 512.0;
                    vec3 result = color.rgb;
                    result *= weight[0];
                    for(int i = 1; i < 5; ++i) {
                        float f = float(i);
                        if(axis == 0) {
                            // x轴的高斯模糊
                            result += texture2D(tMap, vUv + vec2(tex_offset * f, 0.0)).rgb * weight[i];
                            result += texture2D(tMap, vUv - vec2(tex_offset * f, 0.0)).rgb * weight[i];
                        } else {
                            // y轴的高斯模糊
                            result += texture2D(tMap, vUv + vec2(0.0, tex_offset * f)).rgb * weight[i];
                            result += texture2D(tMap, vUv - vec2(0.0, tex_offset * f)).rgb * weight[i];
                        }
                    }
                    gl_FragColor.rgb = result.rgb;
                    gl_FragColor.a = color.a;
                }
            `;
            const canvas = document.querySelector("canvas");
            const renderer = new GlRenderer(canvas);
            const program = renderer.compileSync(fragment, vertex);
            renderer.useProgram(program);
            renderer.setMeshData([
                {
                    positions: [
                        [-1, -1],
                        [-1, 1],
                        [1, 1],
                        [1, -1],
                    ],
                    attributes: {
                        uv: [
                            [0, 0],
                            [0, 1],
                            [1, 1],
                            [1, 0],
                        ],
                    },
                    cells: [
                        [0, 1, 2],
                        [2, 0, 3],
                    ],
                },
            ]);
            // 高斯模糊有两个方向,下面分别对 x 轴和 y 轴执行 2 次渲染为例
            const blurProgram = renderer.compileSync(blurFragment, vertex);
            // 创建两个FBO(帧缓冲对象)交替使用
            const fbo1 = renderer.createFBO();
            const fbo2 = renderer.createFBO();
            // 第一次,渲染原始图形
            renderer.bindFBO(fbo1); // 绑定帧缓冲对象
            renderer.render();
            // 第二次,对x轴高斯模糊
            renderer.useProgram(blurProgram);
            renderer.setMeshData(program.meshData);
            renderer.bindFBO(fbo2);
            renderer.uniforms.tMap = fbo1.texture;
            renderer.uniforms.axis = 0;
            renderer.render();
            // 第三次,对y轴高斯模糊
            renderer.useProgram(blurProgram);
            renderer.bindFBO(fbo1);
            renderer.uniforms.tMap = fbo2.texture;
            renderer.uniforms.axis = 1;
            renderer.render();
            // 第四次,对x轴高斯模糊
            renderer.useProgram(blurProgram);
            renderer.bindFBO(fbo2);
            renderer.uniforms.tMap = fbo1.texture;
            renderer.uniforms.axis = 0;
            renderer.render();
            // 第五次,对y轴高斯模糊
            renderer.useProgram(blurProgram);
            renderer.bindFBO(null);
            renderer.uniforms.tMap = fbo2.texture;
            renderer.uniforms.axis = 1;
            renderer.render();
        </script>
    </body>
</html>

高斯模糊之后,效果如下:

672d873c806c4cfeaa4d3d4622ecfb59.png


如何用后期处理通道实现辉光效果?

实现它的关键,就是在高斯模糊原理的基础上,将局部高斯模糊的图像与原始图像叠加,就实现了最终的局部辉光效果。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>如何用后期处理通道实现辉光效果?</title>
        <style>
            canvas {
                border: 1px dashed salmon;
            }
        </style>
    </head>
    <body>
        <canvas width="512" height="512"></canvas>
        <script src="./common/lib/gl-renderer.js"></script>
        <script>
            const vertex = `
                attribute vec2 a_vertexPosition;
                attribute vec2 uv;
                varying vec2 vUv;
                void main() {
                    gl_PointSize = 1.0;
                    vUv = uv;
                    gl_Position = vec4(a_vertexPosition, 1, 1);
                }
            `;
            const fragment = `
                #ifdef GL_ES
                precision highp float;
                #endif
                float line_distance(in vec2 st, in vec2 a, in vec2 b) {
                    vec3 ab = vec3(b - a, 0);
                    vec3 p = vec3(st - a, 0);
                    float l = length(ab);
                    return cross(p, normalize(ab)).z;
                }
                float seg_distance(in vec2 st, in vec2 a, in vec2 b) {
                    vec3 ab = vec3(b - a, 0);
                    vec3 p = vec3(st - a, 0);
                    float l = length(ab);
                    float d = abs(cross(p, normalize(ab)).z);
                    float proj = dot(p, ab) / l;
                    if(proj >= 0.0 && proj <= l) return d;
                    return min(distance(st, a), distance(st, b));
                }
                float triangle_distance(in vec2 st, in vec2 a, in vec2 b, in vec2 c) {
                    float d1 = line_distance(st, a, b);
                    float d2 = line_distance(st, b, c);
                    float d3 = line_distance(st, c, a);
                    if(d1 >= 0.0 && d2 >= 0.0 && d3 >= 0.0 || d1 <= 0.0 && d2 <= 0.0 && d3 <= 0.0) {
                        return -min(abs(d1), min(abs(d2), abs(d3))); // 内部距离为负
                    }
                    return min(seg_distance(st, a, b), min(seg_distance(st, b, c), seg_distance(st, c, a))); // 外部为正
                }
                float random (vec2 st) {
                    return fract(sin(dot(st.xy, vec2(12.9898,78.233)))*43758.5453123);
                }
                vec3 hsb2rgb(vec3 c){
                    vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), 6.0)-3.0)-1.0, 0.0, 1.0);
                    rgb = rgb * rgb * (3.0 - 2.0 * rgb);
                    return c.z * mix(vec3(1.0), rgb, c.y);
                }
                varying vec2 vUv;
                void main() {
                    vec2 st = vUv;
                    st *= 10.0;
                    vec2 i_st = floor(st);
                    vec2 f_st = 2.0 * fract(st) - vec2(1);
                    float r = random(i_st);
                    float sign = 2.0 * step(0.5, r) - 1.0;
                    float d = triangle_distance(f_st, vec2(-1), vec2(1), sign * vec2(1, -1));
                    gl_FragColor.rgb = (smoothstep(-0.85, -0.8, d) - smoothstep(0.0, 0.05, d)) * hsb2rgb(vec3(r + 1.2, 0.5, r));
                    gl_FragColor.a = 1.0;
                }
            `;
            /**
             * 通过blurFragment,能将第一次渲染后生成的纹理 tMap 内容给显示出来。
             * 给 blurFragment 加了一个关于亮度的滤镜,将颜色亮度大于 filter 值的三角形过滤出来添加高斯模糊。
             * */ 
            const blurFragment = `
                #ifdef GL_ES
                precision highp float;
                #endif
                varying vec2 vUv;
                uniform sampler2D tMap;
                uniform int axis;
                uniform float filter;
                void main() {
                    vec4 color = texture2D(tMap, vUv);
                    float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
                    brightness = step(filter, brightness);
                    // 高斯矩阵的权重值
                    float weight[5];
                    weight[0] = 0.227027;
                    weight[1] = 0.1945946;
                    weight[2] = 0.1216216;
                    weight[3] = 0.054054;
                    weight[4] = 0.016216;
                    // 每一个相邻像素的坐标间隔,这里的512可以用实际的Canvas像素宽代替
                    float tex_offset = 1.0 / 512.0;
                    vec3 result = color.rgb;
                    result *= weight[0];
                    for(int i = 1; i < 5; ++i) {
                        float f = float(i);
                        if(axis == 0) {
                            // x轴的高斯模糊
                            result += texture2D(tMap, vUv + vec2(tex_offset * f, 0.0)).rgb * weight[i];
                            result += texture2D(tMap, vUv - vec2(tex_offset * f, 0.0)).rgb * weight[i];
                        } else {
                            // y轴的高斯模糊
                            result += texture2D(tMap, vUv + vec2(0.0, tex_offset * f)).rgb * weight[i];
                            result += texture2D(tMap, vUv - vec2(0.0, tex_offset * f)).rgb * weight[i];
                        }
                    }
                    gl_FragColor.rgb = brightness * result.rgb;
                    gl_FragColor.a = color.a;
                }
            `;
            // 再增加一个 bloomFragment 着色器,用来做最后的效果混合。 
            const bloomFragment = `
                #ifdef GL_ES
                precision highp float;
                #endif
                uniform sampler2D tMap;
                uniform sampler2D tSource;
                varying vec2 vUv;
                void main() {
                    vec3 color = texture2D(tSource, vUv).rgb;
                    vec3 bloomColor = texture2D(tMap, vUv).rgb;
                    color += bloomColor;
                    // Tone Mapping(色调映射):将对比度过大的图像色调映射到合理的范围内
                    float exposure = 2.0;
                    float gamma = 1.3;
                    vec3 result = vec3(1.0) - exp(-color * exposure);
                    // also gamma correct while we're at it
                    if(length(bloomColor) > 0.0) {
                        result = pow(result, vec3(1.0 / gamma));
                    }
                    gl_FragColor.rgb = result;
                    gl_FragColor.a = 1.0;
                }
            `;
            const canvas = document.querySelector("canvas");
            const renderer = new GlRenderer(canvas);
            const program = renderer.compileSync(fragment, vertex);
            renderer.useProgram(program);
            renderer.setMeshData([
                {
                    positions: [
                        [-1, -1],
                        [-1, 1],
                        [1, 1],
                        [1, -1],
                    ],
                    attributes: {
                        uv: [
                            [0, 0],
                            [0, 1],
                            [1, 1],
                            [1, 0],
                        ],
                    },
                    cells: [
                        [0, 1, 2],
                        [2, 0, 3],
                    ],
                },
            ]);
            // 高斯模糊有两个方向,下面分别对 x 轴和 y 轴执行 2 次渲染为例
            const blurProgram = renderer.compileSync(blurFragment, vertex);
            const bloomProgram = renderer.compileSync(bloomFragment, vertex);
            // 创建三个FBO(帧缓冲对象),fbo1和fbo2交替使用
            const fbo0 = renderer.createFBO();
            const fbo1 = renderer.createFBO();
            const fbo2 = renderer.createFBO();
            // 第一次,渲染原始图形
            renderer.bindFBO(fbo0);
            renderer.render();
            // 第二次,对x轴高斯模糊
            renderer.useProgram(blurProgram);
            renderer.setMeshData(program.meshData);
            renderer.bindFBO(fbo2);
            renderer.uniforms.tMap = fbo0.texture;
            renderer.uniforms.axis = 0;
            renderer.uniforms.filter = 0.7;
            renderer.render();
            // 第三次,对y轴高斯模糊
            renderer.useProgram(blurProgram);
            renderer.bindFBO(fbo1);
            renderer.uniforms.tMap = fbo2.texture;
            renderer.uniforms.axis = 1;
            renderer.uniforms.filter = 0;
            renderer.render();
            // 第四次,对x轴高斯模糊
            renderer.useProgram(blurProgram);
            renderer.bindFBO(fbo2);
            renderer.uniforms.tMap = fbo1.texture;
            renderer.uniforms.axis = 0;
            renderer.uniforms.filter = 0;
            renderer.render();
            // 第五次,对y轴高斯模糊
            renderer.useProgram(blurProgram);
            renderer.bindFBO(fbo1);
            renderer.uniforms.tMap = fbo2.texture;
            renderer.uniforms.axis = 1;
            renderer.uniforms.filter = 0;
            renderer.render();
            // 第六次,叠加辉光
            renderer.useProgram(bloomProgram);
            renderer.setMeshData(program.meshData);
            renderer.bindFBO(null);
            renderer.uniforms.tSource = fbo0.texture;
            renderer.uniforms.tMap = fbo1.texture;
            renderer.uniforms.axis = 1;
            renderer.uniforms.filter = 0;
            renderer.render();
        </script>
    </body>
</html>


9b8d103b94ee4804b88e41359ba98b1a.png



如何用后期处理通道实现烟雾效果?

先构建一个烟雾的扩散模型:每个格子到下一时刻的颜色变化量,等于它周围四个格子的颜色值之和减去它自身颜色值的 4 倍,乘以扩散系数。


9034a403dadb416d94dc560b15a2d581.png


假设扩散系数是常量 0.1,第一轮每一格的颜色值如下:

c218676828594d79aca24898c81b4346.png



按照这个规则不断迭代下去,修改扩散公式的权重以及加入噪声就能得到一个简单的烟雾扩散效果。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>17.如何用后期处理通道实现烟雾效果?</title>
        <style>
            canvas {
                border: 1px dashed salmon;
            }
        </style>
    </head>
    <body>
        <canvas width="512" height="512"></canvas>
        <script src="./common/lib/gl-renderer.js"></script>
        <script>
            const vertex = `
                attribute vec2 a_vertexPosition;
                attribute vec2 uv;
                varying vec2 vUv;
                void main() {
                    gl_PointSize = 1.0;
                    vUv = uv;
                    gl_Position = vec4(a_vertexPosition, 1, 1);
                }
            `;
            const fragment = `
                #ifdef GL_ES
                precision highp float;
                #endif
                varying vec2 vUv;
                uniform sampler2D tMap;
                uniform float uTime;
                vec2 random2(vec2 st){
                    st = vec2( dot(st,vec2(127.1,311.7)),
                            dot(st,vec2(269.5,183.3)) );
                    return -1.0 + 2.0 * fract(sin(st) * 43758.5453123);
                }
                // Gradient Noise by Inigo Quilez - iq/2013
                // https://www.shadertoy.com/view/XdXGW8
                float noise(vec2 st) {
                    vec2 i = floor(st);
                    vec2 f = fract(st);
                    vec2 u = f * f * (3.0 - 2.0 * f);
                    return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ),
                        dot( random2(i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x),
                        mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ),
                        dot( random2(i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x), u.y
                    );
                }
                void main() {
                    vec3 smoke = vec3(0);
                    if(uTime <= 0.0) {
                        vec2 st = vUv - vec2(0.5);
                        float d = length(st);
                        // smoke = vec3(step(d, 0.05));
                        smoke = vec3(1.0 - smoothstep(0.05, 0.055, d));
                    }
                    vec2 st = vUv;
                    float offset = 1.0 / 256.0;
                    vec3 diffuse = texture2D(tMap, st).rgb;
                    vec4 left = texture2D(tMap, st + vec2(-offset, 0.0));
                    vec4 right = texture2D(tMap, st + vec2(offset, 0.0));
                    vec4 up = texture2D(tMap, st + vec2(0.0, -offset));
                    vec4 down = texture2D(tMap, st + vec2(0.0, offset));
                    float rand = noise(st + 5.0 * uTime);
                    float diff = 8.0 * 0.016 * (
                        (1.0 + rand) * left.r + 
                        (1.0 - rand) * right.r + 
                        down.r + 
                        2.0 * up.r - 
                        5.0 * diffuse.r
                    );
                    gl_FragColor.rgb = (diffuse + diff) + smoke;
                    gl_FragColor.a = 1.0;
                }
            `;
            const canvas = document.querySelector("canvas");
            const renderer = new GlRenderer(canvas);
            const program = renderer.compileSync(fragment, vertex);
            renderer.useProgram(program);
            renderer.setMeshData([
                {
                    positions: [
                        [-1, -1],
                        [-1, 1],
                        [1, 1],
                        [1, -1],
                    ],
                    attributes: {
                        uv: [
                            [0, 0],
                            [0, 1],
                            [1, 1],
                            [1, 0],
                        ],
                    },
                    cells: [
                        [0, 1, 2],
                        [2, 0, 3],
                    ],
                },
            ]);
            // 创建两个fbo对象
            const fbo = {
                readFBO: renderer.createFBO(),
                writeFBO: renderer.createFBO(),
                get texture() {
                    return this.readFBO.texture;
                },
                swap() {
                    const tmp = this.writeFBO;
                    this.writeFBO = this.readFBO;
                    this.readFBO = tmp;
                },
            };
            function update(t) {
                renderer.bindFBO(null);
                renderer.uniforms.uTime = t / 1000;
                renderer.uniforms.tMap = fbo.texture;
                renderer.render();
                renderer.bindFBO(fbo.writeFBO);
                renderer.uniforms.tMap = fbo.texture;
                fbo.swap();
                renderer.render();
                requestAnimationFrame(update);
            }
            update(0);
        </script>
    </body>
</html>

cf826b2d85124bff8edf59c3cabb38b0.gif



目录
相关文章
|
2月前
|
机器学习/深度学习 算法 计算机视觉
利用深度学习技术实现自动图像风格转换
本文将介绍如何利用深度学习技术中的神经网络结构,例如卷积神经网络和生成对抗网络,来实现自动图像风格转换。通过对图像特征的提取和风格迁移算法的应用,我们可以实现将一幅图像的风格转换为另一幅图像的艺术效果,为图像处理领域带来全新的可能性。
|
机器学习/深度学习
深度学习数据增强方法-内含(亮度增强,对比度增强,旋转图图像,翻转图像,仿射变化扩充图像,错切变化扩充图像,HSV数据增强)七种方式进行增强-每种扩充一张实现7倍扩)+ 图像缩放代码-批量
深度学习数据增强方法-内含(亮度增强,对比度增强,旋转图图像,翻转图像,仿射变化扩充图像,错切变化扩充图像,HSV数据增强)七种方式进行增强-每种扩充一张实现7倍扩)+ 图像缩放代码-批量
|
15天前
|
数据可视化 网络可视化
混合图形模型MGM的网络可预测性分析
混合图形模型MGM的网络可预测性分析
12 0
|
16天前
|
数据可视化 网络可视化
R语言混合图形模型MGM的网络可预测性分析
R语言混合图形模型MGM的网络可预测性分析
13 0
|
2月前
|
机器学习/深度学习 搜索推荐 物联网
微软开源创新LoRA组合方法,增强文生图复杂细节控制
微软研究团队推出Multi-LoRA Composition技术,改善文本到图像模型的细节控制。利用低秩适应(LoRA)提升图像生成精度,通过LORA SWITCH和LORA COMPOSITE解决组合复杂图像的挑战。新方法在ComposLoRA平台上测试,性能优于基线,为图像生成和个性化内容创作开辟新途径。尽管有学习曲线和定制需求优化的问题,但该研究仍为领域带来显著进步。
238 3
微软开源创新LoRA组合方法,增强文生图复杂细节控制
|
2月前
|
机器学习/深度学习 算法 计算机视觉
视觉智能平台常见问题之量具检测训练好了调用模型如何解决
视觉智能平台是利用机器学习和图像处理技术,提供图像识别、视频分析等智能视觉服务的平台;本合集针对该平台在使用中遇到的常见问题进行了收集和解答,以帮助开发者和企业用户在整合和部署视觉智能解决方案时,能够更快地定位问题并找到有效的解决策略。
20 0
|
5月前
|
机器学习/深度学习 算法 数据处理
【计算机视觉】数据获取、数据标注、数据增强的概念简介
【计算机视觉】数据获取、数据标注、数据增强的概念简介
59 0
|
11月前
|
人工智能 自然语言处理 数据可视化
多模态可控图片生成统一模型来了,模型参数、推理代码全部开源
多模态可控图片生成统一模型来了,模型参数、推理代码全部开源
398 0
|
12月前
|
机器学习/深度学习 编解码 计算机视觉
真的这么丝滑吗?Hinton组提出基于大型全景掩码的实例分割框架,图像视频场景丝滑切换
真的这么丝滑吗?Hinton组提出基于大型全景掩码的实例分割框架,图像视频场景丝滑切换
|
12月前
|
机器学习/深度学习 编解码 移动开发
无需训练,自动扩展的视觉Transformer来了(1)
无需训练,自动扩展的视觉Transformer来了