【车道线检测】一、传统车道线检测:基于霍夫变换的车道线检测史诗级详细教程

1、定义图像显示函数

        首先定义一个函数,函数的作用是通过plt库显示两幅图,为后续实验做准备。该函数的主要功能是:

  1. 从指定路径加载图像
  2. 显示图像的基本信息
  3. 将图像从BGR格式转换为RGB格式
  4. 并在一个图形窗口中显示两幅图像进行对比
import numpy as np
import cv2
import matplotlib.pyplot as plt
import pandas as pd
import time
import warningswarnings.filterwarnings("ignore")def load_image(path):"""从指定路径加载图像并返回。:param path: 图像文件的路径:return: 加载的图像"""img = cv2.imread(path)if img is None:raise FileNotFoundError(f"Image not found at {path}")return imgdef display_image_info(img, title="Image Info"):"""打印图像的基本信息。:param img: 图像数据:param title: 打印信息的标题"""print(f"{title}: Shape = {img.shape}")def convert_to_rgb(img):"""将图像从 BGR 格式转换为 RGB 格式。:param img: 输入图像:return: 转换后的图像"""return cv2.cvtColor(img, cv2.COLOR_BGR2RGB)def compare_images(img1, img2, titles=("Original Image", "Processed Image"), figsize=(16, 5)):"""在一个图形窗口中显示两幅图像进行对比。:param img1: 第一幅图像:param img2: 第二幅图像:param titles: 两幅图像的标题:param figsize: 图形窗口的大小"""fig, axes = plt.subplots(1, 2, figsize=figsize)fig.tight_layout()# 显示第一幅图像axes[0].imshow(convert_to_rgb(img1))axes[0].set_title(titles[0])axes[0].axis('off')# 显示第二幅图像axes[1].imshow(convert_to_rgb(img2))axes[1].set_title(titles[1])axes[1].axis('off')plt.show()# 主程序
if __name__ == "__main__":# 加载图像image_path = 'dataset/test3.jpg'img = load_image(image_path)# 显示图像信息display_image_info(img)# 对比显示原始图像和处理后的图像compare_images(img, img, titles=("Original Image", "RGB Image"))
  • 运行效果如下:(原图和RGB图)

2、将图像转换为灰度图

  • 将图像转换为灰度图:
#将图像转换为灰度图
def convert_to_gray(img):temp = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) return cv2.cvtColor(temp,cv2.COLOR_BGR2RGB) 
gray_img = convert_to_gray(img)
#对比显示原始图像和灰度图像
compare_images(img, gray_img, titles=("Original Image", "Grayscale Image"))
  • 运行效果如下:(原图和灰度图)

3、高斯模糊

        高斯模糊是一种图像处理效果,通常用于减少图像噪声以及降低细节层次它是一种平滑和淡化图像部分的技术,通常用于减少噪声或为图像的前景添加焦点高斯模糊如下:

#高斯模糊
def gaussian_blur(image, kernel_size):"""对图像进行高斯模糊处理。:param image: 输入图像:param kernel_size: 高斯核的大小,必须是奇数:return: 高斯模糊后的图像"""if kernel_size % 2 == 0:raise ValueError("Kernel size must be an odd number.")return cv2.GaussianBlur(image, (kernel_size, kernel_size), 0)# 对灰度图像进行高斯模糊处理
gauss_img = gaussian_blur(gray_img, 5)# 对比显示灰度图像和高斯模糊后的图像
compare_images(gray_img, gauss_img, titles=("Grayscale Image", "Gaussian Blurred Image"))
  • 运行效果如下:(灰度图和高斯处理效果图)

4、边缘检测

        边缘检测是图形图像处理、计算机视觉和机器视觉中的一个基本工具,通常用于特征提取和特征检测,旨在检测一张数字图像中有明显变化的边缘或者不连续的区域,在一维空间中,类似的操作被称作步长检测(step detection)。边缘是一幅图像中不同屈原之间的边界线,通常一个边缘图像是一个二值图像。边缘检测的目的是捕捉亮度急剧变化的区域,而这些区域通常是我们关注的。

