基于yolov5的目标检测和双目测距

news2024/11/18 1:35:41

目录

一.简介

1.双目视觉

2 YOLOv5

二.双目准备

1双目矫正

2.测距部分代码和函数

三.yolov5部分代码代码展示


效果展示

一.简介

1.双目视觉

双目视觉是通过两个摄像机同时拍摄同一场景,通过计算两幅图像的差异来获取深度信息的一种计算机视觉技术。在双目视觉中,两个摄像机的成像位置和角度是预先确定的,它们之间的距离被称为基线,通过计算两个相机拍摄的图像中对应像素点的视差,可以计算出每个像素点的深度。

双目视觉的主要优势在于其可以通过将两个视角的信息进行比较,来消除图像中的噪声和误差,从而获得更准确的深度信息。此外,在近距离测量和物体检测等领域中都有广泛的应用。

双目视觉的基本流程包括以下几个步骤:

  1. 相机标定:确定相机的内外参数,包括焦距、畸变系数、旋转和平移矩阵等,以及两个摄像机之间的基线长度和相对位置关系。

  2. 图像获取:使用两个摄像机同时拍摄同一个场景,获取两幅图像。

  3. 特征提取:从两幅图像中提取特征点或者特征区域,例如SIFT或SURF算法,生成特征点集合。

  4. 特征匹配:通过比较两个图像中的特征点集合,找出相同的特征,建立对应关系。

  5. 视差计算:根据特征点间的视差大小,结合相机标定参数,计算出每个像素点的深度值。

  6. 深度图生成:将深度信息转换为灰度图像,生成深度图。

虽然双目视觉技术能够提供准确的深度信息,并可以运用在机器人导航、三维重建等领域,但是该技术还面临一些挑战,例如光照变化、遮挡和反射等问题,这些问题可能会影响特征提取和匹配,从而影响深度信息的准确性。

2 YOLOv5

YOLOv5是一种目标检测算法,由美国加州大学伯克利分校的研究团队开发。与其前身YOLOv4相比,YOLOv5在速度和检测精度方面有了非常显著的提升。

YOLOv5的全称是You Only Look Once version 5,意为“你只需要看一次”即可完成目标检测任务。它采用深度神经网络架构,在单张图像上进行物体检测,可以同时检测出多个物体,并得到它们的位置、类别和置信度等信息,具有高效、准确的特点。

YOLOv5的主要优势包括:

1. 高速度:相较于其前身YOLOv4,YOLOv5平均检测速度提高了65%,同时还具有更小的模型尺寸和更少的计算量。

2. 高检测精度:通过采用新的网络架构和数据增强技术,YOLOv5在检测精度方面取得了突破性的进展。

3. 简单易用:相对于其他目标检测算法,YOLOv5的代码量较小,易于实现和调试,能够应用于多种不同的应用场景。

目前,YOLOv5已经被广泛应用于自动驾驶、智能安防、工业自动化等领域,在实时物体检测和跟踪任务中具有广泛的应用前景。

二.双目准备

原理参考:双目标定之张正友标定法数学原理详解matlab版-CSDN博客

棋盘格图片自提

链接:https://pan.baidu.com/s/1W31fTtr6db8qgTevulWeMA 
提取码:ybca

二.双目准备

1双目矫正

打开Matlab 上方的工具栏APP,找到图像处理和计算机视觉下的Stereo Camera Calibration工具,打开并将分割后的图片导入

 设置参数,对于一般的相机选择2 Coefficients选项即可,对于大视场相机则选择3 Coefficients选项。拉线删除误差较大的画面:

获取参数

在matlab控制台分别输入 stereoParams.CameraParameters1.IntrinsicMatrix 和stereoParams.CameraParameters2.IntrinsicMatrix 获得左右相机的参数,下边填写时请注意进行矩阵的转置

为了获取左相机的畸变系数:[k1, k2, p1, p2, k3],我们需要分别输入stereoParams.CameraParameters1.RadialDistortion 和 stereoParams.CameraParameters1.TangentialDistortion

分别输入 stereoParams.RotationOfCamera2 和 stereoParams 来获取双目的旋转矩阵和平移矩阵

将以上参数填写进stereoconfig.py文件里,注意转置

import numpy as np
 
