导向滤波算法——OpenGL实现

news2024/12/27 16:29:34

导向滤波

一、介绍

  • 导向滤波又称引导滤波,通过一张引导图片反映边缘、物体等信息,对输入图像进行滤波处理,使输出图像的内容由输入图像决定,但纹理与引导图片相似。

  • 导向滤波的原理是局部线性模型,在保持双边滤波的优势(有效保持边缘,非迭代计算)的同时计算速度很快,从而克服双边滤波速度慢的缺点。

  • 导向滤波(引导滤波)不仅能实现双边滤波的边缘平滑,而且在检测到边缘附近有很好的表现,可应用在图像增强、HDR压缩、图像抠图及图像去雾等场景。

  • 在进行保持边缘滤波时,可以采用原始图像自身或其预处理后的图像作为导向图片。

二、对比双边滤波的优势

  • 1.导向滤波比起双边滤波来说在边界附近效果较好;另外,它还具有 O(N) 的线性时间的速度优势。双边滤波器有非常大的计算复杂度O(N^2),但导向滤波器因为并未用到过于复杂的数学计算,有线性的计算复杂度。
    在这里插入图片描述
  • 2.除了速度优势以外,导向滤波的一个很好的性能就是可以保持梯度,这是bilateral做不到的,因为会有梯度翻转现象。导向滤波器因为在数学上以线性组合为基础出发,输出图片(Output Image)与引导图片(Guidance Image)的梯度方向一致,不会出现梯度反转的问题。
    在这里插入图片描述

三、导向滤波的数学原理(比较复杂,这部分可以不看了)

这部分参考大佬的一篇文章:引导滤波/导向滤波(Guided Filter)

  • 引导滤波的思想用一张引导图像产生权重,从而对输入图像进行处理,这个过程可以表示为下面公式:
    在这里插入图片描述
  • 其中,p为输入图像,I 为导向图,q 为输出图像。在这里我们认为输出图像可以看成导向图 I 的一个局部线性变换,其中k是局部化的窗口的中点,因此属于窗口 ωk 的像素,都可以用导向图对应的像素通过(ak,bk)的系数进行变换计算出来。同时,我们认为输入图像 p 是由 q 加上我们不希望的噪声或纹理得到的,因此有 p = q + n 。
    接下来就是解出这样的系数,使得p和q的差别尽量小,而且还可以保持局部线性模型。这里利用了带有正则项的 linear ridge regression(岭回归)
    在这里插入图片描述
  • 求解以上方程得到a和b在局部的值,对于一个要求的像素可能含在多个窗口中,因此平均后得到:
    在这里插入图片描述
  • 最终得到算法:
    在这里插入图片描述

四、OpenGL实现导向滤波

  • 这里把原图当做导向图。那么上图算法中的I=P,于是方差和协方差是相等的。

  • 按照上面的算法,由于导向滤波需要把原始图片分别绘制a和b,还需要计算a和b的模糊图。为了节省绘制次数,把整个大算法分成2次渲染,第一次渲染求得a和b,第二次渲染求得最终的结果q

  • 思路如下图:
    在这里插入图片描述

  • 为了在2次draw call内完成导向滤波操作,这里用了一个比较巧妙的方式是,在通一个绘制里同时绘制a和b的结果,把它分别画到画布的左半边和右半边(当然也可以分成上下)。

    • 需要注意的是这个画布的宽需要原始图片宽的2倍大,在创建纹理的时候需要注意纹理的尺寸
  • 以下为2次绘制的opengl shader

  • GuidedSubFilter1 片源着色器:

precision highp float;

uniform sampler2D u_origin; // 原图
varying vec2 texcoordOut;

uniform vec2 offset;  // 单个像素步长
uniform float alpha;   // 模糊程度
uniform float eps;   // 正则化参数e

// 均值模糊,5*5
vec3 meanBlur(vec3 colors[25]) {
    highp vec3 sum = vec3(0.0);
    for (int i = 0; i < 25; i++) {
        sum += colors[i];
    }
    return sum * 0.04;
}

