【opencv】教程代码 —features2D(3)Homography—分解单应性矩阵

decompose_homography.cpp 分解单应性矩阵

1f3cf8759d2a1979c1054e4d24bfe9c1.jpeg

left01.jpg  boardSize:9x6  squareSize:0.025

b5dda4984f7911928b3769da8026b2c1.jpeg

left02.jpg

92de7d4b88c7756e55cb3eb041aa944e.png

c31a1fe2f8c8c527266998e13bb16387.png

相机内参

1eaf211b2dced8899b341b6ae026820c.png

#include <iostream> // 引入输入输出流库
#include <opencv2/core.hpp> // 引入OpenCV的核心功能头文件
#include <opencv2/highgui.hpp> // 引入OpenCV的GUI功能头文件
#include <opencv2/calib3d.hpp> // 引入OpenCV的相机标定和三维重建功能头文件


using namespace std; // 使用标准命名空间,例如std::vector可以省略std::
using namespace cv; // 使用opencv命名空间,例如cv::Mat可以省略cv::


namespace // 匿名命名空间
{
// 定义了几种标定板的模式的枚举类型
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };


// 函数用于计算棋盘格的角点
void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners, Pattern patternType = CHESSBOARD)
{
    corners.resize(0); // 清空角点向量


    // 根据不同的标定板类型计算角点
    switch (patternType) {
    case CHESSBOARD:
    case CIRCLES_GRID:
        // 对于棋盘格和圆点网格,遍历每行每列生成角点
        for( int i = 0; i < boardSize.height; i++ )
            for( int j = 0; j < boardSize.width; j++ )
                corners.push_back(Point3f(float(j*squareSize),
                                          float(i*squareSize), 0));
        break;


    case ASYMMETRIC_CIRCLES_GRID:
        // 对于非对称圆点网格,遍历每行每列生成角点,同时考虑横向位置的偏移
        for( int i = 0; i < boardSize.height; i++ )
            for( int j = 0; j < boardSize.width; j++ )
                corners.push_back(Point3f(float((2*j + i % 2)*squareSize),
                                          float(i*squareSize), 0));
        break;


    // 如果模式类型未知则报错
    default:
        CV_Error(Error::StsBadArg, "Unknown pattern type\n");
    }
}


// 计算单应性矩阵的函数,基于旋转矩阵、平移向量、平面到相机的逆距离和平面的法向量
Mat computeHomography(const Mat &R_1to2, const Mat &tvec_1to2, const double d_inv, const Mat &normal)
{
    Mat homography = R_1to2 + d_inv * tvec_1to2*normal.t(); // 计算单应性矩阵
    return homography; // 返回计算出的单应性矩阵
}


// 根据两次相机位姿计算两个相机之间的位姿关系
void computeC2MC1(const Mat &R1, const Mat &tvec1, const Mat &R2, const Mat &tvec2,
                  Mat &R_1to2, Mat &tvec_1to2)
{
    //c2Mc1 = c2Mo * oMc1 = c2Mo * c1Mo.inv()
    R_1to2 = R2 * R1.t(); // 计算旋转矩阵
    tvec_1to2 = R2 * (-R1.t()*tvec1) + tvec2; // 计算平移向量
}


