双目测距--4 双目立体匹配 获取深度图

news2024/9/25 11:19:36

在这之前需要已经完成双目标定,这里是利用双目标定结果利用SGBM算法获取深度图,以及转伪彩图。

目录

StereoSGBM用到的参数:

一、 预处理参数

二 、代价参数

三 、动态规划参数

四、后处理参数

reprojectImageTo3D函数

获取真实距离

联合YOLOv8的思路

 畸变矫正、立体矫正 --> 视差图---> 深度图  代码


OpenCV有三种立体匹配算法:BM算法、SGBM算法、GC算法,这里 我选择了SGBM算法,其速度精度都还不错。

StereoSGBM用到的参数:

这些参数的调整是很痛苦 的事情,但是如果你的参数设置不好,深度图呈现的效果就会很不好,会导致没法获取图像物体离相机的距离!!

opencv中SGBM算法的参数含义及数值选取

一、 预处理参数

1:preFilterCap:水平sobel预处理后,映射滤波器大小。默认为15

int ftzero =max(params.preFilterCap, 15) | 1;

opencv测试例程test_stereomatching.cpp中取63。

二 、代价参数

2:SADWindowSize:计算代价步骤中SAD窗口的大小。由源码得,此窗口默认大小为5。

SADWindowSize.width= SADWindowSize.height = params.SADWindowSize > 0 ?params.SADWindowSize : 5;

注:窗口大小应为奇数,一般应在3x3到21x21之间。

3:minDisparity:最小视差,默认为0。此参数决定左图中的像素点在右图匹配搜索的起点。int 类型

4:numberOfDisparities:视差搜索范围,其值必须为16的整数倍(CV_Assert( D % 16 == 0 );)。最大搜索边界= numberOfDisparities+ minDisparity。int 类型

三 、动态规划参数

动态规划有两个参数,分别是P1、P2,它们控制视差变化平滑性的参数。P1、P2的值越大,视差越平滑。P1是相邻像素点视差增/减 1 时的惩罚系数;P2是相邻像素点视差变化值大于1时的惩罚系数。P2必须大于P1。需要指出,在动态规划时,P1和P2都是常数。

5:opencv测试例程test_stereomatching.cpp中,P1 = 8*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;

6:opencv测试例程test_stereomatching.cpp中,P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;

四、后处理参数

7:uniquenessRatio:唯一性检测参数。对于左图匹配像素点来说,先定义在numberOfDisparities搜索区间内的最低代价为mincost,次低代价为secdmincost。如果满足

即说明最低代价和次第代价相差太小,也就是匹配的区分度不够,就认为当前匹配像素点是误匹配的。

opencv测试例程test_stereomatching.cpp中,uniquenessRatio=10。int 类型

8:disp12MaxDiff:左右一致性检测最大容许误差阈值。int 类型

opencv测试例程test_stereomatching.cpp中,disp12MaxDiff =1。

9:speckleWindowSize:视差连通区域像素点个数的大小。对于每一个视差点,当其连通区域的像素点个数小于speckleWindowSize时,认为该视差值无效,是噪点。

opencv测试例程test_stereomatching.cpp中,speckleWindowSize=100。

10:speckleRange:视差连通条件,在计算一个视差点的连通区域时,当下一个像素点视差变化绝对值大于speckleRange就认为下一个视差像素点和当前视差像素点是不连通的。

reprojectImageTo3D函数

函数描述:

该函数将视差图,通过投影矩阵Q,得到一幅映射图,图像大小与视差图相同,且每个像素具有三个 通道,分别存储了该像素位置在相机坐标系下的三维点坐标在x,y,z三个轴上的值,即每个像素的在相机坐标系下的三维坐标

函数原型:

void cv::reprojectImageTo3D( 
	InputArray disparity, 	//视差图像
	OutputArray _3dImage,	//映射后存储三维坐标的图像
	InputArray Q,			//重投影矩阵 通过stereoRectify得到
	bool handleMissingValues = false, //计算得到的非正常值是否给值,如果为true则给值10000
	int ddepth = -1			//输出类型 -1 即默认为CV_32FC3 还可以是 CV_16S, CV_32S, CV_32F
)

获取真实距离

代码中通过鼠标回调函数 onMouse可以在视差图上左键点击即可获得真实 距离

联合YOLOv8的思路

如果我想把双目相机与YOLOv8结合,检测目标的同时还能返回目标离相机距离。那么输入目标检测网络是某个相机的原图?还是经过畸变矫正及立体矫正之后的某相机图像?

我觉得可能选后者会好点,因为立体矫正对原图有个剪裁的操作(stereRectify()函数的第14的参数我设置为-1)。

所以联合YOLOv8的思路是:

  1. 输入检测网络的图像是经过畸变矫正及立体矫正之后的左相机图像(也可以是右相机图像)
  2. 检测到的目标,用其中心点坐标在深度度上面索取像素值,即左相机坐标系下的三维坐标

另外,我也想过直接从某个相机原图上进行预测目标,但是如何让目标中心点映射到深度图上我暂时想明白

 畸变矫正、立体矫正 --> 视差图---> 深度图  代码

#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/videoio/videoio.hpp>
#include <vector>

#include <iostream>

using namespace cv;
using namespace std;

// 双目摄像机内参
Mat cameraMatrix_L,cameraMatrix_R;
Mat discoeff_L, discoeff_R;

// 双目摄像机外参
Mat R, T;


// 立体校正用
Mat Rl, Rr, Pl, Pr, Q;
Mat mapLx, mapLy, mapRx, mapRy;
Rect validROIL, validROIR;

// 图像
Mat rgbImageL, grayImageL;
Mat rgbImageR, grayImageR;
Mat rectifyImageL, rectifyImageR;

// 图像尺寸
const int imageWidth = 1280/2;
const int imageheight = 360;
Size imageSize = Size(imageWidth, imageheight);



Mat xyz;              //三维坐标

Point origin;         //鼠标按下的起始点
Rect selection;      //定义矩形选框
bool selectObject = false;    //是否选择对象


int blockSize = 0, uniquenessRatio =0, numDisparities=0;
Ptr<StereoBM> bm = StereoBM::create();

// SGBM
/* 参数说明链接:https://blog.csdn.net/wwp2016/article/details/86080722*/
/*Opencv官方文档参数说明写得太模糊了,还得自己上网找解释看*/
int minDisparity; /*最小视差,默认为0。此参数决定左图中的像素点在右图匹配搜索的起点*/
int numDisParitiey; /*视差搜索范围,其值必须为16的整数倍, must be divisible by 16*/
//int blockSize; /*      匹配的块大小*/
int P1; /* 控制视差平滑度的第一个参数,8*number_of_image_channels*blockSize*blockSize */
int P2;/*第二个参数控制视差平滑度,32*number_of_image_channels*blockSize*blockSize*/
int disp12MaxDiff;/*        左右视差检查中允许的最大差异*/
int preFilterCap;/* 水平sobel预处理后,映射滤波器大小。  */
//int uniquenessRatio;/*              唯一性检测参数。 5-15 range is good enough*/
int speckleWindowSize;/* 视差连通区域像素点个数的大小。对于每一个视差点,当其连通区域的像素点个数小于speckleWindowSize时,认为该视差值无效,是噪点, set it somewhere in the 50-200 range. */
int speckRange;/*          视差连通条件,在计算一个视差点的连通区域时,当下一个像素点视差变化绝对值大于speckleRange就认为下一个视差像素点和当前视差像素点是不连通的。,1 or 2 is good enough.*/
int mode=StereoSGBM::MODE_SGBM;/*o StereoSGBM::MODE_HH to run the full-scale two-pass dynamic programming algorithm*/


cv::Ptr<cv::StereoSGBM> sgbm = cv::StereoSGBM::create();


