Opencv 棋盘定位(源码调试2)

刚接触图像处理是从摄像机标定开始,一直好奇opencv程序中是怎么实现棋盘定位的。自己也曾用matlab写过摄像机标定的整个过程,在图像中检测出棋盘的位置是整个标定过程的第一步,但一直不稳定,不知道opencv中采用什么算法检测棋盘的位置。很可惜,网上基本上没有这方面的资料,在opencv原文件中的提示:The algorithms developed and implemented by Vezhnevets Vldimir    aka Dead Moroz (vvp@graphics.cs.msu.ru) See http://graphics.cs.msu.su/en/research/calibration/opencv.html for detailed information。但这个网站似乎打不开。最后终于在yahoo的邮件列表找到这个算法简单的介绍:

1. Dilation of the white squares by 1 pixel, so that the black squares don't touch (it might be the oter way, i'm not shure).
2. Thresholding with a value beneath the medium intensity 

3. Contour extraction and approximation to a rectangle. This extract the black (i suppose) squares.
4. selection of the inner corners by rejecting the points which don't belong to two extracted rectangles.

I noticed that this is not working very well for images taken using a camera with a flash, due to non uniform illumination.But i managed to extract the correct corners by running the contour extraction several times, using several different thresholds, even adaptive thresholding, different combinations of Dilate/Erode and rejecting duplicate rectangles prior to step 4.
当然,牛人觉得opencv中的算法还需要改进,我辈能够汲取opencv中营养,已十分欣喜。

粗略的懂些opencv源码编译的过程,就想看看opencv库中cvFindChessboardCorner()的源码。

工具:opencv 2.1、cmake、vs08

修改opencv安装文件中cvcalibinit.cpp文件,方便调试。把文件中

#pragmacomment(lib,"highgui210d.lib")

#defineDEBUG_CHESSBOARD

这两句的注释去掉。注意如果你用的不是highgui210.lib库,那就需要修改了。

#include". \\include\\opencv\\highgui.h"  

这句的路径改为你电脑中highgui.h所在的目录,主要原文件中这句是相对路径,如果不修该可能导致vs2008编译不通过。

 

现在来看其中的源码,源码真多,大致说明其过程-,-。

总的来说,棋盘的定位用还是图像处理中一些基本概念如直方图均衡化,图像的轮廓和棋盘图像的特点,这不像车牌定位,棋盘上的图像比车牌更有规律,只有黑白方格,棋盘所在背景也比较简单,等其他优点。

cvFindChessboardCorner(),中首先构造两个结构体:

struct CvCBQuad

{

    int count;      // Number of quad neighbors

    int group_idx;  // quad group ID

    int row,col;   // row and column of this quad

    bool ordered;   // true if corners/neighbors are ordered counter-clockwise

    float edge_len;// quad edge len, in pix^2

    // neighbors and corners are synced, i.e., neighbor 0 shares corner 0

    CvCBCorner *corners[4];// Coordinates of quad corners

    struct CvCBQuad *neighbors[4];// Pointers of quad neighbors

};

struct CvCBCorner

CvCBQuad用来存储棋盘上的方格信息,CvCBCorner用来存储棋盘方格的四个角点。CvCBQuad的neighbordors在程序中有重要的作用。

 

整个棋盘定位过程是一个循环过程,先对读入的棋盘图像直方图均衡化,接着自适应(取决于flag参数)二值化,再对二值化后的图像膨胀。为了定位的鲁棒性,自适应二值化和膨胀所采用核的大小不能是唯一的,故不断的循环用不同的参数用对棋盘图像处理,膨胀所采用核的大小逐渐变大。

在每次的循环过程都需要,经过以下步骤。

1、在二值化后图像外围画一白色的矩形框(方便轮廓提取),然后进行轮廓提取cvFindContours。经过膨胀后的二值图像,每个黑色的方格已经被分开,轮廓提取后可以得到每个方格的轮廓,当然还有很多干扰轮廓。对轮廓进行多边形拟合cvApproxPoly,排除不是矩形的轮廓,利用矩形的其他性质,再排除一些干扰轮廓。这些工作主要由icvGenerateQuads函数完成。