# 双目相机参数
class stereoCamera(object):
    def __init__(self):
        # 左相机内参
        self.cam_matrix_left = np.array([   [479.6018,   -0.0769,  652.6060],
                                            [       0,  478.0229,  352.3870],
                                            [       0,         0,         1]
                                        ])
        # 右相机内参
        self.cam_matrix_right = np.array([  [489.9354,   0.2789,  641.6219],
                                            [       0,  487.9356,  354.5612],
                                            [       0,         0,         1]
                                        ])
 
        # 左右相机畸变系数:[k1, k2, p1, p2, k3]
        self.distortion_l = np.array([[-0.0791, 0.0309, -0.0009, -0.0004, -0.0091]])
        self.distortion_r = np.array([[-0.1153, 0.1021, -0.0011,  -0.0005,  -0.0459]])
 
        # 旋转矩阵
        self.R = np.array([ [1.0000,  0.0005, -0.0184],
                            [-0.0005,  1.0000, 0.0001],
                            [ 0.0184,  -0.0001,  1.0000]   
                            ])
        # 平移矩阵
        self.T = np.array([[121.4655], [0.2118], [0.5950]])
        # 焦距
        self.focal_length = 749.402 # 默认值,一般取立体校正后的重投影矩阵Q中的 Q[2,3]
        # 基线距离
        self.baseline = 121.4655 # 单位:mm, 为平移向量的第一个参数(取绝对值)

2.测距部分代码和函数

import sys
import cv2
import numpy as np
import stereoconfig
 
 
# 预处理
def preprocess(img1, img2):
    # 彩色图->灰度图
    if (img1.ndim == 3):  # 判断是否为三维数组
        img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)  # 通过OpenCV加载的图像通道顺序是BGR
    if (img2.ndim == 3):
        img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
 
    # 直方图均衡
    img1 = cv2.equalizeHist(img1)
    img2 = cv2.equalizeHist(img2)
 
    return img1, img2
 
 
# 消除畸变
def undistortion(image, camera_matrix, dist_coeff):
    undistortion_image = cv2.undistort(image, camera_matrix, dist_coeff)
 
    return undistortion_image
 
 
# 获取畸变校正和立体校正的映射变换矩阵、重投影矩阵
# @param:config是一个类,存储着双目标定的参数:config = stereoconfig.stereoCamera()
def getRectifyTransform(height, width, config):
    # 读取内参和外参
    left_K = config.cam_matrix_left
    right_K = config.cam_matrix_right
    left_distortion = config.distortion_l
    right_distortion = config.distortion_r
    R = config.R
    T = config.T
 
    # 计算校正变换
    R1, R2, P1, P2, Q, roi1, roi2 = cv2.stereoRectify(left_K, left_distortion, right_K, right_distortion,
                                                      (width, height), R, T, alpha=0)
 
    map1x, map1y = cv2.initUndistortRectifyMap(left_K, left_distortion, R1, P1, (width, height), cv2.CV_32FC1)
    map2x, map2y = cv2.initUndistortRectifyMap(right_K, right_distortion, R2, P2, (width, height), cv2.CV_32FC1)
 
    return map1x, map1y, map2x, map2y, Q
 
 
# 畸变校正和立体校正
def rectifyImage(image1, image2, map1x, map1y, map2x, map2y):
    rectifyed_img1 = cv2.remap(image1, map1x, map1y, cv2.INTER_AREA)
    rectifyed_img2 = cv2.remap(image2, map2x, map2y, cv2.INTER_AREA)
 
    return rectifyed_img1, rectifyed_img2
 
 
