OpenCV开发笔记(七十六):相机标定(一):识别棋盘并绘制角点

若该文为原创文章,转载请注明原文出处
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/136535848
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)

OpenCV开发专栏(点击传送门)

上一篇:《OpenCV开发笔记(七十五):相机标定矫正中使用remap重映射进行畸变矫正》
下一篇:持续补充中…


前言

  知道图像畸变矫映射的原理之后,那么如何得到相机的内参是矫正的第一步,内参决定了内参矩阵(中心点、焦距等),用内参矩阵才能计算出投影矩阵,从而将原本畸变的图像矫正为平面投影图像。
  本篇描述了相机成形的原理,并绘制出识别的角点。


Demo

  请添加图片描述

  请添加图片描述

  请添加图片描述


相机成形的原理

小孔成像原理

  在这里插入图片描述

  得到矩阵计算原理:
  在这里插入图片描述

  得到计算过程:
  在这里插入图片描述


相机的畸变

  相机的畸变是指相机镜头对物体所成的像相对于物体本身而言的失真程度,它是光学透镜的固有特性。畸变产生的原因主要是透镜的边缘部分和中心部分的放大倍率不一样。
畸变分为以下几类:

  • 径向畸变
  • 切向畸变
  • 薄棱镜畸变
      通常情况下,径向畸变的影响要远远大于其他畸变。畸变是不可消除的,但在实际的应用中,可以通过一些软件来进行畸变的补偿,如OpenCV、MATLAB等。

径向畸变

  主要由透镜不同部位放大倍率不同造成,它又分为枕形畸变和桶形畸变两种。枕形畸变,也称为鞍形形变,视野中边缘区域的放大率远大于光轴中心区域的放大率,常用在远摄镜头中。桶形畸变则与枕形畸变相反,视野中光轴中心区域的放大率远大于边缘区域的放大率,常出现在广角镜头和鱼眼镜头中
  在这里插入图片描述

切向畸变

  主要由透镜安装与成像平面不平行造成,类似于透视原理,如近大远小、圆变椭圆等。
  在这里插入图片描述

薄棱镜畸变

  由透镜设计缺陷和加工安装误差造成,又称为线性畸变。其影响较小,一般忽略不计。


棋牌识别步骤

步骤一:标定采集的数据图像

  采集一张棋盘图片,要确认他是可以被识别的。
  在这里插入图片描述

  读取图像,这里由于图片较大,我们重设大小为原来宽高的1/2:

    // 使用图片std::string srcFilePath = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/chessboard.png";
//    std::string srcFilePath = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/24.jpg";cv::Mat srcMat = cv::imread(srcFilePath);int chessboardColCornerCount = 6;int chessboardRowCornerCount = 9;// 步骤一:读取文件
//    cv::imshow("1", srcMat);
//    cv::waitKey(0);// 步骤二:缩放,太大了缩放下(可省略)cv::resize(srcMat, srcMat, cv::Size(srcMat.cols / 2, srcMat.rows / 2));cv::Mat srcMat2 = srcMat.clone();cv::Mat srcMat3 = srcMat.clone();
//    cv::imshow("2", srcMat);
//    cv::waitKey(0);

步骤二:图像处理,提取角点,并绘制出来

  先灰度化,然后输入预制的纵向横向角数量,使用棋盘角点函数提取角点

    // 步骤三:灰度化cv::Mat grayMat;cv::cvtColor(srcMat, grayMat, cv::COLOR_BGR2GRAY);cv::imshow("3", grayMat);
//    cv::waitKey(0);// 步骤四:检测角点std::vector<cv::Point2f> vectorPoint2fCorners;bool patternWasFound = false;patternWasFound = cv::findChessboardCorners(grayMat,cv::Size(chessboardColCornerCount, chessboardRowCornerCount),vectorPoint2fCorners,cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_FAST_CHECK | cv::CALIB_CB_NORMALIZE_IMAGE);/*enum { CALIB_CB_ADAPTIVE_THRESH = 1,    // 使用自适应阈值将图像转化成二值图像CALIB_CB_NORMALIZE_IMAGE = 2,    // 归一化图像灰度系数(用直方图均衡化或者自适应阈值)CALIB_CB_FILTER_QUADS    = 4,    // 在轮廓提取阶段,使用附加条件排除错误的假设CALIB_CB_FAST_CHECK      = 8     // 快速检测};*/cvui::printf(srcMat, 0, 0, 1.0, 0xFF0000, "found = %s", patternWasFound ? "true" : "false");cvui::printf(srcMat, 0, 24, 1.0, 0xFF0000, "count = %d", vectorPoint2fCorners.size());qDebug() << __FILE__ << __LINE__ << vectorPoint2fCorners.size();// 步骤五:绘制棋盘点cv::drawChessboardCorners(srcMat2,cv::Size(chessboardColCornerCount, chessboardRowCornerCount),vectorPoint2fCorners,patternWasFound);

