【opencv】示例-stereo_match.cpp 立体匹配:通过对左右视图图像进行处理来生成视差图和点云数据...

6dab1feafff1872424f8ab336146169c.png

/*
 *  stereo_match.cpp
 *  calibration
 *
 *  创建者 Victor Eruhimov,日期为 2010年1月18日。
 *  版权所有 2010 Argus Corp.
 *
 */


#include "opencv2/calib3d/calib3d.hpp" // 导入OpenCV相机标定和三维重建相关的头文件
#include "opencv2/imgproc.hpp" // 导入OpenCV图像处理相关的头文件
#include "opencv2/imgcodecs.hpp" // 导入OpenCV图像编解码相关的头文件
#include "opencv2/highgui.hpp" // 导入OpenCV高层GUI(图形界面)相关的头文件
#include "opencv2/core/utility.hpp" // 导入OpenCV核心工具(utility)模块的头文件


#include <stdio.h> // 导入C标准输入输出头文件
#include <sstream> // 导入C++字符串流处理头文件


using namespace cv; // 使用OpenCV的命名空间


// 声明了print_help函数,用于显示帮助信息
static void print_help(char** argv)
{
    // 打印使用demo时的帮助信息
    printf("\nDemo stereo matching converting L and R images into disparity and point clouds\n");
    // 打印程序使用方式的说明
    printf("\nUsage: %s <left_image> <right_image> [--algorithm=bm|sgbm|hh|hh4|sgbm3way] [--blocksize=<block_size>]\n"
           "[--max-disparity=<max_disparity>] [--scale=scale_factor>] [-i=<intrinsic_filename>] [-e=<extrinsic_filename>]\n"
           "[--no-display] [--color] [-o=<disparity_image>] [-p=<point_cloud_file>]\n", argv[0]);
}


// 声明了saveXYZ函数,用于将三维点云数据保存到文件
static void saveXYZ(const char* filename, const Mat& mat)
{
    // 设置三维点深度的最大值
    const double max_z = 1.0e4;
    // 以文本写入方式打开文件
    FILE* fp = fopen(filename, "wt");
    // 遍历图像的每个像素点
    for(int y = 0; y < mat.rows; y++)
    {
        for(int x = 0; x < mat.cols; x++)
        {
            // 读取每个像素点的三维坐标
            Vec3f point = mat.at<Vec3f>(y, x);
            // 如果该点的Z坐标无效,则忽略此点
            if(fabs(point[2] - max_z) < FLT_EPSILON || fabs(point[2]) > max_z) continue;
            // 将有效的三维坐标写入到文件中
            fprintf(fp, "%f %f %f\n", point[0], point[1], point[2]);
        }
    }
    // 关闭文件
    fclose(fp);
}


