您的位置:首页 > 理论基础

角点检测与FindChessboardCorners函数

2016-07-01 13:17 363 查看
目的:

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

函数介绍:

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



函数形式

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。

 

函数测试:

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



图像均为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中的角点坐标顺序排列规律不一定是以行从左上到右下。使用坐标计算映射关系时应提高警惕,对坐标进行重新排列。
基于VC++6.0的代码:
#include <iostream>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
using namespace std;

int main( )
{
cout<<"Draw Chess OpenCV!"<<endl;
char* filename="..//image5.jpg";
char* filename2="..//5.jpg";
IplImage* imgRGB = cvLoadImage(filename);
IplImage* imgGrey = cvLoadImage(filename,CV_LOAD_IMAGE_GRAYSCALE);

if (imgGrey==NULL){//image validation
cout<< "No valid image input."<<endl;
char c=getchar();
return 1;
}

//-------find chessboard corners--------------
int corner_row=7;//interior number of row corners.(this can be countered by fingers.)
int corner_col=7;//interior number of column corners.
int corner_n=corner_row*corner_col;
CvSize pattern_size=cvSize(corner_row,corner_col);
// CvPoint2D32f* corners=new CvPoint2D32f[corner_n];
CvPoint2D32f corners[49];
int corner_count;

int found=cvFindChessboardCorners(//returning non-zero means sucess.
imgGrey,// 8-bit single channel greyscale image.
pattern_size,//how many INTERIOR corners in each row and column of the chessboard.
corners,//an array where the corner locations can be recorded.
&corner_count,// optional, if non-NULL, its a point to an integer where the nuber of corners found can be recorded.
// CV_CALIB_CB_ADAPTIVE_THRESH|CV_CALIB_CB_FILTER_QUADS// check page 382-383.
0
);
cout<<"corner_count = "<<corner_count;
//-------Draw the corner pattern-------
cvDrawChessboardCorners(
imgRGB,
pattern_size,
corners,
corner_count,
found
);
cvSaveImage(filename2,imgRGB);
//to summary a bit of findings.
cout<<"found="<<found<<endl;
cout<<"x="<<corners[1].x;
cout<<",y="<<corners[1].y<<endl;

cvNamedWindow("Find and Draw ChessBoard", 0 );
cvShowImage( "Find and Draw ChessBoard", imgRGB );

cvWaitKey(0);

cvReleaseImage(&imgGrey);
cvReleaseImage(&imgRGB);
cvDestroyWindow("Find and Draw ChessBoard");

return 0;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息