4.1 灰度图像直方图

  • 绘制灰度图像的像素值分布直方图:
#灰度图直方图
plt.hist(gauss_img.ravel(),256,[0,256])
plt.title('hist of gray pixel')
plt.show()
  •  运行效果如下图:

从图像的灰度图像素值分布直方图可以看出像素值主要分布在110到140之间。 

4.2 边缘检测

        图像边缘检测,从上述的图像灰度图的像素值的分布值中我们知道像素值的分布峰值在110-140之间,故canny(gauss_img,110,140),边缘检测如下:

#边缘检测
def canny(image,low_threshold,high_threshold):"""功能: 使用Canny算法进行边缘检测。参数:image: 输入图像,通常应该是灰度图像。low_threshold: 低阈值,用于检测弱边缘。high_threshold: 高阈值,用于检测强边缘。返回: 边缘检测后的图像。"""return cv2.Canny(image,low_threshold,high_threshold)
cannyd_img = canny(gauss_img,110,140)
compare_images(gauss_img,cannyd_img, titles=("Grayscale Image", "Canny Image"))
  • 运行效果如下:

5、提取感兴趣区域(ROI)

5.1 原图提取ROI

  • 代码介绍:

        下列代码实现了一个功能,该功能可以基于给定的多边形顶点来提取图像中的特定区域。这个过程包括创建一个与输入图像相同大小的掩模,然后在这个掩模上填充多边形区域,并使用这个掩模与原始图像进行按位与操作,从而只保留多边形区域内的图像部分。

  • 封装了一个region_of_interest 函数:
    • 创建一个与输入图像相同大小的黑色掩模。
    • 根据图像的通道数确定掩模的颜色。
    • 填充多边形区域为白色,以创建掩模。
    • 将原图像与掩模进行按位与操作,以保留兴趣区域。
  • ROI区域实现如下:
#生成mask掩膜,提取ROI
#ROI即感兴趣区域,英文:Region of interestdef region_of_interest(image: np.ndarray, vertices: np.ndarray) -> np.ndarray:"""应用图像掩模以保留由顶点定义的兴趣区域。参数::param image: 输入图像(numpy数组)。:param vertices: 定义兴趣区域的多边形顶点数组。:return: 应用了掩模的图像。"""# 创建与输入图像相同大小的黑色掩模mask = np.zeros_like(image)# 根据图像的通道数确定掩模的颜色ignore_mask_color = (255,) * image.shape[2] if len(image.shape) > 2 else 255# 填充多边形区域为白色,以创建掩模cv2.fillPoly(mask, vertices, ignore_mask_color)# 将原图像与掩模进行按位与操作,以保留兴趣区域masked_image = cv2.bitwise_and(image, mask)return masked_image# 获取图像尺寸
imshape = img.shape# 设置掩膜区域
temp_v = np.array([[(0, 350), (350, 225), (530, 245), (800, 355), (950, 1000), (0, 700)]], dtype=np.int32)# 调用函数裁剪图像
crop_img = region_of_interest(img, temp_v)# 显示对比图
compare_images(img,crop_img,titles=("Grayscale Image", "ROI Image"))
  •  运行效果如下:

5.2 边缘检测后提取ROI

  • 对边缘检测后的图像进行提取ROI,如下:
crop_mask = region_of_interest(cannyd_img,temp_v)
compare_images(cannyd_img,crop_mask,titles=("Canny Image", "ROI Canny Image"))
  • 运行效果如下:

6、基于霍夫变换检测直线

6.1 什么是霍夫变换?

  • 定义:

        霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,它通过一种投票算法检测具有特定形状的物体。Hough变换是图像处理中从图像中识别几何形状的基本方法之一。Hough变换的基本原理在于利用点与线的对偶性,将原始图像空间的给定的曲线通过曲线表达形式变为参数空间的一个点。这样就把原始图像中给定曲线的检测问题转化为寻找参数空间中的峰值问题。也即把检测整体特性转化为检测局部特性。比如直线、椭圆、圆、弧线等。

        原则上霍夫变换可以检测任何形状,但复杂的形状需要的参数就多,霍夫空间的维数就多,因此在程序实现上所需的内存空间以及运行效率上都不利于把标准霍夫变换应用于实际复杂图形的检测中。霍夫梯度法是霍夫变换的改进(圆检测),它的目的是减小霍夫空间的维度,提高效率。