int main(int argc, char** argv)
{
    // 定义了一系列的字符串变量用来存储命令行参数
    std::string img1_filename = "";
    std::string img2_filename = "";
    std::string intrinsic_filename = "";
    std::string extrinsic_filename = "";
    std::string disparity_filename = "";
    std::string point_cloud_filename = "";


    // 定义了枚举类型,列出了所有双目算法
    enum { STEREO_BM=0, STEREO_SGBM=1, STEREO_HH=2, STEREO_VAR=3, STEREO_3WAY=4, STEREO_HH4=5 };
    int alg = STEREO_SGBM; // 默认使用STEREO_SGBM算法
    int SADWindowSize, numberOfDisparities; // 定义了SAD窗口大小和视差的数量
    bool no_display; // 定义了是否显示结果的标志位
    bool color_display; // 定义了是否彩色显示视差图的标志位
    float scale; // 定义了缩放因子


    // 创建两种双目匹配算法实例对象:StereoBM和StereoSGBM
    Ptr<StereoBM> bm = StereoBM::create(16,9);
    Ptr<StereoSGBM> sgbm = StereoSGBM::create(0,16,3);


    // 使用命令行解析器解析参数
    cv::CommandLineParser parser(argc, argv,
        "{@arg1||}{@arg2||}{help h||}{algorithm||}{max-disparity|0|}{blocksize|0|}{no-display||}{color||}{scale|1|}{i||}{e||}{o||}{p||}");
    // 如果用户请求帮助,则调用print_help函数并退出
    if(parser.has("help"))
    {
        print_help(argv);
        return 0;
    }
    // 获取命令行中指定的左右图像文件名
    img1_filename = samples::findFile(parser.get<std::string>(0));
    img2_filename = samples::findFile(parser.get<std::string>(1));


    // 解析算法参数
    if (parser.has("algorithm"))
    {
        std::string _alg = parser.get<std::string>("algorithm");
        alg = _alg == "bm" ? STEREO_BM :
            _alg == "sgbm" ? STEREO_SGBM :
            _alg == "hh" ? STEREO_HH :
            _alg == "var" ? STEREO_VAR :
            _alg == "hh4" ? STEREO_HH4 :
            _alg == "sgbm3way" ? STEREO_3WAY : -1;
    }
    // 解析其他所有需要的命令行参数
    numberOfDisparities = parser.get<int>("max-disparity");
    SADWindowSize = parser.get<int>("blocksize");
    scale = parser.get<float>("scale");
    no_display = parser.has("no-display");
    color_display = parser.has("color");
    if( parser.has("i") )
        intrinsic_filename = parser.get<std::string>("i");
    if( parser.has("e") )
        extrinsic_filename = parser.get<std::string>("e");
    if( parser.has("o") )
        disparity_filename = parser.get<std::string>("o");
    if( parser.has("p") )
        point_cloud_filename = parser.get<std::string>("p");


    // 检查解析后的参数是否正确
    if (!parser.check())
    {
        parser.printErrors();
        return 1;
    }
    // 检查算法参数是否指定正确
    if( alg < 0 )
    {
        printf("Command-line parameter error: Unknown stereo algorithm\n\n");
        print_help(argv);
        return -1;
    }
    // 检查视差数量设置是否正确
    if ( numberOfDisparities < 1 || numberOfDisparities % 16 != 0 )
    {
        printf("Command-line parameter error: The max disparity (--maxdisparity=<...>) must be a positive integer divisible by 16\n");
        print_help(argv);
        return -1;
    }
    // 检查缩放因子是否正确
    if (scale < 0)
    {
        printf("Command-line parameter error: The scale factor (--scale=<...>) must be a positive floating-point number\n");
        return -1;
    }
    // 检查SAD窗口大小设置是否正确
    if (SADWindowSize < 1 || SADWindowSize % 2 != 1)
    {
        printf("Command-line parameter error: The block size (--blocksize=<...>) must be a positive odd number\n");
        return -1;
    }
    // 检查是否指定了左右图像文件
    if( img1_filename.empty() || img2_filename.empty() )
    {
        printf("Command-line parameter error: both left and right images must be specified\n");
        return -1;
    }
    // 检查内参和外参是否同时指定
    if( (!intrinsic_filename.empty()) ^ (!extrinsic_filename.empty()) )
    {
        printf("Command-line parameter error: either both intrinsic and extrinsic parameters must be specified, or none of them (when the stereo pair is already rectified)\n");
        return -1;
    }
    // 检查生成点云时是否指定了内参和外参
    if( extrinsic_filename.empty() && !point_cloud_filename.empty() )
    {
        printf("Command-line parameter error: extrinsic and intrinsic parameters must be specified to compute the point cloud\n");
        return -1;
    }


    // 根据算法的不同,设置图像的加载模式
    int color_mode = alg == STEREO_BM ? 0 : -1;
    // 加载左右视图图像
    Mat img1 = imread(img1_filename, color_mode);
    Mat img2 = imread(img2_filename, color_mode);


    // 如果左视图图像加载失败,打印错误并退出
    if (img1.empty())
    {
        printf("Command-line parameter error: could not load the first input image file\n");
        return -1;
    }
    // 如果右视图图像加载失败,打印错误并退出
    if (img2.empty())
    {
        printf("Command-line parameter error: could not load the second input image file\n");
        return -1;
    }
    // 如果缩放系数不等于1,则对图像进行缩放
    if (scale != 1.f)
    {
        // 定义两个临时矩阵用于存储缩放后的图像
        Mat temp1, temp2;
        // 根据scale的大小选择合适的插值方法
        int method = scale < 1 ? INTER_AREA : INTER_CUBIC;
        // 对左右图像进行缩放
        resize(img1, temp1, Size(), scale, scale, method);
        img1 = temp1;
        resize(img2, temp2, Size(), scale, scale, method);
        img2 = temp2;
    }
    
    // 获取缩放后的图像大小
    Size img_size = img1.size();
    
    // 定义两个ROI区域以及Q矩阵(用于三维重建)
    Rect roi1, roi2;
    Mat Q;
    
    // 如果内参文件名不为空,则读取内(camera)参和外(stereo)参数
    if( !intrinsic_filename.empty() )
    {
        // 读取内参文件
        FileStorage fs(intrinsic_filename, FileStorage::READ);
        if(!fs.isOpened())
        {
            printf("Failed to open file %s\n", intrinsic_filename.c_str());
            return -1;
        }
    
        // 读取内参矩阵和畸变系数
        Mat M1, D1, M2, D2;
        fs["M1"] >> M1;
        fs["D1"] >> D1;
        fs["M2"] >> M2;
        fs["D2"] >> D2;
    
        // 根据缩放因子调整内参矩阵
        M1 *= scale;
        M2 *= scale;
    
        // 读取外参文件
        fs.open(extrinsic_filename, FileStorage::READ);
        if(!fs.isOpened())
        {
            printf("Failed to open file %s\n", extrinsic_filename.c_str());
            return -1;
        }
    
        // 读取旋转矩阵和平移矩阵
        Mat R, T, R1, P1, R2, P2;
        fs["R"] >> R;
        fs["T"] >> T;
    
        // 对立体图像进行校正
        stereoRectify( M1, D1, M2, D2, img_size, R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, -1, img_size, &roi1, &roi2 );
    
        // 初始化校正映射矩阵
        Mat map11, map12, map21, map22;
        initUndistortRectifyMap(M1, D1, R1, P1, img_size, CV_16SC2, map11, map12);
        initUndistortRectifyMap(M2, D2, R2, P2, img_size, CV_16SC2, map21, map22);
    
        // 应用映射矩阵进行畸变校正和立体校正
        Mat img1r, img2r;
        remap(img1, img1r, map11, map12, INTER_LINEAR);
        remap(img2, img2r, map21, map22, INTER_LINEAR);
    
        // 更新校正后的图像
        img1 = img1r;
        img2 = img2r;
    }
    
    // 计算或更新视差的数量
    numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : ((img_size.width/8) + 15) & -16;
    
    // 配置块匹配(Block Matching)算法的参数
    // 设置块匹配算法的区域兴趣(ROI),由roi1和roi2的矩形区域定义。
    bm->setROI1(roi1);
    bm->setROI2(roi2);
    // 设置前置滤波器的上限值用于块匹配算法。
    bm->setPreFilterCap(31);
    // 设置SAD窗口的大小,比较块大小。如果SADWindowSize变量大于0,就使用该变量的值,否则使用默认值9。
    bm->setBlockSize(SADWindowSize > 0 ? SADWindowSize : 9);
    // 设置最小视差,默认为0。
    bm->setMinDisparity(0);
    // 设置视差的数量,这里使用numberOfDisparities变量的值。
    bm->setNumDisparities(numberOfDisparities);
    // 设置纹理阈值,用于过滤掉纹理不够的区域。
    bm->setTextureThreshold(10);
    // 设置唯一性比例,用于判断最佳视差的唯一性。
    bm->setUniquenessRatio(15);
    // 设置视差连通区域变化的窗口大小,这里为100。
    bm->setSpeckleWindowSize(100);
    // 设置视差连通区域的最大视差变化范围,这里为32。
    bm->setSpeckleRange(32);
    // 设置左右视差图的最大差异,超过这个差异的视差值会被剔除。
    bm->setDisp12MaxDiff(1);
   
    
    // 配置半全局块匹配(Semi-Global Block Matching)算法的参数
    // 为半全局块匹配算法设置前置滤波器的上限值。
    sgbm->setPreFilterCap(63);
    // 计算SGBM算法的SAD窗口大小,如果SADWindowSize变量大于0,使用该变量的值,否则使用默认值3。
    int sgbmWinSize = SADWindowSize > 0 ? SADWindowSize : 3;
    // 设置SGBM算法的块大小。
    sgbm->setBlockSize(sgbmWinSize);
    
    // 根据输入图像的通道数计算常数值。
    int cn = img1.channels();
    
    // 设置SGBM算法的P1和P2参数,这些参数控制视差变化的平滑程度。
    sgbm->setP1(8*cn*sgbmWinSize*sgbmWinSize);
    sgbm->setP2(32*cn*sgbmWinSize*sgbmWinSize);
    // 设置最小视差,默认为0。
    sgbm->setMinDisparity(0);
    // 设置视差数量,这里使用numberOfDisparities变量的值。
    sgbm->setNumDisparities(numberOfDisparities);
    // 设置唯一性比例,用于判断最佳视差的唯一性。
    sgbm->setUniquenessRatio(10);
    // 设置视差连通区域变化的窗口大小,这里为100。
    sgbm->setSpeckleWindowSize(100);
    // 设置视差连通区域的最大视差变化范围,这里为32。
    sgbm->setSpeckleRange(32);
    // 设置左右视差图的最大差异,超过这个差异的视差值会被剔除。
    sgbm->setDisp12MaxDiff(1);
    // 根据选择的算法设置SGBM模式。
    if(alg==STEREO_HH)
        sgbm->setMode(StereoSGBM::MODE_HH);
    else if(alg==STEREO_SGBM)
        sgbm->setMode(StereoSGBM::MODE_SGBM);
    else if(alg==STEREO_HH4)
        sgbm->setMode(StereoSGBM::MODE_HH4);
    else if(alg==STEREO_3WAY)
        sgbm->setMode(StereoSGBM::MODE_SGBM_3WAY);
    
    Mat disp, disp8; // 定义存储视差图和转换后的8位视差图的矩阵。
    
    // 获取当前的时间刻度,用于计算视差计算的耗时。
    int64 t = getTickCount();
    float disparity_multiplier = 1.0f; // 定义视差倍数的默认值。
    
    // 根据选定的算法执行视差计算,并根据返回的数据类型设置合适的倍数。
    if( alg == STEREO_BM )
    {
        bm->compute(img1, img2, disp); // 使用BM算法计算视差。
        if (disp.type() == CV_16S)
            disparity_multiplier = 16.0f; // 如果视差图是16位有符号整型,则将倍数设为16。
    }
    else if( alg == STEREO_SGBM || alg == STEREO_HH || alg == STEREO_HH4 || alg == STEREO_3WAY )
    {
        sgbm->compute(img1, img2, disp); // 使用SGBM算法族计算视差。
        if (disp.type() == CV_16S)
            disparity_multiplier = 16.0f; // 如果视差图是16位有符号整型,则将倍数设为16。
    }
    t = getTickCount() - t; // 计算视差计算耗时。
    printf("Time elapsed: %fms\n", t*1000/getTickFrequency()); // 打印耗时信息。
    
    // 将计算出的视差图转换为8位图像以供显示或存储。
    if( alg != STEREO_VAR )
        disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));
    else
        disp.convertTo(disp8, CV_8U);
    
    Mat disp8_3c; // 定义用于显示彩色视差图的矩阵。
    // 如果选项设置为显示彩色图,则对8位图像应用色彩映射。
    if (color_display)
        cv::applyColorMap(disp8, disp8_3c, COLORMAP_TURBO);
    
    // 如果指定了视差图文件名,则将视差图存储到文件中。
    if(!disparity_filename.empty())
        imwrite(disparity_filename, color_display ? disp8_3c : disp8);
    
    // 如果指定了点云文件名,则保存点云数据到文件中。
    if(!point_cloud_filename.empty())
    {
        printf("storing the point cloud..."); // 打印存储点云数据的信息。
        fflush(stdout);
        Mat xyz; // 定义用于存储3D坐标的矩阵。
        Mat floatDisp; // 定义用于存储转换后的视差图的矩阵。
        // 将视差图转换为浮点型,并应用视差倍数。
        disp.convertTo(floatDisp, CV_32F, 1.0f / disparity_multiplier);
        // 使用Q矩阵将视差图重投影到3D坐标。
        reprojectImageTo3D(floatDisp, xyz, Q, true);
        // 使用saveXYZ函数将3D坐标保存到指定的点云文件中。
        saveXYZ(point_cloud_filename.c_str(), xyz);
        printf("\n"); // 用于换行。
    }
    
    // 如果未设置不显示结果,则创建显示左、右图像和视差图的窗口。
    if( !no_display )
    {
        std::ostringstream oss; // 使用字符串流构建显示的标题。
        oss << "disparity  " << (alg==STEREO_BM ? "bm" :
                                 alg==STEREO_SGBM ? "sgbm" :
                                 alg==STEREO_HH ? "hh" :
                                 alg==STEREO_VAR ? "var" :
                                 alg==STEREO_HH4 ? "hh4" :
                                 alg==STEREO_3WAY ? "sgbm3way" : "");
        oss << "  blocksize:" << (alg==STEREO_BM ? SADWindowSize : sgbmWinSize);
        oss << "  max-disparity:" << numberOfDisparities;
        std::string disp_name = oss.str(); // 从流中获取构建好的标题字符串。
    
        // 创建并显示图像窗口。
        namedWindow("left", cv::WINDOW_NORMAL);
        imshow("left", img1);
        namedWindow("right", cv::WINDOW_NORMAL);
        imshow("right", img2);
        namedWindow(disp_name, cv::WINDOW_AUTOSIZE);
        imshow(disp_name, color_display ? disp8_3c : disp8);
    
        printf("press ESC key or CTRL+C to close..."); // 提示用户如何关闭窗口。
        fflush(stdout);
        printf("\n"); // 用于换行。
        while(1) // 循环等待用户按键操作。
        {
            if(waitKey() == 27) // 如果用户按下ESC键,则退出循环。
                break;
        }
    }
    
    return 0; // 正常结束程序。
}
enum { STEREO_BM=0, STEREO_SGBM=1, STEREO_HH=2, STEREO_VAR=3, STEREO_3WAY=4, STEREO_HH4=5 };