步骤三:进行亚像素角点计算,进一步提取图片准确性

// 步骤六:进一步提取亚像素角点cv::TermCriteria criteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER,   // 类型30,                                   // 参数二: 最大次数0.001);                               // 参数三:迭代终止阈值/*#define CV_TERMCRIT_ITER    1                   // 终止条件为: 达到最大迭代次数终止#define CV_TERMCRIT_NUMBER  CV_TERMCRIT_ITER    //#define CV_TERMCRIT_EPS     2                   // 终止条件为: 迭代到阈值终止*/qDebug() << __FILE__ << __LINE__ << vectorPoint2fCorners.size();cv::cornerSubPix(grayMat,vectorPoint2fCorners,cv::Size(11, 11),cv::Size(-1, -1),criteria);

函数原型

findChessboardCorners:识别预制棋盘角点数量的棋盘

  OpenCV 中用于检测图像中棋盘角点的函数。

bool cv::findChessboardCorners(InputArray image,Size patternSize,OutputArray corners,int flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE)

  参数解释:

  • image:输入的图像,通常是一个灰度图像,因为角点检测在灰度空间中进行更为准确。
  • patternSize:棋盘的内角点数量,例如一个 8x6 的棋盘会有 48 个内角点,所以 patternSize 会是 Size(8, 6)。
  • corners:检测到的角点输出数组。
  • flags:不同的标志,用于指定角点检测的不同方法。可以是以下的一个或多个标志的组合:
    CALIB_CB_ADAPTIVE_THRESH:使用自适应阈值将图像转换为二值图像,而不是使用固定的全局阈值。
    CALIB_CB_NORMALIZE_IMAGE:在寻找角点之前,先对图像进行归一化,以提高鲁棒性。
    CALIB_CB_FAST_CHECK:仅检查角点候选者中的少量点,用于快速检测,但可能不如标准方法准确。

  函数返回值是一个布尔值,如果找到足够的角点以形成一个棋盘模式,则返回 true;否则返回 false。
  findChessboardCorners 函数通常用于相机标定,通过检测棋盘角点来确定图像与真实世界之间的对应关系。一旦角点被检测到,就可以使用这些点来估计相机的内参(如焦距、主点)和外参(如旋转和平移矩阵)。

drawChessboardCorners:绘制棋盘角点

  OpenCV中的一个函数,用于在检测到的棋盘角点周围绘制方框。这对于相机标定、图像对齐等应用非常有用。

void cv::drawChessboardCorners(InputOutputArray image,Size patternSize,InputArray corners,bool patternWasFound)

  参数解释:

  • image:输入的图像,通常是一个彩色图像,函数会在这个图像上绘制角点。
  • patternSize:棋盘的内角点数量,例如一个 8x6 的棋盘会有 48 个内角点,所以 patternSize 会是 Size(8, 6)。
  • corners:检测到的角点,通常是通过 findChessboardCorners 函数得到的。
  • patternWasFound:一个布尔值,表示是否找到了足够的角点来形成一个棋盘模式。如果为 true,则函数会在角点周围绘制彩色的方框;如果为 false,则只会绘制白色的方框。
    这个函数通常与 findChessboardCorners 结合使用,以检测图像中的棋盘角点,并在检测到的角点周围绘制方框。这对于视觉校准和相机标定等任务非常有用。

TermCriteria:迭代终止模板类

  TermCriteria是OpenCV中用于指定迭代算法终止条件的模板类。它取代了之前的CvTermCriteria,并且在许多OpenCV算法中作为迭代求解的结构被使用。

