当前位置: 首页 > news >正文

2.5D视觉——Aruco码定位检测

目录

  • 1.什么是Aruco标记
  • 2.Aruco码解码说明
    • 2.1 Original ArUco
    • 2.2 预设的二维码字典
    • 2.3 大小Aruco二维码叠加
  • 3.函数说明
    • 3.1 cv::aruco::detectMarkers
    • 3.2 cv::solvePnP
  • 4.代码注解
    • 4.1 Landmark图说明
    • 4.2 算法源码注解

1.什么是Aruco标记

  ArUco标记最初由S.Garrido-Jurado等人在2014年发表的论文Automatic generation and detection of highly reliable fiducial markers under occlusion中提出。ArUco的全称是Augmented Reality University of Cordoba,下面给出ArUco标记的一些示例。
在这里插入图片描述
  ArUco标记是可用于摄像机姿态估计的二进制方形基准标记。它的主要优点是检测简单、快速,并且具有很强的鲁棒性。ArUco 标记是由宽黑色边框和确定其标识符(id)的内部二进制矩阵组成的正方形标记。ArUco标记的黑色边框有助于其在图像中的快速检测,内部二进制编码用于识别标记和提供错误检测和纠正。ArUco标记尺寸的大小决定内部矩阵的大小,例如尺寸为 4x4 的标记由 16 位二进制数组成。

  ArUco标记的尺寸可以任意的更改,为了成功检测可根据对象大小和场景选择合适的尺寸。在实际使用中,如果标记的尺寸太小,可能无法检测到它,这时可以选择更换较大尺寸的标记,或者将相机离标记更近一些。

  在机器人应用中,可以将这些标记沿着仓库机器人的路径放置。当安装在机器人上的摄像头检测到这些标记时,由于每个标记都有唯一的ID,并且且标记在仓库中的放置位置已知,因此就可以知道机器人在仓库中的精确位置。

  通俗地说,Aruco标记其实就是一种编码,就和我们日常生活中的二维码是相似的,只不过由于编码方式的不同,导致它们存储信息的方式、容量等等有所差异,所以在应用层次上也会有所不同。由于单个ArUco标记就可以提供足够的对应关系,例如有四个明显的角点内部的二进制编码,所以ArUco标记被广泛用来增加从二维世界映射到三维世界时的信息量,便于发现二维世界与三维世界之间的投影关系,从而实现姿态估计相机矫正等等应用。

  ArUco marker是一种汉明码方格图。它由一个宽的黑边和一个内部的二进制矩阵组成,黑色的边界有利于快速检测到图像,Marker ID是他的二进制矩阵编码。黑色方块对应0,白色方块对应1。一个二维码就是一个矩阵。

2.Aruco码解码说明

Aruco二维码生成网站
https://chev.me/arucogen/

2.1 Original ArUco

  早期的Aruco码Marker id解码规则是(这里以Marker id 21举例):
在这里插入图片描述

  上面是7x7的方格,除去最外层的黑色边框,中间是5x5,其中奇数列是校验位,偶数列是数据位,所以第1、3、5列为校验位2、4列为数据位,根据黑色方块对应0,白色方块对应1,提取出数据位为:

0	0
0	0
0	1
0	1
0	1每行首尾相接整理得:0000010101 转为十进制是1+4+16=21,对应Marker ID

2.2 预设的二维码字典

  OpenCV中预存了一些设置好Marker ID的字典,直接查找相对应的即可。

