感谢以下博客的博主!
【总】基本流程: https://blog.csdn.net/neu_chenguangq/article/details/53454512 (这是主要参考文章)
https://blog.csdn.net/ssw_1990/article/details/53216767
https://blog.csdn.net/X_SANSHAO/article/details/89920378
https://jingyan.baidu.com/article/3c48dd34d783d9e10be3582a.html
https://blog.csdn.net/itas109/article/details/81014467
世界坐标系→相机坐标系→图像坐标系→像素坐标系:https://blog.csdn.net/xueluowutong/article/details/80950915
图像的腐蚀/膨胀都是针对图像中的白色区域来说的:https://blog.csdn.net/robotkang/article/details/80782349
求亚像素角点:https://www.cnblogs.com/riddick/p/8476456.html
亚像素角点倒数第二个参数的用法:https://blog.csdn.net/holybin/article/details/41122493
求世界坐标的困惑:https://bbs.csdn.net/topics/391926793
(calibrateCamera函数:https://blog.csdn.net/dip007/article/details/51498335)(用此函数有错误,不知为何)
改用fisheye::calibrate()函数。
initUndistorRectifyMap的各参数:https://blog.csdn.net/u013341645/article/details/78710740
以下是我的程序:亲测可用
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
int main() {
Mat image1 = imread("C:\\Users\\35749\\Desktop\\1.jpg");
Mat image;
Size size(15,10);//行列的内角数
Size imsize=image1.size();
int corner_row = 15;//单独列出行的内角数,后面计算世界坐标要用
double board_size = 20.0;//每个格子的边长,单位mm
cvtColor(image1, image, CV_RGB2GRAY);
vector<Point2f> corners;
findChessboardCorners(image,size,corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE + CALIB_CB_FAST_CHECK);
TermCriteria criteria = TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 40, 0.001);//当迭代次数超过criteria.maxCount,或者角点位置变化小于criteria.epsilon时,停止迭代过程。
Size winsize(2,2),zerosize(-1,-1);
cornerSubPix(image, corners, winsize, zerosize, criteria);
drawChessboardCorners(image,size,corners,false);
vector<vector<Point2f>> image_corner;//vector<vector<Point2f>>是什么东西?
image_corner.push_back(corners);
vector<Point3f> object;
for (int j = 0; j < 150; j++)
{
object.push_back(Point3f((j % corner_row) * board_size, (j / corner_row) * board_size, 0));//corner_row为一行的角点数;board_size为每个格子的实际边长(以mm为单位)
}
vector<vector<Point3f>> object_points_seq;
object_points_seq.push_back(object);
Matx33d K;
Vec4d D;
int flag = 0;
flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
flag |= cv::fisheye::CALIB_CHECK_COND;
flag |= cv::fisheye::CALIB_FIX_SKEW;
fisheye::calibrate(object_points_seq,image_corner,imsize,K,D,noArray(),noArray(),flag);//此处用calibrateCameraSfisheye类和cv类有何不同?
Mat mapx, mapy;
Matx33d a = Matx33d::eye();
Mat dst_image(image1.size(), image1.type());
fisheye::initUndistortRectifyMap(K,D,a, K, imsize, CV_16SC2, mapx, mapy);//fisheye类和cv类有何不同?
remap(image1, dst_image, mapx, mapy, CV_INTER_LINEAR, BORDER_CONSTANT);
namedWindow("矫正图");
imshow("矫正图", dst_image);
waitKey(0);
return 0;
}
在前人基础上改的,仍有很多地方不懂,如 ① flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC是些什么东西?https://bbs.csdn.net/topics/340136339 https://docs.opencv.org/master/db/d58/group__calib3d__fisheye.html#gga4f2ffc34e07218cffdbdea315bf50b44ab42b5b79bad18428edc607c8f5a4d8db
也就是说,把flag|=……这部分的三行代码,改成 flag |= (1 << 1);
flag |= (1 << 2);
flag |= (1 << 3);
或直接写 int flag=14
也是对的。
② 为什么用fisheye:calibrate()函数可以,用calibrate()函数就不行?
③ 计算世界坐标的原理是什么?相机标定的原理是什么?最后怎么求出矫正图来的?
我只能说是东拼西凑把程序凑出来了吧……