直线检测原理:将要检测的对象转到霍夫空间中,利用累加器找到最优解,即为所求直线。

(注:检测前要对图像二值化处理)

6.2 霍夫变换实现

        下列代码定义了两个函数 hough_lineslsd_lines,分别用于使用霍夫变换和LSD算法检测图像中的直线,并使用了一个装饰器 timed_function 来测量这两个函数的执行时间。

  • 实现如下:
def timed_function(func):"""装饰器,用于测量函数执行时间"""def wrapper(*args, **kwargs):start = time.time()result = func(*args, **kwargs)end = time.time() - startprint(f"{func.__name__} took {end:.4f}s")return resultreturn wrapper@timed_function
def hough_lines(img: np.ndarray, rho: float, theta: float, threshold: int, min_line_length: int, max_line_gap: int) -> np.ndarray:"""使用霍夫变换检测图像中的直线。参数::param img: 输入图像(边缘检测后的二值图像)。:param rho: 线段以像素为单位的距离精度。:param theta: 像素以弧度为单位的角度精度。:param threshold: 霍夫平面累加的阈值。:param min_line_length: 线段最小长度(像素级)。:param max_line_gap: 最大允许断裂长度。:return: 检测到的直线数组。"""lines = cv2.HoughLinesP(img, rho, theta, threshold, np.array([]), min_line_length, max_line_gap)return lines# 参数设置
rho = 1
theta = np.pi / 180
hof_threshold = 20
min_line_len = 30
max_line_gap = 100# 调用函数
lines_hough = hough_lines(crop_mask, rho, theta, hof_threshold, min_line_len, max_line_gap)
  • 上述参数介绍:
    1. rho: 线段以像素为单位的距离精度。
    2. theta: 像素以弧度为单位的角度精度。
    3. hof_threshold: 霍夫平面累加的阈值。
    4. min_line_len: 线段最小长度(像素级)。
    5. max_line_gap: 最大允许断裂长度。
  • 代码运行效果如下:

7、车道线检测并计算斜率

  • 在图像上绘制检测到的车道线,并显示每条线的斜率:
#车道线斜率显示
def draw_lines(image: np.ndarray, lines: np.ndarray) -> np.ndarray:"""在图像上绘制检测到的车道线,并显示每条线的斜率。参数::param image: 输入图像。:param lines: 检测到的直线数组。:return: 绘制了车道线的图像。"""for line in lines:for x1, y1, x2, y2 in line:# 计算直线的斜率fit = np.polyfit((x1, x2), (y1, y2), deg=1)slope = fit[0]slope_str = f"{slope:.2f}"  # 格式化斜率字符串# 绘制直线cv2.line(image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 10)# 在终点附近绘制斜率文本cv2.putText(image, slope_str, (int(x2), int(y2)), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 255), 2)return image# 调用函数
lined_image = draw_lines(img.copy(),lines_hough)# 显示对比图
compare_images(img, lined_image,titles=("Original Image", "Lane line slope Image"))
  • 运行效果如下:

8、计算车道线平均斜率和截距

  • 计算了左右车道线和中心线的平均斜率和截距:

def draw_lines_detection(image: np.ndarray, lines: np.ndarray) -> tuple:"""在图像上绘制检测到的车道线,并计算左右车道线和中心线的平均斜率和截距。参数::param image: 输入图像。:param lines: 检测到的直线数组。:return: 绘制了车道线的图像以及左右车道线和中心线的平均斜率和截距。"""middle_x = image.shape[1] // 2  # 图像的中点left_slopes = []right_slopes = []center_slopes = []left_biases = []right_biases = []center_biases = []for line in lines:for x1, y1, x2, y2 in line:fit = np.polyfit((x1, x2), (y1, y2), deg=1)slope = fit[0]bias = fit[1]if -0.41 < slope < -0.30:  # 左边线cv2.line(image, (x1, y1), (x2, y2), (0, 255, 0), 10)left_slopes.append(slope)left_biases.append(bias)elif 0.38 < slope < 0.42:  # 右边线cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 10)right_slopes.append(slope)right_biases.append(bias)elif slope > 1:  # 中心线cv2.line(image, (x1, y1), (x2, y2), (255, 0, 0), 10)center_slopes.append(slope)center_biases.append(bias)# 计算平均值left_slope = np.mean(left_slopes) if left_slopes else 0left_bias = np.mean(left_biases) if left_biases else 0right_slope = np.mean(right_slopes) if right_slopes else 0right_bias = np.mean(right_biases) if right_biases else 0center_slope = np.mean(center_slopes) if center_slopes else 0center_bias = np.mean(center_biases) if center_biases else 0return image, left_slope, left_bias, right_slope, right_bias, center_slope, center_bias# 调用函数
lined_image, left_slope, left_bias, right_slope, right_bias, center_slope, center_bias = draw_lines_detection(img.copy(), lines_hough)# 显示对比图
compare_images(img, lined_image,titles=("Original Image", "Lane markings detection Image"))
  • 运行效果如下:

 上述代码介绍:

  • 功能: 在图像上绘制检测到的车道线,并计算左右车道线和中心线的平均斜率和截距。
  • 参数:
    • image: 输入图像。
    • lines: 检测到的直线数组。
  • 返回: 绘制了车道线的图像以及左右车道线和中心线的平均斜率和截距。
  • 步骤:
    1. 计算图像的中点。
    2. 初始化存储斜率和截距的列表。
    3. 遍历每条直线,计算斜率和截距。
    4. 根据斜率范围判断直线属于左边线、右边线还是中心线,并分别绘制不同颜色的直线。
    5. 将斜率和截距添加到相应的列表中。
    6. 计算每个类别的平均斜率和截距。
    7. 返回绘制了车道线的图像和计算结果。

9、绘制每一条车道线

  • 在图像上绘制左右车道线和中心线:
def draw_all_line(img, slope, bias, color, y2=230):# 计算起点x1 = 0 if slope == 'left' else img.shape[1] if slope == 'right' else int((img.shape[0] - bias) / slope)y1 = int(slope * x1 + bias) if isinstance(slope, (int, float)) else img.shape[0]# 计算终点x2 = int((y2 - bias) / slope) if isinstance(slope, (int, float)) else x1# 绘制线条line_img = cv2.line(img.copy(), (x1, y1), (x2, y2), color, 10)return line_img# 左边线
left_lines = draw_all_line(img, left_slope, left_bias, (0, 255, 0))
compare_images(img, left_lines,titles=("Original Image", "Left Lane Image"))# 右边线
right_lines = draw_all_line(img, right_slope, right_bias, (0, 0, 255))
compare_images(img, right_lines,titles=("Original Image", "Right Lane Image"))# 中线
center_lines = draw_all_line(img, center_slope, center_bias, (255, 0, 0))
  • 运行效果如下:

10、图像融合--绘制最终的车道线

  • 在一个空白图像上绘制左右车道线和中心线,并将这些线条与原图像进行融合:
import numpy as np
import cv2def draw_line(blank, slope, bias, color, y2=230):# 计算起点if slope == 'left':x1 = 0y1 = int(slope * x1 + bias)elif slope == 'right':x1 = blank.shape[1]y1 = int(slope * x1 + bias)else:y1 = blank.shape[0]x1 = int((y1 - bias) / slope)# 计算终点x2 = int((y2 - bias) / slope) if slope != 'left' and slope != 'right' else x1# 绘制线条cv2.line(blank, (x1, y1), (x2, y2), color, 20)def draw_lines_and_fuse(img, left_slope, left_bias, right_slope, right_bias, center_slope, center_bias):# 创建空白图像blank = np.zeros_like(img)# 绘制左车道线draw_line(blank, left_slope, left_bias, (0, 255, 0))# 绘制右车道线draw_line(blank, right_slope, right_bias, (0, 0, 255))# 绘制中线draw_line(blank, center_slope, center_bias, (255, 0, 0))# 图像融合fusion = cv2.addWeighted(img, 0.8, blank, 1, 0)return fusion# 示例调用
fusion = draw_lines_and_fuse(img, left_slope, left_bias, right_slope, right_bias, center_slope, center_bias)
compare_images(img, fusion,titles=("Original Image", "Image blending--Lane markings detection results"))
  • 运行效果如下:

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

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