// 设置相机内外参数文件路径
void setParameterPath(string path)
{
    string parameterPath1 = path + "intrisics.yml";
    FileStorage fs(parameterPath1, FileStorage::READ);
    if(fs.isOpened())
    {
        fs["cameraMatrixL"] >> cameraMatrix_L;
        fs["cameradistCoeffsL"] >> discoeff_L;
        fs["cameraMatrixR"] >> cameraMatrix_R;
        fs["cameradistCoeffsR"] >> discoeff_R;
        fs.release();

        cout<<"*****左右摄像机 内参 已读取"<<endl;
    }
    else
    {
        cout << "******" << parameterPath1
             << " can not open" << endl;
    }

    string parameterPath2 = path + "extrinsics.yml";
    fs.open(parameterPath2, FileStorage::READ);
    if(fs.isOpened())
    {
        fs["R"] >> R;
        fs["T"] >> T;
        fs["Rl"] >> Rl;
        fs["Rr"] >> Rr;
        fs["Pl"] >> Pl;
        fs["Pr"] >> Pr;
        fs["Q"] >> Q;
        fs["mapLx"] >> mapLx;
        fs["mapLy"] >> mapLy;
        fs["mapRx"] >> mapRx;
        fs["mapRy"] >> mapRy;
        fs.release();
        cout<<"*****左右摄像机  外参 已读取"<<endl<<endl<<endl;
    }
    else
    {
        cout << "******" << parameterPath2
             << " can not open" << endl;
    }
}

// 视差图孔洞填充
void insertDepth32f(cv::Mat& depth)
{
    /*https://blog.csdn.net/qq_41641044/article/details/120693644*/

    for (int i = 0; i < depth.rows; i++)
    {
        for (int j = 0; j < depth.cols; j++)
        {
            if (depth.channels() == 1)
            {
                //图像数组是逐行逐列顺序排列的,也就是第一行,全列,第二行全列的走
                int a,b,indexs = i * depth.cols + j;
                //cout << typeid(depth.data[indexs]).name() << endl;
                a = (int)depth.data[indexs];
                //cout << a << endl;
                if (a == 0 && j > 50 && j< depth.cols-50 && i>50 && i< depth.rows-50)
                {

                    //vector<int> testarray = { (int)depth.data[indexs - 50], (int)depth.data[indexs + 50], (int)depth.data[indexs - 50 * depth.cols], (int)depth.data[indexs + 50 * depth.cols] };
                    b = max({ (int)depth.data[indexs - 50], (int)depth.data[indexs + 50], (int)depth.data[indexs - 50* depth.cols], (int)depth.data[indexs + 50 * depth.cols] });//accumulate(testarray.begin(),testarray.end(),0)/4;
                    //cout << "a的值为:"<<a<<"b的值为:"<<b << endl;
                     depth.data[indexs] = b;
                }
            }
            else if (depth.channels() == 3)
            {
            }
        }
    }

}

// 深度图转伪彩
void convertColor(Mat & image)
{
    /*https://blog.csdn.net/qq_51639530/article/details/124462762*/
    //读取16位深度图(像素范围0~65535),并将其转化为8位(像素范围0~255)
    double minValue, maxValue;    // 最大值,最小值
    cv::Point  minIdx, maxIdx;    // 最小值坐标,最大值坐标
    cv::minMaxLoc(image, &minValue, &maxValue, &minIdx, &maxIdx);

    image -= minValue;
//    image = image / (maxValue - minValue);
    image =image/((numDisparities * 16 + 16)*16.);
    image *= 255;

    //使得越近的地方深度值越大,越远的地方深度值越小,以达到伪彩色图近蓝远红的目的。
    image = 255 - image;

   // cv2 中的色度图有十几种,其中最常用的是 cv2.COLORMAP_JET,蓝色表示较高的深度值,红色表示较低的深度值。
   // cv.convertScaleAbs() 函数中的 alpha 的大小与深度图中的有效距离有关,如果像我一样默认深度图中的所有深度值都在有效距离内,并已经手动将16位深度转化为了8位深度,则 alpha 可以设为1。
    convertScaleAbs(image,image,1);
    applyColorMap(image,image, COLORMAP_JET);

}