// 主函数,使用两个图像、棋盘格大小、方块大小和内参路径进行标定板的单应性分解
void decomposeHomography(const string &img1Path, const string &img2Path, const Size &patternSize,
                         const float squareSize, const string &intrinsicsPath)
{
    // 根据路径读取两张图像
    Mat img1 = imread( samples::findFile( img1Path) );
    Mat img2 = imread( samples::findFile( img2Path) );


    // 查找两幅图像中的角点
    vector<Point2f> corners1, corners2;
    bool found1 = findChessboardCorners(img1, patternSize, corners1);
    bool found2 = findChessboardCorners(img2, patternSize, corners2);


    // 如果任一图像无法找到角点则返回错误
    if (!found1 || !found2)
    {
        cout << "Error, cannot find the chessboard corners in both images." << endl;
        return;
    }


    //! [compute-poses]
    vector<Point3f> objectPoints; // 存储物体在世界坐标系中的点
    // 计算棋盘格角点的世界坐标
    calcChessboardCorners(patternSize, squareSize, objectPoints); 


    // 读取相机的内参
    FileStorage fs( samples::findFile( intrinsicsPath ), FileStorage::READ);
    Mat cameraMatrix, distCoeffs;
    fs["camera_matrix"] >> cameraMatrix; // 相机矩阵
    fs["distortion_coefficients"] >> distCoeffs; // 畸变系数


    // 对两个图像使用solvePnP求解相机位姿
    // 使用solvePnP来估计两幅图片的相机外参即旋转向量和平移向量
    Mat rvec1, tvec1; // 旋转向量和平移向量
    solvePnP(objectPoints, corners1, cameraMatrix, distCoeffs, rvec1, tvec1);
    Mat rvec2, tvec2;
    solvePnP(objectPoints, corners2, cameraMatrix, distCoeffs, rvec2, tvec2);
    //! [compute-poses]


    //! [compute-camera-displacement]
    Mat R1, R2;
    Rodrigues(rvec1, R1); // 旋转向量转换成旋转矩阵
    Rodrigues(rvec2, R2);


    // 计算两个相机位姿之间的相对旋转和平移
    Mat R_1to2, t_1to2;
    computeC2MC1(R1, tvec1, R2, tvec2, R_1to2, t_1to2);
    Mat rvec_1to2;
    Rodrigues(R_1to2, rvec_1to2); // 计算得到的旋转矩阵再转换成旋转向量
    //! [compute-camera-displacement]


    //! [compute-plane-normal-at-camera-pose-1]
    Mat normal = (Mat_<double>(3,1) << 0, 0, 1); // 定义一个垂直于棋盘格表面的法向量
    Mat normal1 = R1*normal; //相机1坐标轴z在世界坐标系的表示// 使用相机1的旋转矩阵变换法向量到相机坐标系下
    //! [compute-plane-normal-at-camera-pose-1]


    //! [compute-plane-distance-to-the-camera-frame-1]
    // 计算棋盘格平面到相机坐标系原点的距离
    Mat origin(3, 1, CV_64F, Scalar(0)); // 定义原点
    Mat origin1 = R1*origin + tvec1; // 相机坐标系1原点在世界坐标系下的表示
    //相机1坐标系原点到标定板平面的距离的逆
    double d_inv1 = 1.0 / normal1.dot(origin1); // 计算平面到相机1原点的逆距离
    //! [compute-plane-distance-to-the-camera-frame-1]


    //! [compute-homography-from-camera-displacement]
    // 根据相机位姿差异计算单应性矩阵
    Mat homography_euclidean = computeHomography(R_1to2, t_1to2, d_inv1, normal1);
    Mat homography =cameraMatrix * homography_euclidean * cameraMatrix.inv();
    // 根据欧几里得单应性矩阵计算实际的单应性矩阵
    // 内参解极约束
    homography /= homography.at<double>(2,2);
    homography_euclidean /= homography_euclidean.at<double>(2,2);
    //! [compute-homography-from-camera-displacement]


    //! [decompose-homography-from-camera-displacement]
    // 分解从相机位移计算得到的单应性矩阵
    vector<Mat> Rs_decomp, ts_decomp, normals_decomp;
    // 使用OpenCV函数decomposeHomographyMat进行分解
    int solutions = decomposeHomographyMat(homography, cameraMatrix, Rs_decomp, ts_decomp, normals_decomp);
    // 显示分解得到的解决方案数和每个解决方案
    cout << "Decompose homography matrix computed from the camera displacement:" << endl << endl;
    for (int i = 0; i < solutions; i++)
    {
      double factor_d1 = 1.0 / d_inv1;
      Mat rvec_decomp;
      Rodrigues(Rs_decomp[i], rvec_decomp); // 将旋转矩阵转换成旋转向量
      cout << "Solution " << i << ":" << endl;
      cout << "rvec from homography decomposition: " << rvec_decomp.t() << endl;
      cout << "rvec from camera displacement: " << rvec_1to2.t() << endl;
      cout << "tvec from homography decomposition: " << ts_decomp[i].t() << " and scaled by d: " << factor_d1 * ts_decomp[i].t() << endl;
      cout << "tvec from camera displacement: " << t_1to2.t() << endl;
      cout << "plane normal from homography decomposition: " << normals_decomp[i].t() << endl;
      cout << "plane normal at camera 1 pose: " << normal1.t() << endl << endl;
    }
    //! [decompose-homography-from-camera-displacement]


    //! [estimate homography]
    // 使用findHomography()估计两幅图像间点的单应性矩阵
    Mat H = findHomography(corners1, corners2);
    //! [estimate homography]


    //! [decompose-homography-estimated-by-findHomography]
    // 分解由findHomography()函数估计得到的单应性矩阵
    solutions = decomposeHomographyMat(H, cameraMatrix, Rs_decomp, ts_decomp, normals_decomp);
    cout << "Decompose homography matrix estimated by findHomography():" << endl << endl;
    for (int i = 0; i < solutions; i++)
    {
      double factor_d1 = 1.0 / d_inv1;
      Mat rvec_decomp;
      Rodrigues(Rs_decomp[i], rvec_decomp); // 将旋转矩阵转换成旋转向量
      cout << "Solution " << i << ":" << endl;
      cout << "rvec from homography decomposition: " << rvec_decomp.t() << endl;
      cout << "rvec from camera displacement: " << rvec_1to2.t() << endl;
      cout << "tvec from homography decomposition: " << ts_decomp[i].t() << " and scaled by d: " << factor_d1 * ts_decomp[i].t() << endl;
      cout << "tvec from camera displacement: " << t_1to2.t() << endl;
      cout << "plane normal from homography decomposition: " << normals_decomp[i].t() << endl;
      cout << "plane normal at camera 1 pose: " << normal1.t() << endl << endl;
    }
    //! [decompose-homography-estimated-by-findHomography]
}


