OpenCV中角点未检测到原因与FindChessboardCorners函数

本博客参考两位前辈的实验记录角点检测与FindChessboardCorners函数 和 OpenCV学习笔记(33)棋盘格角点检测练习程序,总结整理而成。

实验历程:

我在前几天的实验中,总是检测不到角点,很郁闷OpenCV中角点未检测到原因与FindChessboardCorners函数_第1张图片。来来回回测了七八组数据,都没有第一次测量的那种效果。因为标定板的原因,要贴掉一部分的标定板才可以使用。第一次做的实验图片有点暗,所以想把图片再重新拍一下,就随便贴了一下,这一随便拍就出现问题了,导致角点提取不出来,然后又以为是曝光问题,图片太暗了,导致图片角点提取不出来,又去调整曝光,拍了几组照片还是找不到角点,后来感觉是透明胶带的问题,改用纸胶带,用纸胶带可以去除透明胶带的一些问题,比如透明胶带放时间长了,拉出来透明胶带边缘有些黑边,也会影响后面的角点提取,用新的透明胶带,好好贴,应该也没啥问题。纸透明一点不会影响角点的提取,只要被纸覆盖住了,基本就不会被检测到角点。下面是我实验中因为胶带的原因检测不到的角点实验结果输出图:

透明胶带贴到内角点上,影响角点的提取

结合上面实验阐述——

反思实验拍照和贴纸注意事项:

  • 如果因为学校的标定板,不适用OpenCV算法,就需要贴掉一部分来使用,毕竟买一块新的精度高点的标定板代价还是很大的,能用学校已经有的,尽量利用已经有的资源。
  • pattern_size参数传递内点数,内点是黑色方块相互连通的位置。为了便于辨识方向,每行每列对应的角点数不能相同 。如果行列数相同,那么函数每次画出来的角点起始位置会变化,不利于标定。 
  • 要学会将能提取出来角点在图片上显示出来,这样有利于找到原因,而不是去盲目的去猜测原因是啥,在这要特别感谢OpenCV学习笔记(33)棋盘格角点检测练习程序这位博主的博客。
  • 在拍摄图片的时候应注意减少干扰,例如灯光、背景、自然光等。
  • 如果需要贴纸的话,可以选择纸胶带减少反光。
  • 如果不需要贴纸,在将打印的棋盘格贴在平整的板子上时,透明胶带不要贴到内角点上,不然可能影响到角点检测,如上图中我提取不到完整的角点以及下面的原图与运行结果图中的图2。
  • 提取不到角点,和贴纸的厚度没啥关系。正常的A4纸放上去,就算能看到里面的格子的影子,但它格子的边缘,你可以试试苗一下,根本苗不清楚的,所以FindChessboardCorners函数应该也会忽略它,我猜是这样的。哈哈哈。你也可以这样想,普通的透明胶带都可以影响它提取角点,那可是透明的呀,更何况纸都把角点覆盖住了,看的非常模糊了。所以贴上的纸不会因为角点行数和列数不对的原因影响角点提取。
  • 试验表明,棋盘图像不能收到干扰,换言之就是不能干扰到程序判定棋盘内角点的Size,否则检测失败。具体参见findChessboardCorners函数学习笔记。

目的:

在研究坐标映射的相关问题时,遇到棋盘坐标匹配出错的问题。其中涉及到一个关键函数FindChessboardCorners。以下将对其做一定的介绍和分析。

函数介绍:

FindChessboardCorners是opencv的一个函数,可以用来寻找棋盘图的内角点位置。

OpenCV中角点未检测到原因与FindChessboardCorners函数_第2张图片

 

函数形式

int cvFindChessboardCorners( const void* image, CvSize pattern_size, CvPoint2D32f* corners, int* corner_count = NULL, int flags = CV_CALIB_CB_ADAPTIVE_THRESH );