# 立体校正检验----画线
def draw_line(image1, image2):
    # 建立输出图像
    height = max(image1.shape[0], image2.shape[0])
    width = image1.shape[1] + image2.shape[1]
 
    output = np.zeros((height, width, 3), dtype=np.uint8)
    output[0:image1.shape[0], 0:image1.shape[1]] = image1
    output[0:image2.shape[0], image1.shape[1]:] = image2
 
    # 绘制等间距平行线
    line_interval = 50  # 直线间隔:50
    for k in range(height // line_interval):
        cv2.line(output, (0, line_interval * (k + 1)), (2 * width, line_interval * (k + 1)), (0, 255, 0), thickness=2,
                 lineType=cv2.LINE_AA)
 
    return output
 
 
# 视差计算
def stereoMatchSGBM(left_image, right_image, down_scale=False):
    # SGBM匹配参数设置
    if left_image.ndim == 2:
        img_channels = 1
    else:
        img_channels = 3
    blockSize = 3
    paraml = {'minDisparity': 0,
              'numDisparities': 64,
              'blockSize': blockSize,
              'P1': 8 * img_channels * blockSize ** 2,
              'P2': 32 * img_channels * blockSize ** 2,
              'disp12MaxDiff': 1,
              'preFilterCap': 63,
              'uniquenessRatio': 15,
              'speckleWindowSize': 100,
              'speckleRange': 1,
              'mode': cv2.STEREO_SGBM_MODE_SGBM_3WAY
              }
 
    # 构建SGBM对象
    left_matcher = cv2.StereoSGBM_create(**paraml)
    paramr = paraml
    paramr['minDisparity'] = -paraml['numDisparities']
    right_matcher = cv2.StereoSGBM_create(**paramr)
 
    # 计算视差图
    size = (left_image.shape[1], left_image.shape[0])
    if down_scale == False:
        disparity_left = left_matcher.compute(left_image, right_image)
        disparity_right = right_matcher.compute(right_image, left_image)
    else:
        left_image_down = cv2.pyrDown(left_image)
        right_image_down = cv2.pyrDown(right_image)
        factor = left_image.shape[1] / left_image_down.shape[1]
 
        disparity_left_half = left_matcher.compute(left_image_down, right_image_down)
        disparity_right_half = right_matcher.compute(right_image_down, left_image_down)
        disparity_left = cv2.resize(disparity_left_half, size, interpolation=cv2.INTER_AREA)
        disparity_right = cv2.resize(disparity_right_half, size, interpolation=cv2.INTER_AREA)
        disparity_left = factor * disparity_left
        disparity_right = factor * disparity_right
 
    # 真实视差(因为SGBM算法得到的视差是×16的)
    trueDisp_left = disparity_left.astype(np.float32) / 16.
    trueDisp_right = disparity_right.astype(np.float32) / 16.
 
    return trueDisp_left, trueDisp_right
 
 
def getDepthMapWithQ(disparityMap: np.ndarray, Q: np.ndarray) -> np.ndarray:
    points_3d = cv2.reprojectImageTo3D(disparityMap, Q)  # points_3d 是一个三维的数组,前面两个是宽和高,第三维是一个(x,y,z)的坐标
    points = points_3d[:, :, 0:3]
 
    depthMap = points_3d[:, :, 2]  # 索引三维数组的最后一维,就是深度信息
    reset_index = np.where(np.logical_or(depthMap < 0.0, depthMap > 65535.0))
    depthMap[reset_index] = 0
 
    return depthMap.astype(np.float32)
 
 
if __name__ == '__main__':
    # 读取图片
    cap = cv2.VideoCapture(0)
    cap.set(3, 1280)
    cap.set(4, 480)  # 打开并设置摄像头
 
    while True:
        ret, frame = cap.read()
        iml = frame[0:480, 0:640]
        imr = frame[0:480, 640:1280]  # 分割双目图像
 
 
        if (iml is None) or (imr is None):
            print("Error: Images are empty, please check your image's path!")
            sys.exit(0)
        height, width = iml.shape[0:2]    # 对图像进行切片操作,前面两位是高和宽
 
        iml_, imr_ = preprocess(iml, imr)  # 预处理,一般可以削弱光照不均的影响,不做也可以
 
        # 读取相机内参和外参
        # 使用之前先将标定得到的内外参数填写到stereoconfig.py中的StereoCamera类中
        config = stereoconfig.stereoCamera()
        # print(config.cam_matrix_left)
 
        # 立体校正
        map1x, map1y, map2x, map2y, Q = getRectifyTransform(height, width, config)  # 获取用于畸变校正和立体校正的映射矩阵以及用于计算像素空间坐标的重投影矩阵
        iml_rectified, imr_rectified = rectifyImage(iml, imr, map1x, map1y, map2x, map2y)
        # print(Q)
 
        # 绘制等间距平行线,检查立体校正的效果
        line = draw_line(iml_rectified, imr_rectified)
        cv2.imwrite('check_rectification.png', line)
 
        # 立体匹配
        disp, _ = stereoMatchSGBM(iml_rectified, imr_rectified, False)  # 这里传入的是经立体校正的图像
 
        cv2.imwrite('disaprity.png', disp * 4)
 
        # fx = config.cam_matrix_left[0, 0]
        # fy = fx
        # cx = config.cam_matrix_left[0, 2]
        # cy = config.cam_matrix_left[1, 2]
 
        # print(fx, fy, cx, cy)
 
        # 计算像素点的3D坐标(左相机坐标系下)
        points_3d = cv2.reprojectImageTo3D(disp, Q)  # 参数中的Q就是由getRectifyTransform()函数得到的重投影矩阵
 
 
 
        # 设置想要检测的像素点坐标(x,y)
        x = 120
        y = 360
        cv2.circle(iml, (x, y), 5, (0, 0, 255), -1)
 
        # x1 = points_3d[y, x]   # 索引 (y, x) 对应的是三维坐标 (x1, y1, z1)
        # print(x1)
 
        print('x:', points_3d[int(y), int(x), 0], 'y:', points_3d[int(y), int(x), 1], 'z:',
              points_3d[int(y), int(x), 2])  # 得出像素点的三维坐标,单位mm
        print('distance:', (points_3d[int(y), int(x), 0] ** 2 + points_3d[int(y), int(x), 1] ** 2 + points_3d[
            int(y), int(x), 2] ** 2) ** 0.5)  # 计算距离,单位mm
 
 
        cv2.namedWindow("disparity", 0)
        cv2.imshow("disparity", iml)
        # cv2.setMouseCallback("disparity", onMouse,  0)
 
 
        # 等待用户按键,如果按下 'q' 键或者 Esc 键,则退出循环
        c = cv2.waitKey(1) & 0xFF
        if c == 27 or c == ord('q'):
            break
 
    # 释放视频对象并关闭窗口
    cap.release()
    cv2.destroyAllWindows()

三.yolov5部分代码代码展示

# 读取相机内参和外参
    config = stereoconfig_040_2.stereoCamera()
    
    # 立体校正
    map1x, map1y, map2x, map2y, Q = getRectifyTransform(720, 1280, config)  # 获取用于畸变校正和立体校正的映射矩阵以及用于计算像素空间坐标的重投影矩阵
    
    for path, img, im0s, vid_cap in dataset:
        img = torch.from_numpy(img).to(device)
        img = img.half() if half else img.float()  # uint8 to fp16/32
        img /= 255.0  # 0 - 255 to 0.0 - 1.0
        if img.ndimension() == 3:
            img = img.unsqueeze(0)

        # Inference
        t1 = time_synchronized()
        pred = model(img, augment=opt.augment)[0]

        # Apply NMS
        pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes, agnostic=opt.agnostic_nms)
        t2 = time_synchronized()

        # Apply Classifier
        if classify:
            pred = apply_classifier(pred, modelc, img, im0s)
        
        
 
        # Process detections
        for i, det in enumerate(pred):  # detections per image
            if webcam:  # batch_size >= 1
                p, s, im0, frame = path[i], '%g: ' % i, im0s[i].copy(), dataset.count
                
            else:
                p, s, im0, frame = path, '', im0s, getattr(dataset, 'frame', 0)

            ###############################
            #stereo code
            fps_set = 10 #setting the frame
            if(accel_frame % fps_set == 0):
                #t3 = time.time() # stereo time start 0.510s
                #string = ''
                
                #thread = threading.Thread(target = mythread,args = ((config,im0,map1x, map1y, map2x, map2y,Q)) )
                
                thread= MyThread(stereo_threading,args = (config,im0,map1x, map1y, map2x, map2y,Q))
                thread.start()
                
                #if(accel_frame % fps_set == 0):
                #    thread.join()
                #points_3d = thread.get_result()
                print()
                print(threading.active_count())                              #获取已激活的线程数
                print(threading.enumerate())    # see the thread list,查看所有线程信息,一个<_MainThread(...)> 带多个 <Thread(...)>
                print()
                print("############## Frame is %d !##################" %accel_frame)

            

            p = Path(p)  # to Path
            if webcam:
                save_stream_path = str(save_stream_dir / "stream0.mp4")  # save streams path
            else:   
                save_path = str(save_dir / p.name)  # img.jpg
                txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}')  # img.txt
            
           
            
            
            s += '%gx%g ' % img.shape[2:]  # print string
            #print("txt_path is %s"%txt_path)
            gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwh

            if len(det):
                # Rescale boxes from img_size to im0 size
                det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()

                # Print results
                for c in det[:, -1].unique():
                    n = (det[:, -1] == c).sum()  # detections per class
                    s += f"{n} {names[int(c)]} {'s' * (n > 1)} , "  # add to string