// 命令行参数解析中用到的参数模板字符串
const char* params
    = "{ help h         |       | print usage }"
      "{ image1         | left02.jpg | path to the source chessboard image }"
      "{ image2         | left01.jpg | path to the desired chessboard image }"
      "{ intrinsics     | left_intrinsics.yml | path to camera intrinsics }"
      "{ width bw       | 9     | chessboard width }"
      "{ height bh      | 6     | chessboard height }"
      "{ square_size    | 0.025 | chessboard square size }";
}


// main函数 - 程序入口点
int main(int argc, char *argv[])
{
    // 解析命令行输入的参数
    CommandLineParser parser(argc, argv, params);


    // 如果参数中包含help,则打印程序的帮助信息
    if ( parser.has("help") )
    {
        parser.about("Code for homography tutorial.\n"
                     "Example 4: decompose the homography matrix.\n");
        parser.printMessage();
        return 0;
    }


    // 获取棋盘格尺寸参数、方块大小并调用decomposeHomography函数
    Size patternSize(parser.get<int>("width"), parser.get<int>("height"));
    float squareSize = (float) parser.get<double>("square_size");
    decomposeHomography(parser.get<String>("image1"),
                        parser.get<String>("image2"),
                        patternSize, squareSize,
                        parser.get<String>("intrinsics"));


    return 0; // 程序正常结束
}

代码的主要功能是通过两张棋盘格图像来计算它们之间的单应性矩阵,并对该矩阵进行分解以获得相对旋转向量、平移向量和正常向量。这个过程通常用于计算机视觉中相机的位姿估计和校准。代码使用了OpenCV的相关函数完成图像处理和矩阵运算。