eee9983d057c4435d686bdd70a1ed1a0.png

什么是视差图

047eaa55d1d5a937e9f132be4e8b94b2.png

在计算视差图时,遮挡或缺乏纹理的区域会有什么表现?

80a6ba14b4ec5b53a1a8544950ab7e0c.png

SGBM算法是如何处理遮挡和纹理缺失问题的?

dfda5f1553c44ce2ba3e5b2579ce68a8.png

stereoRectify( M1, D1, M2, D2, img_size, R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, -1, img_size, &roi1, &roi2 );

ad562c68f29003be64cc0a514ba3d61a.png

这个函数的主要目的是通过计算两个矫正映射,让来自两个摄像头的图像在水平方向上对准,简化立体匹配的复杂性,提高计算效率和质量。正确定位了坐标对齐后,图像中对应的点就可以直接在同一行上进行匹配,使得视差计算更加准确和便捷。

reprojectImageTo3D(floatDisp, xyz, Q, true);

4ea77b4642d82c12b3a8a8e8a681ec64.png

909e0a4a1f6e42d87acfbc5ae52636ca.png

这个函数中的投影变换矩阵Q是如何计算得到的?

d2f0f6c5139b1cc22e7d7909a667fc72.png

The End

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

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

相关文章

stm32移植嵌入式数据库FlashDB

