自动驾驶规划 - 5次多项式拟合

news2024/11/24 5:38:51

简介

自动驾驶运动规划中会用到各种曲线,主要用于生成车辆的轨迹,常见的轨迹生成算法,如贝塞尔曲线,样条曲线,以及apollo EM Planner的五次多项式曲线,城市场景中使用的是分段多项式曲线,在EM Planner和Lattice Planner中思路是,都是先通过动态规划生成点,再用5次多项式生成曲线连接两个点(虽然后面的版本改动很大,至少lattice planner目前还是这个方法)。

在这里可以看出5次多项式的作用,就是生成轨迹,这里的轨迹不一定是车行驶的轨迹,比如S—T图中的线,是用来做速度规划的。 如下图:

请添加图片描述

在apollo里面用到了,3-5次多项式,

  • cubic_polynomial_curve1d,三次多项式曲线
  • quartic_polynomial_curve1d,四次多项式曲线-
  • quintic_polynomial_curve1d,五次多项式曲线

3次多项式

f ( x ) = C 0 + C 1 x + C 2 x 2 + C 3 x 3 − − − − ( 1 ) f(x) = C_0 + C_1x + C_2x^2+ C_3x^3 ----(1) f(x)=C0+C1x+C2x2+C3x3(1)
x求导====>
f ′ ( x ) = C 1 + 2 C 2 x + 3 C 3 x 2 f'(x) = C_1 + 2C_2x+ 3C_3x^2 f(x)=C1+2C2x+3C3x2
f ( x ) = 2 C 2 + 6 C 3 x f(x) = 2C_2+ 6C_3x f(x)=2C2+6C3x
因为是连接两个已知点,所以两个轨迹点的信息是已知的。
如已知,当x=0,代如得:
f ( 0 ) = C 0 ; f ′ ( 0 ) = C 1 ; f ′ ′ ( 0 ) = 2 C 2 f(0) = C_0 ; f'(0) = C_1;f''(0) =2C_2 f(0)=C0f(0)=C1f′′(0)=2C2

所以
C 0 = f ( 0 ) ; C 1 = f ′ ( 0 ) ; C 2 = f ′ ′ ( 0 ) / 2 C_0 = f(0);C_1 = f'(0); C_2 = f''(0)/2 C0=f(0)C1=f(0)C2=f′′(0)/2
将终点 (X_end,f(X_end))带入得到C_3

C 3 = ( f ( x p ) − C 0 − C 1 x p − C 2 x p 2 ) / x p 3 C_3 = (f(x_p)-C_0-C_1x_p-C_2x_p^2)/x_p^3 C3=(f(xp)C0C1xpC2xp2)/xp3

(1)式的所有未知参数都求出,代入x可以得到两点间的轨迹。

apollo中3次多项式的计算

// cubic_polynomial_curve1d.cc
CubicPolynomialCurve1d::CubicPolynomialCurve1d(const double x0,
                                               const double dx0,
                                               const double ddx0,
                                               const double x1,
                                               const double param) {
  ComputeCoefficients(x0, dx0, ddx0, x1, param);
  param_ = param;
  start_condition_[0] = x0;
  start_condition_[1] = dx0;
  start_condition_[2] = ddx0;
  end_condition_ = x1;
}

void CubicPolynomialCurve1d::ComputeCoefficients(const double x0,
                                                 const double dx0,
                                                 const double ddx0,
                                                 const double x1,
                                                 const double param) {
  DCHECK(param > 0.0);
  const double p2 = param * param;
  const double p3 = param * p2;
  coef_[0] = x0;
  coef_[1] = dx0;
  coef_[2] = 0.5 * ddx0;
  coef_[3] = (x1 - x0 - dx0 * param - coef_[2] * p2) / p3;
}

5次多项式