/*****立体匹配*****/
void stereo_match(int,void*)
{
    bm->setBlockSize(2*blockSize+5);     //SAD窗口大小,5~21之间为宜
    bm->setROI1(validROIL);
    bm->setROI2(validROIR);
    bm->setPreFilterCap(31);
    bm->setMinDisparity(0);  //最小视差,默认值为0, 可以是负值,int型
    bm->setNumDisparities(numDisparities*16+16);//视差窗口,即最大视差值与最小视差值之差,窗口大小必须是16的整数倍,int型
    bm->setTextureThreshold(10);
    bm->setUniquenessRatio(uniquenessRatio);//uniquenessRatio主要可以防止误匹配
    bm->setSpeckleWindowSize(100);
    bm->setSpeckleRange(32);
    bm->setDisp12MaxDiff(-1);
    Mat disp, disp8;
    bm->compute(rectifyImageL, rectifyImageR, disp);//输入图像必须为灰度图


    disp.convertTo(disp8, CV_8U, 255 / ((numDisparities * 16 + 16)*16.));//计算出的视差是CV_16S格式
    reprojectImageTo3D(disp, xyz, Q, true); //在实际求距离时,ReprojectTo3D出来的X / W, Y / W, Z / W都要乘以16(也就是W除以16),才能得到正确的三维坐标信息。
    xyz = xyz * 16;
    imshow("disparity", disp8);
}



void Stereo_SGBM_match(int,void*)
{
    P1 = 8 * grayImageL.channels() * blockSize*blockSize;
    P2 = 4*P1;
    sgbm->setP1(P1);
    sgbm->setP2(P2);
    sgbm->setMinDisparity(0);//此参数决定左图中的像素点在右图匹配搜索的起点

    sgbm->setSpeckleRange(32);



    // 下面6个参数用按钮来调节
    sgbm->setNumDisparities(numDisparities*16+16); // 必须能被16整除; 视差搜索范围
    sgbm->setBlockSize(blockSize); //  > = 1的奇数
    sgbm->setDisp12MaxDiff(1); //左右一致性检测最大容许误差阈值
    sgbm->setPreFilterCap(9);
    sgbm->setUniquenessRatio(uniquenessRatio); // 5~15
    sgbm->setSpeckleWindowSize(100); // 50~200

    Mat disp, disp8;

    // 对左右视图的左边进行边界延拓,以获取与原始视图相同大小的有效视差区域
    /* 加大numDisparities值,深度图左边会变黑,但是整图尺寸变大!很有效哦*/
    /*https://blog.csdn.net/u011574296/article/details/87546622*/
    copyMakeBorder(rectifyImageL,rectifyImageL,0,0,numDisparities,0,cv::BORDER_REPLICATE);
    copyMakeBorder(rectifyImageR,rectifyImageR,0,0,numDisparities,0,cv::BORDER_REPLICATE);

    sgbm->compute(rectifyImageL, rectifyImageR, disp); // //得出的结果是以16位符号数的形式的存储的,出于精度需要,所有的视差在输出时都扩大了16倍(2^4)

    disp = disp.colRange(numDisparities, rectifyImageL.cols).clone();
//    insertDepth32f(disp); 没有用,不能呢消除空洞

    // 可以试一试闭合运算或者开启运算
//    cv::Mat element(7, 7, disp.type(), cv::Scalar(1));
//    morphologyEx(disp, disp, MORPH_CLOSE, element);




    disp.convertTo(disp8, CV_8U, 255 / ((numDisparities * 16 + 16)*16.));//计算出的视差是CV_16S格式,

    reprojectImageTo3D(disp, xyz, Q, true); //在实际求距离时,ReprojectTo3D出来的X / W, Y / W, Z / W都要乘以16(也就是W除以16),才能得到正确的三维坐标信息。
    xyz = xyz * 16;
    imshow("disparity", disp8);

    applyColorMap(disp8, disp8, COLORMAP_RAINBOW);
    imshow("color", disp8);
}