void main()
{
    // 因为这个shader最终画到一个 2*w, h 尺寸的一个FBO上,左边是导向滤波的a结果,右边是导向滤波的b结果,所以这里需要计算在原始纹理上真实的采样坐标
    highp vec2 originTexcoord;
    if (texcoordOut.x < 0.5) {
        originTexcoord = vec2(texcoordOut.x * 2.0, texcoordOut.y);
    } else {
        originTexcoord = vec2((texcoordOut.x - 0.5) * 2.0, texcoordOut.y);
    }
    
    // 采样原图 I 的 5*5 个点
    highp vec3 origin[25];
    
    origin[0] = texture2D(u_origin, originTexcoord).rgb;
    
    origin[1] = texture2D(u_origin, originTexcoord + vec2(offset.x, 0.0)).rgb;
    origin[2] = texture2D(u_origin, originTexcoord + vec2(-offset.x, 0.0)).rgb;
    origin[3] = texture2D(u_origin, originTexcoord + vec2(0.0, offset.y)).rgb;
    origin[4] = texture2D(u_origin, originTexcoord + vec2(0.0, -offset.y)).rgb;
    
    origin[5] = texture2D(u_origin, originTexcoord + vec2(offset.x, offset.y)).rgb;
    origin[6] = texture2D(u_origin, originTexcoord + vec2(offset.x, -offset.y)).rgb;
    origin[7] = texture2D(u_origin, originTexcoord + vec2(-offset.x, offset.y)).rgb;
    origin[8] = texture2D(u_origin, originTexcoord + vec2(-offset.x, -offset.y)).rgb;
    
    origin[9] = texture2D(u_origin, originTexcoord + vec2(2.0 * offset.x, 0)).rgb;
    origin[10] = texture2D(u_origin, originTexcoord + vec2(-2.0 * offset.x, 0)).rgb;
    origin[11] = texture2D(u_origin, originTexcoord + vec2(0, 2.0 * offset.y)).rgb;
    origin[12] = texture2D(u_origin, originTexcoord + vec2(0, -2.0 * offset.y)).rgb;
    
    origin[13] = texture2D(u_origin, originTexcoord + vec2(2.0 * offset.x, 2.0 * offset.y)).rgb;
    origin[14] = texture2D(u_origin, originTexcoord + vec2(2.0 * offset.x, -2.0 * offset.y)).rgb;
    origin[15] = texture2D(u_origin, originTexcoord + vec2(-2.0 * offset.x, 2.0 * offset.y)).rgb;
    origin[16] = texture2D(u_origin, originTexcoord + vec2(-2.0 * offset.x, -2.0 * offset.y)).rgb;
    
    origin[17] = texture2D(u_origin, originTexcoord + vec2(2.0 * offset.x, offset.y)).rgb;
    origin[18] = texture2D(u_origin, originTexcoord + vec2(-2.0 * offset.x, offset.y)).rgb;
    origin[19] = texture2D(u_origin, originTexcoord + vec2(offset.x, 2.0 * offset.y)).rgb;
    origin[20] = texture2D(u_origin, originTexcoord + vec2(-offset.x, 2.0 * offset.y)).rgb;
    
    origin[21] = texture2D(u_origin, originTexcoord + vec2(2.0 * offset.x, -offset.y)).rgb;
    origin[22] = texture2D(u_origin, originTexcoord + vec2(-2.0 * offset.x, -offset.y)).rgb;
    origin[23] = texture2D(u_origin, originTexcoord + vec2(offset.x, -2.0 * offset.y)).rgb;
    origin[24] = texture2D(u_origin, originTexcoord + vec2(-offset.x, -2.0 * offset.y)).rgb;
    
    // 计算原图的平方 I*I
    highp vec3 origin2[25];
    for (int i = 0; i < 25; i++) {
        origin2[i] = origin[i] * origin[i];
    }
    
    // 原图 I 的均值模糊
    highp vec3 originMean = meanBlur(origin);
    // 原图平方 I*I 的均值模糊
    highp vec3 origin2Mean = meanBlur(origin2);
    
    originMean = mix(origin[0], originMean, alpha);
    origin2Mean = mix(origin2[0], origin2Mean, alpha);
    
    // 原图模糊的平方
    highp vec3 originMean2 = originMean * originMean;
    
    // 计算方差(对于磨皮来说引导图和原图是同一个图,方差和协方差是同一个)
    highp vec3 variance = origin2Mean - originMean2;
    
    // 计算导向滤波的AB结果
    highp vec3 A = variance / (variance + eps);
    highp vec3 B = originMean - A * originMean;
    
    // 把AB分别写到图像的左半部分和右半部分
    if (texcoordOut.x < 0.5) {
        gl_FragColor = vec4((A + 1.0) * 0.5, 1.0);
    } else {
        gl_FragColor = vec4((B + 1.0) * 0.5, 1.0);
    }
    
}

  • GuidedSubFilter2 片源着色器:
precision highp float;

uniform sampler2D u_origin; // 原图
uniform sampler2D u_AB;    // guided1的结果,左边是导向滤波的a结果,右边是导向滤波的b结果
varying vec2 texcoordOut;

uniform vec2 offset;  // 单个像素步长
uniform float alpha;   // 模糊程度

// 均值模糊,5*5
vec3 meanBlur(vec3 colors[25]) {
    highp vec3 sum = vec3(0.0);
    for (int i = 0; i < 25; i++) {
        sum += colors[i];
    }
    return sum * 0.04;
}

void main()
{
    // 采样图 A 的 5*5 个点
    highp vec3 colorA[25];
    highp vec2 texcoordA = vec2(texcoordOut.x * 0.5, texcoordOut.y);
    
    colorA[0] = texture2D(u_AB, texcoordA).rgb;
    
    colorA[1] = texture2D(u_AB, texcoordA + vec2(offset.x, 0.0)).rgb;
    colorA[2] = texture2D(u_AB, texcoordA + vec2(-offset.x, 0.0)).rgb;
    colorA[3] = texture2D(u_AB, texcoordA + vec2(0.0, offset.y)).rgb;
    colorA[4] = texture2D(u_AB, texcoordA + vec2(0.0, -offset.y)).rgb;
    
    colorA[5] = texture2D(u_AB, texcoordA + vec2(offset.x, offset.y)).rgb;
    colorA[6] = texture2D(u_AB, texcoordA + vec2(offset.x, -offset.y)).rgb;
    colorA[7] = texture2D(u_AB, texcoordA + vec2(-offset.x, offset.y)).rgb;
    colorA[8] = texture2D(u_AB, texcoordA + vec2(-offset.x, -offset.y)).rgb;
    
    colorA[9] = texture2D(u_AB, texcoordA + vec2(2.0 * offset.x, 0)).rgb;
    colorA[10] = texture2D(u_AB, texcoordA + vec2(-2.0 * offset.x, 0)).rgb;
    colorA[11] = texture2D(u_AB, texcoordA + vec2(0, 2.0 * offset.y)).rgb;
    colorA[12] = texture2D(u_AB, texcoordA + vec2(0, -2.0 * offset.y)).rgb;
    
    colorA[13] = texture2D(u_AB, texcoordA + vec2(2.0 * offset.x, 2.0 * offset.y)).rgb;
    colorA[14] = texture2D(u_AB, texcoordA + vec2(2.0 * offset.x, -2.0 * offset.y)).rgb;
    colorA[15] = texture2D(u_AB, texcoordA + vec2(-2.0 * offset.x, 2.0 * offset.y)).rgb;
    colorA[16] = texture2D(u_AB, texcoordA + vec2(-2.0 * offset.x, -2.0 * offset.y)).rgb;
    
    colorA[17] = texture2D(u_AB, texcoordA + vec2(2.0 * offset.x, offset.y)).rgb;
    colorA[18] = texture2D(u_AB, texcoordA + vec2(-2.0 * offset.x, offset.y)).rgb;
    colorA[19] = texture2D(u_AB, texcoordA + vec2(offset.x, 2.0 * offset.y)).rgb;
    colorA[20] = texture2D(u_AB, texcoordA + vec2(-offset.x, 2.0 * offset.y)).rgb;
    
    colorA[21] = texture2D(u_AB, texcoordA + vec2(2.0 * offset.x, -offset.y)).rgb;
    colorA[22] = texture2D(u_AB, texcoordA + vec2(-2.0 * offset.x, -offset.y)).rgb;
    colorA[23] = texture2D(u_AB, texcoordA + vec2(offset.x, -2.0 * offset.y)).rgb;
    colorA[24] = texture2D(u_AB, texcoordA + vec2(-offset.x, -2.0 * offset.y)).rgb;
    
    // 采样图 B 的 5*5 个点
    highp vec3 colorB[25];
    highp vec2 texcoordB = vec2(texcoordOut.x * 0.5 + 0.5, texcoordOut.y);
    
    colorB[0] = texture2D(u_AB, texcoordB).rgb;
    
    colorB[1] = texture2D(u_AB, texcoordB + vec2(offset.x, 0.0)).rgb;
    colorB[2] = texture2D(u_AB, texcoordB + vec2(-offset.x, 0.0)).rgb;
    colorB[3] = texture2D(u_AB, texcoordB + vec2(0.0, offset.y)).rgb;
    colorB[4] = texture2D(u_AB, texcoordB + vec2(0.0, -offset.y)).rgb;
    
    colorB[5] = texture2D(u_AB, texcoordB + vec2(offset.x, offset.y)).rgb;
    colorB[6] = texture2D(u_AB, texcoordB + vec2(offset.x, -offset.y)).rgb;
    colorB[7] = texture2D(u_AB, texcoordB + vec2(-offset.x, offset.y)).rgb;
    colorB[8] = texture2D(u_AB, texcoordB + vec2(-offset.x, -offset.y)).rgb;
    
    colorB[9] = texture2D(u_AB, texcoordB + vec2(2.0 * offset.x, 0)).rgb;
    colorB[10] = texture2D(u_AB, texcoordB + vec2(-2.0 * offset.x, 0)).rgb;
    colorB[11] = texture2D(u_AB, texcoordB + vec2(0, 2.0 * offset.y)).rgb;
    colorB[12] = texture2D(u_AB, texcoordB + vec2(0, -2.0 * offset.y)).rgb;
    
    colorB[13] = texture2D(u_AB, texcoordB + vec2(2.0 * offset.x, 2.0 * offset.y)).rgb;
    colorB[14] = texture2D(u_AB, texcoordB + vec2(2.0 * offset.x, -2.0 * offset.y)).rgb;
    colorB[15] = texture2D(u_AB, texcoordB + vec2(-2.0 * offset.x, 2.0 * offset.y)).rgb;
    colorB[16] = texture2D(u_AB, texcoordB + vec2(-2.0 * offset.x, -2.0 * offset.y)).rgb;
    
    colorB[17] = texture2D(u_AB, texcoordB + vec2(2.0 * offset.x, offset.y)).rgb;
    colorB[18] = texture2D(u_AB, texcoordB + vec2(-2.0 * offset.x, offset.y)).rgb;
    colorB[19] = texture2D(u_AB, texcoordB + vec2(offset.x, 2.0 * offset.y)).rgb;
    colorB[20] = texture2D(u_AB, texcoordB + vec2(-offset.x, 2.0 * offset.y)).rgb;
    
    colorB[21] = texture2D(u_AB, texcoordB + vec2(2.0 * offset.x, -offset.y)).rgb;
    colorB[22] = texture2D(u_AB, texcoordB + vec2(-2.0 * offset.x, -offset.y)).rgb;
    colorB[23] = texture2D(u_AB, texcoordB + vec2(offset.x, -2.0 * offset.y)).rgb;
    colorB[24] = texture2D(u_AB, texcoordB + vec2(-offset.x, -2.0 * offset.y)).rgb;
    
    // 分别对图A和图B做均值模糊
    highp vec3 meanA = meanBlur(colorA);
    highp vec3 meanB = meanBlur(colorB);
    
    meanA = meanA * 2.0 - 1.0;
    meanB = meanB * 2.0 - 1.0;
    
    meanA = mix(colorA[0] * 2.0 - 1.0, meanA, alpha);
    meanB = mix(colorB[0] * 2.0 - 1.0, meanB, alpha);
    
    // 导向滤波的最后一步融合
    highp vec3 originColor = texture2D(u_origin, texcoordOut).rgb;
    highp vec3 resultColor = meanA * originColor + meanB;
    resultColor = mix(originColor, resultColor, alpha);
    
    gl_FragColor = vec4(resultColor, 1.0);
}