本次实验的程序链接stm32f103FlashDB嵌入式数据库程序资源-CSDN文库 一、介绍 FlashDB 是一款超轻量级的嵌入式数据库&#xff0c;专注于提供嵌入式产品的数据存储方案。与传统的基于文件系统的数据库不同&#xff0c;FlashDB 结合了 Flash 的特性&#xff0c;具有较强的性能…

【GD32】INA226电压电流功率检测模块

2.46 INA226电压电流功率检测模块 2.46.1 模块来源​ 采购链接&#xff1a;​ INA226电压电流功率检测模块 资料下载&#xff1a;&#xff08;基于该模块的资料&#xff0c;百度云链接等&#xff09;​ 链接&#xff1a;http://pan.baidu.com/s/1c0DbuXa 密码&#xff1a;3p2…

开源版中文和越南语贷款源码贷款平台下载 小额贷款系统 贷款源码运营版

后台 代理 前端均为vue源码&#xff0c;前端有中文和越南语 前端ui黄色大气&#xff0c;逻辑操作简单&#xff0c;注册可对接国际短信&#xff0c;可不对接 用户注册进去填写资料&#xff0c;后台审批&#xff0c;审批状态可自定义修改文字显示 源码免费下载地址抄笔记 (chaob…

Abstract Factory抽象工厂模式详解