本项目不开源,需要的私聊 ,谢谢

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

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

相关文章

文心一言 VS 讯飞星火 VS chatgpt (117)-- 算法导论10.3 2题

二、用go语言&#xff0c;对一组同构对象用单数组表示法实现&#xff0c;写出过程ALLOCATE-OBJECT和FREE-OBJECT。 文心一言&#xff1a; 在Go语言中&#xff0c;我们通常使用指针和结构体来表示和操作复杂的数据结构。对于一组同构对象&#xff0c;我们可以使用一个数组来存…

SQL INSERT INTO 语句(在表中插入)

SQL INSERT INTO 语句 INSERT INTO 语句用于向表中插入新的数据行。 SQL INSERT INTO 语法 INSERT INTO 语句可以用两种形式编写。  第一个表单没有指定要插入数据的列的名称&#xff0c;只提供要插入的值&#xff0c;即可添加一行新的数据&#xff1a; INSERT INTO table_n…

【马蹄集】—— 概率论专题:排列组合

概率论专题&#xff1a;排列组合 目录 MT2226 抽奖概率MT2227 饿饿&#xff01;饭饭&#xff01;MT2228 甜甜花的研究MT2229 赌石MT2230 square MT2226 抽奖概率 难度&#xff1a;黄金    时间限制&#xff1a;1秒    占用内存&#xff1a;128M 题目描述 小码哥正在进行抽奖…

