基于VGG-16+Android+Python的智能车辆驾驶行为分析—深度学习算法应用(含全部工程源码)+数据集+模型(三)

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
  • 模块实现
    • 1. 数据预处理
    • 2. 模型构建
    • 3. 模型训练及保存
      • 1)模型训练
      • 2)模型保存
    • 4. 模型生成
      • 1)模型导入及调用
      • 2)相关代码
        • (1)布局文件
        • (2)主活动类
  • 相关其它博客
  • 工程源代码下载
  • 其它资料下载


在这里插入图片描述

前言

本项目采用VGG-16网络模型,使用Kaggle开源数据集,旨在提取图片中的用户特征,最终在移动端实现对不良驾驶行为的识别功能。

首先,通过使用VGG-16网络模型,本项目能够深入学习和理解驾驶场景图像中的特征。VGG-16是一种深度卷积神经网络,特别适用于图像识别任务,通过多层次的卷积和池化层,能够有效地提取图像中的抽象特征。

其次,项目利用Kaggle提供的开源数据集,包括各种驾驶场景图像,覆盖了不同的驾驶行为和条件。这样的数据集是训练模型所需的关键资源。

接下来,利用训练好的VGG-16模型,项目提取图像中的用户特征。包括驾驶行为的姿势、眼神、手部动作等方面的特征,有助于判断是否存在不良驾驶行为。

最后,通过在移动端实现这个模型,可以将不良驾驶行为的识别功能直接部署到车辆或驾驶辅助系统中。这种实时的、移动端的识别方案有望在驾驶安全和监管方面发挥积极的作用。

总的来说,项目结合了深度学习、图像处理和移动端技术,致力于实现对不良驾驶行为的智能化识别,为提升驾驶安全提供了一种创新的解决方案。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述
VGG-16网络架构如图所示。

在这里插入图片描述

运行环境

本部分包括Python环境、TensorFlow环境、Pycharm环境和Android环境。

详见博客。

模块实现

本项目包括4个模块:数据预处理、模型构建、模型训练及保存、模型生成。下面分别给出各模块的功能介绍及相关代码。

1. 数据预处理

本部分包括数据集来源、内容和预处理。

详见博客。

2. 模型构建

数据加载进模型之后,需要定义模型结构,并优化损失函数。

详见博客。

3. 模型训练及保存

在定义模型架构和编译后,通过训练集训练,使模型可以识别数据集中图像的特征。

1)模型训练

模型训练相关代码如下:

train_generator = train_datagen.flow_from_directory(train_data_dir, target_size=(img_height, img_width), batch_size=32, class_mode='categorical')
#读取训练集
validation_generator = train_datagen.flow_from_directory(validation_data_dir, target_size=(img_height, img_width), batch_size=32, class_mode='categorical')
#读取验证集
model.fit_generator(train_generator, samples_per_epoch=nb_train_samples, epochs=nb_epoch, validation_data=validation_generator, nb_val_samples=nb_validation_samples)
#训练模型
model.save('model+weights.h5')
#保存模型及权重

2)模型保存

上述由Keras库生成的模型及权重文件为.h5格式,为了能够被Android程序读取,需要将.h5文件转换为.pb格式的文件,模型被保存后,可以被重用,也可以移植到其他环境中使用。

def h5_to_pb(h5_model, output_dir, model_name, out_prefix="output_", log_tensorboard=True):#.h5模型文件转换成.pb模型文件if os.path.exists(output_dir) == False:os.mkdir(output_dir)out_nodes = []for i in range(len(h5_model.outputs)):out_nodes.append(out_prefix + str(i + 1))tf.identity(h5_model.output[i], out_prefix + str(i + 1))sess = backend.get_session()from tensorflow.python.framework import graph_util, graph_io#写入.pb模型文件init_graph = sess.graph.as_graph_def()main_graph = graph_util.convert_variables_to_constants(sess, init_graph, out_nodes)graph_io.write_graph(main_graph, output_dir, name=model_name, as_text=False)#输出日志文件if log_tensorboard:from tensorflow.python.tools import import_pb_to_tensorboardimport_pb_to_tensorboard.import_to_tensorboard(os.path.join(output_dir, model_name), output_dir)

4. 模型生成

将图片转化为数据,输入TensorFlow的模型中并获取输出。