绘制结果:

正则化参数eps=0.02正则化参数eps=0.02
正则化参数eps=0.02
正则化参数eps=0.02

动态效果展示

  • 1.固定模糊程度(0.5),修改正则化参数eps(变化范围 0~0.1)
    请添加图片描述
  • 2.固定正则化参数eps(0.05),修改模糊程度0~1
    请添加图片描述

源代码Git:https://github.com/sysu-huangwei/GuidedFilter

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/187132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【学习笔记】多线程

1、线程基础 1.1 创建线程的几种方式 继承Thread 类&#xff0c;覆盖run方法实现Runable接口。实现run方法。然后 通过Thread类构造方法获取Thread对象。实现Callable接口。实现call方法。 call方法可以抛出异常。也可以有返回值。 run与start 调用run方法任然是主线程在执行。…

这个 Python 游戏库,打开就能玩一天

会 Python 的小伙伴&#xff0c;选择用 Python 让“大风车”吱呦呦地转&#xff01;还有的小伙伴&#xff0c;选择用 Turtle 库绘制童年的卡通人物 我们其实还可以选择用 Python 开发小游戏&#xff0c;回忆童年的美好时光。 “凹凸版”吃豆子 这次并非用pygame制作的&#…

MyBatis超详细学习笔记(黑马)