积极开拓北美市场,泡泡玛特在美国的首家直营门店正式开业

近几年&#xff0c;随着年轻人在消费市场的声量越来越大&#xff0c;潮玩便像一阵风似地席卷新消费空间&#xff0c;形成一种独特的流行趋势。作为中国领先的潮流文化娱乐公司&#xff0c;泡泡玛特除了深耕潮玩产品本身&#xff0c;也在不断拓展业务版图&#xff0c;推进国际化…

P1664 每日打卡心情好 题解

文章目录 题目背景题目描述输入格式输出格式样例样例输入样例输出 数据范围与提示思路及部分实现完整代码文章小结 题目背景 在洛谷中&#xff0c;打卡不只是一个简单的鼠标点击动作&#xff0c;通过每天在洛谷打卡&#xff0c;可以清晰地记录下自己在洛谷学习的足迹。通过每天…

测试Android webview 加载本地html

最近开发一个需要未联网功能的App, 不熟悉使用Java原生开发界面&#xff0c;于是想使用本地H5做界面&#xff0c;本文测试了使用本地html加载远程数据。直接上代码&#xff1a; MainActivity.java package com.alex.webviewlocal;import androidx.appcompat.app.AppCompatAct…

2023年【汽车驾驶员(高级)】考试报名及汽车驾驶员(高级)考试试卷

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 汽车驾驶员&#xff08;高级&#xff09;考试报名是安全生产模拟考试一点通总题库中生成的一套汽车驾驶员&#xff08;高级&#xff09;考试试卷&#xff0c;安全生产模拟考试一点通上汽车驾驶员&#xff08;高级&…

博客后台模块续更(四)

八、博客后台模块-Excel表格 1. 接口分析 在分类管理中点击导出按钮可以把所有的分类导出到Excel文件 请求方式 请求地址 请求头 GET /content/category/export 需要token请求头 响应体&#xff1a; 直接导出一个Excel文件 失败的话响应体如下&#xff1a; {"c…

2023年全球顶尖科学家排行榜单公布(附TOP100名单)

近期&#xff0c;斯坦福大学和Elsevier共同发布了全球前2%顶尖科学家榜单(Worlds Top 2% Scientists)。这份榜单也备受博士后、访问学者及联合培养申请者关注&#xff0c;所以知识人网小编特整理TOP100名单。 2023年10月4日&#xff0c;斯坦福大学和全球最大学术出版商Elsevier…

jvm的jshell,学生的工具