/*****描述:鼠标操作回调*****/
static void onMouse(int event, int x, int y, int, void*)
{
    if (selectObject)
    {
        selection.x = MIN(x, origin.x);
        selection.y = MIN(y, origin.y);
        selection.width = std::abs(x - origin.x);
        selection.height = std::abs(y - origin.y);
    }

    switch (event)
    {
    case EVENT_LBUTTONDOWN:   //鼠标左按钮按下的事件
        origin = Point(x, y);
        selection = Rect(x, y, 0, 0);
        selectObject = true;
        cout << origin <<"in world coordinate is: " << xyz.at<Vec3f>(origin) << endl;
        break;
    case EVENT_LBUTTONUP:    //鼠标左按钮释放的事件
        selectObject = false;
        if (selection.width > 0 && selection.height > 0)
        break;
    }
}






/*****主函数*****/
int main()
{
    /* 读取相机内外参数*/
    setParameterPath("/home/jason/work/my--camera/calibration/");

    /*立体校正*/
    stereoRectify(cameraMatrix_L, discoeff_L,
                  cameraMatrix_R, discoeff_R,
                  imageSize, R, T,
                  Rl, Rr, Pl, Pr, Q,
                  CALIB_ZERO_DISPARITY, -1,
                  imageSize,
                  &validROIL, &validROIR);

    initUndistortRectifyMap(cameraMatrix_L, discoeff_L,
                            Rl, Pl, imageSize,
                            CV_32FC1, mapLx, mapLy);
    initUndistortRectifyMap(cameraMatrix_R, discoeff_R,
                            Rr, Pr, imageSize,
                            CV_32FC1, mapRx, mapRy);


    /*读取图片*/
    VideoCapture cap(2);

    if (!cap.isOpened())
    {
        cout << "***** camera can't open!!"<< endl <<endl;
        return 1;
    }
    else
    {
        cout << "*****camera is open"<< endl;

    }

    cap.set(CAP_PROP_FRAME_WIDTH, imageWidth*2);
    cap.set(CAP_PROP_FRAME_HEIGHT, imageheight);
    cap.set(CAP_PROP_FPS, 30);


    namedWindow("disparity", cv::WINDOW_AUTOSIZE);
//   /*BM算法用*/
//    // 创建SAD窗口 Trackbar
//    createTrackbar("BlockSize:\n", "disparity",&blockSize, 8, stereo_match);
//    // 创建视差唯一性百分比窗口 Trackbar
//    createTrackbar("UniquenessRatio:\n", "disparity", &uniquenessRatio, 50, stereo_match);
//    // 创建视差窗口 Trackbar
//    createTrackbar("NumDisparities:\n", "disparity", &numDisparities, 16, stereo_match);

    /*SGBM算法用*/
    createTrackbar("NumDisparities:\n", "disparity", &numDisparities, 16, Stereo_SGBM_match);
    createTrackbar("BlockSize:\n", "disparity",&blockSize, 8, Stereo_SGBM_match);
//    createTrackbar("disp12MaxDiff:\n", "disparity", &disp12MaxDiff, -1, Stereo_SGBM_match);
//    createTrackbar("preFilterCap:\n", "disparity", &preFilterCap, 50, Stereo_SGBM_match);
    createTrackbar("uniquenessRatio:\n", "disparity", &uniquenessRatio, 50, Stereo_SGBM_match);
//    createTrackbar("speckleWindowSize:\n", "disparity", &speckleWindowSize, 200, Stereo_SGBM_match);





    //鼠标响应函数setMouseCallback(窗口名称, 鼠标回调函数, 传给回调函数的参数,一般取0)
    setMouseCallback("disparity", onMouse, 0);
    Mat doubleImage;
    while (1)
    {
        cap >> doubleImage;

        rgbImageL = doubleImage(Rect(Point(0,0), Point(imageWidth, imageheight))).clone();
        rgbImageR = doubleImage(Rect(Point(imageWidth, 0), Point(imageWidth*2, imageheight))).clone();

        cvtColor(rgbImageL, grayImageL, COLOR_BGR2GRAY);
        cvtColor(rgbImageR, grayImageR, COLOR_BGR2GRAY);
        imshow("before Rectify", doubleImage);

        /*remap之后,左右相机的图像已经共面并行对准了*/
        remap(grayImageL,rectifyImageL, mapLx, mapLy, INTER_LINEAR);
        remap(grayImageR, rectifyImageR, mapRx, mapRy, INTER_LINEAR);

        /*把校正结果显示出来*/
        Mat rgbRectifyImageL, rgbRectifyImageR;
        cvtColor(rectifyImageL, rgbRectifyImageL, COLOR_GRAY2BGR);
        cvtColor(rectifyImageR, rgbRectifyImageR, COLOR_GRAY2BGR);

        //显示在同一张图上
        Mat canvas;
        double sf;
        int w, h;
        sf = 600. / MAX(imageSize.width, imageSize.height);
        w = cvRound(imageSize.width * sf);
        h = cvRound(imageSize.height * sf);
        canvas.create(h, w * 2, CV_8UC3);   //注意通道

        //左图像画到画布上
        Mat canvasPart = canvas(Rect(w * 0, 0, w, h));                                //得到画布的一部分
        resize(rgbRectifyImageL, canvasPart, canvasPart.size(), 0, 0, INTER_AREA);     //把图像缩放到跟canvasPart一样大小
        Rect vroiL(cvRound(validROIL.x*sf), cvRound(validROIL.y*sf),                //获得被截取的区域
            cvRound(validROIL.width*sf), cvRound(validROIL.height*sf));
        //rectangle(canvasPart, vroiL, Scalar(0, 0, 255), 3, 8);                      //画上一个矩形
        cout << "Painted ImageL" << endl;

        //右图像画到画布上
        canvasPart = canvas(Rect(w, 0, w, h));                                      //获得画布的另一部分
        resize(rgbRectifyImageR, canvasPart, canvasPart.size(), 0, 0, INTER_LINEAR);
        Rect vroiR(cvRound(validROIR.x * sf), cvRound(validROIR.y*sf),
            cvRound(validROIR.width * sf), cvRound(validROIR.height * sf));
        //rectangle(canvasPart, vroiR, Scalar(0, 0, 255), 3, 8);
        cout << "Painted ImageR" << endl;

        //画上对应的线条
        for (int i = 0; i < canvas.rows; i += 16)
            line(canvas, Point(0, i), Point(canvas.cols, i), Scalar(0, 255, 0), 1, 8);
        imshow("rectified", canvas);


        /*
        获得深度
        */

//        stereo_match(0,0);
        Stereo_SGBM_match(0,0);

        if ((char)waitKey(1) == 'q')
        {
            break;
        }



    }


    return 0;
}