struct TermCriteria {  enum { COUNT=1, MAX_ITER=COUNT, EPS=2 };  TermCriteria();  TermCriteria(int type, int maxCount, double epsilon);  TermCriteria(const CvTermCriteria& criteria);  
};

  构造时需要三个参数:

  • 类型(type):它决定了迭代终止的条件。类型可以是CV_TERMCRIT_ITER、CV_TERMCRIT_EPS或CV_TERMCRIT_ITER+CV_TERMCRIT_EPS。在C++中,这些宏对应的版本分别为TermCriteria::COUNT、TermCriteria::EPS。
    CV_TERMCRIT_ITER或TermCriteria::COUNT:表示迭代终止条件为达到最大迭代次数;
    CV_TERMCRIT_EPS或TermCriteria::EPS:表示迭代到特定的阈值就终止;
    CV_TERMCRIT_ITER+CV_TERMCRIT_EPS:则表示两者都作为迭代终止条件。
  • 迭代的最大次数(maxCount):这是算法可以执行的最大迭代次数。
  • 特定的阈值(epsilon):当满足这个精确度时,迭代算法会停止。

cornerSubPix:亚像素角点提取

  OpenCV中用于精确化角点位置,其函数原型如下:

void cv::cornerSubPix(InputArray image,InputOutputArray corners,Size winSize,Size zeroZone,TermCriteria criteria);

  参数解释:

  • image:输入图像的像素矩阵,最好是8位灰度图像,这样检测效率会更高。
  • corners:初始的角点坐标向量,同时作为亚像素坐标位置的输出,因此需要是浮点型数据。
  • winSize:搜索窗口的大小,它表示的是搜索窗口的一半尺寸。
  • zeroZone:死区的一半尺寸,死区是搜索窗口内不对中央位置做求和运算的区域。这是为了避免自相关矩阵出现某些可能的奇异性。
  • criteria:角点搜索的停止条件,通常包括迭代次数、角点位置变化量或角点误差变化量等。

  cornerSubPix函数用于在初步提取的角点信息上进一步提取亚像素信息,从而提高相机标定的精度。在相机标定、目标跟踪和三维重建等应用中,精确的角点位置是非常重要的,因此cornerSubPix函数在这些领域有广泛的应用。


Demo源码

