【相机标定】相机标定中的坐标变换,内外参求解,畸变校正,标定代码

🚀本文循序渐进,从坐标系变换、求解单应 H {\color{#86C166}{H}} H、求解内参 K {\color{#E16B8C}{K}} K、求解外参 [ R 1 R 2 T ] \begin{bmatrix}{\color{#2EA9DF}{R_1}}&{\color{#2EA9DF}{R_2}}&{\color{#2EA9DF}{T}} \end{bmatrix} [R1R2T]、畸变校正 [ k 1 k 2 k 3 p 1 p 2 ] \begin{bmatrix}{\color{#F75C2F}{k_1}}&{\color{#F75C2F}{k_2}}&{\color{#F75C2F}{k_3}}&{\color{#77428D}{p_1}}&{\color{#77428D}{p_2}} \end{bmatrix} [k1k2k3p1p2]、联合优化 p a r a m {\color{#FBE251}{param}} param、标定代码、注意事项的8个方面概括性的总结了传统相机校正的理论推导和工程应用,文章比较精炼,适合备为复习和应用参考。

注意,这里的外参是相对于标定板的2D外参,如果要求解相机相当于载体坐标系的外参,则可以将标定板与地面平行或垂直放置,通过测量求出标定板与载体坐标系的变换关系,进而将相机相对于标定板的外参转换为相对于载体坐标系的外参。

而若要直接求解相对于世界坐标系(或载体坐标系)3D外参,而不做两步转换,请参考这篇博客:
【PnP】详细公式推导,使用DLT直接线性变换法求解相机外参


🌔01
坐标系变换关系

设世界坐标系 X W X_W XW,相机坐标系 X C X_C XC,图像物理坐标系 x x x,图像像素坐标系 u u u.

则世界坐标系与相机坐标系有以下变换关系:

[ X C Y C Z C 1 ] = [ R 3 × 3 T 3 × 1 0 1 ] [ X W Y W Z W 1 ] \begin{bmatrix}X_C\\Y_C\\Z_C\\1\end{bmatrix}=\begin{bmatrix}{\color{#2EA9DF}{R_{3\times3}}}&{\color{#2EA9DF}{T_{3\times1}}}\\0&1 \end{bmatrix}\begin{bmatrix}X_W\\Y_W\\Z_W\\1\end{bmatrix} XCYCZC1 =[R3×30T3×11] XWYWZW1

相机坐标系与图像物理坐标系有以下变换关系, f f f为物理焦距:

Z C [ x y 1 ] = [ f 0 0 0 0 f 0 0 0 0 1 0 ] [ X C Y C Z C 1 ] Z_C\begin{bmatrix}x\\y\\1\end{bmatrix}=\begin{bmatrix}f&0&0&0\\0&f&0&0\\0&0&1&0\end{bmatrix}\begin{bmatrix}X_C\\Y_C\\Z_C\\1\end{bmatrix} ZC xy1 = f000f0001000 XCYCZC1

图像物理坐标系与图像像素坐标系有以下变换关系, a a a为像元尺寸, ( u 0 , v 0 ) (u_0,v_0) (u0,v0)为像平面中心像素坐标:

[ u v 1 ] = [ 1 a x 0 u 0 0 1 a y v 0 0 0 1 ] [ x y 1 ] \begin{bmatrix}u\\v\\1\end{bmatrix}=\begin{bmatrix}\frac{1}{a_x}&0&u_0\\0&\frac{1}{a_y}&v_0\\0&0&1\end{bmatrix}\begin{bmatrix}x\\y\\1\end{bmatrix} uv1 = ax1000ay10u0v01 xy1

综合起来,世界坐标系与图像像素坐标系有以下变换关系(像素焦距 F x = f a x , F y = f a y F_x=\frac{f}{a_x},F_y=\frac{f}{a_y} Fx=axf,Fy=ayf):

Z C [ u v 1 ] = [ F x 0 u 0 0 0 F y v 0 0 0 0 1 0 ] [ R 3 × 3 T 3 × 1 0 1 ] [ X W Y W Z W 1 ] Z_C\begin{bmatrix}u\\v\\1\end{bmatrix}=\begin{bmatrix}F_x&0&u_0&0\\0&F_y&v_0&0\\0&0&1&0\end{bmatrix}\begin{bmatrix}{\color{#2EA9DF}{R_{3\times3}}}&{\color{#2EA9DF}{T_{3\times1}}}\\0&1 \end{bmatrix}\begin{bmatrix}X_W\\Y_W\\Z_W\\1\end{bmatrix} ZC uv1 = Fx000Fy0u0v01000 [R3×30T3×11] XWYWZW1

简化后有:

Z C [ u v 1 ] = [ F x 0 u 0 0 F y v 0 0 0 1 ] [ R 3 × 3 T 3 × 1 ] [ X W Y W Z W 1 ] = K [ R 3 × 3 T 3 × 1 ] [ X W Y W Z W 1 ] Z_C\begin{bmatrix}u\\v\\1\end{bmatrix}=\begin{bmatrix}F_x&0&u_0\\0&F_y&v_0\\0&0&1\end{bmatrix}\begin{bmatrix}{\color{#2EA9DF}{R_{3\times3}}}&{\color{#2EA9DF}{T_{3\times1}}} \end{bmatrix}\begin{bmatrix}X_W\\Y_W\\Z_W\\1\end{bmatrix}={\color{#E16B8C}{K}}\begin{bmatrix}{\color{#2EA9DF}{R_{3\times3}}}&{\color{#2EA9DF}{T_{3\times1}}} \end{bmatrix}\begin{bmatrix}X_W\\Y_W\\Z_W\\1\end{bmatrix} ZC uv1 = Fx000Fy0u0v01 [R3×3T3×1] XWYWZW1 =K[R3×3T3×1] XWYWZW1

Z W ≡ 0 Z_W\equiv0 ZW0时(e.g. 对象是标定板),有以下单应变换:

[ u v 1 ] = 1 Z C K [ R 1 R 2 T ] [ X W Y W 1 ] = H [ X W Y W 1 ] = [ H 1 H 2 H 3 ] [ X W Y W 1 ] \begin{bmatrix}u\\v\\1\end{bmatrix}=\frac{1}{Z_C}{\color{#E16B8C}{K}}\begin{bmatrix}{\color{#2EA9DF}{R_1}}&{\color{#2EA9DF}{R_2}}&{\color{#2EA9DF}{T}} \end{bmatrix}\begin{bmatrix}X_W\\Y_W\\1\end{bmatrix}={\color{#86C166}{H}}\begin{bmatrix}X_W\\Y_W\\1\end{bmatrix}=\begin{bmatrix}{\color{#86C166}{H_1}}&{\color{#86C166}{H_2}}&{\color{#86C166}{H_3}}\end{bmatrix}\begin{bmatrix}X_W\\Y_W\\1\end{bmatrix} uv1 =ZC1K[R1R2T] XWYW1 =H XWYW1 =[H1H2H3] XWYW1


🌔02
求解单应变换

其中 H {\color{#86C166}{H}} H有9个元素,但其中一个元素作为齐次参数(令 h 33 {\color{#86C166}{h_{33}}} h33=1),所以只需要求解其中的8个未知参数,

也就说,单张图片至少要检测4个角点即获取4对 ( u , v , 1 ) − ( X W , Y W , 1 ) (u,v,1)-(X_W,Y_W,1) (u,v,1)(XW,YW,1)的关系式得到8个方程来求解 H H H的数值.


🌔03
求解相机内参

1 Z C K [ R 1 R 2 T ] = [ H 1 H 2 H 3 ] \frac{1}{Z_C}{\color{#E16B8C}{K}}\begin{bmatrix}{\color{#2EA9DF}{R_1}}&{\color{#2EA9DF}{R_2}}&{\color{#2EA9DF}{T}} \end{bmatrix}=\begin{bmatrix}{\color{#86C166}{H_1}}&{\color{#86C166}{H_2}}&{\color{#86C166}{H_3}}\end{bmatrix} ZC1K[R1R2T]=[H1H2H3]有:

{ R 1 = Z C K − 1 H 1 , R 2 = Z C K − 1 H 2 \begin{cases}{\color{#2EA9DF}{R_1}}=Z_C{\color{#E16B8C}{{\color{#E16B8C}{K^{-1}}}} {\color{#86C166}{H_1}}},\\{\color{#2EA9DF}{R_2}}=Z_C{\color{#E16B8C}{K^{-1}}} {\color{#86C166}{H_2}}\end{cases} {R1=ZCK1H1,R2=ZCK1H2

R 1 T R 2 = 0 {\color{#2EA9DF}{R_1^T}}{\color{#2EA9DF}{R_2}}=0 R1TR2=0 R 1 T R 1 = R 2 T R 2 {\color{#2EA9DF}{R_1^T}}{\color{#2EA9DF}{R_1}}={\color{#2EA9DF}{R_2^T}}{\color{#2EA9DF}{R_2}} R1TR1=R2TR2有:

{ H 1 T K − T K − 1 H 2 = 0 , H 1 T K − T K − 1 H 1 = H 2 T K − T K − 1 H 2 \begin{cases}{\color{#86C166}{H_1^T}}{\color{#E16B8C}{K^{-T}}}{\color{#E16B8C}{K^{-1}}}{\color{#86C166}{H_2}}=0,\\{\color{#86C166}{H_1^T}}{\color{#E16B8C}{K^{-T}}}{\color{#E16B8C}{K^{-1}}}{\color{#86C166}{H_1}}={\color{#86C166}{H_2^T}}{\color{#E16B8C}{K^{-T}}}{\color{#E16B8C}{K^{-1}}}{\color{#86C166}{H_2}}\end{cases} {H1TKTK1H2=0,H1TKTK1H1=H2TKTK1H2

因为 K {\color{#E16B8C}{K}} K中有4个未知参数,则至少需要2张图片,每张图片提供一组上述的两个方程,构成4个方程,此时将构造出方程 A x = b Ax=b Ax=b x x x为4个未知参数构成的向量( x x x等效为内参 K {\color{#E16B8C}{K}} K,同时 A , b A,b A,b表示一些常量).

而在实际操作时,往往拍摄多张图片,此时方程数目大于未知数数目,因而使用最小二乘法来求解,由此可以求得 K {\color{#E16B8C}{K}} K

m i n    ∣ ∣ A x − b ∣ ∣ 2 ⇒ \mathbf{min}\;||Ax-b||^2\quad\Rightarrow min∣∣Axb2

A T ( A x − b ) = 0 ⇒ A^T(Ax-b)=0\quad\Rightarrow AT(Axb)=0

x = ( A T A ) − 1 A T b x=(A^TA)^{-1}A^Tb x=(ATA)1ATb


🌔04
求解相机外参

对于每一张图片,其外参都不一样.

R 1 T R 1 = 1 {\color{#2EA9DF}{R_1^T}}{\color{#2EA9DF}{R_1}}=1 R1TR1=1有:

Z C 2 H 1 T K − T K − 1 H 1 = 1 Z_C^2{\color{#86C166}{H_1^T}}{\color{#E16B8C}{K^{-T}}}{\color{#E16B8C}{K^{-1}}}{\color{#86C166}{H_1}}=1 ZC2H1TKTK1H1=1

由此可以解有:

Z C = 1 ∣ ∣ K − 1 H 1 ∣ ∣ Z_C=\frac{1}{||{\color{#E16B8C}{K^{-1}}}{\color{#86C166}{H_1}}||} ZC=∣∣K1H1∣∣1

由此有:

[ R 1 R 2 T ] = Z C K − 1 [ H 1 H 2 H 3 ] \begin{bmatrix}{\color{#2EA9DF}{R_1}}&{\color{#2EA9DF}{R_2}}&{\color{#2EA9DF}{T}} \end{bmatrix}=Z_C{\color{#E16B8C}{K^{-1}}}\begin{bmatrix}{\color{#86C166}{H_1}}&{\color{#86C166}{H_2}}&{\color{#86C166}{H_3}}\end{bmatrix} [R1R2T]=ZCK1[H1H2H3]


🌔05
畸变的公式

径向畸变是由透镜自身引起的,不可忽略,而切向畸变一般是由安装引起的,常可以忽略。这里两种畸变都予以考虑。

归一化相机坐标系(通过尺度变换,使得 Z C = 1 Z_C=1 ZC=1)中:

对于径向畸变,有以下畸变公式,其中 X C ′ , Y C ′ X_C',Y_C' XC,YC为带畸变的坐标, X C , Y C X_C,Y_C XC,YC为真实坐标, r 2 = X C 2 + Y C 2 r^2=X_C^2+Y_C^2 r2=XC2+YC2

{ X C ′ = X C ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) , Y C ′ = Y C ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) \begin{cases}X_{C}'=X_C(1+{\color{#F75C2F}{k_1}}r^2+{\color{#F75C2F}{k_2}}r^4+{\color{#F75C2F}{k_3}}r^6),\\Y_{C}'=Y_C(1+{\color{#F75C2F}{k_1}}r^2+{\color{#F75C2F}{k_2}}r^4+{\color{#F75C2F}{k_3}}r^6)\end{cases} {XC=XC(1+k1r2+k2r4+k3r6),YC=YC(1+k1r2+k2r4+k3r6)

如果在径向畸变的基础上考虑切向畸变,有以下畸变公式:

{ X C ′ = X C ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) + [ 2 p 1 X C Y C + p 2 ( r 2 + 2 X C 2 ) ] , Y C ′ = Y C ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) + [ 2 p 2 X C Y C + p 1 ( r 2 + 2 Y C 2 ) ] \begin{cases} X_{C}'=X_C(1+{\color{#F75C2F}{k_1}}r^2+{\color{#F75C2F}{k_2}}r^4+{\color{#F75C2F}{k_3}}r^6)+[2{\color{#77428D}{p_1}}X_CY_C+{\color{#77428D}{p_2}}(r^2+2X_C^2)],\\ Y_{C}'=Y_C(1+{\color{#F75C2F}{k_1}}r^2+{\color{#F75C2F}{k_2}}r^4+{\color{#F75C2F}{k_3}}r^6)+[2{\color{#77428D}{p_2}}X_CY_C+{\color{#77428D}{p_1}}(r^2+2Y_C^2)] \end{cases} {XC=XC(1+k1r2+k2r4+k3r6)+[2p1XCYC+p2(r2+2XC2)],YC=YC(1+k1r2+k2r4+k3r6)+[2p2XCYC+p1(r2+2YC2)]

在联合迭代优化开始前,可以先将畸变系数任意设置一个合理的初值。


🌔06
联合优化

⭐️注意在前面几个小节中求取的内参和外参都是初始值,接下来会与畸变系数联合优化求解。
即联合优化求解参数: p a r a m = [ K , R i , T i , k 1 , k 2 , k 3 , p 1 , p 2 ] {\color{#FBE251}{param}}=\begin{bmatrix}{\color{#E16B8C}{K}},{\color{#2EA9DF}{R_i}},{\color{#2EA9DF}{T_i}},{\color{#F75C2F}{k_1}},{\color{#F75C2F}{k_2}},{\color{#F75C2F}{k_3}},{\color{#77428D}{p_1}},{\color{#77428D}{p_2}}\end{bmatrix} param=[K,Ri,Ti,k1,k2,k3,p1,p2]

设以下符号表示:

  • 角点像素坐标的观测值 m m m ( u , v ) (u,v) (u,v),与之对应的世界坐标系坐标 M M M ( X W , Y W ) (X_W,Y_W) (XW,YW)

  • 图像的个数为 n n n,每张图像的角点数为 m m m

  • m ^ i j = g ( p a r a m , M i j ) \hat m_{ij}=g({\color{#FBE251}{param}},M_{ij}) m^ij=g(param,Mij)为在考虑畸变时,用第 i i i张图像的第 j j j个角点的世界坐标经重投影函数 g g g后得到的像素坐标估计值 m ^ i j \hat m_{ij} m^ij​.

则可以通过求解最小化估计值观测值的误差这一优化问题(可使用Levenberg-Marquardt算法),求得参数 p a r a m {\color{#FBE251}{param}} param

m i n ∑ i = 1 n ∑ j = 1 m ∣ ∣ m i j − m ^ i j ∣ ∣ 2 \mathbf{min} \sum_{i=1}^{n}\sum_{j=1}^{m}||m_{ij}-\hat m_{ij}||^2 mini=1nj=1m∣∣mijm^ij2


🌔07
标定代码

以下是封装好重要函数的相机标定Python程序和注释解释。

#重要的函数
#1 ok, corners = detect_chessboard(img, rows, cols)  角点检测
#2 cv2.drawChessboardCorners(img, (cols, rows), corners, ok) 画角点
#3 ok, camera_mat, dist_coeff, rvecs, tvecs = cv2.calibrateCamera( 标定
#4      object_points, img_points, img_wh, camera_mat, dist_coeff,
#       criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 100, 1e-6))
#5 proj_points = cv2.projectPoints(object_points[i], rvecs[i], tvecs[i], camera_mat, dist_coeff)[0] 重投影
import os
import cv2
import numpy as np
np.set_printoptions(precision=4, suppress=True) #关闭科学计数法,便于显示


def image_from_camera():
    # 从摄像头中读取图像并保存(按键盘s键, 按ESC键退出程序)
    cap = cv2.VideoCapture(0)
    assert cap.isOpened(), 'Fail to open camera!'

    # 指定一个目录用于存放摄像头中截取的图像
    save_dir = '../data'
    # 图像文件命名范式: 0001.jpg, 0002.jpg, ...
    name_format = '%04d.jpg'
    name_idx = 1

    while True:
        ok, img = cap.read()
        assert ok, 'Fail to read camera!'
        cv2.imshow('1', img)
        key = cv2.waitKey(1) #以1ms为限制等待
        if key == -1:  # 什么键也没有按下
            continue
        if (key == 27):  # ESC键
            break
        if chr(key) == 's':  # s 键
            name = os.path.join(save_dir, name_format % name_idx)
            name_idx += 1
            cv2.imwrite(name, img)
            print('Saved image to \'%s\'', name)
    return

def detect_chessboard(img, rows=12, cols=6, subpix_sz=5):
    """
    从棋盘格图像中检测棋盘格角点
    :param img: 棋盘格图像,BGR或gray
    :param rows: 角点行数(不是方块的个数, 不算边缘角点) height
    :param cols: 角点列数  width
    :param subpix_sz: 对棋盘格角点坐标优化时的局部搜索范围,应不大于图像中最小方块的边长,单位是像素
    :return: 检测的角点,shape=(rows*cols,1,2)。如果实际检测的角点数目小于rows*cols则报错。
    corners (num,1,2)
    """

    ok, corners = cv2.findChessboardCorners(
        img, (cols, rows),
        cv2.CALIB_CB_ADAPTIVE_THRESH | cv2.CALIB_CB_NORMALIZE_IMAGE | cv2.CALIB_CB_FAST_CHECK)

    if ok:
        #亚像素级优化(GRAY),增加其准确性
        #zeroZone设置排除的区域,设置为(-1,-1)表示全部区域都检测
        #criteria迭代终止条件(次数或精度)
        corners = cv2.cornerSubPix(
            img if len(img.shape) == 2 else cv2.cvtColor(img, cv2.COLOR_BGR2GRAY),
            corners, (subpix_sz, subpix_sz), (-1, -1),
            (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.01))

    return ok, corners


if __name__ == '__main__':
    # 第一步,用摄像头采集一些棋盘格图片
    # image_from_camera()

    # 第二步,读取每张图片,进行角点检测
    imgs = []  # 所选取的图像
    img_paths = []  # 对应的路径
    img_points = []  #9,72,1,2# 从图像中检测的角点
    cols, rows = 12, 6
    img_num = len(os.listdir(r'../data'))
    draw = False
    for i in range(1, img_num+1):
        img_path = '../data/%04d.jpg' % i
        img = cv2.imread(img_path) #BGR或GRAY格式
        assert img is not None, 'Fail to read image: ' + img_path
        ok, corners = detect_chessboard(img, rows, cols)
        if not ok:
            cv2.putText(img, 'Fail to detect corners!', org=(50, 200),
                        fontFace=cv2.FONT_HERSHEY_PLAIN , fontScale=4, color=(255, 255, 0), thickness=2)
            cv2.imshow('chessboard-corners-%04d'%i, img)
            cv2.waitKey()
            cv2.destroyWindow('chessboard-corners-%04d'%i)
        else:
            if draw:
                cv2.drawChessboardCorners(img, (cols, rows), corners, ok)
                cv2.imshow('chessboard-corners-%04d'%i, img)
                cv2.waitKey()
                cv2.destroyWindow('chessboard-corners-%04d'%i)
            imgs.append(img)
            img_paths.append(img_path)
            img_points.append(corners)

    nimgs = len(imgs)
    img_wh = img.shape[1::-1]  # (W,H)图像的宽以及高,所有图片必须具有相同尺寸,标定时要用到
    print('Got {} images for camera calibration.'.format(nimgs))

    # 第三步,进行相机标定
    # 先构造世界坐标系下的角点坐标,角点应该进行正确排序:先是第一行第一列,然后第一行第二列,...
    object_points = np.zeros((rows * cols, 1, 3), dtype='float32')
    square_sz = 138  #mm    any constant (edge length of eac chess board square, in millimeters or meters)
    for r in range(rows):
        for c in range(cols):
            object_points[r * cols + c, 0, 0] = c * square_sz  # world coordinate - X 行方向
            object_points[r * cols + c, 0, 1] = r * square_sz  # world coordinate - Y 列方向
    object_points = [object_points] * nimgs #9,72,1,3
    # 标定
    camera_mat = np.eye(3, 3)  # 如果有初始相机参数,可以在这里进行设置,将提高标定准确率
    dist_coeff = np.zeros((5, 1))  # 畸变参数k1 k2 k3 p1 p2
    ok, camera_mat, dist_coeff, rvecs, tvecs = cv2.calibrateCamera(
        object_points, img_points, img_wh, camera_mat, dist_coeff,
        criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 100, 1e-6))
    #R (9,3,1) T (9,3,1)
    # 每个旋转向量 rvec 的尺寸为 (3, 1),表示一个三维向量。这个向量通常是以列向量的形式表示的,包含三个元素,分别对应于绕 x、y、z 轴的旋转角度(以弧度为单位)
    assert ok and cv2.checkRange(camera_mat) and cv2.checkRange(dist_coeff), 'Calibration failed!' #checkRange预测是否在有效范围之内

    # 保存标定结果
    print('camera_mat:\n', camera_mat)
    print('dist_coeff:\n', dist_coeff)
    np.save(r'../output/camera_mat', camera_mat)
    np.save(r'../output/dist_coeff', dist_coeff)
    print('Saved calibration results to: camera_mat.npy and dist_coeff.npy')

    # 第四步,做一些简单的验证

    # 计算标定误差:将物理点投影到图像空间中,并与对应的图像点进行比较,计算重投影误差
    for i in range(nimgs):
        proj_points = cv2.projectPoints(object_points[i], rvecs[i], tvecs[i], camera_mat, dist_coeff)[0]  #第二个返回时雅可比矩阵,一般用不上
        average_err = cv2.norm(proj_points, img_points[i], cv2.NORM_L2) / len(img_points[i])  #单位mm
        print('Reprojection error for image \'%s\': %g' % (img_paths[i], average_err))

    # 对相机畸变进行补偿,得到去畸变的图像
    for i in range(nimgs):
        img_undistort = cv2.undistort(imgs[i], camera_mat, dist_coeff)  #校正
        cv2.imshow('original', imgs[i])
        cv2.imshow('undistort', img_undistort)
        if cv2.waitKey() == 27:
            break


🌔08
注意事项

  • 标定板选用长宽不一样的,以免角点检测失误;
  • 拍摄角度尽量不要使横纵方向完全颠倒;
  • 标定过程中保证相机的光圈和焦距参数不变;
  • 图片应尽量多些,测试可用10-25张。
<think>好的,用户遇到了Vue Router的警告:“No match found for location with path '/#Home'”,需要解决这个问题。首先,我得回忆一下Vue Router的相关知识,以及常见的路由配置错误。根据用户提供的引用内容,类似的问题通常与路由配置不正确或动态路由未生效有关。 首先,用户提到的路径是'/#Home',这里的#号可能是哈希模式的一部分。Vue Router有两种模式:哈希模式(hash mode)和历史模式(history mode)。哈希模式会在URL中添加#符号,而历史模式则依赖服务器配置。用户可能在哈希模式下配置了路由,但路径中的#号后面可能没有正确匹配路由。 接下来,我需要检查用户的路由配置是否正确。比如,是否定义了名为'Home'的路由路径。如果用户使用的是哈希模式,那么实际路径应该是'/#/home'而不是'/#Home',因为Vue Router在哈希模式下会自动处理#后面的部分作为路由路径。所以,路径中的大小写可能有问题,或者路径定义不正确。 另外,动态路由未加载也是一个常见问题,尤其是在页面刷新时。如果Home路由是动态添加的,可能在初始化时没有正确加载,导致路由匹配失败。这时候需要确保动态路由在创建路由器实例之前已经添加好,或者在导航守卫中处理。 还有可能用户在使用Vue 3和Vue Router 4时,404页面的配置方式发生了变化。之前的版本可能使用通配符*来匹配404,而新版本需要使用带有自定义正则表达式的数来捕获所有路径。如果用户没有正确配置404路由,可能会导致无法匹配的路由产生警告。 另外,检查路由的路径是否含有不必要的#号。例如,在哈希模式下,正确的路径应该是'#/home',而用户可能错误地写成了'/#Home',这可能导致路由无法正确解析。这时候需要修正路径中的大小写和斜杠的位置。 最后,建议用户检查路由定义中的path属性是否正确,使用重定向来处理旧路径,以及确保动态路由在适当的时候被加载。同时,使用Vue Devtools来检查当前的路由状态,帮助定位问题。</think>针对Vue Router出现的$[No\ match\ found\ for\ location\ with\ path\ /\#Home]$警告,以下是分步解决方案: ### 1. 检查路由配置模式 确认使用的是**哈希模式**还是**历史模式**,哈希模式默认路径格式为$/#/path$: ```typescript // router/index.ts import { createRouter, createWebHashHistory } from 'vue-router' const router = createRouter({ history: createWebHashHistory(), // 明确使用哈希模式 routes: [...] }) ``` 若错误混用两种模式会导致路径解析异常[^3] ### 2. 验证路由路径定义 检查路由配置中是否正确定义了$Home$路由: ```typescript { path: '/Home', // 注意大小写敏感 name: 'Home', component: () => import('@/views/Home.vue') } ``` 或推荐使用标准小写路径: ```typescript { path: '/home', redirect: '/Home' // 添加重定向处理旧路径 } ``` ### 3. 处理动态路由加载 若涉及动态路由,需在路由守卫中确保加载完成: ```typescript router.beforeEach(async (to, from, next) => { if (!router.hasRoute(to.name)) { await loadDynamicRoutes() // 动态加载路由的方法 return next(to.fullPath) } next() }) ``` 动态路由未加载会导致刷新时匹配失败[^4] ### 4. 配置通配符路由 添加404兜底路由捕获未匹配路径: ```typescript { path: '/:catchAll(.*)', component: NotFoundComponent } ``` Vue Router 4.x需使用自定义正则语法[^4] ### 5. 调试工具验证 通过Vue Devtools检查: - 当前激活路由状态 - 完整路由表结构 - 导航守卫执行情况 ### 6. 路径标准化处理 在导航时使用规范化路径: ```javascript // 错误写法 router.push('/#Home') // 正确写法(哈希模式) router.push('/home') // 或生成标准化路径 router.push({ path: '/home' }) ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值