其实做这个项目目前有一个一直未解决的问题,即深度图中空洞问题,如果您有解决办法,烦请给个机会交流一下

参考:

sgbm参数设置_wwp2016的博客-CSDN博客

视觉深度图后处理中空洞填充问题_深度图空洞填充_乘风破浪的混子的博客-CSDN博客

关于深度图/视差图转为伪彩色的方法_深度图转伪彩图_via无心的博客-CSDN博客双目立体匹配方法:BM、SGBM、GC算法的实现及性能对比(附代码)_bm立体匹配_slam02∞的博客-CSDN博客

双目立体匹配算法SGBM_sgbm算法_Alan Lan的博客-CSDN博客

【OpenCV】reprojectImageTo3D函数_魏Gordon的博客-CSDN博客

【OpenCV】reprojectImageTo3D函数_魏Gordon的博客-CSDN博客

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

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

相关文章

ChatGPT - 快速生成 流程图

文章目录 Prompt输出Copy 到 drawio Prompt 我想做一个研发标准化的流程,但是我是一个小白,不懂研发管理的流 程,我希望你作为一个经验丰富的技术管理人员,请帮我梳理一个完整流程,包括需求分析、概要设计,代码走查等等,输出的节点不少于18个,包含逻辑判断的分支,要通循实事求…