模式定义 提供一个创建一系列相关或互相依赖对象的接口&#xff0c;而无需指定它们具体的类。 代码示例 public class AbstractFactoryTest {public static void main(String[] args) {IDatabaseUtils iDatabaseUtils new OracleDataBaseUtils();IConnection connection …

架构师系列-搜索引擎ElasticSearch(六)- 映射

映射配置 在创建索引时&#xff0c;可以预先定义字段的类型&#xff08;映射类型&#xff09;及相关属性。 数据库建表的时候&#xff0c;我们DDL依据一般都会指定每个字段的存储类型&#xff0c;例如&#xff1a;varchar、int、datetime等&#xff0c;目的很明确&#xff0c;就…

oarcle 19c ADG补丁升级(19.3-19.22)

一、备库操作 1.关闭备库数据库实例 sqlplus / as sysdba startup shutdown immediate # 查看oracle进程 ps -ef | grep sqlplus 2.关闭监听 lsnrctl start lsnrctl stop lsnrctl status 3.升级Opatch # 备份当前Opatch目录 su - oracle cd $ORACLE_HOME mv OPatch OPat…

康耐视visionpro-CogFindLineTool操作工具详细说明

◆CogFindeLineTool功能说明: 检测图像的直线边缘,实现边缘的定位、测量。 ◆CogFindeLineTool操作说明: ①.打开工具栏,双击或点击鼠标拖拽添加CogFindLineTool工具 ②.添加输入图像,点击鼠标右键“链接到”选择输入图像或以连线拖拽的方式选择相应输入图像 ③.所选空间…