decomposeHomography用于执行相机位移下单应性矩阵的分解与计算。整个代码流程包括:

1. 读取两幅图像并在棋盘格中找到角点。2. 从外部文件读取相机内参。3. 使用solvePnP函数估计两幅图像相对于世界坐标系的姿态。4. 计算相机1到相机2的旋转和平移。5. 计算参考平面的法线向量和到相机1的距离。6. 根据相机间的位移计算出单应性矩阵。7. 使用decomposeHomographyMat函数分解由相机位移计算出的单应性矩阵。8. 通过findHomography函数估计两个视图间的单应性矩阵,并分解之。 代码的最终目的是从两幅图像计算出相机的位移,并从位移中分解出单应性矩阵,这通常用于场景的三维重构和姿态估计。

终端输出:

Decompose homography matrix computed from the camera displacement:


Solution 0:
rvec from homography decomposition: [-0.09198300601684746, -0.5372581107203847, 1.310868858823169]
rvec from camera displacement: [-0.09198300601684731, -0.5372581107203847, 1.310868858823169]
tvec from homography decomposition: [-0.7747960935447347, -0.02751122265362334, -0.6791979966698382] and scaled by d: [-0.1578091502009057, -0.005603439026252055, -0.1383378924669762]
tvec from camera displacement: [0.1578091502009057, 0.005603439026252086, 0.1383378924669763]
plane normal from homography decomposition: [-0.1973513031094161, 0.6283452092297845, -0.7524857215914424]
plane normal at camera 1 pose: [0.1973513031094159, -0.6283452092297841, 0.7524857215914428]


Solution 1:
rvec from homography decomposition: [-0.09198300601684746, -0.5372581107203847, 1.310868858823169]
rvec from camera displacement: [-0.09198300601684731, -0.5372581107203847, 1.310868858823169]
tvec from homography decomposition: [0.7747960935447347, 0.02751122265362334, 0.6791979966698382] and scaled by d: [0.1578091502009057, 0.005603439026252055, 0.1383378924669762]
tvec from camera displacement: [0.1578091502009057, 0.005603439026252086, 0.1383378924669763]
plane normal from homography decomposition: [0.1973513031094161, -0.6283452092297845, 0.7524857215914424]
plane normal at camera 1 pose: [0.1973513031094159, -0.6283452092297841, 0.7524857215914428]


Solution 2:
rvec from homography decomposition: [0.1053487844994422, -0.1561929302268701, 1.40135654775989]
rvec from camera displacement: [-0.09198300601684731, -0.5372581107203847, 1.310868858823169]
tvec from homography decomposition: [-0.4666552458868745, 0.105003306671971, -0.9130076449288979] and scaled by d: [-0.09504754657871854, 0.02138689486465782, -0.1859598438525694]
tvec from camera displacement: [0.1578091502009057, 0.005603439026252086, 0.1383378924669763]
plane normal from homography decomposition: [-0.3131715302799941, 0.8421206250806385, -0.4390403687998199]
plane normal at camera 1 pose: [0.1973513031094159, -0.6283452092297841, 0.7524857215914428]


Solution 3:
rvec from homography decomposition: [0.1053487844994422, -0.1561929302268701, 1.40135654775989]
rvec from camera displacement: [-0.09198300601684731, -0.5372581107203847, 1.310868858823169]
tvec from homography decomposition: [0.4666552458868745, -0.105003306671971, 0.9130076449288979] and scaled by d: [0.09504754657871854, -0.02138689486465782, 0.1859598438525694]
tvec from camera displacement: [0.1578091502009057, 0.005603439026252086, 0.1383378924669763]
plane normal from homography decomposition: [0.3131715302799941, -0.8421206250806385, 0.4390403687998199]
plane normal at camera 1 pose: [0.1973513031094159, -0.6283452092297841, 0.7524857215914428]


Decompose homography matrix estimated by findHomography():