f ( x ) = C 0 + C 1 x + C 2 x 2 + C 3 x 3 + C 4 x 4 + C 5 x 5 − − − − ( 3 − 1 ) f(x) = C_0 + C_1x + C_2x^2+ C_3x^3+C_4x^4+C_5x^5 ----(3-1) f(x)=C0+C1x+C2x2+C3x3+C4x4+C5x5(31)
x求导====>
f ′ ( x ) = C 1 + 2 C 2 x + 3 C 3 x 2 + 4 C 4 x 3 + 5 C 5 x 4 − − − − ( 3 − 2 ) f'(x) = C_1 + 2C_2x+ 3C_3x^2+4C_4x^3+5C_5x^4----(3-2) f(x)=C1+2C2x+3C3x2+4C4x3+5C5x4(32)

f ′ ′ ( x ) = 2 C 2 + 6 C 3 x + 12 C 4 x 2 + 20 C 5 x 3 − − − − ( 3 − 3 ) f''(x) = 2C_2+ 6C_3x+12C_4x^2+20C_5x^3----(3-3) f′′(x)=2C2+6C3x+12C4x2+20C5x3(33)
因为是连接两个已知点,所以两个轨迹点的信息是已知的。
如已知,当x=0,代如得:
f ( 0 ) = C 0 ; f ′ ( 0 ) = C 1 ; f ′ ′ ( 0 ) = 2 C 2 f(0) = C_0 ; f'(0) = C_1;f''(0) =2C_2 f(0)=C0f(0)=C1f′′(0)=2C2

所以
C 0 = f ( 0 ) ; C 1 = f ′ ( 0 ) ; C 2 = f ′ ′ ( 0 ) / 2 C_0 = f(0);C_1 = f'(0); C_2 = f''(0)/2 C0=f(0)C1=f(0)C2=f′′(0)/2
将终点 (x_e,f(x_e))带入 (3-1) (3-2) (3-3)

得到
f ( x e ) = C 0 + C 1 x e + C 2 x e 2 + C 3 x e 3 + C 4 x e 4 + C 5 x e 5 − − − − ( 3 − 4 ) f(x_e) = C_0 + C_1x_e + C_2x_e^2+ C_3x_e^3+C_4x_e^4+C_5x_e^5 ----(3-4) f(xe)=C0+C1xe+C2xe2+C3xe3+C4xe4+C5xe5(34)
x求导====>
f ′ ( x ) = C 1 + 2 C 2 x e + 3 C 3 x e 2 + 4 C 4 x e 3 + 5 C 5 x e 4 − − − − ( 3 − 5 ) f'(x) = C_1 + 2C_2x_e+ 3C_3x_e^2+4C_4x_e^3+5C_5x_e^4----(3-5) f(x)=C1+2C2xe+3C3xe2+4C4xe3+5C5xe4(35)

f ′ ′ ( x ) = 2 C 2 + 6 C 3 x e + 12 C 4 x e 2 + 20 C 5 x e 3 − − − − ( 3 − 6 ) f''(x) = 2C_2+ 6C_3x_e+12C_4x_e^2+20C_5x_e^3----(3-6) f′′(x)=2C2+6C3xe+12C4xe2+20C5xe3(36)