Git-常规用法-含解决分支版本冲突解决方法

前置条件 已经创建了Gitee账号 创建一个远程仓库 个人主页-新建一个仓库-起好仓库名字-简介 远程仓库地址 Git的优点 Git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。于2005年以GPL发布。采用了分布式版本库的做法&…

深入探索 RabbitMQ:功能丰富的消息中间件一

在现代分布式系统的构建中&#xff0c;消息中间件扮演着至关重要的角色。作为这一领域的佼佼者&#xff0c;RabbitMQ以其独特的特性和强大的功能&#xff0c;为应用程序提供了高效可靠的消息传递解决方案。以下是对RabbitMQ及其显著特点的更详细探讨。 什么是 RabbitMQ&#x…

考试酷基本功修炼课学习历程_FPGA成长篇

本文为明德扬原创文章&#xff0c;转载请注明出处&#xff01;作者&#xff1a;明德扬学员&#xff1a;考试酷账号&#xff1a;11167760 我是硬件工程师&#xff0c;日常工作中主要跟数字电路、模拟电路、嵌入式系统打交道&#xff0c;当然也会涉及到FPGA&#xff0c;但是苦于…

【Vue】新手一步一步安装 vue 语言开发环境

文章目录 1、下载node.js安装包 1、下载node.js安装包 1.打开node.js的官网下载地址&#xff1a;http://nodejs.cn/download/ 选择适合自己系统的安装包&#xff1a;winds、mac 2. 配置node.js和npm环境变量 安装好之后&#xff0c;对npm安装的全局模块所在路径以及缓存所在路…