Solution 0:
rvec from homography decomposition: [0.1552207660862356, -0.1521327237748819, 1.323678685010914]
rvec from camera displacement: [-0.09198300601684731, -0.5372581107203847, 1.310868858823169]
tvec from homography decomposition: [-0.4482361641899351, 0.02485247517069353, -1.034409633494862] and scaled by d: [-0.09129597935439666, 0.005061909862158862, -0.2106867943469173]
tvec from camera displacement: [0.1578091502009057, 0.005603439026252086, 0.1383378924669763]
plane normal from homography decomposition: [-0.1384902519298367, 0.9063331412907092, -0.3992251083267753]
plane normal at camera 1 pose: [0.1973513031094159, -0.6283452092297841, 0.7524857215914428]


Solution 1:
rvec from homography decomposition: [0.1552207660862356, -0.1521327237748819, 1.323678685010914]
rvec from camera displacement: [-0.09198300601684731, -0.5372581107203847, 1.310868858823169]
tvec from homography decomposition: [0.4482361641899351, -0.02485247517069353, 1.034409633494862] and scaled by d: [0.09129597935439666, -0.005061909862158862, 0.2106867943469173]
tvec from camera displacement: [0.1578091502009057, 0.005603439026252086, 0.1383378924669763]
plane normal from homography decomposition: [0.1384902519298367, -0.9063331412907092, 0.3992251083267753]
plane normal at camera 1 pose: [0.1973513031094159, -0.6283452092297841, 0.7524857215914428]


Solution 2:
rvec from homography decomposition: [-0.2886605520980661, -0.5210498746612311, 1.381242036724107]
rvec from camera displacement: [-0.09198300601684731, -0.5372581107203847, 1.310868858823169]
tvec from homography decomposition: [-0.8705960844288273, 0.1353018264406045, -0.7037701811073137] and scaled by d: [-0.1773215293631533, 0.02755804582536839, -0.1433427131894416]
tvec from camera displacement: [0.1578091502009057, 0.005603439026252086, 0.1383378924669763]
plane normal from homography decomposition: [-0.2284582164830118, 0.6009247378618285, -0.7659610321335505]
plane normal at camera 1 pose: [0.1973513031094159, -0.6283452092297841, 0.7524857215914428]


Solution 3:
rvec from homography decomposition: [-0.2886605520980661, -0.5210498746612311, 1.381242036724107]
rvec from camera displacement: [-0.09198300601684731, -0.5372581107203847, 1.310868858823169]
tvec from homography decomposition: [0.8705960844288273, -0.1353018264406045, 0.7037701811073137] and scaled by d: [0.1773215293631533, -0.02755804582536839, 0.1433427131894416]
tvec from camera displacement: [0.1578091502009057, 0.005603439026252086, 0.1383378924669763]
plane normal from homography decomposition: [0.2284582164830118, -0.6009247378618285, 0.7659610321335505]
plane normal at camera 1 pose: [0.1973513031094159, -0.6283452092297841, 0.7524857215914428]

4e77715ade5f051f6e694f593e818fdd.png

a890d008417b11f5f935509f9f769e7f.png

如何计算相机间的转换矩阵?

88655865a194130991d82e04a535761e.png

如何使用solvePnP函数进行相机标定?

e638f60a6df69ab67916967293d4e732.png

Mat homography_euclidean = computeHomography(R_1to2, t_1to2, d_inv1, normal1);

880f95100bbc44eed34c436e47dd0c66.png

df6d8705862e2c4df59d00bf049f6f27.png

int solutions = decomposeHomographyMat(homography, cameraMatrix, Rs_decomp, ts_decomp, normals_decomp);

e6bc0e899b4837f031f0d251101cd2de.png

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB 自定义中值滤波(54)

MATLAB 自定义中值滤波(54) 一、算法介绍二、算法实现1.原理2.代码一、算法介绍 中值滤波,是一种常见的点云平滑算法,改善原始点云的数据质量问题,MATLAB自带的工具似乎不太友好,这里提供自定义实现的点云中值滤波算法,具体效果如下所示: 中值滤波前: 中值滤波后:…