1)模型导入及调用

本部分包括模型导入及调用的操作方法。

a. 编写代码进行实际预测之前,需要将转换后的模型添加到应用程序的资源文件夹中。在Android Studio中,鼠标右键"项目",跳转至Add Folder(添加文件夹)部分,并选择AssetsFolder(资源文件夹)。在应用程序目录中创建一个资源文件夹,将模型复制到其中,如图所示。

在这里插入图片描述

b. 将新的Java类添加到项目的主程序包中,并命名为ImageUtils,ImageUtils为图片工具类,可用于Bitmap、byte、array、Drawable图片类型之间进行转换以及缩放。

相关代码如下:

package com.example.doremi.testkeras2tensorflow;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.os.Environment;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import org.json.*;
//用于处理图像的实用程序类
public class ImageUtils {/**返回转换矩阵,处理裁切(如果需要保持宽高比)和旋转*参数srcWidth为源帧的宽度*参数srcHeight为源帧的高度*参数dstWidth为目标帧的宽度*参数dstHeight为目标帧的高度*参数applyRotation为旋转的角度,为90°的整数倍*参数maintainAspectRatio为是否维持缩放比例*返回满足所需要求的转换*/public static Matrix getTransformationMatrix(final int srcWidth,final int srcHeight,final int dstWidth,final int dstHeight,final int applyRotation,final boolean maintainAspectRatio) {final Matrix matrix = new Matrix();if (applyRotation != 0) {//进行平移,使图像中心在原点matrix.postTranslate(-srcWidth / 2.0f, -srcHeight / 2.0f);//绕原点旋转matrix.postRotate(applyRotation);}//考虑已经应用的旋转(如果有),然后确定每个轴需要多少缩放。final boolean transpose = (Math.abs(applyRotation) +90) % 180 == 0;final int inWidth = transpose ? srcHeight : srcWidth;final int inHeight = transpose ? srcWidth : srcHeight;//必要时应用缩放if (inWidth != dstWidth || inHeight != dstHeight) {final float scaleFactorX = dstWidth / (float) inWidth;final float scaleFactorY = dstHeight / (float) inHeight;if (maintainAspectRatio) {//按最小比例缩放,以便在保持宽高比的同时完全填充,某些图像可能会截掉边缘final float scaleFactor = Math.max(scaleFactorX, scaleFactorY);matrix.postScale(scaleFactor, scaleFactor);} else {//精确缩放matrix.postScale(scaleFactorX, scaleFactorY);}}if (applyRotation != 0) {//从以原点为中心的参考转换回目标帧matrix.postTranslate(dstWidth / 2.0f, dstHeight / 2.0f);}return matrix;}public static Bitmap processBitmap(Bitmap source,int size){int image_height = source.getHeight();int image_width = source.getWidth();Bitmap croppedBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);Matrix frameToCropTransformations = getTransformationMatrix(image_width,image_height,size,size,0,false);Matrix cropToFrameTransformations = new Matrix();frameToCropTransformations.invert(cropToFrameTransformations);final Canvas canvas = new Canvas(croppedBitmap);canvas.drawBitmap(source, frameToCropTransformations, null);return croppedBitmap;}public static float[] normalizeBitmap(Bitmap source,int size,float mean,float std){float[] output = new float[size * size * 3];int[] intValues = new int[source.getHeight() * source.getWidth()];source.getPixels(intValues, 0, source.getWidth(), 0, 0, source.getWidth(), source.getHeight());for (int i = 0; i < intValues.length; ++i) {final int val = intValues[i];output[i * 3] = (((val >> 16) & 0xFF) - mean)/std;output[i * 3 + 1] = (((val >> 8) & 0xFF) - mean)/std;output[i * 3 + 2] = ((val & 0xFF) - mean)/std;}return output;}public static Object[] argmax(float[] array){int best = -1;float best_confidence = 0.0f;for(int i = 0;i < array.length;i++){float value = array[i];if (value > best_confidence){best_confidence = value;best = i;}}return new Object[]{best,best_confidence};}public static String getLabel( InputStream jsonStream,int index){String label = "";try {byte[] jsonData = new byte[jsonStream.available()];jsonStream.read(jsonData);jsonStream.close();String jsonString = new String(jsonData,"utf-8");JSONObject object = new JSONObject(jsonString);label = object.getString(String.valueOf(index));}catch (Exception e){}return label;}
}

c. 在主活动(main activity)添加代码,被用于显示图像和预测结果。

public void predict(final Bitmap bitmap){//在后台线程中运行预测new AsyncTask<Integer,Integer,Integer>(){@Overrideprotected Integer doInBackground(Integer ...params){//将图像大小调整为150*150Bitmap resized_image = ImageUtils.processBitmap(bitmap,150);//归一化像素floatValues=ImageUtils.normalizeBitmap(resized_image,150,127.5f,1.0f);//将输入传到tensorflowtf.feed(INPUT_NAME,floatValues,1,150,150,3);//计算预测tf.run(new String[]{OUTPUT_NAME});//将输出复制到预测数组中tf.fetch(OUTPUT_NAME,PREDICTIONS);//获得最高预测Object[] results = argmax(PREDICTIONS);int class_index = (Integer) results[0];float confidence = (Float) results[1];try{final String conf = String.valueOf(confidence * 100).substring(0,5);//将预测的类别索引转换为实际的标签名称final String label = ImageUtils.getLabel(getAssets().open("labels.json"),class_index);//展示结果runOnUiThread(new Runnable() {@Overridepublic void run() {progressBar.dismiss();resultView.setText(label + " : " + conf + "%");}});}catch (Exception e){}return 0;}}.execute(0);
}

2)相关代码

本部分包括布局文件和主活动类。

(1)布局文件

布局文件相关代码如下:

/res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><android.support.design.widget.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:theme="@style/AppTheme.AppBarOverlay"><android.support.v7.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="?attr/colorPrimary"app:popupTheme="@style/AppTheme.PopupOverlay" /></android.support.design.widget.AppBarLayout><include layout="@layout/content_main" /><android.support.design.widget.FloatingActionButtonandroid:id="@+id/predict"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="bottom|end"android:layout_margin="@dimen/fab_margin"app:srcCompat="@android:drawable/ic_media_play" />
</android.support.design.widget.CoordinatorLayout>
/res/layout/content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/appbar_scrolling_view_behavior"tools:context=".MainActivity"tools:showIn="@layout/activity_main"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="30dp"android:layout_marginBottom="30dp"android:text="Click the Red-Colored floating button below to show and predict the image"/><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:adjustViewBounds="true"android:scaleType="fitCenter"android:id="@+id/imageview"android:layout_marginBottom="10dp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/results"/></LinearLayout></ScrollView>
</android.support.constraint.ConstraintLayout>
(2)主活动类

主活动类相关代码如下:

package com.specpal.mobileai;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.renderscript.ScriptGroup;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.JsonReader;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import org.json.*;
import org.tensorflow.contrib.android.TensorFlowInferenceInterface;
import java.io.FileInputStream;
import java.io.InputStream;
public class MainActivity extends AppCompatActivity {//加载流推理库static {System.loadLibrary("tensorflow_inference");}//模型存放路径和输入/输出节点名称private String MODEL_PATH = "file:///android_asset/model+weights_22424.pb";private String INPUT_NAME = "zero_padding2d_1_input";private String OUTPUT_NAME = "output_1";private TensorFlowInferenceInterface tf;//保存预测的数组和图像数据的浮点值float[] PREDICTIONS = new float[10];private float[] floatValues;private int[] INPUT_SIZE = {150,150,3};ImageView imageView;TextView resultView;Snackbar progressBar;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);setSupportActionBar(toolbar);//初始化TensorFlowtf = new TensorFlowInferenceInterface(getAssets(),MODEL_PATH);imageView = (ImageView) findViewById(R.id.imageview);resultView = (TextView) findViewById(R.id.results);progressBar = Snackbar.make(imageView,"PROCESSING IMAGE",Snackbar.LENGTH_INDEFINITE);final FloatingActionButton predict = (FloatingActionButton) findViewById(R.id.predict);predict.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {try{//从ASSETS文件夹读取图片InputStream imageStream = getAssets().open("testimage4.gif");Bitmap bitmap = BitmapFactory.decodeStream(imageStream);imageView.setImageBitmap(bitmap);progressBar.show();predict(bitmap);}catch (Exception e){}}});}//计算最大预测及其置信度的函数public Object[] argmax(float[] array){int best = -1;float best_confidence = 0.0f;for(int i = 0;i < array.length;i++){float value = array[i];if (value > best_confidence){best_confidence = value;best = i;}}return new Object[]{best,best_confidence};}public void predict(final Bitmap bitmap){//在后台线程中运行预测new AsyncTask<Integer,Integer,Integer>(){@Overrideprotected Integer doInBackground(Integer ...params){//将图像大小调整为150 x*150Bitmap resized_image = ImageUtils.processBitmap(bitmap,150);//归一化像素floatValues=ImageUtils.normalizeBitmap(resized_image,150,127.5f,1.0f);//将输入传到TensorFlowtf.feed(INPUT_NAME,floatValues,1,150,150,3);//计算预测tf.run(new String[]{OUTPUT_NAME});//将输出复制到预测数组中tf.fetch(OUTPUT_NAME,PREDICTIONS);//获得最高预测Object[] results = argmax(PREDICTIONS);int class_index = (Integer) results[0];float confidence = (Float) results[1];try{final String conf = String.valueOf(confidence * 100).substring(0,5);//将预测的类别索引转换为实际的标签名称final String label = ImageUtils.getLabel(getAssets().open("labels.json"),class_index);//展示结果runOnUiThread(new Runnable() {@Overridepublic void run() {progressBar.dismiss();resultView.setText(label + " : " + conf + "%");}});}catch (Exception e){}return 0;}}.execute(0);}
}

相关其它博客

基于VGG-16+Android+Python的智能车辆驾驶行为分析—深度学习算法应用(含全部工程源码)+数据集+模型(一)

基于VGG-16+Android+Python的智能车辆驾驶行为分析—深度学习算法应用(含全部工程源码)+数据集+模型(二)

基于VGG-16+Android+Python的智能车辆驾驶行为分析—深度学习算法应用(含全部工程源码)+数据集+模型(四)

工程源代码下载

详见本人博客资源下载页


其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

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

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

相关文章

bug-ku--计算器

F12 maxlength"1" 限制的是你能输入几位数 改成3就行 来那个数相相加就能输入了 flag{464f5f406e7e182014500fc49f7aedfc}

【异步绘制】UIView刷新原理 与 异步绘制

快捷目录 壹、 iOS界面刷新机制贰、浅谈UIView的刷新与绘制概述一.UIView 与 CALayer1. UIView 与 CALayer的关系2. CALayer的一些常用属性contents属性contentGravity属性contentsScale属性maskToBounds属性contentsRect属性 二.View的布局与显示1.图像显示原理2.布局layoutSu…

【UE】在蓝图中修改材质实例的参数的两种方式

目录 方式一、通过“在材质上设置标量/向量参数值”节点实现 方式二、通过“设置标量/向量参数值”节点实现 方式一、通过“在材质上设置标量/向量参数值”节点实现 1. 在材质中设置了两个参数 2. 创建材质实例 3. 创建一个蓝图&#xff0c;对静态网格体赋予材质实例 在事件…

【C++初阶】类与对象(上)

类与对象&#xff08;上&#xff09; 1.面向过程和面向对象初步认识2.类的引入3.类的定义4.类的访问限定符及封装4.1 访问限定符4.2 封装 5.类的作用域6.类的实例化7.类对象模型7.1 如何计算类对象的大小7.2 结构体内存对齐规则 8.this指针8.1 this指针的引出8.2 this指针的特性…

【算法与数据结构】53、LeetCode最大子数组和

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;程序一共两个变量&#xff0c;一个result一个count。result用来记录最终的结果&#xff0c;count记录当…

LAMP平台——构建PHP运行环境

在构建LAMP平台时&#xff0c;各组件的安装顺序依次为Linux、Apache、MySQL、PHP。其中Apache和 MySQL的安装并没有严格的顺序&#xff1b;而PHP环境的安装一般放到最后&#xff0c;负责沟通Web服务器和数据库 系统以协同工作。 PHP 即 Hypertext Preprocessor&#xff08;超级…

数据结构 之map/set练习

文章目录 1. 只出现一次的数字算法原理&#xff1a;代码&#xff1a; 2. 随机链表的复制算法原理&#xff1a;代码&#xff1a; 3. 宝石与石头算法原理&#xff1a;代码&#xff1a; 4. 坏键盘打字算法原理&#xff1a;代码&#xff1a; 5. 前K个高频单词算法原理&#xff1a;代…

图片的批量建码怎么做?一图一码的制作方法

在使用图片展示内容时&#xff0c;经常会有同一类型的图片信息是有区别的&#xff0c;如果需要将每张图片批量生成二维码图片&#xff0c;那么出了一张一张去制作之外&#xff0c;有没有能够一键批量建码的功能可以解决这个问题呢&#xff1f;下面来给大家分享一下图片批量建码…

SpringBoot 源码解析1:环境搭建

SpringBoot 源码解析1&#xff1a;环境搭建 1.项目结构2.pom.xml3.MyApplication 1.项目结构 最简单的spring-web项目 2.pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns…

记删除CK不彻底问题 及 新增表TTL机制

问题背景&#xff1a;对CK表进行删除时&#xff0c;发现无法彻底删除&#xff0c;并报错如下&#xff1a; 同时也会有下面的报错信息&#xff1a; 解决过程&#xff1a; 确认CK 节点是否健康存活&#xff0c;select * from system.clusters 可以查看&#xff1b;确认CK元数据是…

基于ssm日用品网站设计论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本日用品网站就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&…

linux系统的u盘/mmc/sd卡等的支持热插拔和自动挂载行为

1.了解mdev mdev是busybox自带的一个简化版的udev。udev是从Linux 2.6 内核系列开始的设备文件系统&#xff08;DevFS&#xff09;的替代品&#xff0c;是 Linux 内核的设备管理器。总的来说&#xff0c;它取代了 devfs 和 hotplug&#xff0c;负责管理 /dev 中的设备节点。同时…

openEuler商业化进展可观:累计装机量超610万套,市场持续扩容

12月15日至16日&#xff0c;以“崛起数字时代&#xff0c;引领数智未来”为主题的操作系统大会&#xff06;openEuler Summit 2023在北京国家会议中心举办。大会旨在汇聚全球产业界创新力量&#xff0c;构筑坚实的基础软件根基&#xff0c;推动基础软件技术持续创新&#xff0c…

win10 node-red安装及管理配置

win10 node-red安装及管理配置 一、安装node.js环境二、安装node-red环境2.1 node-red安装2.2 node-red安全登录方式 三、pm2管理node-red服务3.1 安装pm23.2 pm2管理node-red服务 四、常用命令4.1 npm命令4.2 pm2命令 更多 本文旨在详细介绍windows10系统下的node-red开发配置…

visio打出根号,下标,并调整符号的大小

插入公式对象 打出根号和带下标的字母 调整符号大小 把做好的公式符号弄到visio中的图中 ctrla 复制符号 进入visio中粘贴 并 调整大小 调整大小直接拖动边框上的圆点即可。

java SSM酒店客房管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM酒店客房管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采…

在开发微信小程序的时候,报错navigateBack:fail cannot navigate back at firstpage

这个错误的意思是&#xff1a;在这个页面已经是第一个页面了&#xff0c;没办法再返回了 报错原因 这个错误原因其实也简单&#xff0c;就是在跳转的时候使用了wx.redirectTo()&#xff0c;使用wx.redirectTo()相当于重定向&#xff0c;不算是从上一个页面跳转过来的&#xf…

com.sun.org.apache.xerces.internal.impl.dv.util.Base64

com.sun.org.apache.xerces.internal.impl.dv.util.Base64 Access restriction: The type Base64 is not API (restriction on required library D:\Java\jdk1.8.0_341\jre\lib\rt.jar) Maven Update Project 虽然没错误了&#xff0c;但是有警告&#xff0c;好奇&#xff1f;…

python进度条

分享一个进度条python库 瞬间觉得很酷 :)) 它的名字叫tqdm 效果图&#xff1a; 代码&#xff1a; import time from tqdm import tqdmfor i in tqdm(range(100), desc"Loading", unit"kb"):time.sleep(0.1)

中通单号查询,中通快递物流查询,对需要的单号进行备注

批量查询中通快递单号的物流信息&#xff0c;对需要的单号进行备注。 所需工具&#xff1a; 一个【快递批量查询高手】软件 中通快递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;并登录 步骤2&#xff1a;点击主界面左上角的“…