/*** @brief Predefined markers dictionaries/sets* Each dictionary indicates the number of bits and the number of markers contained* - DICT_ARUCO_ORIGINAL: standard ArUco Library Markers. 1024 markers, 5x5 bits, 0 minimumdistance*/
enum PREDEFINED_DICTIONARY_NAME {DICT_4X4_50 = 0,DICT_4X4_100,DICT_4X4_250,DICT_4X4_1000,DICT_5X5_50,DICT_5X5_100,DICT_5X5_250,DICT_5X5_1000,DICT_6X6_50,DICT_6X6_100,DICT_6X6_250,DICT_6X6_1000,DICT_7X7_50,DICT_7X7_100,DICT_7X7_250,DICT_7X7_1000,DICT_ARUCO_ORIGINAL,DICT_APRILTAG_16h5,     ///< 4x4 bits, minimum hamming distance between any two codes = 5, 30 codesDICT_APRILTAG_25h9,     ///< 5x5 bits, minimum hamming distance between any two codes = 9, 35 codesDICT_APRILTAG_36h10,    ///< 6x6 bits, minimum hamming distance between any two codes = 10, 2320 codesDICT_APRILTAG_36h11     ///< 6x6 bits, minimum hamming distance between any two codes = 11, 587 codes
};

举例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3 大小Aruco二维码叠加

应用场景:如无人机降落时可以使用大小Aruco码叠加实现精准降落。在距离地面较远时,通过大的Aruco码进行定位,在距离较近时,由于大的Aruco已经识别不全了,需要小的Aruco码进行定位。

  白色方格内黑色占比小于二分之一,则还是当做白色方格,所以可以叠加小二维码,而不影响大二维码检测。
  如下图所示的大小重叠二维码,小二维码的存在也是不影响大二维码识别的,因为中间方格内的小二维码,黑色占比大于二分之一,所以检测大二维码时,小二维码依旧被当作黑色方格。
在这里插入图片描述

3.函数说明

3.1 cv::aruco::detectMarkers

cv::aruco::detectMarkers(image_, dictionary_, corners, ids, detectorParams_, rejected);
// 参数:
// (1)image :输入的需要检测标记的图像。 
// (2)dictionary :进行检测的字典对象指针,这里的字典就是我们创建aruco 标记时所使用的字典,检测什么类型的aruco 标记就使用什么类型的字典。 
// (3)corners :输出参数,检测到的aruco 标记的角点列表,是一个向量数组,每个元素对应一个检测到的标记,每个标记有四个角点,其四个角点均按其原始顺序返回 (从左上角开始顺时针旋转)。 
// (4)ids:输出参数,检测到的每个标记的id,需要注意的是第三个参数和第四个参数具有相同的大小。 
// (5)parameters:ArUco 检测器的参数。是一个 cv::aruco::DetectorParameters 类型的对象,用于设置检测器的各种参数,例如边缘阈值、最小标记区域等。
// (6)rejectedImgPoints:输出参数,被拒绝的标记角点。这些角点未能形成有效的标记。  

3.2 cv::solvePnP

  cv::solvePnP 是 OpenCV 库中用于解决 PnP (Perspective-n-Point) 问题的函数。PnP 问题的目标是从一组已知的三维空间点和它们在二维图像平面上的投影,估计出相机的外参,即相机的位置和朝向。cv::solvePnP 函数的目标是求解相机的 旋转矩阵(R)和 平移向量(T),从而描述从世界坐标系到相机坐标系的变换。

  cv::solvePnP 计算的结果是世界坐标系在相机坐标系中的位姿,即 旋转向量(rvec)和平移向量(tvec)。
CV_EXPORTS_W bool solvePnP( InputArray objectPoints, InputArray imagePoints,InputArray cameraMatrix, InputArray distCoeffs,OutputArray rvec, OutputArray tvec,bool useExtrinsicGuess = false, int flags = SOLVEPNP_ITERATIVE );// objectPoints    				    // 3D 世界坐标系中的点
// imagePoints     				    // 对应的 2D 图像坐标
// cameraMatrix                     // 相机内参矩阵
// distCoeffs                       // 畸变系数(可选,默认为 0)
// rvec                             // 输出的旋转向量
// tvec                             // 输出的平移向量
// bool useExtrinsicGuess = false   // 是否使用外部猜测值
// int flags = 0                    // 计算方法的标志位,指定不同的求解方法