相关文章

Ftrans数据跨境传输方案:保护隐私与促进合作

数据跨境传输是指在不同国家、地区和法律框架下进行的数据交换和传输&#xff0c;数据跨境传输流程周期是数据产生--数据传输--数据接收&#xff0c;而困境来源也来自这3个环节&#xff1a; 1.本地合规限制 数据出口国&#xff08;数据输出国&#xff09;的法律对于数据收集的…

Mybatis学习笔记(三)

十、MyBatis的逆向工程 (一)逆向工程介绍 MyBatis的一个主要的特点就是需要程序员自己编写sql&#xff0c;那么如果表太多的话&#xff0c;难免会很麻烦&#xff0c;所以mybatis官方提供了一个逆向工程&#xff0c;可以针对单表自动生成mybatis执行所需要的代码&#xff08;包…

Github 2024-11-08Java开源项目日报 Top9

根据Github Trendings的统计,今日(2024-11-08统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目9Vue项目1经验丰富的Java(后端)开发人员核心面试问题和答案 | 互联网Java工程师进阶知识完全扫盲 创建周期:2085 天开发语言:Java协议…

【新闻文本分类识别】Python+CNN卷积神经网络算法+深度学习+人工智能+机器学习+文本处理

一、介绍 文本分类识别系统。本系统使用Python作为主要开发语言&#xff0c;首先收集了10种中文文本数据集&#xff08;“体育类”, “财经类”, “房产类”, “家居类”, “教育类”, “科技类”, “时尚类”, “时政类”, “游戏类”, “娱乐类”&#xff09;&#xff0c;然…

数据结构 ——— 链式二叉树的前中后序遍历递归实现

目录 前言 链式二叉树示意图​编辑 手搓一个链式二叉树 链式二叉树的前序遍历 链式二叉树的中序遍历 链式二叉树的后序遍历 前言 在上一章学习了链式二叉树的前中后序遍历的解析 数据结构 ——— 链式二叉树的前中后序遍历解析-CSDN博客 接下来要学习的是代码实现链式…

<项目代码>YOLOv8 pcb板缺陷检测<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

yarn报错`warning ..\..\package.json: No license field`:已解决

出现这个报错有两个原因 1、项目中没有配置许可证 在项目根目录package.json添加 {"name": "next-starter","version": "1.0.0",# 添加这一行"license": "MIT", }或者配置私有防止发布到外部仓库 {"priv…

大模型学习笔记------CLIP模型解读与思考

大模型学习笔记------CLIP模型详解 1、为什么提出CLIP模型2、CLIP模型详解3、CLIP模型的意义4、一些思考 上文说到&#xff0c;多模态大模型应该是非常有发展前景的&#xff0c;首先来学习 CLIP&#xff08;Contrastive Language-Image Pretraining&#xff09;这个多模态模型…

昇思25天学习打卡营第1天|快速入门

昇思25天学习打卡营第1天|快速入门 目录 昇思25天学习打卡营第1天|快速入门实操教程 一、MindSpore内容简介 主要特点&#xff1a; MindSpore的组成部分&#xff1a; 二、入门实操步骤 1. 安装必要的依赖包 2. 下载并处理数据集 3. 构建网络模型 4. 训练模型 5. 测试…

【Python TensorFlow】入门到精通

TensorFlow 是一个开源的机器学习框架&#xff0c;由 Google 开发&#xff0c;广泛应用于机器学习和深度学习领域。本篇将详细介绍 TensorFlow 的基础知识&#xff0c;并通过一系列示例来帮助读者从入门到精通 TensorFlow 的使用。 1. TensorFlow 简介 1.1 什么是 TensorFlow…

Python 学习完基础语法知识后,如何进一步提高?

入门Python后&#xff0c;就可以拿些小案例练手了&#xff0c;这时候千万不要傻乎乎地成天啃语法书。 编程是一门实践的手艺&#xff0c;讲究孰能生巧。不管是去手撸算法、或者照葫芦画瓢写几个小游戏都可以让你的Python突飞猛进。 之前看github比较多&#xff0c;推荐给大家…

Java:数据结构-再谈String类

字符串常量池 首先我们来思考这段代码&#xff0c;为什么运行结果一个是true&#xff0c;一个是false呢&#xff1f; public class Test {public static void main(String[] args) {String s1"123";String s2"123";String s3new String("555")…

书生第四期实训营基础岛——L1G2000 玩转书生「多模态对话」与「AI搜索」产品

基础任务 MindSearch使用示例 书生浦语使用示例 书生万象使用示例 进阶任务 问题&#xff1a;目前生成式AI在学术和工业界有什么最新进展&#xff1f; 回答截图&#xff1a; 知乎回答链接&#xff1a;目前生成式AI在学术和工业界有什么最新进展&#xff1f;

ReactPress:重塑内容管理的未来

ReactPress Github项目地址&#xff1a;https://github.com/fecommunity/reactpress 欢迎提出宝贵的建议&#xff0c;欢迎一起共建&#xff0c;感谢Star。 ReactPress&#xff1a;重塑内容管理的未来 在当今信息爆炸的时代&#xff0c;一个高效、易用的内容管理系统&#xff0…

短视频矩阵系统源码/抖去推源头技术4年开发

#短视频矩阵系统# #短视频矩阵系统源码# #短视频矩阵系统源码开发# #短视频矩阵系统源头技术开发# 抖音短视频矩阵系统集成开发是指利用抖音平台的开放接口和API&#xff0c;构建一个系统&#xff0c;该系统能够管理多个抖音矩阵账号&#xff0c;实现内容的统一发布、账号管理、…

CJ/T188-2004 报文举例

CJ/T188-2004 报文举例 # 读水表地址 # 请求报文&#xff1a; FE FE FE FE 68 AA AA AA AA AA AA AA AA 03 03 81 0A 00 49 16FE FE FE FE &#xff1a;前导字符 FE68 &#xff1a;起始字符AA &#xff1a;仪表类型AA AA AA AA AA AA AA &#xff1a;仪表地址&#xff08;当…

JavaEE进阶---第一个SprintBoot项目创建过程我的感受

文章目录 1.我的创建感受2.环境配置说明2.1xml文件国内源2.2配置流程 3.创建项目4.项目创建说明5.第一个程序--helloworld 1.我的创建感受 今天是学习这个spring boot项目创建的一天&#xff0c;这个确实过程坎坷&#xff0c;于是我自己决定弄一个这个IDEA的 专业版本&#xf…

7.1、实验一:RIPv1配置

一、源文件 7.1、实验一&#xff1a;RIPv1配置: https://url02.ctfile.com/d/61945102-63657205-d343fe?p2707 (访问密码: 2707) 二、实验目的 学会配置RIPv1路由 查看和调试RIPv1路由协议相关信息 三、实验要求 1.拓扑图 2. 四、开始实验 1.配置ip 配置R1 配置R2 配置…

【ARM Linux 系统稳定性分析入门及渐进 1.3 -- Crash工具编译过程】

文章目录 Build Procedure安装二进制 RPM从源代码重建构建过程从 tar 映像构建ARM 平台 Crash 工具安装从源 RPM 构建Build Procedure 从 RHEL3 版本开始,如果在系统安装时选择了开发工具包集(Development Tools),crash 工具会自动安装。然而,对于其他内核版本,或者如果…

【2023工业图像异常检测文献】GRAD: 基于异常生成和重权密集对比模式的异常检测方法

Generating and Reweighting Dense Contrastive Patterns for Unsupervised Anomaly Detection 1、Background 图像异常检测在各个领域扮演着至关重要的角色&#xff0c;包括工业产品缺陷检测、医学图像病变检测、使用X光图像的安全检查以及视频监控。 然而&#xff0c;由于无…