【SpringCloud微服务实践】服务注册与发现

注册与发现 在之前的示例中&#xff0c;采取的是硬编码的方式&#xff0c;需要调用的微服务的地址是被我们写死在文件或代码中的。在传统应用程序中&#xff0c;一般都是这么做的&#xff0c;然而这种方式存在不少缺陷&#xff1a; 静态配置&#xff1a;因为是写死的网络地址…

力扣sql中等篇练习(十五)

力扣sql中等篇练习(十五) 1 页面推荐 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 a 示例输入 b 示例输出 1.2 示例sql语句 # ①找到1所对应的朋友 ②找到其朋友喜欢的页面 ③删选掉自己喜欢的页面 # 可能朋友中存在喜欢同样的界面 SELECT distinct page_id reco…

Java每日一练(20230507) 组合总和、缺失的正数、单词搜索II

目录 1. 组合总和 &#x1f31f;&#x1f31f; 2. 缺失的第一个正数 &#x1f31f;&#x1f31f;&#x1f31f; 3. 单词搜索 II &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/…

数字化转型导师坚鹏:企业干部如何进行数字化转型

企业干部如何进行数字化转型 ——数字化转型背景下重塑企业干部核心竞争力 授课背景&#xff1a; 很多银行存在以下问题&#xff1a; 企业干部不知道如何进行数字化转型&#xff1f; 企业干部不清楚银行数字化能力模型的内涵&#xff1f; 企业干部不知道如何通过数字化…

总结843

学习目标&#xff1a; 5月&#xff08;张宇强化18讲&#xff0c;背诵25篇短文&#xff0c;熟词僻义300词基础词&#xff09; 每日必复习&#xff08;5分钟&#xff09; 做记录本上3道题 学习内容&#xff1a; 暴力英语&#xff1a;回环诵读&#xff0c;继续背一篇阅读理解&…

前端实战项目:网易云静态页面——轮播图

前言 目前这个前端项目持续更新中~ 网易云静态页面——导航栏 Flex布局 文章目录 前言实现目标静态实现页面大致样子添加模糊的背景图添加图片下载客户端部分轮播图小圆点第一个小圆点变成红色以及当鼠标放上其他任一小圆点也变成红色左右按钮总代码 动态实现 实现目标 建立相…

Shift_RAM ip核的使用——ROM调用mif文件、传至Shift_RAM输出

Altera_Shift Register&#xff08;RAM-based&#xff09;ip核 前言1.创建mif文件&#xff0c;通过ROM ip核调用该mif文件1.1创建mif文件1.2顺序填充mif文件1.3创建ROM ip核调用mif文件 2.计数器读取mif文件中的数据2.1写一个0-15的循环计数器2.2实例化ROM ip核、调用计数器模块…

【C++学习】类和对象--多态

多态的基本语法 多态是C面向对象三大特性之一 静态多态&#xff1a; 函数重载和运算符重载属于静态多态&#xff0c;复用函数名&#xff08;函数地址早绑定&#xff0c;编译阶段确定函数地址&#xff09; 动态多态&#xff1a; 派生类和虚函数实现运行时多态&#xff08;函数地…

Python |浅谈爬虫的由来