参数说明:

  • objectPoints:一个包含了 N 个三维点的向量,每个点的类型是 cv::Point3f,即 (x, y, z) 坐标。该点是世界坐标系下的坐标。
  • imagePoints:一个包含了 N 个二维点的向量,每个点的类型是 cv::Point2f,即 (x, y) 坐标。这些是已知的三维点投影到相机图像平面上的二维坐标。
  • cameraMatrix:相机的内参矩阵,通常是一个 3x3 的矩阵,描述相机的焦距和主点(通常是图像中心),其形式如下:
cameraMatrix = [ fx  0   cx ][  0   fy  cy ][  0    0   1 ]

fx、fy:焦距,单位为像素,通常等于图像的焦距与像素尺寸的比值。
cx、cy:主点坐标,通常是图像中心。

  • distCoeffs:相机的畸变系数。这个参数是一个 1x5 或 1x8 的矩阵,表示相机的径向畸变和切向畸变的系数。一般情况下,畸变系数会是:
    k1, k2, k3:径向畸变系数
    p1, p2:切向畸变系数
    如果没有畸变或畸变系数未知,可以传入零矩阵(即 cv::Mat::zeros(1, 5, CV_64F))。
  • rvec:输出的旋转向量,表示从世界坐标系到相机坐标系的旋转变换。旋转向量是一个 3x1 的矩阵,它是 Rodrigues 旋转公式的参数。可以使用 cv::Rodrigues 将旋转向量转换为旋转矩阵。
  • tvec:输出的平移向量,表示从世界坐标系到相机坐标系的平移。它是一个 3x1 的矩阵,单位通常是米或者毫米,表示相机位置相对于世界坐标系的平移量。
  • useExtrinsicGuess(可选):一个布尔值,指示是否使用外部猜测的旋转和平移向量进行初始化。默认值是 false,如果设置为 true,可以加速求解。
  • flags(可选):计算方法的标志位。可以选择不同的 PnP 求解方法,例如:
    cv::SOLVEPNP_ITERATIVE:标准的迭代求解方法(默认)
    cv::SOLVEPNP_EPNP:基于 EPnP (Efficient PnP) 的求解方法,适用于更少的点
    cv::SOLVEPNP_DLS:基于 DLS (Direct Linear Solver) 的求解方法,适用于多点情况
    cv::SOLVEPNP_P3P:专门用于 4 个点的求解方法,适用于精度要求较高的应用。

返回值:
cv::solvePnP 返回一个布尔值,表示是否成功求解。

4.代码注解

4.1 Landmark图说明

在这里插入图片描述
  上图是Landmark图,其中包含了四个Aruco码,id分别是21,23,25,27(从左上角开始,顺时针旋转),每个Aruco码的边长是40mm,每个Aruco码相对于Landmark图的中心偏移是5mm。

4.2 算法源码注解

  • 结构体声明
/*** @brief    姿态的四元数*/
struct OrientQuaternion
{double w;double x;double y;double z;
};/*** @brief    位置的xyz方向偏移*/
struct Location
{double x;double y;double z;
};
  • getObjectPoints
    获取每张Landmark图上所有Aruco码的角点坐标(4x4)指实际的物理坐标,需要测量Landmark图实际的尺寸,这里以Landmark图的中心点为原点,每个Aruco码有四个角点。
