【视觉基础篇】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



目录
相关文章
|
3月前
|
文字识别 算法 安全
视觉智能开放平台产品使用合集之人脸修复增强接口采用什么方法增强人像
视觉智能开放平台是指提供一系列基于视觉识别技术的API和服务的平台,这些服务通常包括图像识别、人脸识别、物体检测、文字识别、场景理解等。企业或开发者可以通过调用这些API,快速将视觉智能功能集成到自己的应用或服务中,而无需从零开始研发相关算法和技术。以下是一些常见的视觉智能开放平台产品及其应用场景的概览。
|
机器学习/深度学习
深度学习数据增强方法-内含(亮度增强,对比度增强,旋转图图像,翻转图像,仿射变化扩充图像,错切变化扩充图像,HSV数据增强)七种方式进行增强-每种扩充一张实现7倍扩)+ 图像缩放代码-批量
深度学习数据增强方法-内含(亮度增强,对比度增强,旋转图图像,翻转图像,仿射变化扩充图像,错切变化扩充图像,HSV数据增强)七种方式进行增强-每种扩充一张实现7倍扩)+ 图像缩放代码-批量
|
1月前
|
机器学习/深度学习 PyTorch 算法框架/工具
图像数据增强库综述:10个强大图像增强工具对比与分析
在深度学习和计算机视觉领域,数据增强是提升模型性能和泛化能力的关键技术。本文全面介绍了10个广泛使用的图像数据增强库,分析其特点和适用场景,帮助研究人员和开发者选择最适合需求的工具。这些库包括高性能的GPU加速解决方案(如Nvidia DALI)、灵活多功能的Albumentations和Imgaug,以及专注于特定框架的Kornia和Torchvision Transforms。通过详细比较各库的功能、特点和适用场景,本文为不同需求的用户提供丰富的选择,助力深度学习项目取得更好的效果。选择合适的数据增强库需考虑性能需求、任务类型、框架兼容性及易用性等因素。
127 11
|
6月前
|
数据可视化 开发工具 计算机视觉
LabVIEW视觉采集软件(VAS)、视觉生成器(VB)和视觉开发模块(VDM)之间有什么不同
LabVIEW视觉采集软件(VAS)、视觉生成器(VB)和视觉开发模块(VDM)之间有什么不同
55 1
|
6月前
|
机器学习/深度学习 搜索推荐 物联网
微软开源创新LoRA组合方法,增强文生图复杂细节控制
微软研究团队推出Multi-LoRA Composition技术,改善文本到图像模型的细节控制。利用低秩适应(LoRA)提升图像生成精度,通过LORA SWITCH和LORA COMPOSITE解决组合复杂图像的挑战。新方法在ComposLoRA平台上测试,性能优于基线,为图像生成和个性化内容创作开辟新途径。尽管有学习曲线和定制需求优化的问题,但该研究仍为领域带来显著进步。
411 3
微软开源创新LoRA组合方法,增强文生图复杂细节控制
|
12月前
|
机器学习/深度学习 传感器 自动驾驶
视觉BEV基本原理和方案解析
视觉BEV在高德高精地图地面要素识别、车道线拓扑构建、车端融合定位等业务场景中都扮演了重要角色。
|
6月前
|
机器学习/深度学习 编解码 API
视觉智能平台常见问题之分割后的图片尺寸会变得比较大如何解决
视觉智能平台是利用机器学习和图像处理技术,提供图像识别、视频分析等智能视觉服务的平台;本合集针对该平台在使用中遇到的常见问题进行了收集和解答,以帮助开发者和企业用户在整合和部署视觉智能解决方案时,能够更快地定位问题并找到有效的解决策略。
|
6月前
|
机器学习/深度学习 计算机视觉
YOLOv5改进 | 2023 | SCConv空间和通道重构卷积(精细化检测,又轻量又提点)
YOLOv5改进 | 2023 | SCConv空间和通道重构卷积(精细化检测,又轻量又提点)
204 1
|
6月前
|
机器学习/深度学习 计算机视觉
YOLOv8改进 | 2023 | SCConv空间和通道重构卷积(精细化检测,又轻量又提点)
YOLOv8改进 | 2023 | SCConv空间和通道重构卷积(精细化检测,又轻量又提点)
220 0
|
6月前
|
监控 算法 数据库
入门了解——三维人脸数据的优点
入门了解——三维人脸数据的优点
40 0