05.MySQL索引事务

1. 索引 1.1 概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。 可以对表中的一列或多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各自的数据结构实现 1.2 作用 数据库中的表、数据、索引之间的关系&#xff0c;类似于书架上的…

C++ - 面向对象(二)

一. 类的6个默认成员函数 在我们前面学习的类中&#xff0c;我们会定义成员变量和成员函数&#xff0c;这些我们自己定义的函数都是普通的成员函数&#xff0c;但是如若我们定义的类里什么也没有呢&#xff1f;是真的里面啥也没吗&#xff1f;如下 class Date {}; 如果一个类…

架构师系列-搜索引擎ElasticSearch(七)- 集群管理之分片

集群健康检查 Elasticsearch 的集群监控信息中包含了许多的统计数据&#xff0c;其中最为重要的一项就是集群健康&#xff0c;它在 status字段中展示为 green&#xff08;所有主分片和副本分片都正常&#xff09;、yellow&#xff08;所有数据可用&#xff0c;有些副本分片尚未…

EEG-GCNN 论文问题整理

auc是什么&#xff1f; AUC是指接收者操作特征曲线&#xff08;ROC曲线&#xff09;下的面积&#xff0c;用于评估分类模型的性能。AUC的取值范围在0到1之间&#xff0c;越接近1表示模型的性能越好&#xff0c;越接近0.5表示模型的性能越差。AUC的计算方法是通过计算ROC曲线下…

Kafka分布式数据处理平台

目录 一.消息队列基本介绍 1.为什么需要消息队列 2.使用消息队列的好处 2.1 解耦 耦合&#xff08;非解耦&#xff09; 解耦 2.2 可恢复性 2.3 缓冲 2.4 灵活性 & 峰值处理能力 2.5 异步通信 3.消息队列的两种模式 3.1 点对点模式 3.2 发布/订阅模式 二.Kafk…

【脚本】多功能Ubuntu临时授予用户sudo权限管理工具

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 设计原理和初衷可以看这里&#xff1a;【技巧】Ubuntu临时授予用户sudo权限&#xff0c;并在一定时间后自动撤销_ubuntu jianshao sudo-CSDN博客文章浏览阅读404次。非常实用_ubuntu jianshao sudohttps://blog.c…

# 达梦sql查询 Sql 优化

达梦sql查询 Sql 优化 文章目录 达梦sql查询 Sql 优化注意点测试数据单表查询 Sort 语句优化优化过程 多表关联SORT 优化函数索引的使用 注意点 关于优化过程中工具的选用&#xff0c;推荐使用自带的DM Manage&#xff0c;其它工具在查看执行计划等时候不明确在执行计划中命中…

Echarts简单的多表联动效果和添加水印和按钮切换数据效果

多表联动 多表联动效果指的是在多个表格之间建立一种交互关系&#xff0c;以便它们之间的操作或选择能够相互影响。通常情况下&#xff0c;多表联动效果可以通过以下方式之一实现&#xff1a; 数据关联&#xff1a; 当在一个表格中选择或操作某些数据时&#xff0c;另一个表格…

【opencv】示例-stiching.cpp 图像拼接

#include "opencv2/imgcodecs.hpp" // 导入opencv图像编码功能库 #include "opencv2/highgui.hpp" // 导入opencv高层用户界面功能库 #include "opencv2/stitching.hpp" // 导入opencv图像拼接功能库#include <iostream> // 导入输入输出…