/*** @brief        获取每张Landmark图上所有Aruco码的角点坐标* @note* @param[in]    idx          根据不同的标记类型,指定生成哪种类型的3D点坐标。idx == 1:    对应特定范围的Aruco ID(21到27)idx == 2:    对应特定范围的Aruco ID(31到37)idx == 0:    对应特定范围的Aruco ID(1到7)* @param[in]    ids          Aruco标记的ID列表,每个ID对应一个检测到的Aruco标记* @param[out]   obj_points   Aruco标记的四个角点的3D点坐标(Z方向默认给0)* @return*/
int getObjectPoints(int idx, const std::vector<int> &ids, std::vector<cv::Point3f> &obj_points)
{obj_points.clear();float code_size, offset_size;int code_pos = 0;if (idx == 1) {code_size   = 0.04 / 2; // 每个Aruco码的边长 40mmoffset_size = code_size + 0.005; // 以landmark图中心点为基准,Aruco码的偏移为5mmcode_pos    = 21;} else if (idx == 2) {code_size   = 0.02 / 2;offset_size = code_size + 0.0025;code_pos    = 31;} else {code_size   = 0.03;offset_size = 0.035;code_pos    = 1;}// 确保传入的 ids 数组中的编号必须是以 code_pos为基础的偶数编号//(例如,code_pos=21,则有效编号是 27, 25, 23, 21 等,确保 landmark中的id号是按照规则的)int num, temp;num = ids.size();int i;for (i = 0; i < num; i++) {temp = (ids[i] - code_pos) / 2;temp *= 2;temp += code_pos;if (temp != ids[i])return -1;}cv::Point3f c4[4], c_offset[4];c4[0]       = cv::Point3f(-code_size, code_size, 0);c4[1]       = cv::Point3f(code_size, code_size, 0);c4[2]       = cv::Point3f(code_size, -code_size, 0);c4[3]       = cv::Point3f(-code_size, -code_size, 0);c_offset[0] = cv::Point3f(-offset_size, offset_size, 0);  // 1c_offset[1] = cv::Point3f(offset_size, offset_size, 0);   // 3c_offset[2] = cv::Point3f(-offset_size, -offset_size, 0); // 5c_offset[3] = cv::Point3f(offset_size, -offset_size, 0);  // 7for (i = 0; i < num; i++) {obj_points.push_back(c4[0] + c_offset[(ids[i] - code_pos) / 2]);obj_points.push_back(c4[1] + c_offset[(ids[i] - code_pos) / 2]);obj_points.push_back(c4[2] + c_offset[(ids[i] - code_pos) / 2]);obj_points.push_back(c4[3] + c_offset[(ids[i] - code_pos) / 2]);}return 0;
}
  • rotVecToQuaternion
/*** @brief   旋转向量转四元数* @note* @param	rvec[in]  旋转向量* @param	ori[out]  四元数* @return  0 代表转换成功*/
inline int rotVecToQuaternion(float *rvec, OrientQuaternion &ori)
{float r, x, y, z;x = rvec[0];y = rvec[1];z = rvec[2];r = sqrt(x * x + y * y + z * z);x /= r;y /= r;z /= r;r /= 2.0;ori.w = cos(r);ori.x = x * sin(r);ori.y = y * sin(r);ori.z = z * sin(r);return 0;
}
  • quaternionToEuler
/*** @brief    四元数转换为欧拉角* @note* @param    ori[int]       四元数* @param    rx,ry,rz[out]      欧拉角(弧度)* @return*/
inline int QuaternionToEuler(OrientQuaternion &ori, double &rx, double &ry, double &rz)
{float rpyInfo[3] = { 0, 0, 0 };memset(rpyInfo, 0, sizeof(rpyInfo));// 算法提供的四元数转欧拉角,得到的欧拉角是角度且顺序是z,y,xfloat RotN[3][3];RotN[0][0] = 2 * (ori.w * ori.w + ori.x * ori.x) - 1;RotN[0][1] = 2 * (ori.x * ori.y - ori.w * ori.z);RotN[0][2] = 2 * (ori.x * ori.z + ori.w * ori.y);RotN[1][0] = 2 * (ori.x * ori.y + ori.w * ori.z);RotN[1][1] = 2 * (ori.w * ori.w + ori.y * ori.y) - 1;RotN[1][2] = 2 * (ori.y * ori.z - ori.w * ori.x);RotN[2][0] = 2 * (ori.x * ori.z - ori.w * ori.y);RotN[2][1] = 2 * (ori.y * ori.z + ori.w * ori.x);RotN[2][2] = 2 * (ori.w * ori.w + ori.z * ori.z) - 1;double eps = 1e-16;if (fabs(RotN[0][0]) < eps && fabs(RotN[1][0]) < eps) {rpyInfo[0] = 0.0;rpyInfo[1] = atan2(-RotN[2][0], RotN[0][0]) * 180 / M_PI;rpyInfo[2] = atan2(-RotN[1][2], RotN[1][1]) * 180 / M_PI;} else {rpyInfo[0] = atan2(RotN[1][0], RotN[0][0]) * 180 / M_PI;rpyInfo[1] = atan2(-RotN[2][0], sqrt(RotN[0][0] * RotN[0][0] + RotN[1][0] * RotN[1][0])) * 180 / M_PI;rpyInfo[2] = atan2(RotN[2][1], RotN[2][2]) * 180 / M_PI;}// 算法返回的顺序是z,y,x,需要反转打印rx = rpyInfo[2] / 180.0 * M_PI;ry = rpyInfo[1] / 180.0 * M_PI;rz = rpyInfo[0] / 180.0 * M_PI;return 0;
}
  • calCameraInLandmarkPose
      算法思想:首先通过OpenCV自带的detectMarkers函数,检测出所有的Aruco码的四个角点的像素坐标,然后根据事先测量好的Landmark图实际尺寸,以中心点为原点,计算出实际的所有的Aruco码的四个角点的3D坐标(这里Z方向设置0),通过OpenCV自带的solvePnP函数,计算得到相机相对于世界坐标系的外参(这里是以Landmark图中心点为世界坐标系),即 旋转向量(rvec)和平移向量(tvec),世界坐标系在相机坐标系中的位姿。
      所以最终得到的是T_target2camera
/*** @brief        计算landmark图在相机下的位姿信息* @note* @param[in]    image                图像信息* @param[in]    cam_intrinsics       相机的内参矩阵* @param[in]    cam_distortion       相机的畸变系数* @param[out]   landmark_to_cam_pose landmark图相对于相机的位姿* @return       landmark图计算结果*           --0 计算成功*               失败返回错误码*/
int calLandmarkInCameraPose(cv::Mat &image,const std::vector<double> &cam_intrinsics,const std::vector<double> &cam_distortion,std::vector<double> &landmark_to_cam_pose)
{if (image.cols() == 0 || image.rows() == 0) {return -1;}OrientQuaternion landmark_ori;Location landmark_loc;// 加载用于生成标记的字典cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_50);// 存储检测到的标记的 IDstd::vector<int> ids;// 声明包含检测到的标记角和被拒绝的候选标记的角点// 在检测过程中,可能会有一些候选标记没有通过验证(例如它们可能是噪声或误识别的对象),这些被拒绝的候选会被存储在rejectCandidates中std::vector<std::vector<cv::Point2f>> corners, reject_candidates;// 使用默认值初始化检测器参数cv::Ptr<cv::aruco::DetectorParameters> parameters;parameters = cv::aruco::DetectorParameters::create();// 使用 ArUco 方法检测角点后,通过轮廓点线拟合的方法来细化角点位置parameters->cornerRefinementMethod = cv::aruco::CORNER_REFINE_CONTOUR;// 检测图像中的标记,靶标cv::aruco::detectMarkers(preview_image, dictionary, corners, ids, parameters, reject_candidates);int j;// 3D 世界坐标系中的点std::vector<cv::Point3f> obj_pts;int obj_idx;obj_pts.clear();// ids.size()表示一张landmark图中有多少张Aruco标记图// Aruco码中的ID需要去查字典if (ids.size() > 0 && ids.size() <= 4) {if (ids[0] > 20 && ids[0] <= 27)obj_idx = 1;else if (ids[0] > 30 && ids[0] <= 37)obj_idx = 2;else if (ids[0] > 0 && ids[0] <= 7)obj_idx = 0;else {obj_idx = -1;return arva::ErrorREC::E_REC_LANDMARK_WRONG;}j = getObjectPoints(obj_idx, ids, obj_pts);// std::cout << "Landmark id is " << obj_idx << std::endl;} else {// 未检测到Landmarkstd::cout << "There is no target in the image!" << std::endl;return -1;}// 角点对应的 2D 图像像素坐标std::vector<cv::Point2f> image_pts;unsigned int k;// if(ids.size() == 4)if (ids.size() > 0 && ids.size() <= 4) {float dx, dy, dis;dx  = corners[0][0].x - corners[0][1].x;dy  = corners[0][0].y - corners[0][1].y;dis = sqrt(dx * dx + dy * dy);for (k = 0; k < ids.size(); k++) {// 绘制landmark上面的角点cv::circle(preview_image, corners[k][0], dis / 15, cv::Scalar(255, 0, 0), dis / 30, 8);cv::circle(preview_image, corners[k][1], dis / 15, cv::Scalar(0, 0, 255), dis / 30, 8);cv::circle(preview_image, corners[k][2], dis / 15, cv::Scalar(0, 255, 0), dis / 30, 8);for (j = 0; j < 4; j++) {image_pts.push_back(corners[k][j]);}}}// 打印 objPts 中的所有点std::cout << "objPts" << std::endl;for (size_t i = 0; i < objPts.size(); i++) {std::cout << "Point " << i << ": (" << objPts[i].x << ", " << objPts[i].y << ", " << objPts[i].z << ")"<< std::endl;}// 打印 imgPts 中的所有点std::cout << "imgPts" << std::endl;for (size_t i = 0; i < imgPts.size(); i++) {std::cout << "Point " << i << ": (" << imgPts[i].x << ", " << imgPts[i].y << ")" << std::endl;}float img_intrinsics[9];for (int n = 0; n < cam_intrinsics.size(); n++) {img_intrinsics[n] = cam_intrinsics[n];}cv::Mat camera_matrix = cv::Mat(3, 3, CV_32FC1, img_intrinsics);float img_distortion[5];for (int m = 0; m < cam_distortion.size(); m++) {img_distortion[m] = cam_distortion[m];}cv::Mat distortion_coefficients = cv::Mat(5, 1, CV_32FC1, img_distortion);float tv[3], rv[3];cv::Mat tvec = cv::Mat(3, 1, CV_32FC1, tv);cv::Mat rvec = cv::Mat(3, 1, CV_32FC1, rv);if (ids.size() > 0 && ids.size() <= 4) {bool state;// 计算出相机相对于Landmark图中心点的旋转和位移向量state = cv::solvePnP(obj_pts, image_pts, camera_matrix, distortion_coefficients, rvec, tvec);// Rodrigues(rvec,r_m);if (state) {// 将solvePnP输出的旋转向量转换为四元数rotVecToQuaternion(rv, landmark_ori);landmark_loc.x = tv[0];landmark_loc.y = tv[1];landmark_loc.z = tv[2];// 输出Posture结构体的位姿信息,需要将四元数转为欧拉角进行赋值landmark_to_cam_pose.push_back(landmark_loc.x);landmark_to_cam_pose.push_back(landmark_loc.y);landmark_to_cam_pose.push_back(landmark_loc.z);double rx, ry, rz;double rx, ry, rz;quaternionToEuler(landmark_ori, rx, ry, rz);landmark_to_cam_pose.push_back(rx);landmark_to_cam_pose.push_back(ry);landmark_to_cam_pose.push_back(rz);return -1;} else {std::cout << "solvePnP failed" << std::endl;}}return -1;
}

在这里插入图片描述

相关文章:

2.5D视觉——Aruco码定位检测

目录 1.什么是Aruco标记2.Aruco码解码说明2.1 Original ArUco2.2 预设的二维码字典2.3 大小Aruco二维码叠加 3.函数说明3.1 cv::aruco::detectMarkers3.2 cv::solvePnP 4.代码注解4.1 Landmark图说明4.2 算法源码注解 1.什么是Aruco标记 ArUco标记最初由S.Garrido-Jurado等人在…...

【PSQLException: An I/O error occurred while sending to the backend.】

PSQLException: An I/O error occurred while sending to the backend. java项目定时任务执行耗时很长的sql语句(很多条sql,从很多表中,很多数据中查询,处理)总之,耗时很长(PG数据库)。报错I/O error,Caused by : java.net.SocketTimeoutException: Read time out场景…...

图像基础算法学习笔记

目录 概要 一、图像采集 二、图像标注 四、图像几何变换 五、图像边缘检测 Sobel算子 Scharrt算子 Laplacian算子 Canny边缘检测 六、形态学转换 概要 参考书籍&#xff1a;《机器视觉与人工智能应用开发技术》 廖建尚&#xff0c;钟君柳 出版时间&#xff1a;2024-…...

【Elasticsearch】01-ES安装

1. 安装 安装elasticsearch。 docker run -d \--name es \-e "ES_JAVA_OPTS-Xms512m -Xmx512m" \-e "discovery.typesingle-node" \-v es-data:/usr/share/elasticsearch/data \-v es-plugins:/usr/share/elasticsearch/plugins \--privileged \--networ…...

网络性能测试

一、iperf网络性能测试工具 测试udp丢包率 在服务器启动 iperf 服务端 iperf -p 9000 -s -u -i 1参数说明&#xff1a; -p : 端口号 -s : 表示服务端 -u : 表示 udp 协议 -i : 检测的时间间隔(单位&#xff0c;秒) 在客户端&#xff0c;启动 iperf 客户端 iperf -c xxx.xxx.14…...

docker:docker: Get https://registry-1.docker.io/v2/: net/http: request canceled

无数次的拉镜像让人崩溃&#xff1a; rootnode11:~/ragflow/docker# more rag.sh #export HTTP_PROXYhttp://192.168.207.127:7890 #export HTTPS_PROXYhttp://192.168.207.127:7890 #export NO_PROXYlocalhost,127.0.0.1,.aliyun.com docker compose -f docker-compose-gpu-C…...

esp32c3开发板通过micropython的mqtt库连MQTT物联网消息服务器

MQTT介绍 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的消息协议&#xff0c;旨在设备之间进行通信&#xff0c;尤其是在网络条件较差的情况下。MQTT v3.1.1 和 MQTT v5 是该协议的两个主要版本。 MQTT v3.1.1&#xff1a; 优点&#xff…...

OceanBase 升级过程研究(4.2.1.6-4.2.1.8)

模拟业务 使用benchmark加载10仓数据模拟业务场景 升级方法 使用滚动升级方式来进行OB升级。该方法前提是OB集群必须满足官方规定的高可用架构(如果 Zone 个数小于 3&#xff0c;滚动升级时则无法构成多数派), 滚动升级的原理就是轮流完成每个ZONE的升级工作&#xff0c;由于…...

ubuntu下怎么设置机器程序开机自启?

在 Ubuntu 中&#xff0c;可以通过多种方法设置程序或脚本在系统启动时自动运行。以下是几种常见方法&#xff1a; 方法 1&#xff1a;使用 crontab crontab 是一个定时任务管理工具&#xff0c;可以用来设置程序在开机时自动运行。 1. 打开终端&#xff0c;编辑当前用户的 …...

Cesium 相机系统

Cesium 的相机系统是其 3D 地球渲染引擎的重要组成部分&#xff0c;它控制用户在虚拟地球上的视图和交互体验。Cesium 的相机系统具备灵活性和强大的功能&#xff0c;允许开发者自定义视图、导航和交互方式。以下是 Cesium 相机系统的主要特点和功能&#xff1a; 1. 相机的基本…...

数据结构(基本概念及顺序表——c语言实现)

基本概念&#xff1a; 1、引入 程序数据结构算法 数据&#xff1a; 数值数据&#xff1a;能够直接参加运算的数据&#xff08;数值&#xff0c;字符&#xff09; 非数值数据&#xff1a;不能够直接参加运算的数据&#xff08;字符串、图片等&#xff09; 数据即是信息的载…...

ZYNQ程序固化——ZYNQ学习笔记7

一、ZYNQ启动过程 二、 SD卡启动实操 1、对ZYNQ进行配置添加Flash 2、添加SD卡 3、重新生成硬件信息 4、创建vitis工程文件 5、勾选板级支持包 6、对系统工程进行整体编译&#xff0c;生成两个Debug文件&#xff0c;如图所示。 7、插入SD卡&#xff0c;格式化为 8、考入BOOT.…...

labview使用报表工具从数据库导出数据

之前写了一篇labview从数据库导出数据到excel电子表格&#xff0c;但是是基于调用excel的activeX控件&#xff0c;有时候会有一些bug&#xff0c;就比如我工作机就无法显示方法&#xff0c;后面大哥指点才知道没有的原因是excel安装不完整。像我的工作机就没有这个选项。就需要…...

#define定义宏(2)

大家好&#xff0c;今天给大家分享两个技巧。 首先我们应该先了解一下c语言中字符串具有自动连接的特点。注意只有将字符串作为宏参数的时候才可以把字符串放在字符串中。 下面我们来讲讲这两个技巧 1.使用#&#xff0c;把一个宏参数变成对应的字符串。 2.##的作用 可以把位…...

CentOS网络配置

上一篇文章&#xff1a;VMware Workstation安装Centos系统 在CentOS系统中进行网络配置是确保系统能够顺畅接入网络的重要步骤。本文将详细介绍如何配置静态IP地址、网关、DNS等关键网络参数&#xff0c;以帮助需要的人快速掌握CentOS网络配置的基本方法和技巧。通过遵循本文的…...

基于vue框架的的网上宠物交易管理系统46sn1(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,宠物分类,宠物信息 开题报告内容 基于Vue框架的网上宠物交易管理系统开题报告 一、研究背景 随着互联网技术的飞速发展和人们生活水平的提高&#xff0c;宠物已成为许多家庭的重要成员。宠物市场的繁荣不仅体现在实体店的遍地开…...

MySQL数据库:SQL语言入门 【2】(学习笔记)

目录 2&#xff0c;DML —— 数据操作语言&#xff08;Data Manipulation Language&#xff09; &#xff08;1&#xff09;insert 增加 数据 &#xff08;2&#xff09;delete 删除 数据 truncate 删除表和数据&#xff0c;再创建一个新表 &#xff08;3&#xf…...

MySQL深度剖析-索引原理由浅入深

什么是索引&#xff1f; 官方上面说索引是帮助MySQL高效获取数据的数据结构&#xff0c;通俗点的说&#xff0c;数据库索引好比是一本书的目录&#xff0c;可以直接根据页码找到对应的内容&#xff0c;目的就是为了加快数据库的查询速度。 索引是对数据库表中一列或多列的值进…...

路径规划——RRT-Connect算法

路径规划——RRT-Connect算法 算法原理 RRT-Connect算法是在RRT算法的基础上进行的扩展&#xff0c;引入了双树生长&#xff0c;分别以起点和目标点为树的根节点同时扩展随机树从而实现对状态空间的快速搜索。在此算法中以两棵随机树建立连接为路径规划成功的条件。并且&…...

数据科学与SQL:如何计算排列熵?| 基于SQL实现

目录 0 引言 1 排列熵的计算原理 2 数据准备 3 问题分析 4 小结 0 引言 把“熵”应用在系统论中的信息管理方法称为熵方法。熵越大&#xff0c;说明系统越混乱&#xff0c;携带的信息越少&#xff1b;熵越小&#xff0c;说明系统越有序&#xff0c;携带的信息越多。在传感…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

智能职业发展系统:AI驱动的职业规划平台技术解析

智能职业发展系统&#xff1a;AI驱动的职业规划平台技术解析 引言&#xff1a;数字时代的职业革命 在当今瞬息万变的就业市场中&#xff0c;传统的职业规划方法已无法满足个人和企业的需求。据统计&#xff0c;全球每年有超过2亿人面临职业转型困境&#xff0c;而企业也因此遭…...

数据挖掘是什么?数据挖掘技术有哪些?

目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...

Axure Rp 11 安装、汉化、授权

Axure Rp 11 安装、汉化、授权 1、前言2、汉化2.1、汉化文件下载2.2、windows汉化流程2.3、 macOs汉化流程 3、授权 1、前言 Axure Rp 11官方下载链接&#xff1a;https://www.axure.com/downloadthanks 2、汉化 2.1、汉化文件下载 链接: https://pan.baidu.com/s/18Clf…...