【Node.js】大文件上传

概述 大文件上传通常采用分片上传。如果因为某些原因上传突然中断&#xff0c;解决问题之后可以接着之前的分片上传&#xff0c;而不需要从头开始上传&#xff0c;也就是断点续传。此外还可以利用多个网络连接并行上传多个分片&#xff0c;提高上传速度。 注&#xff1a;前端不…

动手学机器学习逻辑斯谛回归+习题

逻辑斯谛函数下的线性模型 现需要用线性模型做分类问题&#xff0c;简单的阶跃函数在阈值处不可导&#xff0c;可导处导数均为0&#xff0c;性质不好 所以把0&#xff0c;1问题转化成P(y0|x)&#xff0c;P(y1|x)的问题&#xff0c;这样就把离散的分类任务变成了求概率分布的回…

ROS传感器图像转换

ros通过摄像头来获得图片&#xff0c;传感器数据类型为sensor_msgs中的Image&#xff0c;具体的数据类型组成&#xff1a; sensor_msgs/Image Documentationhttp://docs.ros.org/en/api/sensor_msgs/html/msg/Image.html但是我们一般使用opencv对图像进行处理&#xff0c;所以…

Python字符串字母大小写变换,高级Python开发技术

寻找有志同道合的小伙伴&#xff0c;互帮互助,群里还有不错的视频学习教程和PDF电子书&#xff01; ‘’’ demo ‘tHis iS a GOod boOK.’ print(demo.casefold()) print(demo.lower()) print(demo.upper()) print(demo.capitalize()) print(demo.title()) print(dem…

Python字典操作

假设我们有一个学生信息数据库&#xff0c;其中存储了每个学生的姓名、年龄、性别和成绩。我们可以使用字典来表示每个学生的信息&#xff0c;并将所有学生存储在一个字典列表中。 设计者&#xff1a;ISDF 版本&#xff1a;v1.0 日期&#xff1a;03/29/2024# 定义学生信息字典列…

如何划分训练集、测试集、验证集

训练集、测试集和验证集是在机器学习和数据科学中常用的术语&#xff0c;用于评估和验证模型的性能。它们通常用于监督学习任务中。 1. 训练集&#xff08;Training Set&#xff09;&#xff1a;训练集是用于训练机器学习模型的数据集。在训练期间&#xff0c;模型使用训练集中…

小狐狸ChatGPT付费AI创作系统V2.8.0独立版 + H5端 + 小程序前端

狐狸GPT付费体验系统的开发基于国外很火的ChatGPT&#xff0c;这是一种基于人工智能技术的问答系统&#xff0c;可以实现智能回答用户提出的问题。相比传统的问答系统&#xff0c;ChatGPT可以更加准确地理解用户的意图&#xff0c;提供更加精准的答案。同时&#xff0c;小狐狸G…

图形推理 总结

原则 1.图形相似且元素基本不变&#xff1a;此时多考虑图形的位置移动规律&#xff0c;如平移、旋转、翻转等。 2.图形相似但元素有同有异&#xff1a;这种情况下常考组合叠加-去异存同、去同存异等;元素遍历;部分传递等。 3.图形相异但较规则&#xff1a;常考对称、直曲性、…

JDK8的下载安装与环境变量配置教程

前言 官网下载&#xff1a;Java Archive Downloads - Java SE 8u211 and later 现在应该没人用32位的系统了吧&#xff0c;直接下载Windows x64 Installer jdk-8u391-windows-x64.exe 一、安装JDK 1. 打开jdk-8u391-windows-x64.exe 2. 直接下一步 3. 这个地方不要动他&…

神经网络与深度学习(一)

线性回归 定义 利用数理统计中回归分析&#xff0c;来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法 要素 训练集&#xff08;训练数据&#xff09;输出数据拟合函数数据条目数 场景 预测价格&#xff08;房屋、股票等&#xff09;、预测住院时间&#…

