在实际使用单目摄像头的时候,所拍摄的图像由于镜头安装工艺以及sensor本身的问题,往往存在切向畸变和径向畸变(具体原理可以查看学习OpenCV这本书)。
如上图中,左图主要是径向畸变的两种形式----呈现在图像中就是外扩和内缩。这样图像中越远离图像中心的部分畸变越严重,直观上大家就关注图像边界处的现实生活中的直线特征物体。这个是最容易判断是否存在严重径向畸变的依据。而切向畸变,老实讲,这个我在应用场景中,纯粹是靠感觉判断的。
总而言之,这些畸变对于机器视觉这一类对于精度要求较为严格的领域会造成较大误差,尤其是双目重建中。解决这一类畸变的数学原理目前常用的是张氏棋盘标定法。由于较为简单使用,被大多数人所接受,也很早录入到OpenCV中。当然在Matlab中也有相应的张氏标定法来矫正畸变。这里我们着重比较opencv最新出的SB标定法和原始的Corners标定法的区别。
/***************opencv3.4 Version*******************************/
for (int i = 1; i <= PicNum; i++)
{
string filename = "./images/right/right" + to_string(i) + ".jpg";
image = imread(filename);
vector corners;
cvtColor(image, imageGray, COLOR_BGR2GRAY);
bool found;
found = findChessboardCorners(image, boardSize, pointbuf,
CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_FILTER_QUADS);
if (found)
{
cornerSubPix(imageGray, pointbuf, Size(winSize, winSize),
Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
drawChessboardCorners(image, boardSize, Mat(corners), found);
vector< Point3f > obj;
for (int i = 0; i < boardSize.height; i++)
for (int j = 0; j < boardSize.width; j++)
obj.push_back(Point3f((float)j * square_size, (float)i * square_size, 0));
if (found)
{
cout << i << ". Found corners!" << endl;
image_points.push_back(corners);
object_points.push_back(obj);
}
}
cv::namedWindow("image", WINDOW_NORMAL);
cv::imshow("image", image);
cv::waitKey(0);
}
这是在Open3.4版本中的棋盘角点获取方法,使用的是findChessboardCorners+cornerSubPix两个函数的组合方法,下面是其提取角点的图:
最终其单目标定重投影误差为:
而在Open4.3版本中,查找角点的方法发生了改变,也就是SB标定法:
/************OpenCV4.3 Version*******************************/
for (int i = 1; i <= 18; i++)
{
string filename = "./images/right/right" + to_string(i) + ".jpg";
image = imread(filename);
vector corners;
cvtColor(image, imageGray, COLOR_BGR2GRAY);
bool found;
found = findChessboardCornersSB(image, boardSize, corners,CALIB_CB_EXHAUSTIVE | CALIB_CB_ACCURACY);
if (found)
{
drawChessboardCorners(image, boardSize, Mat(corners), found);
vector< Point3f > obj;
for (int i = 0; i < boardSize.height; i++)
for (int j = 0; j < boardSize.width; j++)
obj.push_back(Point3f((float)j * square_size, (float)i * square_size, 0));
if (found)
{
cout << i << ". Found corners!" << endl;
image_points.push_back(corners);
object_points.push_back(obj);
}
}
cv::namedWindow("image", WINDOW_NORMAL);
cv::imshow("image", image);
cv::waitKey(0);
}
上述组合函数仅仅只用了一个函数findChessboardCornersSB来代替,其效果更好了,如下:
其重投影误差为:
很明显,OpenCV4.3其提取的角点精度更高了,这也是一个大的惊喜。后续的博客中将会逐步阐述这个精度提升带来的改变。感兴趣的读者可以去尝试这个新的算法,相当不错。
下载链接https://download.csdn.net/detail/u013317903/12431482