目录 一、MyBatis快速入门 &#xff08;一&#xff09;打开MyBatis中文官网 &#xff08;二&#xff09;在工程中&#xff08;pom.xml&#xff09;导入MyBatis依赖 &#xff08;三&#xff09;编写MyBatis核心配置文件——替换连接信息&#xff0c;解决硬编码问题 &#x…

关于加强网络舆情监测的几点建议,TOOM强化舆情监控有方法

网络舆情监测是一项旨在通过监测网络上的舆情信息&#xff0c;了解社会舆论和网络话语状况&#xff0c;分析舆情动态&#xff0c;预测舆情走向&#xff0c;并进行舆情管控的工作。主要通过计算机技术和信息科学手段对网络信息进行收集、整理、分析和报告&#xff0c;以便于管理…

Golang - 操作Redis

Golang - 操作Redis go-redis是Golang语言连接、操作Redis服务的客户端&#xff0c;几乎包含了对Redis的所有操作&#xff0c;具体如下&#xff1a; 简单易用 兼容多种Redis部署架构,可用于Redis服务器、Redis群集、Redis Sentinel&#xff0c;甚至Redis服务器环go-redis 支持…

配置TF-A源码

配置TF-A源码 1.对tf-a源码进行解压 $> tar xfz tf-a-stm32mp-2.2.r2-r0.tar.gz 2.打补丁 进入/home/ubuntu/FSMP1A/tf-a-stm32mp-2.2.r2-r0/tf-a-stm32mp-2.2.r2目录 执行 for p in ls -1 ../*.patch; do patch -p1 < $p; done 3.配置工具链 1)进入/home/ubuntu/FS…

05 CSS-CSS语法【尚硅谷JavaWeb教程】

05 CSS-CSS语法【尚硅谷JavaWeb教程】 JAVAWEB的学习笔记 学习视频来自&#xff1a;https://www.bilibili.com/video/BV1AS4y177xJ/?vd_source75dce036dc8244310435eaf03de4e330 为什么需要CSS 传统的园区网络采用设备和链路冗余来保证高可靠性&#xff0c;但其链路利用率低、…

Task7:动态函数

目录注意一 Filter函数二 Subtotal函数注意 filter&#xff0c;目前只有office365支持 一 Filter函数 作用&#xff1a;需要根据指定的条件&#xff0c;将符合条件的所有记录从数据源表格式查找过来之前方法&#xff1a; 用高级筛选&#xff08;缺点&#xff1a;在查询下一个…

SAP ADM100-Unit4 数据库工作原理:中央数据库管理与DBA Cockpit

概览 本节介绍DBA Cockpit,介绍SAP环境下数据库管理和监控的要点。 使用DBA Cockpit计划日历去计划数据和日志信息的周期性备份。 课程目标 备份数据库内容 检查数据库备份是否成功被执行。 1、DBA Cockpit总览 为了最少的系统停机时间和更高的系统性能,必须计划定期的…

云计算|OpenStack|社区版OpenStack安装部署文档(一 --- 前期硬件准备和部署规划)

前言&#xff1a; 社区版OpenStack是比较难以安装部署的&#xff0c;本文将就安装部署做一个详细的说明。 首先&#xff0c;OpenStack社区版本众多&#xff0c;如何选择一个合适的版本是第一个要解决的问题&#xff08;这里的合适是指的OpenStack版本和操作系统的版本合适&am…

MATLAB-自动控制原理-时域分析

目录 step函数&#xff08;求阶跃响应&#xff09;: impulse函数&#xff08;求脉冲响应&#xff09;: lsim函数&#xff08;求输出&#xff09;: 1&#xff0c;求二阶系统不同阻尼比条件下的阶跃响应曲线 2&#xff0c;求二阶负反馈系统的动态性能指标 利用MATLAB可以方…

五、好友关注,feed流推送

文章目录关注和取消关注&#xff0c;共同关注Feed流推送Feed介绍Timeline推模式Feed流滚动分页滚动分页查询收邮箱官方命令文档&#xff1a;https://redis.io/commands/ 关注和取消关注&#xff0c;共同关注 需求&#xff1a; 可以对一个用户进行关注和取消关注查询和一个用…

深刻理解状态机设计需要避免的冒险;处理单元里的control和datapath;时序电路可能存在essential hazard;竞争冒险【SV】【VLSI】

深刻理解状态机设计需要避免的冒险&#xff1b;处理单元里的control和datapath&#xff1b;时序电路可能存在essential hazard&#xff1b;竞争冒险【SV】【VLSI】0. 前言&#xff1a;时序电路可能存在essential hazard1. 理解control和datapath1.1 Datapath control2. 硬件电路…

JavaScript XHR、Fetch

前后端分离的优势 ◼ 早期的网页都是通过后端渲染来完成的&#xff1a;服务器端渲染&#xff08;SSR&#xff0c;server side render&#xff09;&#xff1a; \qquad 客户端发出请求-> 服务端接收请求并返回相应HTML文档-> 页面刷新&#xff0c;客户端加载新的HTML文…

如何采用conda配置python虚拟环境

文章目录一、创建python虚拟环境二、配置刚创建的虚拟环境三、将虚拟环境配置到相应项目一、创建python虚拟环境 首先选中要配置环境的文件 如下&#xff1a; 在此处输入cmd按回车 此处我创建一个环境名为hands3dtext&#xff0c;环境版本为3.7.2的初始环境 conda create -n…

Visual Studio 2015配置OpenCV4.5.3(c++版)

学习目标学会在Visual Studio 2015部署Opencv一个简单的C Opencv实例一、 Visual Studio 2015配置Opencv4.5.31.1 Visual Studio 2015网上关于Visual Studio 2015的下载&#xff0c;也有很多介绍。大家自行搜索安装。1.2 OpenCVOpenCV大家根据需求下载相应版本&#xff0c;官网…

ObjectARX如何修改多行文字的格式

一 AutoCAD中多行文字的格式设置 AutoCAD在设置多行文字格式时使用了非常特殊的方式&#xff0c;多行文字整体可以有诸多格式属性&#xff0c;比如字高、颜色、旋转角度等等&#xff1b;但是&#xff0c;多行文字的每一个字符其实也可以有自己单独的格式。 比如&#xff0c;下…

java ssm学校二手服饰交易系统服装商城的卖家

目 录 Abstract 1 第一章 绪论 2 1.1课题背景 2 1.2课题研究的目的和意义 3 1.3论文所做的主要工作 3 第二章 技术介绍 4 2.1 B/S架构 4 2.2 MySQL 介绍 4 2.3 JSP技术介绍 4 第三章 系统分析与设计 6 3.1 可行性分析 6 3.2系统说明 6 3.…

Hexo 添加 Github 贡献图

参考&#xff1a;https://akilar.top/posts/1f9c68c9/ 安装 hexo-filter-gitcalendar 插件 执行命令安装 hexo-filter-gitcalendar 插件 npm install hexo-filter-gitcalendar --save在站点配置文件 _config.yml 或者主题配置文件如 _config.butterfly.yml 中添加 # hexo-filte…

jmeter录制脚本及报错:Could not create script recorder解决办法

本文分两部分&#xff1a;一、录制脚本最简单步骤&#xff1b;二、报错解决步骤 一、录制脚本步骤 1、右击【测试计划】添加一个线程组&#xff08;用于存放录制的脚本&#xff09;&#xff1b; 2、右击测试计划添加一个HTTP代理服务器&#xff08;添加--非测试元件--HTTP代理…