深入探讨Docker in Docker:原理与实战指南

在软件开发和部署中&#xff0c;容器化技术已经成为一个不可或缺的工具。而在使用Docker进行容器化时&#xff0c;有时可能会遇到需要在一个Docker容器中运行另一个Docker容器的情况&#xff0c;这就是所谓的"Docker in Docker"&#xff08;简称DinD&#xff09;。本…

java数组与集合框架(二)-- 集合框架,Iterator迭代器,list

集合框架&#xff1a; 用于存储数据的容器。 Java 集合框架概述 一方面&#xff0c;面向对象语言对事物的体现都是以对象的形式&#xff0c;为了方便对多个对象的操作&#xff0c;就要对对象进行存储。另一方面&#xff0c;使用Array存储对象方面具有一些弊端&#xff0c;而…

Redis从入门到精通(一)Redis安装与启动、Redis客户端的使用

文章目录 写在最前第1章 Redis概述1.1 初识Redis1.1.1 NoSQL1.1.2 Redis的特点与优势 1.2 安装Redis1.2.1 安装依赖库1.2.2 安装Redis1.2.3 启动Redis1.2.3.1 默认启动1.2.3.2 指定配置启动1.2.3.3 开机自启 1.3 Redis客户端1.3.1 命令行客户端1.3.2 图形化桌面客户端1.3.3 编程…

RVM安装Ruby笔记(Mac)

环境 硬件&#xff1a;Macbook Pro 系统&#xff1a;macOS 14.1 安装公钥 通过gpg安装公钥失败&#xff0c;报错如下&#xff1a; 换了几个公钥地址&#xff08;hkp://subkeys.pgp.net&#xff0c;hkp://keys.gnupg.net&#xff0c;hkp://pgp.mit.edu&#xff09;&#xff0c;…

Mysql or与in的区别

创建一个表格 内涵一千万条数据 这张表中&#xff0c;只有id有建立索引&#xff0c;且其余都没有 测试1&#xff1a;使用or的情况下&#xff0c;根据主键进行查询 可以看到根据主键id进行or查询 花费了30-114毫秒&#xff0c;后面30多毫秒可能是因为Mysql的Buffer Pool缓冲池的…

图论做题笔记:dfs

Leetcode - 797&#xff1a;所有可能的路径 题目&#xff1a; 给你一个有 n 个节点的 有向无环图&#xff08;DAG&#xff09;&#xff0c;请你找出所有从节点 0 到节点 n-1 的路径并输出&#xff08;不要求按特定顺序&#xff09; graph[i] 是一个从节点 i 可以访问的所有节…

深入理解数据结构(1):复杂度详解

文章主题&#xff1a;复杂度详解&#x1f331;所属专栏&#xff1a;深入理解数据结构&#x1f4d8;作者简介&#xff1a;更新有关深入理解数据结构知识的博主一枚&#xff0c;记录分享自己对数据结构的深入解读。&#x1f604;个人主页&#xff1a;[₽]的个人主页&#x1f525;…

Intellij IDEA / Android studio 可持续开发笔记

Intellij 的Java/安卓工具链有着一种不可持续性&#xff0c;这种不可持续性体现在多个方面。 首先是不可持续运行。IDEA 使用时间越长&#xff0c;内存占用越大&#xff0c;从不主动释放。运行时间越长&#xff0c;日志越多&#xff0c;从不主动清理。 然后是不完整的开源&am…

java多线程——概述,创建方式及常用方法

前言&#xff1a; 学习到多线程了&#xff0c;整理下笔记&#xff0c;daydayup!!! 多线程 什么是线程 线程&#xff08;Thread&#xff09;是一个程序内部的一条执行流程。若程序只有一条执行流程&#xff0c;那这个程序就是单线程的程序。 什么是多线程 多线程是指从软硬件上…