做网站国外访问/经典软文案例
AutoX.js - openCV多分辨率找图
一、起因
AutoXjs 中有两个找图相关的方法 findImage 和 matchTemplate,之前一直没发现什么问题,但最近在一次测试找图时,明明大图和模板图的轮廓都清晰,却怎么也找不到图,降低阈值参数后找到的结果乱七八糟,我仔细对比图像后发现原因,竟是大图相较于模板抠图时的画面等比缩小了1.2倍,仅仅是0.2倍的整体像素差异,致使搜图失败。
于是我就去翻了AutoX 的具体实现代码,发现这部分代码已是5年前继承于 autojs 的部分代码,具体代码文件在:TemplateMatching.java
其实现原理是借助 opencv的 Imgproc.matchTemplate 方法,以下是部分代码文档:
/*** 采用图像金字塔算法快速找图** @param img 图片* @param template 模板图片* @param matchMethod 匹配算法* @param weakThreshold 弱阈值。该值用于在每一轮模板匹配中检验是否继续匹配。如果相似度小于该值,则不再继续匹配。* @param strictThreshold 强阈值。该值用于检验最终匹配结果,以及在每一轮匹配中如果相似度大于该值则直接返回匹配结果。* @param maxLevel 图像金字塔的层数* @return*/
public static List<Match> fastTemplateMatching(Mat img, Mat template, int matchMethod, float weakThreshold, float strictThreshold, int maxLevel, int limit) {TimingLogger logger = new TimingLogger(LOG_TAG, "fast_tm");
从中我们可以得知,其采用了“图像金字塔算法快速找图”的处理方式,大体流程是这样的,先将大图和模板图都进行等比缩放,比如宽高都缩小为原来的1/2,如果此时能找到满足阈值的点P1,那么在图像细节更丰富的大图中点P1一定也符合阈值。将图像先等比例缩小,表示图像的矩阵尺寸也就变小,这样执行找图时,整体的计算量减小,找图效率就会大大提高。
这里采用的金字塔算法快速找图,图像尺寸变换就像金字塔,每提高一层图像就变,宽高就缩小一半。方法中的level
参数就是控制起始找图层级的,从 level
层开始从上往下搜图,level=0
,即金字塔最底层,也就是原图和模板一比一对比。例如:level=2
就代表从第3层开始往下找图,先在第3层找到 >=threshold 阈值的匹配点就加到最终结果中,剩余 < threshold 且 >=weakThreshold 的疑似匹配点就在第二层中重点关注,以此类推,直到连 >=weakThreshold 的点位也没有就结束找图。
我本以为将level参数调高就能忽略掉大图放大1.2倍的找图问题,但是level过高会导致图像挤成一团,再尝试降低 threshold,虽得到了几个结果,但都是不相干的位置,根本没法用。仔细一想,level参数只是控制找图效率的,这种快速找图的方式根本不适用于大图或模板图分辨率发生变化后的找图场景,而这种情形是很常见的,比如在你手机上开发的脚本放到平板或者别的型号手机上导致找图失败,再比如游戏场景中因双指缩放导致的画面变化。
为了适应大图分辨率可能发生变化的找图场景,我参照 AutoX 中的找图代码,重新用js实现了一版。由于我只看了找图这一部分的相关源码,项目其他的代码不熟悉,就暂时不打算通过提交 PR 为项目做贡献了,有能力的朋友可以完善此部分功能。
二、具体实现
重点部分我已加了文档说明和注释,来不及看也没关系,直接看 main() 方法中的示例,开箱即用。
importClass(org.opencv.imgproc.Imgproc);
importClass(org.opencv.core.Core);
importClass(org.opencv.core.Rect);
importClass(org.opencv.core.Mat);
importClass(org.opencv.core.Point);
importClass(org.opencv.core.Size);
importClass(org.opencv.core.CvType);
importClass(org.opencv.core.Scalar);
importClass(org.opencv.imgcodecs.Imgcodecs);/*** @param {number[]} region 是一个两个或四个元素的数组。* (region[0], region[1])表示找色区域的左上角;region[2]*region[3]表示找色区域的宽高。如果只有region只有两个元素,则找色区域为(region[0], region[1])到屏幕右下角。* 如果不指定region选项,则找色区域为整张图片。* @param {*} img* @returns {org.opencv.core.Rect}*/
function buildRegion(region, img) {if (region == undefined) {region = [];}let x = region[0] === undefined ? 0 : region[0];let y = region[1] === undefined ? 0 : region[1];let width = region[2] === undefined ? img.getWidth() - x : region[2];let height = region[3] === undefined ? img.getHeight() - y : region[3];if (x < 0 || y < 0 || x + width > img.width || y + height > img.height) {throw new Error('out of region: region = [' + [x, y, width, height] + '], image.size = [' + [img.width, img.height] + ']');}return new Rect(x, y, width, height);
}/*** @param {number} threshold 图片相似度。取值范围为0~1的浮点数。默认值为0.9* @param {number[]} region 找图区域* @param {number[]} scaleFactors 大图的宽高缩放因子,默认为 [1, 0.9, 1.1, 0.8, 1.2]* @param {number} max 找图结果最大数量,默认为5* @param {boolean} grayTransform 是否进行灰度化预处理,默认为true。* 通常情况下将图像转换为灰度图可以简化匹配过程并提高匹配的准确性,当然,如果你的匹配任务中颜色信息对匹配结果具有重要意义,* 可以跳过灰度化步骤,直接在彩色图像上进行模板匹配。*/
function MatchOptions(threshold, region, scaleFactors, max, grayTransform) {this.threshold = threshold;this.region = region;this.scaleFactors = scaleFactors;this.max = max;this.grayTransform = grayTransform;
}const defaultMatchOptions = new MatchOptions(0.9,undefined,[[1, 1],[0.9, 0.9],[1.1, 1.1],[0.8, 0.8],[1.2, 1.2]],5,true
);
// 校验参数
MatchOptions.check = function (options) {if (options == undefined) {return defaultMatchOptions;}// deep copylet newOptions = JSON.parse(JSON.stringify(options));if (newOptions.threshold == undefined) {newOptions.threshold = defaultMatchOptions.threshold;}if (newOptions.region && !Array.isArray(newOptions.region)) {throw new TypeError('region type is number[]');}if (newOptions.max == undefined) {newOptions.max = defaultMatchOptions.max;}if (newOptions.scaleFactors == undefined) {newOptions.scaleFactors = defaultMatchOptions.scaleFactors;} else if (!Array.isArray(newOptions.scaleFactors)) {throw new TypeError('scaleFactors');}for (let index = 0; index < newOptions.scaleFactors.length; index++) {let factor = newOptions.scaleFactors[index];if (Array.isArray(factor) && factor[0] > 0 && factor[1] > 0) {// nothing} else if (typeof factor === 'number') {newOptions.scaleFactors[index] = [factor, factor];} else {throw new TypeError('scaleFactors');}}if (newOptions.grayTransform === undefined) {newOptions.grayTransform = defaultMatchOptions.grayTransform;}return newOptions;
};function Match(point, similarity, scaleX, scaleY) {this.point = point;this.similarity = similarity;this.scaleX = scaleX;this.scaleY = scaleY;
}/*** 找图,在图中找出所有匹配的位置* @param {Image} img* @param {Image} template* @param {MatchOptions} options 参数见上方定义* @returns {Match[]}*/
function matchTemplate(img, template, options) {if (img == null || template == null) {throw new Error('ParamError');}options = MatchOptions.check(options);console.log('参数:', options);let largeMat = img.mat;let templateMat = template.mat;let largeGrayMat;let templateGrayMat;if (options.region) {options.region = buildRegion(options.region, img);largeMat = new Mat(largeMat, options.region);}// 灰度处理if (options.grayTransform) {largeGrayMat = new Mat();Imgproc.cvtColor(largeMat, largeGrayMat, Imgproc.COLOR_BGR2GRAY);templateGrayMat = new Mat();Imgproc.cvtColor(templateMat, templateGrayMat, Imgproc.COLOR_BGR2GRAY);}// =================================================let finalMatches = [];for (let factor of options.scaleFactors) {let [fx, fy] = factor;let resizedTemplate = new Mat();Imgproc.resize(templateGrayMat || templateMat, resizedTemplate, new Size(), fx, fy, Imgproc.INTER_LINEAR);// 执行模板匹配,标准化相关性系数匹配法let matchMat = new Mat();Imgproc.matchTemplate(largeGrayMat || largeMat, resizedTemplate, matchMat, Imgproc.TM_CCOEFF_NORMED);let currentMatches = _getAllMatch(matchMat, resizedTemplate, options.threshold, factor, options.region);console.log('缩放比:', factor, '可疑目标数:', currentMatches.length);for (let match of currentMatches) {if (finalMatches.length === 0) {finalMatches = currentMatches.slice(0, options.max);break;}if (!isOverlapping(finalMatches, match)) {finalMatches.push(match);}if (finalMatches.length >= options.max) {break;}}resizedTemplate.release();matchMat.release();if (finalMatches.length >= options.max) {break;}}largeMat !== img.mat && largeMat.release();largeGrayMat && largeGrayMat.release();templateGrayMat && templateGrayMat.release();return finalMatches;
}function _getAllMatch(tmResult, templateMat, threshold, factor, rect) {let currentMatches = [];let mmr = Core.minMaxLoc(tmResult);while (mmr.maxVal >= threshold) {// 每次取匹配结果中的最大值和位置,从而使结果按相似度指标从高到低排序let pos = mmr.maxLoc; // Pointlet value = mmr.maxVal;let start = new Point(Math.max(0, pos.x - templateMat.width() / 2), Math.max(0, pos.y - templateMat.height() / 2));let end = new Point(Math.min(tmResult.width() - 1, pos.x + templateMat.width() / 2),Math.min(tmResult.height() - 1, pos.y + templateMat.height() / 2));// 屏蔽已匹配到的区域Imgproc.rectangle(tmResult, start, end, new Scalar(0), -1);mmr = Core.minMaxLoc(tmResult);if (rect) {pos.x += rect.x;pos.y += rect.y;start.x += rect.x;start.y += rect.y;end.x += rect.x;end.y += rect.y;}let match = new Match(pos, value, factor[0], factor[1]);// 保存匹配点的大致范围,用于后续去重。设置enumerable为false相当于声明其为私有属性Object.defineProperty(match, 'matchAroundRect', { value: new Rect(start, end), writable: true, enumerable: false });currentMatches.push(match);}return currentMatches;
}/*** 判断新检测到的点位是否与之前的某个点位重合。* @param {Match[]} matches* @param {Match} newMatch* @returns {boolean}*/
function isOverlapping(matches, newMatch) {for (let existingMatch of matches) {// 也可判断两点间的距离,但是平方、开方运算不如比较范围简单高效if (existingMatch.matchAroundRect.contains(newMatch.point)) {if (newMatch.similarity > existingMatch.similarity) {existingMatch.point = newMatch.point;existingMatch.similarity = newMatch.similarity;existingMatch.scaleX = newMatch.scaleX;existingMatch.scaleY = newMatch.scaleY;existingMatch.matchAroundRect = newMatch.matchAroundRect;}return true;}}return false;
}
/*** 根据搜图结果在原图上画框* @param {Match[]} matches* @param {*} srcMat* @param {*} templateMat*/
function showMatchRectangle(matches, srcMat, templateMat) {for (let match of matches) {let start = match.point;let end = new Point(match.point.x + templateMat.width() * match.scaleX,match.point.y + templateMat.height() * match.scaleY);Imgproc.rectangle(srcMat, start, end, new Scalar(0, 0, 255), 3);}const saveName = '/sdcard/Download/temp.jpg';let img2 = images.matToImage(srcMat);images.save(img2, saveName);app.viewFile(saveName);img2.recycle();
}function main() {let largeImage = images.read('/sdcard/Download/large.jpg');let template = images.read('/sdcard/Download/template.jpg');console.log('大图尺寸:', [largeImage.getWidth(), largeImage.getHeight()]);console.log('模板尺寸:', [template.getWidth(), template.getHeight()]);let startTs = Date.now();let result = matchTemplate(largeImage, template, {threshold: 0.85,region: [100, 100],grayTransform: false,scaleFactors: [1, 0.9, 1.1, 0.8, 1.2],max: 6});console.log('找图耗时:', (Date.now() - startTs) / 1000);console.log(result);// 将结果画框展示showMatchRectangle(result, largeImage.mat, template.mat);template.recycle();largeImage.recycle();
}// 初始化openCV
runtime.getImages().initOpenCvIfNeeded();
main();
备注说明
-
参数
threhold
、region
、max
跟AutoX中的一样。 -
grayTransform:是否将图像进行灰度预处理,开启可大幅提高找图效率,默认为true。
对于模板匹配任务,通常关注的是图像的纹理和亮度变化,而不是颜色差异。因此,将图像转换为灰度图可以降低计算复杂度,减少模板匹配过程中的噪声干扰,并提高匹配的稳定性和准确性。如果你的模板小图中纹理不明显,或是一团颜色相近的色块,就得关闭该功能。
-
scaleFactors:是对小图模板的缩放因子,数组类型,默认为
[1, 0.9, 1.1, 0.8, 1.2]
。每一项可以是数字,表示宽高等比例缩放,也可以是长度为2的数组,表示宽、高对应的缩放比,例如:[0.9, 1, [1.1, 1.2]]
这里重点强调一点,我没有在 openCV 里找到可以直接用于忽略图像比例差异的搜图方法,只能手动指定可能的缩放范围,依次对小图模板进行缩放后再搜图。理论上,只要你设置的(不重复)缩放因子足够多,就一定能找到目标,除非图中没有😁。
-
max参数的妙用:搜图过程中,默认在找到前 max 个符合阈值的匹配点就退出,但是可能存在一种情况,例如先在缩放比为 1.1 的情况下找到了相似度为 0.8 的点 P1,此时若还没有找够 max 个匹配点,在后续比例为 1.2 的情况下,检测到点 P1 处的相似度提高到0.9,就将原来 P1 点的信息更新为更准确的信息。理解了这一点,如果你将 max 设置的非常大,我的搜图算法就会按照
scaleFactors
中设置的全部缩放因子都检测一遍,不会提前结束,那么最终结果中所有的 Match 对象中保存的都是最佳匹配点的信息,你可以凭借最终结果中的 scaleX、scaleY 信息,动态调整scaleFactors
参数,使其优先匹配最佳缩放比,提高后续的找图效率。
三、测试结果展示
以下是一个测试数据,模板图是一坨近乎白色的光团,对比了 grayTransform
参数开启和关闭的情况,虽然效率相差好几倍,但是此时还是关闭灰度预处理的结果更准确。
希望大家在使用时,清楚每个参数改变所产生的效果。
-
模板小图
-
5个缩放因子下的找图结果
-
开启灰度处理
-
未开启灰度处理
相关文章:

AutoX.js - openCV多分辨率找图
AutoX.js - openCV多分辨率找图 一、起因 AutoXjs 中有两个找图相关的方法 findImage 和 matchTemplate,之前一直没发现什么问题,但最近在一次测试找图时,明明大图和模板图的轮廓都清晰,却怎么也找不到图,降低阈值参…...

Python爬虫实战案例——第七例
文章中所有内容仅供学习交流使用,不用于其他任何目的!严禁将文中内容用于任何商业与非法用途,由此产生的一切后果与作者无关。若有侵权,请联系删除。 目标:LI视频采集 地址:aHR0cHM6Ly93d3cucGVhcnZpZGVv…...

C# 图解教程 第5版 —— 第13章 数组
文章目录 13.1 数组13.1.1 定义13.1.2 重要细节 13.2 数组的类型13.3 数组是对象13.4 一维数组和矩形数组13.5 实例化一维数组或矩形数组13.6 访问数组元素(*)13.7 初始化数组13.7.1 显示初始化一维数组13.7.2 显示初始化矩形数组13.7.3 初始化矩形数组的…...

android studio启动Task配置
Android studio 高版本默认不开启Task配置,需要自己手动开启 1.低版本配置路径:(复制他人图片) 2.高版本路径:添加下图勾选配置即可 3.gradle task 3.1 初识task gradle中所有的构建工作都是由task完成的,它帮我们处…...

Xcode运行程序提示 Executable Path is a Directory 问题解决
一、首先运行模拟器报错(没有记录),解决办法: TARGET->Build Settings->Architectures -> Exclude Architectures里面填入arm64,后运行模拟器成功 二、其次模拟器开发完成后,xcode运行真机调试&…...

决策树的优缺点
决策树优点 1. 易于理解和解释,因为树木可以画出来被看见 2. 需要很少的数据准备。其他很多算法通常都需要数据规范化,需要创建虚拟变量并删除空值等。但请注意, sklearn中的决策树模块不支持对缺失值的处理。 3. 使用树的成本(比…...

Flask后端开发(二) - 功能实现和项目总结
目录 1. 功能1:修改文件参数值1.1. 获取网页端传参1.2. 读取文件1.2.1. 一般文件读取方式1.2.2. 特殊文件 —— mlx文件1.2.3. 特殊文件 —— .xlx文件1.3. 查找数据修改位置,替换数据2. 功能2:读取结果数据2.1. 实时数据展示如何存储相关数据?2.2. 读取相关数据,整理、打…...

思维训练第五课插入语和主谓一致
系列文章目录 文章目录 系列文章目录前言一、插入语插入语的分类1、常用作插入语的副词 Indeed的确 certainly 当然 surely 无疑地 however 然而 等2、形容词及词组作插入语3、常作插入语的介词短语4、常作插入语的分词短语 Strictly speaking严格地说,generally sp…...

开源利器:it-tools 项目介绍
作为一名开发人员,我们在日常工作和学习中常常需要使用一系列小工具,如JSON格式化、JSON转表格、当前时间戳、XML格式化、SQL格式化、密码生成以及UUID生成等。通常情况下,我们会在网上搜索各种在线工具来满足这些需求。然而,这些…...

基于和声算法的无人机航迹规划-附代码
基于和声算法的无人机航迹规划 文章目录 基于和声算法的无人机航迹规划1.和声搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要:本文主要介绍利用和声算法来优化无人机航迹规划。 1.和声搜索算法 …...

[Linux]线程池
[Linux]线程池 文章目录 [Linux]线程池线程池的概念线程池的优点线程池的应用场景线程池的实现 线程池的概念 线程池是一种线程使用模式。线程池是一种特殊的生产消费模型,用户作为生产者,线程池作为消费者和缓冲区。 线程过多会带来调度开销,…...

使用es实现轻量级分布式锁
文章目录 [toc] 1.前言2.实现3.总结 1.前言 一般来说,实现分布式锁的方式有哪几种? 一:Redisson实现 二:ZK实现 这两种实现网上的实现是千篇一律,在本文就不做过多的讲解了 其它方式好像没有了,真的是这…...

富文本编辑器特殊字符的解码编码
var HtmlUtil {/*1.用浏览器内部转换器实现html转码*/htmlEncode:function (html){//1.首先动态创建一个容器标签元素,如DIVvar temp document.createElement ("div");//2.然后将要转换的字符串设置为这个元素的innerText(ie支持)或者textContent(火狐&…...

几种软件开发方法对比
几种软件开发方法对比 1 综述 软件开发方法是一种使用早已定义好的技术集及符号表示习惯来组织软件生产的过程。 本文对净室方法、结构化方法、面向对象方法、原型法、逆向工程等方法进行梳理,并对各种开发方法特点、优点进行对比。 2 净室方法 2.1 特点 净…...

在Maven中发布项目到Nexus私有服务器
一、测试环境 Sonatype Nexus 3.61.0-02 Maven 3.9.2 二、环境配置 2.1找到maven的配置文件 2.2添加私有仓库账户密码 <servers><server><id>nexus</id><username>admin</username><password>admin</password></server&…...

TypeScript - 类 -类的继承
浅谈类的继承 类的继承 就是对一个类进行扩展,可以扩展属性、方法。 类的继承 可以很好的解决代码冗余的问题。比如 : 【学生】类 拥有 基本的 姓名、年龄 两个属性, 【体育生】类也属于【学生】类,有 姓名、年龄、训练项目 三个…...

QT: QLineEdit 密码模式、QLineEdit输入模式
setEchoMode(QLineEdit::Normal) 是一个函数,用于设置 QLineEdit 对象的输入模式。具体用法如下: lineEdit->setEchoMode(QLineEdit::Normal);该函数的作用是将 QLineEdit 对象的输入模式设置为“正常模式”,在此模式下,用户的…...

ES6中Map集合
Map集合是一个新的数据结构,它可以存储键值对,并且可以使用任何类型的值作为键,包括对象、数组和函数。Map也是一种可迭代的结构,可以使用for...of循环遍历。 在ES6中,我们可以使用Map构造函数来创建一个Map集合&…...

【Leetcode Sheet】Weekly Practice 13
Leetcode Test 1155 掷骰子等于目标和的方法数(10.24) 这里有 n 个一样的骰子,每个骰子上都有 k 个面,分别标号为 1 到 k 。 给定三个整数 n , k 和 target ,返回可能的方式(从总共 kn 种方式中)滚动骰子的数量,使正面朝上的数…...

技术贴 | 一文掌握 Google Test 框架
一、简介 1. 引言 在开发过程中,如何保证代码的质量以及程序的正确性成为了我们亟需解决的问题,其中测试用例成为了不必可少的一部分。测试用例不仅可以帮助我们验证代码的正确性,还能帮助我们捕获潜在的错误,提高代码的可靠性和…...

基于深度学习的中文情感分类 - 卷积神经网络 情感分类 情感分析 情感识别 评论情感分类 计算机竞赛
文章目录 1 前言2 情感文本分类2.1 参考论文2.2 输入层2.3 第一层卷积层:2.4 池化层:2.5 全连接softmax层:2.6 训练方案 3 实现3.1 sentence部分3.2 filters部分3.3 featuremaps部分3.4 1max部分3.5 concat1max部分3.6 关键代码 4 实现效果4.…...

非线性时滞系统的无模型预测控制
摘 要 非线性时滞系统的预测控制应用广泛,比如电子设备、石油化工、造纸等行业,都会运用到非线性时滞系统的预测控制系统或工具。更高效率和更高精度的非线性时滞系统的预测控制一直是研究的热点。在我们日常生活中,非线性时滞系统的预测控制…...

局域网内两台电脑共享文件夹(通过网线直连共享数据)
文章目录 2.设置共享文件夹3.访问共享文件夹 1.将两台电脑置于同一局域网下 用网线将两台电脑连接关闭两台电脑防火墙将两台电脑IP地址设置在同一局域网下 测试是否在同一局域网下,使用ping命令 ping 192.168.0.122.设置共享文件夹 选择想要共享的文件夹ÿ…...

什么是 CNN? 卷积神经网络? 怎么用 CNN 进行分类?(3)
参考视频:https://www.youtube.com/watch?vE5Z7FQp7AQQ&listPLuhqtP7jdD8CD6rOWy20INGM44kULvrHu 视频7:CNN 的全局架构 卷积层除了做卷积操作外,还要加上 bias ,再经过非线性的函数,这么做的原因是 “scaled p…...

一致性hash负载均衡
Hash算法的问题 今天看下一致性hash,常见的负载均衡可能使用过hash,比如nginx中,如果使用session最简单就是通过hash,比如根据用户的请求ip进行hash,让不同用户的请求打到同一台服务器,这样状态处理起来最…...

MAC下安装Python
MAC基本信息: 执行命令: brew install cmake protobuf rust python3.10 git wget 遇到以下问题: > Downloading https://mirrors.aliyun.com/homebrew/homebrew-bottles/rust-1.59.0 Already downloaded: /Users/xxxx/Library/Caches/Ho…...

Android NDK开发详解之JNI中的库文件
Android NDK开发详解之JNI中的库文件 简介工作原理流程原生 activity 和应用 简介 本部分简要介绍了 NDK 的工作原理。Android NDK 是一组使您能将 C 或 C(“原生代码”)嵌入到 Android 应用中的工具。能够在 Android 应用中使用原生代码对于想执行以下…...

KNN模型
使用K-Nearest Neighbors (KNN)算法进行分类。首先加载一个数据集,然后进行预处理,选择最佳的K值,并训练一个KNN模型。 # encodingutf-8 import numpy as np datas np.loadtxt(datingTestSet2.txt) # 加载数据集,返回一个numpy数…...

Python 学习1 基础
文章目录 基础字符串字面量常用的值类型注释变量print语句数据类型数据类型转换标识符运算符 字符串拓展小结 2023.10.28 周六 最近打算学一下Python,毕竟确实简单方便,而且那个编程语言排名还是在第一。不过不打算靠它吃饭,深不深入暂且不说…...

网络协议--TCP的超时与重传
21.1 引言 TCP提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确认都有可能会丢失。TCP通过在发送时设置一个定时器来解决这种问题。如果当定时器溢出时还没有收到确认,它就重传该数据。对任何实现而言,关键之处就在于超时和重…...