基于OpenCV的双目深度估计实现与改进

2023-05-16

双目深度估计

一、传统方法

​ 常用的方法有SAD匹配算法,BM算法,SGBM算法,GC算法

1.1、SAD算法

​ SAD(Sum of absolute differences)是一种图像匹配算法 ,基本思想是:差的绝对值之和。此算法常用于图像块匹配,将每个像素对应数值之差的绝对值求和,据此评估两个图像块的相似度。该算法快速、但并不精确,通常用于多级处理的初步筛选。

基本流程:

(1)构造一个小窗口,类似于卷积核;

(2)用窗口覆盖左边的图像,选择出窗口覆盖区域内的所有像素点;

(3)同样用窗口覆盖右边的图像并选择出覆盖区域的像素点;

(4)左边覆盖区域减去右边覆盖区域,并求出所有像素点灰度差的绝对值之和;

(5)移动右边图像的窗口,重复(3)-(4)的处理(这里有个搜索范围,超过这个范围跳出);

(6)找到这个范围内SAD值最小的窗口,即找到了左图锚点的最佳匹配的像素块。

1.2 BM算法

![image](https://images2015.cnblogs.com/blog/451660/201601/451660-20160114151753835-1022576108.png)

​ BM 算法对图像进行双向匹配,首先通过匹配代价在右图中计算得出匹配点。然后相同的原理及计算在左图中的匹配点。比较找到的左匹配点和源匹配点是否一致,如果你是,则匹配成功。

优点是速度很快,但是效果不佳。

基于OpenCV的实现

void BM()
{
  IplImage * img1 = cvLoadImage("left.png",0);
    IplImage * img2 = cvLoadImage("right.png",0);
    CvStereoBMState* BMState=cvCreateStereoBMState();
    assert(BMState);
    BMState->preFilterSize=9;
    BMState->preFilterCap=31;
    BMState->SADWindowSize=15;
    BMState->minDisparity=0;
    BMState->numberOfDisparities=64;
    BMState->textureThreshold=10;
    BMState->uniquenessRatio=15;
    BMState->speckleWindowSize=100;
    BMState->speckleRange=32;
    BMState->disp12MaxDiff=1;

    CvMat* disp=cvCreateMat(img1->height,img1->width,CV_16S);
    CvMat* vdisp=cvCreateMat(img1->height,img1->width,CV_8U);
    int64 t=getTickCount();
    cvFindStereoCorrespondenceBM(img1,img2,disp,BMState);
    t=getTickCount()-t;
    cout<<"Time elapsed:"<<t*1000/getTickFrequency()<<endl;
    cvSave("disp.xml",disp);
    cvNormalize(disp,vdisp,0,255,CV_MINMAX);
    cvNamedWindow("BM_disparity",0);
    cvShowImage("BM_disparity",vdisp);
    cvWaitKey(0);
    //cvSaveImage("cones\\BM_disparity.png",vdisp);
    cvReleaseMat(&disp);
    cvReleaseMat(&vdisp);
    cvDestroyWindow("BM_disparity");
}

其中minDisparity是控制匹配搜索的第一个参数,代表了匹配搜苏从哪里开始,numberOfDisparities表示最大搜索视差数uniquenessRatio表示匹配功能函数,这三个参数比较重要,可以根据实验给予参数值 .

1.3 SGBM算法

​ OpenCV中的SGBM算法是一种半全局立体匹配算法,立体匹配的效果明显好于局部匹配算法,但是同时复杂度上也要远远大于局部匹配算法。算法主要是参考Stereo Processing by Semiglobal Matching and Mutual Information。 opencv中实现的SGBM算法计算匹配代价没有按照原始论文的互信息作为代价,而是按照块匹配的代价。

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

**numDisparities:**视差搜索范围长度,其值必须为16的整数倍。最大视差 maxDisparity = minDisparity + numDisparities -1;

**blockSize:**SAD代价计算窗口大小,默认为5。窗口大小为奇数,一般在33 到2121之间;

**P1、P2:**能量函数参数,P1是相邻像素点视差增/减 1 时的惩罚系数;P2是相邻像素点视差变化值大于1时的惩罚系数。P2必须大于P1。需要指出,在动态规划时,P1和P2都是常数。

一般建议:
P1 = 8cnsgbm.SADWindowSizesgbm.SADWindowSize;P2 = 32cnsgbm.SADWindowSizesgbm.SADWindowSize;

实验总结:

  1. blockSize(SADWindowSize) 越小,也就是匹配代价计算的窗口越小,视差图噪声越大;blockSize越大,视差图越平滑;太大的size容易导致过平滑,并且误匹配增多,体现在视差图中空洞增多;
  2. 惩罚系数控制视差图的平滑度,P2>P1,P2越大则视差图越平滑;
  3. 八方向动态规划较五方向改善效果不明显,主要在图像边缘能够找到正确的匹配

1.4 GC算法

GC算法在OpenCV3中已经没有了相应的API,因为这种方法虽然效果好,但是计算量实在是太大,不实用。

二、深度学习方法

​ 深度图除了应用传统方法计算之外,还可以通过最近几年非常火热的机器学习,深度学习等技术进行实现。目前在无人驾驶领域有迫切的应用。深度估计不仅仅可以用双目进行深度估计,甚至还可以用单目图像进行深度估计。双目深度估计在三维重建,HCI,AR,自动驾驶等领域至关重要,单目深度估计也有意义。尽管有不少硬件能够直接得到深度图,但它们都有各自的缺陷。比如3D LIDAR设备非常昂贵;基于结构光的深度摄像头比如Kinect等在室外无法使用,且得到的深度图噪声比较大;而双目摄像头需要利用立体匹配算法,计算量比较大,而且对于低纹理场景效果不好。单目摄像头相比来说成本最低,设备也较普及,所以从单目摄像头估计出深度仍然是一个可选的方案,应用比其它方案更加广泛。举个SLAM的例子,对于单目SLAM来说,从单张图(或者是静止的图序列)是无法在几何上得到深度的。如果能通过算法给出一个粗略的深度估计(相当于从数据集中获得图像的深度先验),对于算法的收敛性和鲁棒性也是一个很大的提升 。

2.1 PSMNet(双目)–CVPR2018

​ PSMNet(Pyramid Stereo Matching Network)是利用双目立体图像中进行深度估计的,它提出了一个全新的金字塔匹配网络在立体匹配中利用全局环境信息。空间金字塔池化(SPP)和空洞卷积(dilated convolution)用来扩大感受野。通过这个方法,PSMNet将像素级别的特征拓展到包含不同尺度感受野的区域级别的特征,将全局和局部特征信息结合起来构成匹配代价卷以获得更加可靠的视差估计值。除此之外,本文还设计了一个结合了中间监督的堆叠沙漏3D卷积神经网络去调整匹配代价卷(类似传统算法中的代价聚合过程)。这个堆叠的沙漏3D-CNN重复进行由精到粗再由粗到精(top-down/bottom-up)的过程来提高对全局信息的利用程度。

下图是PSMNet的整体网络结构:

这里写图片描述

其中最重要的部分是空间金字塔池化模块

​ 单独从一个像素的强度(灰度或RGB值)很难判断环境关系。因此借助物体的环境信息来丰富图像特征能够有助于一致性估计,尤其对于不适定区域。在本文中,物体(例如汽车)和次级区域(车窗,轮胎等)的关系由SPP模块学习来结合多层级的环境信息。

​ 在何凯明的论文中,SPP被设计用来去除CNN中的尺寸约束。由SPP生成的不同级别的特征图被平整后送入全卷积层用于分类,在此之后SPP被用于语义分割问题。ParseNet使用全局平均池化来结合全局环境信息。PSPNet拓展了ParseNet,采用包含不同尺度和次级区域信息的分层全局池化。在PSPNet中,SPP模块使用自适应平均池化把特征压缩到四个尺度上,并紧跟一个1*1的卷积层来减少特征维度,之后低维度的特征图通过双线性插值的方法进行上采样以恢复到原始图片的尺寸。不同级别的特征图都结合成最终的SPP特征图。

​ 在本文中,我们为SPP设计了4个尺度的平均池化:6464,3232,1616,88。并与PSPNet一样,采用了1*1卷积和上采样。在简化模型测试中(ablation study),我们设计了大量的实验来展示不同级别的特征图的影响。

​ 本文的实验结果在KITT数据集上取得了最好的成绩。

###2.2 DORN(单目)-CVPR2018

​ 本文(Deep Ordinal Regression Network for Monocular Depth Estimation)是ROB2018中深度预测的冠军方案,它与传统的深度预测方法不同。传统的方法是利用视角、纹理、目标大小、目标位置、遮挡关系最为深度预测的特征线索;当前使用的基于深度卷积网络的方法大多采用的是用于图像分类的特征提取网络,这些网络由于有池化层的操作或者步长较大的卷积曹祖,导致预测的分辨率较低,虽然可以通过转置卷积、跨层连接等方式进行分辨率的方法,但是这样网络结构的复杂度和时间开销和计算成本相应增加 。本文提出的方案采用扩张卷积的方式进行多尺度融合。网络结构如下图:

这里写图片描述

这个方法中最重要的亮点是提出了多尺度融合方法。网络中的 ASPP部分采用不同扩张系数的扩张卷积操作,能够在不改变图像分辨率的前提下,有效得到不同感受野大小的卷积操作,进而得到多尺度融合特征

三、实验

​ 由于SGBM算法视差效果好速度快的特点,常常被广泛应用和改进,所以我就没有对其他算法进行重新实现,只在Codeing Test中实验了SGBM算法,并对该算法进行了改进。

3.1 SGBM算法的实现

Mat SGBM(Mat left,Mat right)
{
  Mat disp,color(disp.size(),CV_8UC3);
	int mindisparity = 0;
	int ndisparities = 64;  
	int SADWindowSize = 11; 
	//SGBM
	cv::Ptr<cv::StereoSGBM> sgbm = cv::StereoSGBM::create(mindisparity, ndisparities, SADWindowSize);
	int P1 = 8 * left.channels() * SADWindowSize* SADWindowSize;
	int P2 = 32 * left.channels() * SADWindowSize* SADWindowSize;
	sgbm->setP1(P1);
	sgbm->setP2(P2);
	sgbm->setPreFilterCap(15);
	sgbm->setUniquenessRatio(10);
	sgbm->setSpeckleRange(2);
	sgbm->setSpeckleWindowSize(100);
	sgbm->setDisp1![微信截图_20180918210933](E:\学习\深度学习\活体检测\双目摄像头\因特尔测试\display_results\微信截图_20180918210933.png)
}


3.2 灰度转伪彩色

​ 为了让实验效果更佳的明显,我对实验结果进行了彩色可视化,具体是算法试下如下:

Mat gray2Color(Mat img)
{
   
   Mat img_color(img.rows, img.cols, CV_8UC3);//构造RGB图像
   #define IMG_B(img,y,x) img.at<Vec3b>(y,x)[0]
   #define IMG_G(img,y,x) img.at<Vec3b>(y,x)[1]
   #define IMG_R(img,y,x) img.at<Vec3b>(y,x)[2]
   uchar tmp2=0;
   for (int y=0;y<img.rows;y++)//转为彩虹图的具体算法,主要思路是把灰度图对应的0~255的数值分别转换成彩虹色:红、橙、黄、绿、青、蓝。
   {
      for (int x=0;x<img.cols;x++)
      {
         tmp2 = img.at<uchar>(y,x);
         if (tmp2 <= 51)
         {
            IMG_B(img_color,y,x) = 255;
            IMG_G(img_color,y,x) = tmp2*5;
            IMG_R(img_color,y,x) = 0;
         }
         else if (tmp2 <= 102)
         {
            tmp2-=51;
            IMG_B(img_color,y,x) = 255-tmp2*5;
            IMG_G(img_color,y,x) = 255;
            IMG_R(img_color,y,x) = 0;
         }
         else if (tmp2 <= 153)
         {
            tmp2-=102;
            IMG_B(img_color,y,x) = 0;
            IMG_G(img_color,y,x) = 255;
            IMG_R(img_color,y,x) = tmp2*5;
         }
         else if (tmp2 <= 204)
         {
            tmp2-=153;
            IMG_B(img_color,y,x) = 0;
            IMG_G(img_color,y,x) = 255-uchar(128.0*tmp2/51.0+0.5);
            IMG_R(img_color,y,x) = 255;
         }
         else
         {
            tmp2-=204;
            IMG_B(img_color,y,x) = 0;
            IMG_G(img_color,y,x) = 127-uchar(127.0*tmp2/51.0+0.5);
            IMG_R(img_color,y,x) = 255;
         }
      }
   }
    return img_color;
}

3.3 实验效果

在这里插入图片描述

图1 原始图片(Right) 视差图 视差图转为伪彩色

在这里插入图片描述

图2 原始图片(Right) 视差图 视差图转为伪彩色

这里写图片描述

图3 原始图片(Right) 视差图 视差图转为伪彩色

3.2 对SGBM算法的改进

​ 从上面的可视化深度图中可以看出,深度信息中存在许多的空洞,为了填充这些缺失的空洞值,对算法SGBM进行了改进。

改进思路:

​ ① 以视差图dispImg为例。计算图像的积分图integral,并保存对应积分图中每个积分值处所有累加的像素点个数n(空洞处的像素点不计入n中,因为空洞处像素值为0,对积分值没有任何作用,反而会平滑图像)。

② 采用多层次均值滤波。首先以一个较大的初始窗口去做均值滤波(积分图实现均值滤波就不多做介绍了,可以参考我之前的一篇博客),将大区域的空洞赋值。然后下次滤波时,将窗口尺寸缩小为原来的一半,利用原来的积分图再次滤波,给较小的空洞赋值(覆盖原来的值);依次类推,直至窗口大小变为3x3,此时停止滤波,得到最终结果。

③ 多层次滤波考虑的是对于初始较大的空洞区域,需要参考更多的邻域值,如果采用较小的滤波窗口,不能够完全填充,而如果全部采用较大的窗口,则图像会被严重平滑。因此根据空洞的大小,不断调整滤波窗口。先用大窗口给所有空洞赋值,然后利用逐渐变成小窗口滤波覆盖原来的值,这样既能保证空洞能被填充上,也能保证图像不会被过度平滑。

算法实现:

//将噪声和空洞进行填充
Mat insertDepth32f(cv::Mat depth)
{
    const int width = depth.cols;
    const int height = depth.rows;
    float* data = (float*)depth.data;
    cv::Mat integralMap = cv::Mat::zeros(height, width, CV_64F);
    cv::Mat ptsMap = cv::Mat::zeros(height, width, CV_32S);
    double* integral = (double*)integralMap.data;
    int* ptsIntegral = (int*)ptsMap.data;
    memset(integral, 0, sizeof(double) * width * height);
    memset(ptsIntegral, 0, sizeof(int) * width * height);
    for (int i = 0; i < height; ++i)
    {
        int id1 = i * width;
        for (int j = 0; j < width; ++j)
        {
            int id2 = id1 + j;
            if (data[id2] > 1e-3)
            {
                integral[id2] = data[id2];
                ptsIntegral[id2] = 1;
            }
        }
    }
    // 积分区间
    for (int i = 0; i < height; ++i)
    {
        int id1 = i * width;
        for (int j = 1; j < width; ++j)
        {
            int id2 = id1 + j;
            integral[id2] += integral[id2 - 1];
            ptsIntegral[id2] += ptsIntegral[id2 - 1];
        }
    }
    for (int i = 1; i < height; ++i)
    {
        int id1 = i * width;
        for (int j = 0; j < width; ++j)
        {
            int id2 = id1 + j;
            integral[id2] += integral[id2 - width];
            ptsIntegral[id2] += ptsIntegral[id2 - width];
        }
    }
    int wnd;
    double dWnd = 2;
    while (dWnd > 1)
    {
        wnd = int(dWnd);
        dWnd /= 2;
        for (int i = 0; i < height; ++i)
        {
            int id1 = i * width;
            for (int j = 0; j < width; ++j)
            {
                int id2 = id1 + j;
                int left = j - wnd - 1;
                int right = j + wnd;
                int top = i - wnd - 1;
                int bot = i + wnd;
                left = max(0, left);
                right = min(right, width - 1);
                top = max(0, top);
                bot = min(bot, height - 1);
                int dx = right - left;
                int dy = (bot - top) * width;
                int idLeftTop = top * width + left;
                int idRightTop = idLeftTop + dx;
                int idLeftBot = idLeftTop + dy;
                int idRightBot = idLeftBot + dx;
                int ptsCnt = ptsIntegral[idRightBot] + ptsIntegral[idLeftTop] - (ptsIntegral[idLeftBot] + ptsIntegral[idRightTop]);
                double sumGray = integral[idRightBot] + integral[idLeftTop] - (integral[idLeftBot] + integral[idRightTop]);
                if (ptsCnt <= 0)
                {
                    continue;
                }
                data[id2] = float(sumGray / ptsCnt);
            }
        }![微信截图_20180918210755](E:\学习\深度学习\活体检测\双目摄像头\因特尔测试\display_results\微信截图_20180918210755.png)
    return depth;
}

改进效果

这里写图片描述

图4 原始图片(Right) 视差图 视差图填充之后

在这里插入图片描述

图5 原始图片(Right) 视差图 视差图填充后

在这里插入图片描述

图6 视差图彩色图 视差图填充后的彩色图

通过实验发现,改进后的算法比原来的效果要好不少,例如图6中填充后的视差彩色图的噪声明显比没有填充的视差图少很多。说明改进之后还是很有效的。

四、总结

​ 不管是传统方法还是深度学习的方法进行深度估计都有各自的优点,但是我更看好应用深度学习的方法。因为深度学习的方法可以学习到更多的特征,不仅仅是多尺度的特征还可以是多层次的特征。目前在自动驾驶领域应用的也多数是深度学习的方法进行深度估计,因为效果明显优于传统的方法。

##参考文献:

https://www.cnblogs.com/polly333/p/5130375.html
https://www.cnblogs.com/riddick/p/8486223.html?utm_source=debugrun&utm_medium=referral
Chang, Jia-Ren, and Yong-Sheng Chen. “Pyramid Stereo Matching Network.” Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2018.
Fu, Huan, et al. “Deep Ordinal Regression Network for Monocular Depth Estimation.” Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2018.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于OpenCV的双目深度估计实现与改进 的相关文章

  • C++中struct的使用

    C 43 43 语言继承了C语言的struct xff0c 并且加以扩充 在C语言中struct是只能定义数据成员 xff0c 而不能定义成员函数的 而在C 43 43 中 xff0c struct类似于class xff0c 在其中既可以
  • Windows与Linux之间互传文件的方法

    以下方法均是以Windows为操作机 xff1a 1 通过WinSCP WinSCP是一款开源的SFTP客户端 xff0c 运行于Windows系统下 xff0c 遵照GPL发布 WinSCP除了SFTP xff0c 还支持SSH SCP
  • 非对称加密算法RSA公钥私钥的模数和指数提取方法

    生成非对称加密算法RSA公钥 私钥的方法 xff1a 1 通过OpenSSL库生成 xff0c 可参考 https github com fengbingchun OpenSSL Test blob master demo OpenSSL
  • Base64简介

    Base64是一种基于64个可打印字符来表示二进制数据的表示方法 由于2 6 61 64 xff0c 所以每6个比特为一个单元 xff0c 对应某个可打印字符 3个字节有24个比特 xff0c 对应于4个Base64单元 xff0c 即3个
  • HTTP协议简介

    HTTP HyperText Transfer Protocol 超文本传输协议 xff1a 是一种用于分布式 协作式和超媒体信息系统的应用层协议 HTTP是万维网的数据通信的基础 设计HTTP最初的目的是为了提供一种发布和接收HTML页面
  • HTTPS协议简介

    HTTPS HyperText Transfer Protocol Secure 超文本传输安全协议 xff1a 是一种透过计算机网络进行安全通信的传输协议 HTTPS经由HTTP进行通信 xff0c 但利用SSL TLS来加密数据包 HT
  • base64开源库介绍及使用

    网上有一些开源的base64编解码库的实现 xff0c 下面介绍几个 xff1a cppcodec是一个仅包括头文件的C 43 43 11库 xff0c 用于编解码RFC 4648中指定的base64 base64url base32 ba
  • Ubuntu下使用CMake编译OpenSSL源码操作步骤(C语言)

    OpenSSL的版本为1 0 1g xff0c 在ubuntu下通过CMake仅编译c代码不包括汇编代码 xff0c 脚本内容如下 xff1a build sh内容 xff1a bin bash real path 61 realpath
  • ImageNet图像数据集介绍

    ImageNet图像数据集始于2009年 xff0c 当时李飞飞教授等在CVPR2009上发表了一篇名为 ImageNet A Large Scale Hierarchical Image Database 的论文 xff0c 之后就是基于
  • 网络文件系统(NFS)简介

    网络文件系统 Network File System NFS 是一种分布式文件系统协议 xff0c 最初由Sun Microsystems公司开发 xff0c 并于1984年发布 其功能旨在允许客户端主机可以像访问本地存储一样通过网络访问服
  • 实时流协议(RTSP)简介

    RTSP Real Time Streaming Protocol xff0c RFC2326 xff0c 实时流传输协议 xff0c 是TCP IP协议体系中的一个应用层协议 xff0c 由哥伦比亚大学 网景 Netscape 和Real
  • 远程过程调用RPC简介

    RPC Remote Procedure Call 远程过程调用 xff1a 是一种通过网络从远程计算机程序上请求服务 xff0c 而不需要了解底层网络技术的思想 RPC是一种技术思想而非一种规范或协议 xff0c 常见RPC技术和框架有
  • C语言中头文件包含的处理原则

    很多事不深入以为自己懂了 xff0c 但真正用到项目上 xff0c 才发现了问题 曾以为自己写C语言已经轻车熟路了 xff0c 特别是对软件文件的工程管理上 xff0c 因为心里对自己的代码编写风格还是有自信的 毕竟刚毕业时老大对我最初的训
  • Unity3D物体自动躲避障碍物

    Unity版本 2017 4 4f1 基本思路 物体向前发射一个射线 xff0c 检测到碰撞后 xff0c 根据碰撞信息选择新的方向 最终结果如下 具体实现步骤代码 1 物体添加胶囊体碰撞组件CapsuleCollider 通过发射虚拟胶囊
  • nginx的请求接收流程(二)

    在ngx http process request line函数中 xff0c 解析完请求行之后 xff0c 如果请求行的uri里面包含了域名部分 xff0c 则将其保持在请求结构的headers in成员的server字段 xff0c h
  • C++学习_udp协议(socket)的封装

    C 43 43 学习笔记 xff0c UDP socket 协议的封装实现 1 配置QT下的pro文件 1 TEMPLATE 61 app 2 CONFIG 43 61 console 3 CONFIG 61 app bundle 4 CO
  • 西门子PLC学习笔记一(S7-300简介)

    使用了Step7有几天了 xff0c 现在系统的学习一下 xff0c 现记录一下学习的内容 1 S7 300硬件结构 S7 300或者S7 400的PLC是模块式的PLC xff0c 各种模块式相互独立的 xff0c 分别安装在机架上 硬件
  • 外网访问树莓派服务器(自购域名+Sakura Frp内网穿透)

    首先在域名代理商 xff08 如腾讯云 xff09 购买一个喜欢的域名 注册Sakura Frp账号 xff0c 进入管理面板后 xff0c 创建隧道 xff0c 服务器选择可建站类型的 xff0c 隧道类型为HTTP xff0c 本地地址
  • Python删除全部已安装的pip包

    pip freeze span class token operator gt span allpackages txt pip uninstall r allpackages txt y
  • Vue父组件主动获取子组件的值和方法

    在父组件使用子组件的代码中 xff0c 为子组件加上ref 61 34 name 自己设置一个名称 34 然后在代码中 xff1a span class token keyword this span span class token pu

随机推荐

  • 动态规划详解

    动态规划的入门 xff0c 一般是从斐波拉契数列开始 该数列由0和1开始 xff0c 后面的每一项数字都是前面两项数字的和 xff0c 定义如下 xff1a F 0 61 0 F 1 61 1 F n 61 F n 1 43 F n 2 其
  • Concept Whitening(for Interpretable Image Recognition)

    和BatchNorm相比有很多优点 xff0c 并且可以直接替换BatchNorm 有更好的interpretability xff08 可解释性 xff09 xff0c 可以可视化得解释神经网络层的含义 xff08 这是最突出的特点 xf
  • homebrew安装、换源

    首先确认你的Mac已经安装了命令行工具 xff1a Command Line Tools CLT for Xcode 打开终端 xff0c 输入git version xff0c 命令 xff0c 如果没有安装 xff0c macOS会跳出
  • macOS查看磁盘读写数据总量、磁盘健康、磁盘启动次数等信息

    首先确保安装了homebrew xff0c 如果没有安装可以按照这篇文章的教程安装 xff1a homebrew安装 换源 然后安装磁盘工具smartmontools brew span class token function insta
  • 30天自制C++服务器

    30天自制C 43 43 服务器 如访问慢 xff0c 可以到这里观看 xff1a csblog 教程的配套网络库 xff1a pine xff0c star and fork 先说结论 xff1a 不管使用什么语言 xff0c 一切后台开
  • 【C语言】之实现 printf 函数功能

    span class token comment 文件名 myPrintf c 文件功能 使用putchar函数模拟printf函数的功能 编辑人 王廷云 编辑时间 2017 10 14 修改时间 2018 1 12 span span c
  • 30天自制C++服务器day05-epoll高级用法-Channel登场

    在上一天 xff0c 我们已经完整地开发了一个echo服务器 xff0c 并且引入面向对象编程的思想 xff0c 初步封装了Socket InetAddress和Epoll xff0c 大大精简了主程序 xff0c 隐藏了底层语言实现细节
  • EasyVim:简单强大的VIM配置

    EasyVim 简单易用的vim配置 xff0c 熟练后可大大提高开发效率 xff08 VS Code的两倍以上 xff09 安装 安装过程需要从github下载很多插件 xff0c 国内尽量挂VPN span class token fu
  • README

    EasyVim 简单易用的vim配置 xff0c 熟练后可大大提高开发效率 xff08 VS Code的两倍以上 xff09 安装 安装过程需要从github下载很多插件 xff0c 国内尽量挂VPN span class token fu
  • C语言static和inline

    C语言static和inline C语言的static和inline的用法看似简单 但有很多坑 xff0c 一些编程老手也会犯错误 xff0c 网上也几乎很少有教程能讲清楚 下面先说结论 xff0c 再进行推导 xff1a 头文件里不能单独
  • STC51单片机学习笔记4——stc12c56 串口

    stc12c56 串口 xff08 没有用独立波特率发生器 xff0c 用T1不分频 中断式接受与发送 xff09 烧写程序时 xff0c 一定要选用外部晶振 xff08 烧写软件默认为内部晶振 xff08 5M 6M xff09 xff0
  • 如何直接使用别人的conda环境(免安装)

    如何直接使用别人的conda环境 xff08 免安装 xff09 1 复制conda文件夹2 修改配置文件3 修改环境路径和包路径4 修改环境路径和包路径 有时候为了更加方便 xff0c 可以直接使用其他用户的环境 xff0c 而不是自己重
  • 元组,字典,列表排序

    经常需要对元组或者字典等序列按照特定的规则进行排序 xff0c 如按照年龄进行排序 gt gt gt student tuples 61 39 john 39 39 A 39 15 39 jane 39 39 B 39 12 39 dave
  • Enable VT-x in your BIOS security settings (refer to documentation for your computer)

    创建一个安卓模拟器的时候无法运行 提示为 Intel HAXM 要求运行AVD 但是VT x 没有被允许 意思就是说主机支持VT x xff0c 但是处于未开启状态 你需要进入BOIS中进行设置 BOIS出现Lenovo时按F2进入 选择S
  • numpy数组的操作取前行和取列

    这个数组跟MATLAB简直不要太像 首先得导包 xff0c from numpy import 如果你要取前几行 a 61 c 0 3 前0 1 2行 b 61 c 0 2 4 第0行的第2和第3列不包括第4列 xff0c 因为列下标也是从
  • CMake官方教程

    很好的一个官方教程翻译文档 CMake简介 CMake是一个跨平台的 开源的构建工具 cmake是makefile的上层工具 xff0c 它们的目的正是为了产生可移植的makefile xff0c 并简化自己动手写makefile时的巨大工
  • TeamTalk HttpParser详解

    1 简介 TeamTalk http解析实际上是利用了ngnix的http parse解析库 2 HTTP简介 请求报文 参考图解HTTP 上野宣 响应报文 参考图解HTTP 上野宣 URI格式 参考图解HTTP 上野宣 3 ngnix h
  • MATLAB随机生成大小也是随机的矩形(地形图一)

    有一个需求需要要生成地貌一样的随机地形图 xff0c 首先我通过在固定大小的矩形面板上生成多个大小不一的矩形 xff0c 然后赋予每个矩形随机的高度 xff0c 然后再进行滤波得到想要的地形图 先直接贴一段代码 xff0c 看看是如何在面板
  • nvidia-smi:command not found 问题解决,Failed to initialize NVML: Driver/library version mismatch

    在装驱动之后 发现nvidia smi不能用了 于是在网上找到了解决方案 简单来看 xff0c 就两步 1 unload nvidia kernel mod 2 reload nvidia kernel mod 执行起来就是 1 sudo
  • 基于OpenCV的双目深度估计实现与改进

    双目深度估计 一 传统方法 常用的方法有SAD匹配算法 xff0c BM算法 xff0c SGBM算法 xff0c GC算法 1 1 SAD算法 SAD Sum of absolute differences 是一种图像匹配算法 xff0c