2、寻找每个方格的相邻方格,并记相邻方格的个数,连同相邻方格的信息存在相应CvCBQuad结构体中。二值图像在膨胀后原本相邻的方格,分开了,原来相连部分有一个公共点,现在分开变成了两个点。找到相邻的方格之后,计算出原来的公共点,用公共点替代膨胀后分开的点。这主要由icvFindQuadNeighborhors函数完成。

3、对所有“方格”(包括被误判的)分类,分类的原则是类内所有方格是相邻的。由icvFindConnectedQuads函数完成。

4、根据已知所求的角点个数,判别每个类中方格是否为所求的棋盘方格,并对棋盘方格排序,即该方格位于哪行那列。在这个过程中,可以添加每类方格总缺少的方格,也可以删除每类方格中多余的方格。icvOrderFoundConnetedQuads函数完成该过程。

5、icvCleanFoundConnectedQuads函数、icvCheckQuadGroup函数根据已知棋盘的方格个数(由棋盘的角点数计算出来)确认方格位置及个数是否正确,并确定粗略强角点的位置(两个方格的相连位置)。icvCheckBoardMonotony再次检验棋盘方格是否提取正确。

6、以上如果有一步所有方格都不符合要求,则进入一个新的循环。若循环结束,还尚未找到符合要求的方格,则棋盘定位失败,退出函数。

最后,cvFindCornerSubpix()根据上步的强角点位置,确定强角点的精确位置。

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
您可以使用OpenCV提供的相机标定示例程序来进行圆形棋盘相机标定。在文件夹中,您可以找到名为camera_calibration.cpp的源代码文件,其中包含了OpenCV相机标定的实例程序。您还需要修改in_VID5和VID5两个XML文档来设置标定参数和标定图片路径。此外,OpenCV的相机标定程序还支持Checkerboard(棋盘)、Symmetric Circle Grid(对称圆网)和Asymmetric Circle Grid(非对称圆网)三种标定图案。您可以根据需要选择合适的标定图案进行相机标定。\[1\] 如果您需要生成一张黑白对称圆点的图像作为标定图案,您可以使用以下代码。这段代码使用了OpenCV库来生成一张黑白对称圆点的图像,您可以根据需要修改圆点个数、图片分辨率和图片式。\[3\] ```cpp #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace cv; using namespace std; #define WINDOW_WIDTH 1200 //定义窗口大小的宏 #define WINDOW_LENTH 1700 #define WINDOW_NAME1 "【绘制图1】" //为窗口标题定义的宏 #define WINDOW_NAME2 "【绘制图2】" //为窗口标题定义的宏 void drawFilledCircle(Mat img, Point center) { int thickness = -1; int lineType = 8; circle(img, center, WINDOW_WIDTH / 12, Scalar(0, 0, 0), thickness, lineType); } int main() { Mat atomImage(WINDOW_WIDTH, WINDOW_LENTH, CV_8UC3, Scalar(255, 255, 255)); for (int i = 180 + WINDOW_WIDTH / 12; i < WINDOW_LENTH; i = i + WINDOW_WIDTH / 4) { for (int j = 50 + WINDOW_WIDTH / 12; j < WINDOW_WIDTH; j = j + WINDOW_WIDTH / 4) { drawFilledCircle(atomImage, cv::Point(i, j)); } } imwrite("symmetricCirclesGridPattern.png", atomImage); imshow(WINDOW_NAME1, atomImage); waitKey(0); return(0); } ``` 这段代码将生成一张名为symmetricCirclesGridPattern.png的黑白对称圆点图像,并显示在窗口中。您可以根据需要修改窗口大小和窗口标题。\[3\] #### 引用[.reference_title] - *1* *3* [MATLAB/OpenCV--基于棋盘/对称圆点/非对称圆点--相机标定教程](https://blog.csdn.net/m0_51729073/article/details/121268125)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [C++ OpenCV相机标定---实心圆点、棋盘](https://blog.csdn.net/huhu7777/article/details/126927710)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值