本文概要 本篇文章主要介绍Python爬虫的由来以及过程&#xff0c;适合刚入门爬虫的同学&#xff0c;文中描述和代码示例很详细&#xff0c;干货满满&#xff0c;感兴趣的小伙伴快来一起学习吧&#xff01; &#x1f31f;&#x1f31f;&#x1f31f;个人简介&#x1f31f;&…

快速搭建一个spring入门案例及整合日志

目录 环境要求 构建模块 程序开发 引入依赖 创建java类 创建配置文件 创建测试类测试 运行测试程序 程序分析 spring中配置启用Log4j2日志框架 Log4j2日志概述 引入Log4j2依赖 加入日志配置文件 测试 使用日志 环境要求 JDK&#xff1a;Java17&#xff08;Spring6要…

Linux高性能服务器编程|阅读笔记:第6章 - 高级I/O函数

目录 简介6.1 pipe函数6.2 dup函数和dup2函数6.3 readv函数和writev函数6.4 sendfile函数6.5 mmap函数和munmap函数6.6 splice函数6.7 tee函数6.8 fcntl函数结语 简介 Hello&#xff01; 非常感谢您阅读海轰的文章&#xff0c;倘若文中有错误的地方&#xff0c;欢迎您指出&…

10-Vue技术栈之脚手架配置代理(解决跨域问题)+ GitHub用户搜索案例

目录 1、基本使用1.1 方法一1.2 方法二 2、GitHub用户搜索案例 1、基本使用 1.1 方法一 ​ 在vue.config.js中添加如下配置&#xff1a; devServer:{proxy:"http://localhost:5000" }说明&#xff1a; 优点&#xff1a;配置简单&#xff0c;请求资源时直接发给前…

用三角函数解决几何问题

如图&#xff0c;在 △ A B C \triangle ABC △ABC 中&#xff0c; A C > 5 , A B > A C AC>5,AB>AC AC>5,AB>AC&#xff0c;点 E E E 是 A B AB AB 上一点&#xff0c;链接 C E CE CE&#xff0c;将 △ B C E \triangle BCE △BCE 沿 C E CE CE 折叠&…

【unity之数据持久化】-Unity公共类PlayerPrefs

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

FreeRTOS 内存管理

文章目录 一、FreeRTOS 内存管理简介二、 内存碎片三、heap_1 内存分配方法1. 分配方法简介2. 内存申请函数详解3. 内存释放函数详解 四、heap_2 内存分配方法1. 分配方法简介2. 内存块详解3. 内存堆初始化函数详解4. 内存块插入函数详解5. 内存申请函数详解6. 内存释放函数详解…

操作系统考试复习——第四章 4.3连续分配存储管理方式

在这里的开头需要讲述一下碎片&#xff0c;碎片分为内碎片和外碎片两种。 内碎片&#xff1a;分区之内未被利用的空间外碎片&#xff1a;分区之间难以利用的空闲分区&#xff08;通常是小空闲分区&#xff09;。 连续分配存储管理方式: 为了能将用户程序装入内存&#xff0c…

力扣刷题Day12_2

144.二叉树的前序遍历 测试代码main() class TreeNode:def __init__(self, valNone, leftNone, rightNone):self.val valself.left leftself.right rightfrom typing import Listclass Solution:def preorderTraversal(self, root: TreeNode) -> List[int]:s Solution…

C++易错编程练习题(1)

0 编程练习 基础不牢靠&#xff0c;回头来补课。小白这个系列主要是为了重新打基础&#xff0c;为一些常见的易错编程练习题提供记录。其间若有错误&#xff0c;欢迎指出&#xff0c;轻喷勿骂。毕竟小白确实是基础不牢靠。 1 题目 自定义函数之整数处理。 题目描述 输入10个…

多视图局部共现和全局一致性学习提高乳腺图像分类的综合性

文章目录 Multi-view Local Co-occurrence and Global Consistency Learning Improve Mammogram Classification Generalisation摘要本文方法global consistency modulelocal co-occurrence module (LCM) 实验结果 Multi-view Local Co-occurrence and Global Consistency Lear…