jshell 在我眼里&#xff0c;只能作为学校教学的一个玩具&#xff0c;事实上官方也做了解释&#xff0c;以下是官方的解释&#xff1a; 在学习编程语言时&#xff0c;即时反馈很重要&#xff0c;并且 它的 API。学校引用远离Java的首要原因 教学语言是其他语言有一个“REPL”…

CSS 定位布局

定位布局共有4种方式 CSS定位使你可以将一个元素精确地放在页面上指定的地方。联合使用定位和浮动&#xff0c;能够创建多种高级而精确的布局。其中&#xff0c;定位布局共有4种方式。 固定定位&#xff08;fixed&#xff09;相对定位&#xff08;relative&#xff09;绝对定…

用Vue3.0 写过组件吗?如果想实现一个 Modal你会怎么设计?

一、组件设计 组件就是把图形、非图形的各种逻辑均抽象为一个统一的概念&#xff08;组件&#xff09;来实现开发的模式 现在有一个场景&#xff0c;点击新增与编辑都弹框出来进行填写&#xff0c;功能上大同小异&#xff0c;可能只是标题内容或者是显示的主体内容稍微不同 …

安卓逆向之抽象函数public abstract的hook定位处理

一、抽象类调用过程 1、定义接口 public abstract class AbsNetHelper{public abstract int X(int x,int y); }2、其他类调用 public class f extends AbsNetHelper {public abstract int X(int x,int y){ return xy;} }二、如何HOOK 想hook调用AbsNetHelper类的X抽…

攻防世界web篇-robots

打开网址后&#xff0c;发现是一个空白页面的网页 但是&#xff0c;这个题目是robots&#xff0c;所以就联想到robots.txt这个目录&#xff0c;于是我就试了一下 注意&#xff1a;这里有个php的文件&#xff0c;这个应该就是一个目录文件 当输入后&#xff0c;直接回车&#…

【C语言必知必会 | 子系列第四篇】深入剖析选择结构(2)

引言 C语言是一门面向过程的、抽象化的通用程序设计语言&#xff0c;广泛应用于底层开发。它在编程语言中具有举足轻重的地位。 此文为【C语言必知必会】子系列第四篇&#xff0c;基于进行C语言选择结构的编程题专项练习&#xff0c;结合专题优质题目&#xff0c;带领读者从0开…

VMware Workstation里面安装ubuntu20.04的流程

文章目录 前言一、获取 desktop ubuntu20.04 安装镜像二、VMware Workstation下安装ubuntu20.041. VMware Workstation 创建一个新的虚拟机2. ubuntu20.04的安装过程3. 登录ubuntu20.044. 移除 ubuntu20.04 安装镜像总结参考资料前言 本文主要介绍如何在PC上的虚拟机(VMware W…

ESP32C3 LuatOS TM1650①驱动测试

合宙TM1650驱动资料 TM1650.lua源码 引脚连接 TM1650ESP32C3SCLGPIO5SDAGPIO4 下载TM1650.lua源码&#xff0c;并以文件形式保存在项目文件夹中 驱动测试源码 --注意:因使用了sys.wait()所有api需要在协程中使用 -- 用法实例 PROJECT "ESP32C3_TM1650" VERSION …

批量xls转换为xlsx

import win32com.client as win32 import os# 另存为xlsx的文件路径 xlsx_file r"F:\志丹\1020Excel汇总\成果表备份\xlsx" xls_file r"F:\志丹\1020Excel汇总\成果表备份" for file in os.scandir(xls_file):suffix file.name.split(".")[-1…

AQS源码与实现原理

前言 前段时间在看ReentrantLocak及其依赖的基础模板类AbstractQueuedSynchronizer的源码&#xff0c;自己看源码同时在网上找文章&#xff0c;然而对源码中的一些细节问题还是不太理解&#xff0c;比如为什么阻塞的线程因中断被唤醒后需要重新中断&#xff0c;为什么被Condit…

uipath 调用 webapi 接口使用示例

环境依赖下载 提示&#xff1a;需要先按照webapi包依赖 文章目录 环境依赖下载一、webapi是什么&#xff1f;二、使用步骤1.导入cURL http 请求 一、webapi是什么&#xff1f; UiPath WebAPI包是一个用于实现与Web服务进行交互的UiPath活动库。它基于.NET Framework 4.5及以上…