联立可得
C 3 = 10 ( f ( x p ) − 1 / 2 ∗ f ′ ′ ( 0 ) x p 2 − f ′ ( 0 ) x p − f ( 0 ) ) − 4 ( f ′ ( x p ) − f ′ ′ ( 0 ) x p − f ′ ( 0 ) ) x p + 1 / 2 ∗ ( f ′ ′ ( x p ) − f ′ ′ ( 0 ) ) x p 2 x p 3 C_3 = \frac{10(f(x_p)-1/2*f''(0)x_p^2-f'(0)x_p-f(0))-4(f'(x_p)-f''(0)x_p-f'(0))x_p+1/2*(f''(x_p)-f''(0))x_p^2}{x_p^3} C3=xp310(f(xp)1/2f′′(0)xp2f(0)xpf(0))4(f(xp)f′′(0)xpf(0))xp+1/2(f′′(xp)f′′(0))xp2

C 4 = − 15 ( f ( x p ) − 1 / 2 ∗ f ′ ′ ( 0 ) x p 2 − f ′ ( 0 ) x p − f ( 0 ) ) + 7 ( f ′ ( x p ) − f ′ ′ ( 0 ) x p − f ′ ( 0 ) ) x p − 1 / 2 ∗ ( f ′ ′ ( x p ) − f ′ ′ ( 0 ) ) x p 2 x p 4 C_4 = \frac{-15(f(x_p)-1/2*f''(0)x_p^2-f'(0)x_p-f(0))+7(f'(x_p)-f''(0)x_p-f'(0))x_p-1/2*(f''(x_p)-f''(0))x_p^2}{x_p^4} C4=xp415(f(xp)1/2f′′(0)xp2f(0)xpf(0))+7(f(xp)f′′(0)xpf(0))xp1/2(f′′(xp)f′′(0))xp2

C 5 = 6 ( f ( x p ) − 1 / 2 ∗ f ′ ′ ( 0 ) x p 2 − f ′ ( 0 ) x p − f ( 0 ) ) − 3 ( f ′ ( x p ) − f ′ ′ ( 0 ) x p − f ′ ( 0 ) ) x p + 1 / 2 ∗ ( f ′ ′ ( x p ) − f ′ ′ ( 0 ) ) x p 2 x p 5 C_5 = \frac{6(f(x_p)-1/2*f''(0)x_p^2-f'(0)x_p-f(0))-3(f'(x_p)-f''(0)x_p-f'(0))x_p+1/2*(f''(x_p)-f''(0))x_p^2}{x_p^5} C5=xp56(f(xp)1/2f′′(0)xp2f(0)xpf(0))3(f(xp)f′′(0)xpf(0))xp+1/2(f′′(xp)f′′(0))xp2

apollo中5次多项式的计算

void QuinticPolynomialCurve1d::ComputeCoefficients(
    const double x0, const double dx0, const double ddx0, const double x1,
    const double dx1, const double ddx1, const double p) {
  CHECK_GT(p, 0.0);

  coef_[0] = x0;
  coef_[1] = dx0;
  coef_[2] = ddx0 / 2.0;

  const double p2 = p * p;
  const double p3 = p * p2;

  // the direct analytical method is at least 6 times faster than using matrix
  // inversion.
  const double c0 = (x1 - 0.5 * p2 * ddx0 - dx0 * p - x0) / p3;
  const double c1 = (dx1 - ddx0 * p - dx0) / p2;
  const double c2 = (ddx1 - ddx0) / p;

  coef_[3] = 0.5 * (20.0 * c0 - 8.0 * c1 + c2);
  coef_[4] = (-15.0 * c0 + 7.0 * c1 - c2) / p;
  coef_[5] = (6.0 * c0 - 3.0 * c1 + 0.5 * c2) / p2;
}

5次多项式拟合

import math

import matplotlib.pyplot as plt
import numpy as np

# parameter
MAX_T = 100.0  # maximum time to the goal [s]
MIN_T = 5.0  # minimum time to the goal[s]

show_animation = True

class QuinticPolynomial:

    def __init__(self, xs, vxs, axs, xe, vxe, axe, time):
        # calc coefficient of quintic polynomial
        # See jupyter notebook document for derivation of this equation.
        # 根据初始状态c0 c1 c2
        self.a0 = xs # x(t)
        self.a1 = vxs # v(t)
        self.a2 = axs / 2.0 # a(t)

        A = np.array([[time ** 3, time ** 4, time ** 5],
                      [3 * time ** 2, 4 * time ** 3, 5 * time ** 4],
                      [6 * time, 12 * time ** 2, 20 * time ** 3]])
        b = np.array([xe - self.a0 - self.a1 * time - self.a2 * time ** 2,
                      vxe - self.a1 - 2 * self.a2 * time,
                      axe - 2 * self.a2])
        # Ax=b 求解x
        x = np.linalg.solve(A, b)
        # 计算c3 c4 c5
        self.a3 = x[0]
        self.a4 = x[1]
        self.a5 = x[2]
    # 根据时间计算点x(t)
    def calc_point(self, t):
        xt = self.a0 + self.a1 * t + self.a2 * t ** 2 + \
             self.a3 * t ** 3 + self.a4 * t ** 4 + self.a5 * t ** 5
        return xt
    # 计算v(t)
    def calc_first_derivative(self, t):
        xt = self.a1 + 2 * self.a2 * t + \
             3 * self.a3 * t ** 2 + 4 * self.a4 * t ** 3 + 5 * self.a5 * t ** 4

        return xt
    # 计算a(t)  
    def calc_second_derivative(self, t):
        xt = 2 * self.a2 + 6 * self.a3 * t + 12 * self.a4 * t ** 2 + 20 * self.a5 * t ** 3

        return xt
    # 计算jerk(t)  
    def calc_third_derivative(self, t):
        xt = 6 * self.a3 + 24 * self.a4 * t + 60 * self.a5 * t ** 2

        return xt


def quintic_polynomials_planner(sx, sy, syaw, sv, sa, gx, gy, gyaw, gv, ga, max_accel, max_jerk, dt):
    """
    quintic polynomial planner

    input
        s_x: start x position [m]
        s_y: start y position [m]
        s_yaw: start yaw angle [rad]
        sa: start accel [m/ss]
        gx: goal x position [m]
        gy: goal y position [m]
        gyaw: goal yaw angle [rad]
        ga: goal accel [m/ss]
        max_accel: maximum accel [m/ss]
        max_jerk: maximum jerk [m/sss]
        dt: time tick [s]

    return
        time: time result
        rx: x position result list
        ry: y position result list
        ryaw: yaw angle result list
        rv: velocity result list
        ra: accel result list

    """

    vxs = sv * math.cos(syaw)# 起点速度在x方向分量
    vys = sv * math.sin(syaw)# 起点速度在y方向分量
    vxg = gv * math.cos(gyaw)# 终点速度在x方向分量
    vyg = gv * math.sin(gyaw)# 终点速度在y方向分量

    axs = sa * math.cos(syaw)# 起点加速度在x方向分量
    ays = sa * math.sin(syaw)# 终点加速度在y方向分量
    axg = ga * math.cos(gyaw)# 起点加速度在x方向分量
    ayg = ga * math.sin(gyaw)# 终点加速度在y方向分量

    time, rx, ry, ryaw, rv, ra, rj = [], [], [], [], [], [], []

    for T in np.arange(MIN_T, MAX_T, MIN_T):
        xqp = QuinticPolynomial(sx, vxs, axs, gx, vxg, axg, T)
        yqp = QuinticPolynomial(sy, vys, ays, gy, vyg, ayg, T)

        time, rx, ry, ryaw, rv, ra, rj = [], [], [], [], [], [], []

        for t in np.arange(0.0, T + dt, dt):
            time.append(t)
            rx.append(xqp.calc_point(t))
            ry.append(yqp.calc_point(t))

            vx = xqp.calc_first_derivative(t)
            vy = yqp.calc_first_derivative(t)
            v = np.hypot(vx, vy)
            yaw = math.atan2(vy, vx)
            rv.append(v)
            ryaw.append(yaw)

            ax = xqp.calc_second_derivative(t)
            ay = yqp.calc_second_derivative(t)
            a = np.hypot(ax, ay)
            if len(rv) >= 2 and rv[-1] - rv[-2] < 0.0:
                a *= -1
            ra.append(a)

            jx = xqp.calc_third_derivative(t)
            jy = yqp.calc_third_derivative(t)
            j = np.hypot(jx, jy)
            if len(ra) >= 2 and ra[-1] - ra[-2] < 0.0:
                j *= -1
            rj.append(j)

        if max([abs(i) for i in ra]) <= max_accel and max([abs(i) for i in rj]) <= max_jerk:
            print("find path!!")
            break

    if show_animation:  # pragma: no cover
        for i, _ in enumerate(time):
            plt.cla()
            # for stopping simulation with the esc key.
            plt.gcf().canvas.mpl_connect('key_release_event',
                                         lambda event: [exit(0) if event.key == 'escape' else None])
            plt.grid(True)
            plt.axis("equal")
            plot_arrow(sx, sy, syaw)
            plot_arrow(gx, gy, gyaw)
            plot_arrow(rx[i], ry[i], ryaw[i])
            plt.title("Time[s]:" + str(time[i])[0:4] +
                      " v[m/s]:" + str(rv[i])[0:4] +
                      " a[m/ss]:" + str(ra[i])[0:4] +
                      " jerk[m/sss]:" + str(rj[i])[0:4],
                      )
            plt.pause(0.001)

    return time, rx, ry, ryaw, rv, ra, rj


def plot_arrow(x, y, yaw, length=1.0, width=0.5, fc="r", ec="k"):  # pragma: no cover
    """
    Plot arrow
    """

    if not isinstance(x, float):
        for (ix, iy, iyaw) in zip(x, y, yaw):
            plot_arrow(ix, iy, iyaw)
    else:
        plt.arrow(x, y, length * math.cos(yaw), length * math.sin(yaw),
                  fc=fc, ec=ec, head_width=width, head_length=width)
        plt.plot(x, y)


def main():

    sx = 10.0  # start x position [m]
    sy = 10.0  # start y position [m]
    syaw = np.deg2rad(10.0)  # start yaw angle [rad]
    sv = 1.0  # start speed [m/s]
    sa = 0.1  # start accel [m/ss]
    gx = 30.0  # goal x position [m]
    gy = -10.0  # goal y position [m]
    gyaw = np.deg2rad(20.0)  # goal yaw angle [rad]
    gv = 1.0  # goal speed [m/s]
    ga = 0.1  # goal accel [m/ss]
    max_accel = 1.0  # max accel [m/ss]
    max_jerk = 0.5  # max jerk [m/sss]
    dt = 0.1  # time tick [s]

    time, x, y, yaw, v, a, j = quintic_polynomials_planner(
        sx, sy, syaw, sv, sa, gx, gy, gyaw, gv, ga, max_accel, max_jerk, dt)

    if show_animation:  # pragma: no cover
        plt.plot(x, y, "-r")

        plt.subplots()
        plt.plot(time, [np.rad2deg(i) for i in yaw], "-r")
        plt.xlabel("Time[s]")
        plt.ylabel("Yaw[deg]")
        plt.grid(True)

        plt.subplots()
        plt.plot(time, v, "-r")
        plt.xlabel("Time[s]")
        plt.ylabel("Speed[m/s]")
        plt.grid(True)

        plt.subplots()
        plt.plot(time, a, "-r")
        plt.xlabel("Time[s]")
        plt.ylabel("accel[m/ss]")
        plt.grid(True)

        plt.subplots()
        plt.plot(time, j, "-r")
        plt.xlabel("Time[s]")
        plt.ylabel("jerk[m/sss]")
        plt.grid(True)

        plt.show()


if __name__ == '__main__':
    main()

在这里插入图片描述
在这里插入图片描述

上图模拟了车辆曲线的拟合过程的轨迹,箭头代表方向。

过程的速度在这里插入图片描述

感觉5次多项式和贝塞尔曲线还是挺像的,有时间写一篇五次多项式、贝塞尔曲线、样条曲线的对比。

参考:

  • https://blog.csdn.net/qq_36458461/article/details/110007656
  • https://zhuanlan.zhihu.com/p/567375631

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

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

相关文章

springCloud之OAuth2

认证授权过程 在认证和授权的过程中涉及的三方包括&#xff1a; 1、服务提供方&#xff0c;用户使用服务提供方来存储受保护的资源&#xff0c;如照片&#xff0c;视频&#xff0c;联系人列表。 2、用户&#xff0c;存放在服务提供方的受保护的资源的拥有者。 3、客户端&am…

【spring】事务

概述 1、什么事务 事务是数据库操作最基本单元&#xff0c;逻辑上一组操作&#xff0c;要么都成功&#xff0c;如果有一个失败所有操 作都失败 2、事务四个特性&#xff08;ACID&#xff09; &#xff08;1&#xff09;原子性 &#xff08;2&#xff09;一致性 &#xff08;3…

java语言跨平台的特性:“一次编译,到处运行”

“一次编译&#xff0c;到处运行”是java语言跨平台的特性&#xff0c;平台指的是操作系统平台。 程序从源代码到运行的三个必经阶段&#xff1a;编码——编译——运行&#xff0c;调试。 首先编码阶段&#xff0c;需要编码语言是一个程序设计语言&#xff0c;而我们的java是程…

ChatGPT解答:python大批量读写ini文件时,性能很低,有什么解决方法吗,给出具体的思路和实例

ChatGPT解答&#xff1a; python大批量读写ini文件时&#xff0c;性能很低&#xff0c;有什么解决方法吗&#xff0c;给出具体的思路和实例 ChatGPTDemo Based on OpenAI API (gpt-3.5-turbo). python大批量读写ini文件时&#xff0c;性能很低&#xff0c;有什么解决方法吗&…

springboot工程搭建的几种方式

一、通过idea工具搭建&#xff0c;如下&#xff1a; 新建Project和Module&#xff0c;选择Spring initializr&#xff0c;点击Next&#xff0c;进入到如下页面填写 填写完后点击Next 到如下页面&#xff0c;根据你的具体所需&#xff0c;选择要使用的技术依赖 点击Next 点击FIn…

巾帼绽芬芳 一起向未来(中篇)

编者按&#xff1a;为了隆重纪念纪念“三八”国际妇女节113周年&#xff0c;快来与你全方位、多层次分享交流“三八”国际妇女节的前世今生。分上篇&#xff08;节日简介、节日发展和节日意义&#xff09;、中篇&#xff08;节日活动宗旨和世界各国庆祝方式&#xff09;和下篇&…

云原生之docker网络详解

云原生之docker网络详解一、相关概念1.2、CNM1.3、libnetwork二、实操2.1、docker network常用命令2.2、运行一个docker容器&#xff0c;查看CNM三个概念2.3、查看docker0在内核路由表上的记录2.4、查看网络列表2.5、网络隔离效果展示2.6、host驱动网络一、相关概念 1.1、网桥…

链表经典刷题--快慢指针与双指针

本篇总结链表解题思路----快慢指针&#xff0c;其实也就是双指针&#xff0c;这个快慢并不单纯指“快慢”&#xff0c;它更多的可以表示&#xff0c;速度快慢&#xff0c;距离长度&#xff0c;时间大小等等&#xff0c;用法很有趣也很独特&#xff0c;理解它的思想&#xff0c;…

「并发编程实战」常见的限流方案

「并发编程实战」常见的限流方案 文章目录「并发编程实战」常见的限流方案一、概述二、计数器限流方案三、时间窗口限流方案四、令牌桶限流方案五、漏桶限流方案六、高并发限流算法小结文章参考&#xff1a; 追忆四年前&#xff1a;一段关于我被外企CTO用登录注册吊打的不堪往事…

01 | n2n虚拟局域网

1 n2n简介 为了满足两个不同局域网的机器进行通信&#xff0c;让不同网段的机器能够进行P2P( 点对点 peer-to-peer ) 通信。2 n2n源码 https://github.com/ntop/n2n.git3 n2n名词 3.1 SuperNode 超级节点 SuperNode 相当与注册中心, 它会记录边缘节点的连接信息&#xff0c;…

案例09-数据类型不一致导致equals判断为false

一&#xff1a;背景介绍 在判断课程id和班级id的时候如果一致就像课程信息进行更新&#xff0c;如果不一致就插入一条新的数据。其实两个变量的值是一致的但是类型是不一致的。这就导致数据库中已经有一条这样的数据了&#xff0c;在判断的时候结果为false&#xff0c;就有插入…

【这一篇就够】mysql创建JSON数据的索引

一. 创建索引 由于json有两类不同的数据形式&#xff0c;即&#xff1a;json对象&#xff08;如&#xff1a;{"id": 1, "name":"he"}&#xff09;&#xff0c;json数组&#xff08;如&#xff1a;["1","2","3"]&…

nexus安装与入门

安装 nexus-3.31.1-01-unix.tar.gz 链接&#xff1a;https://pan.baidu.com/s/1YrJMwpGxmu8N2d7XMl6fSg 提取码&#xff1a;kfeh 上传到服务器&#xff0c;解压 tar -zvxf nexus-3.31.1-01-unix.tar.gz进入bin目录&#xff0c;启动 ./nexus start查看状态 ./nexus status默…

初始Linux操作系统

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。座右铭&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石&#xff0c;故能成其高。个人主页&#xff1a;小李会科技的…

Linux常用命令等

目录 1.Linux常用命令 (1)系统命令 (2)文件操作命令 2.vim编辑器 3.linux系统中,软件安装 (1) rpm 安装,RedHat Package Manager (2)yum 安装 (3)源代码编译安装 1.Linux常用命令 Linux命令是非常多的,对于像嵌入式开发工程师,运维工程师需要掌握的命令是非常多的.对于…

旋转矩形框标注--roLabelImg的使用

1. 旋转目标标注roLabelImg roLabelImg是一款开源的,可标注带旋转角度的矩形区域的标注软件。roLabelImg源码github地址: https://github.com/cgvict/roLabelImg labelme和labelimg只能标矩形框,但不能标注旋转角度。roLabelImg既能标矩形框也能标注矩形框的选择角度,因此…

复旦发布中国版 ChatGPT :MOSS

不知道这个人工智能&#xff0c;有没有获得完整的一生。ChatGPT 是最先进的 AI&#xff0c;也是最热门的应用 —— 自去年 11 月底发布以来&#xff0c;它的月活跃用户两个月超过一亿&#xff0c;轻松拿到了全球互联网史上用户增长速度的第一。它也是一种门槛很高的技术。由于 …

服务预热配置化在泛型化方法上的实践

背景 由于开发过程中&#xff0c;个别dubbo接口的调用会在服务发布过程中&#xff0c;出现P99耗时报警问题。因此我们计划通过预热服务接口&#xff0c;通过预热来触发JIT&#xff0c;构建DB资源长链接。实现服务接口上线后&#xff0c;耗时过长&#xff0c;资源等待等问题&am…

基于RWEQ模型的土壤风蚀模数估算及其变化归因分析

查看原文>>>基于RWEQ模型的土壤风蚀模数估算及其变化归因分析 土壤风蚀是一个全球性的环境问题。中国是世界上受土壤风蚀危害最严重的国家之一&#xff0c;土壤风蚀是中国干旱、半干旱及部分湿润地区土地荒漠化的首要过程。中国风蚀荒漠化面积达160.74104km2&#xff…

python re模块匹配字符串

python 正则模块re 要使用python3中的RE则必须引入 re模块 import re re模块的match函数 result re.match(^[A-Z]{1}[a-z], s) match 尝试从字符串的起始位置匹配一个模式&#xff0c;如果不是起始位置匹配成功的话&#xff0c;match()就返回none。 匹配到了&#xff0c;则…