void OpenCVManager::testFindChessboardCorners()
{
#define FindChessboardCornersUseCamera 1
#if !FindChessboardCornersUseCamera// 使用图片std::string srcFilePath = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/chessboard.png";
//    std::string srcFilePath = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/24.jpg";cv::Mat srcMat = cv::imread(srcFilePath);
#else// 使用摄像头cv::VideoCapture capture;// 插入USB摄像头默认为0if(!capture.open(0)){qDebug() << __FILE__ << __LINE__  << "Failed to open camera: 0";}else{qDebug() << __FILE__ << __LINE__  << "Succeed to open camera: 0";}while(true){cv::Mat srcMat;capture >> srcMat;
#endifint chessboardColCornerCount = 6;int chessboardRowCornerCount = 9;// 步骤一:读取文件
//    cv::imshow("1", srcMat);
//    cv::waitKey(0);// 步骤二:缩放,太大了缩放下(可省略)cv::resize(srcMat, srcMat, cv::Size(srcMat.cols / 2, srcMat.rows / 2));cv::Mat srcMat2 = srcMat.clone();cv::Mat srcMat3 = srcMat.clone();
//    cv::imshow("2", srcMat);
//    cv::waitKey(0);// 步骤三:灰度化cv::Mat grayMat;cv::cvtColor(srcMat, grayMat, cv::COLOR_BGR2GRAY);cv::imshow("3", grayMat);
//    cv::waitKey(0);// 步骤四:检测角点std::vector<cv::Point2f> vectorPoint2fCorners;bool patternWasFound = false;patternWasFound = cv::findChessboardCorners(grayMat,cv::Size(chessboardColCornerCount, chessboardRowCornerCount),vectorPoint2fCorners,cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_FAST_CHECK | cv::CALIB_CB_NORMALIZE_IMAGE);/*enum { CALIB_CB_ADAPTIVE_THRESH = 1,    // 使用自适应阈值将图像转化成二值图像CALIB_CB_NORMALIZE_IMAGE = 2,    // 归一化图像灰度系数(用直方图均衡化或者自适应阈值)CALIB_CB_FILTER_QUADS    = 4,    // 在轮廓提取阶段,使用附加条件排除错误的假设CALIB_CB_FAST_CHECK      = 8     // 快速检测};*/cvui::printf(srcMat, 0, 0, 1.0, 0xFF0000, "found = %s", patternWasFound ? "true" : "false");cvui::printf(srcMat, 0, 24, 1.0, 0xFF0000, "count = %d", vectorPoint2fCorners.size());qDebug() << __FILE__ << __LINE__ << vectorPoint2fCorners.size();// 步骤五:绘制棋盘点cv::drawChessboardCorners(srcMat2,cv::Size(chessboardColCornerCount, chessboardRowCornerCount),vectorPoint2fCorners,patternWasFound);
#if FindChessboardCornersUseCameracv::imshow("0", srcMat);cv::imshow("4", srcMat2);if(!patternWasFound){cv::imshow("5", srcMat3);cv::waitKey(1);continue;}
#endif// 步骤六:进一步提取亚像素角点cv::TermCriteria criteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER,   // 类型30,                                   // 参数二: 最大次数0.001);                               // 参数三:迭代终止阈值/*#define CV_TERMCRIT_ITER    1                   // 终止条件为: 达到最大迭代次数终止#define CV_TERMCRIT_NUMBER  CV_TERMCRIT_ITER    //#define CV_TERMCRIT_EPS     2                   // 终止条件为: 迭代到阈值终止*/qDebug() << __FILE__ << __LINE__ << vectorPoint2fCorners.size();cv::cornerSubPix(grayMat,vectorPoint2fCorners,cv::Size(11, 11),cv::Size(-1, -1),criteria);// 步骤七:绘制棋盘点cv::drawChessboardCorners(srcMat3,cv::Size(chessboardColCornerCount, chessboardRowCornerCount),vectorPoint2fCorners,patternWasFound);cv::imshow("5", srcMat3);
//    cv::waitKey(0);#if FindChessboardCornersUseCameracv::waitKey(1);}
//    cv::imshow(_windowTitle.toStdString(), dstMat);
#elsecv::waitKey(0);
#endif}

对应工程模板v1.67.0

  在这里插入图片描述


入坑

入坑一:无法检测出角点

问题

  检测角点失败
  在这里插入图片描述

原因

  输入棋牌横向竖向角点的数量入函数,而不是输入行数和列数。

解决

  输入正确的横向纵向角点数量即可。
  在这里插入图片描述

入坑二:检测亚像素角点崩溃

问题

  检测亚像素角点函数崩溃
  在这里插入图片描述

原因

  输入要是灰度mat

解决

  将灰度图输入即可。


上一篇:《OpenCV开发笔记(七十五):相机标定矫正中使用remap重映射进行畸变矫正》
下一篇:持续补充中…


若该文为原创文章,转载请注明原文出处
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/136535848

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

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

相关文章

阿珊比较Vue和React:两大前端框架的较量

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【你也能从零基础学会网站开发】Web建站之HTML+CSS入门篇 常用HTML标签(3)

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01; &#x1f3c5; 欢迎评论 ❤️点赞&#x1f4ac;评论 &#x1f4c2;收藏 &#x1f4c2;加关注 HTML框架集…

Linux环境下使用interrupt方式操作UART

目录 概述 1 Linux环境下UART设备 2 轮询方式操作UART功能实现 2.1 打开串口函数&#xff1a;usr_serial_open 2.2 关闭串口函数&#xff1a; usr_serial_close 2.3 发送数据函数&#xff1a; usr_serial_sendbytes 2.4 接收数据函数&#xff1a; usr_serial_readinterr…

使用腾讯云快速搭建WordPress网站流程详解

专栏系列文章&#xff1a; WordPress建站主题美化系列教程https://blog.csdn.net/seeker1994/category_12184577.html 一文搞懂WordPress是什么&#xff1f;为什么用它建站&#xff1f;怎么安装与部署&#xff1f; 初次安装WordPress后如何进行网站设置&#xff08;主题安装、…

简站wordpress主题看上去差不多 实际大不一样

有人说简站wordpress主题&#xff0c;都差不多嘛。我表示无语。表面看上去是差不多的&#xff0c;实际的细节是不一样的。 下面以编号&#xff1a;JZP4431和编号&#xff1a;JZP4878这两个主题为例子来讲一下&#xff0c;简站wordpress主题&#xff0c;在细节方面的不一样之处…

ChatGPT/GPT4科研技术应用与AI绘图(包含Claude3、Gemini、Sora、GPTs中大模型的最新技术)

2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车…

基础数据运营 - 面经 - 自如租房

招聘要求&#xff1a; 投递时间&#xff1a; 2023.12.28 BOSS直聘 联系HR 2023.12.29 面试 面试流程&#xff1a; 自我介绍&#xff0c;正常完整表述 你能介绍一下你的实习经历吗&#xff1f;主要做了哪些工作&#xff0c;得到了哪些结论出来 一般Excel有用到过么&#x…

Java工作需求后端代码--实现树形结构

加油&#xff0c;新时代打工人&#xff01; 前端页面 带树形结构的表格 最近在新项目上加班加点&#xff0c;下面是个实现树形结构的数据表格。 需求&#xff1a; 在前端页面表格中展示成树形结构的数据。 技术&#xff1a; 后端&#xff1a;Java、Mybatis-Plus、HuTool树形的…

etcd入门指南

目录 一.etcd的介绍和发展 1.什么是etcd 2.ecsd的发展历史 3.etcd特点 4.使用场景 5.关键字 6.工作原理 7.下载地址 二.将etcd部署到linux 1.etcd安装前介绍 2.安装etcd 1. 创建并切换到下载目录 ​编辑 2.下载或者解压 3切换至etcd根目录&#xff0c;运行查看命令l…

华为OD机试 - 服务器广播 - 矩阵(Java 2024 C卷 200分)

目录 专栏导读一、题目描述二、输入描述三、输出描述1、输入2、输出3、说明 四、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷…

土地变化的“预言家”:DNDC模型在双碳背景下的应用探索

由于全球变暖、大气中温室气体浓度逐年增加等问题的出现&#xff0c;“双碳”行动特别是碳中和已经在世界范围形成广泛影响。国家领导人在多次重要会议上讲到&#xff0c;要把“双碳”纳入经济社会发展和生态文明建设整体布局。同时&#xff0c;提到要把减污降碳协同增效作为促…

定时执行专家V7.1 多国语言版本英文版发布 - TimingExecutor V7.1 English Version Release

目录 ◆ About TimingExecutor ◆ Main Frame ◆ Job Dailog ◆ Trigger Dialog ◆ Setting Dialog ◆ About Dialog ◆ Job Detail Information panel ◆ Statistics Information panel ◆ About TimingExecutor 《定时执行专家》是一款制作精良、功能强大、毫秒精度…

Spring Boot中实现图片上传功能的两种策略

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

vue页面刷新问题:返回之前打开的页面,走了create方法(解决)

vue页面刷新问题&#xff1a;返回之前打开的页面&#xff0c;走了create方法&#xff08;解决&#xff09; 直接上图&#xff0c; 我们在开发的时候经常会复制粘贴&#xff0c;导致vue文件的name没有及时修改 我们需要保证name和浏览器的地址一致&#xff0c;这样才能实现缓…

两天学会微服务网关Gateway-Gateway HelloWorld快速入门

锋哥原创的微服务网关Gateway视频教程&#xff1a; Gateway微服务网关视频教程&#xff08;无废话版&#xff09;_哔哩哔哩_bilibiliGateway微服务网关视频教程&#xff08;无废话版&#xff09;共计17条视频&#xff0c;包括&#xff1a;1_Gateway简介、2_Gateway工作原理、3…

智引未来:2024年科技革新引领工业界变革与机遇

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

上海亚商投顾:沪指冲高回落 旅游股尾盘逆市走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一市场情绪 沪指昨日冲高回落&#xff0c;深成指午后跌超1%&#xff0c;创业板指跌超2%&#xff0c;北证50指数跌逾3%。设备…

51-27 DirveVLM:自动驾驶与大型视觉语言模型的融合

本文由清华大学和理想汽车共同发布于2024年2月25日&#xff0c;论文名称DRIVEVLM: The Convergence of Autonomous Driving and Large Vision-Language Models. DriveVLM是一种新颖的自动驾驶系统&#xff0c;旨在针对场景理解挑战&#xff0c;利用最近的视觉语言模型VLM&…

spring启动时如何自定义日志实现

一、现象 最近在编写传统的springmvc项目时&#xff0c;遇到了一个问题&#xff1a;虽然在项目的web.xml中指定了log4j的日志启动监听器Log4jServletContextListener&#xff0c;且开启了日志写入文件&#xff0c;但是日志文件中只记录业务代码中我们声明了日志记录器的日志&a…

leetcode69---x 的平方根

大家好&#xff0c;我是大唐&#xff0c;刚刷完了几道经典的leetcode题&#xff0c;今天给大家分享一道leetcode上面的二分查找经典题型---x 的平方根&#xff0c;我们往下看。 题目描述 给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。 由于返回类型是整数&a…