参数说明

  • Image:     输入的棋盘图,必须是8位的灰度或者彩色图像。
  • pattern_size:    棋盘图中每行和每列角点的个数。
  • Corners:     检测到的角点
  • corner_count:     输出,角点的个数。如果不是NULL,函数将检测到的角点的个数存储于此变量。
  • Flags:    各种操作标志,可以是0或者下面值的组合:
    • CV_CALIB_CB_ADAPTIVE_THRESH - 使用自适应阈值(通过平均图像亮度计算得到)将图像转换为黑白图,而不是一个固定的阈值。
    • CV_CALIB_CB_NORMALIZE_IMAGE - 在利用固定阈值或者自适应的阈值进行二值化之前,先使用cvNormalizeHist来均衡化图像亮度。
    • CV_CALIB_CB_FILTER_QUADS - 使用其他的准则(如轮廓面积,周长,方形形状)来去除在轮廓检测阶段检测到的错误方块。

补充说明

函数cvFindChessboardCorners试图确定输入图像是否是棋盘模式,并确定角点的位置。如果所有角点都被检测到且它们都被以一定顺序排布,函数返回非零值,否则在函数不能发现所有角点或者记录它们地情况下,函数返回0。例如一个正常地棋盘图右8x8个方块和7x7个内角点,内角点是黑色方块相互联通的位置。这个函数检测到地坐标只是一个大约的值,如果要精确确定它们的位置,可以使用函数cvFindCornerSubPix。
 

函数测试:

测试图像(左)和运行结果(右)

OpenCV中角点未检测到原因与FindChessboardCorners函数_第3张图片

图像均为640*360的8*8黑白格棋盘图,7*7个内点。

  • 图1.计算机图像,成功检测出所有49个角点,顺序以行从左上到右下
  • 图2.正面实拍图像,检测出48个角点,其中正确47个,错误一个,没有标记顺序,只标记位置
  • 图3.正面实拍图像,成功检测出所有49个角点,顺序以行从左上到右下
  • 图4.侧面实拍图像,成功检测出所有49个角点,顺序以列从右上到左下
     

结果分析:

  • 1图与3图,角特性良好,正面拍摄,函数顺利找到角点位置
  • 2图中,未检测出的右上角两个角点可能是由于胶带干扰,角特征变的不明显。检测到的错误点是因为背景图像中有黑色物体,导致计算机误认为其为黑色方格。
  • 4图中,由于拍摄角度倾斜,棋盘图像发生变形,角点查找顺序发生变化。可以通过重新排列矩阵Corners的大小来得到1图与3图同样的效果

反思与函数应用注意事项:

  • pattern_size参数传递内点数,8*8的棋盘只有7*7内点。
  • 图像选取应注意减少干扰,例如光照与背景等。
  • Corners中的角点坐标顺序排列规律不一定是以行从左上到右下。使用坐标计算映射关系时应提高警惕,对坐标进行重新排列。

 

运行环境:win7 + VS2010 + OpenCV2.4.9

我是在我相机标定程序里面直接修改的,借鉴一些下面的代码和想法进行需要的修改。你们也可以根据需要进行相应的修改。

#include "opencv2/opencv.hpp"
 
#define m 9
#define n 6
 
using namespace std;
using namespace cv;
 
void main()
{
	Mat srcimage;
	Mat grayimage;
	vector corners;
	Size PatSize;
 
	PatSize.width = m;
	PatSize.height = n;
 
	srcimage = imread("a111.bmp");
	bool ret=findChessboardCorners(srcimage, PatSize, corners);
	//Mat viewGray;
	//cvtColor(srcimage, viewGray, COLOR_BGR2GRAY);
	//cornerSubPix(viewGray, corners, Size(11, 11),
	//	Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
	drawChessboardCorners(srcimage, PatSize, Mat(corners), ret);
	namedWindow("chessboard corners");
	imshow("chessboard corners", srcimage);
 
	waitKey(0);
}

运行结果:

OpenCV中角点未检测到原因与FindChessboardCorners函数_第4张图片

 

你可能感兴趣的:(opencv,C++)