opencv学习笔记--标定与矫正
素材来源于网络和程序参照《学习opencv》11-1
opencv使用的标定方法应该是张老师的,但是因为图片全是近景,效果不是很明显,只有这张图片矫正后与原图有较大变化。反正该直的直了,没弯就好
附上代码和19张不同角度拍摄棋盘图案(点我)
////////////////////////////////////////////////////////////////////////////////////
// 使用19张棋盘图案进行标定并显示棋盘图案矫正结果
////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <opencv.hpp>
using namespace cv;
using namespace std;
// 图案称
char* boardname[19] = {
"0.bmp", "1.bmp", "2.bmp", "3.bmp",
"4.bmp", "5.bmp", "6.bmp", "7.bmp",
"8.bmp", "9.bmp", "10.bmp", "11.bmp",
"12.bmp", "13.bmp", "14.bmp", "15.bmp",
"16.bmp", "17.bmp", "18.bmp"
};
int n_boards = 19; // 文件下表0-19一共19张不同角度拍摄的棋盘图案
int board_w = 12; // 每张棋盘图案有12角点数量为12行12列
int board_h = 12;
IplImage *src[19] = { nullptr }; // 原图像
IplImage *dest[19] = { nullptr }; // 矫正后的图像
int main(int argc, char* argv[])
{
int board_n = board_w * board_h; // 每张图像期望的角点数量
CvSize board_sz = cvSize(board_w, board_h);
// 申请内存
CvMat* image_points = cvCreateMat(n_boards*board_n, 2, CV_32FC1);
CvMat* object_points = cvCreateMat(n_boards*board_n, 3, CV_32FC1);
CvMat* point_counts = cvCreateMat(n_boards, 1, CV_32SC1);
CvMat* intrinsic_matrix = cvCreateMat(3, 3, CV_32FC1);
CvMat* distortion_coeffs = cvCreateMat(4, 1, CV_32FC1);
CvPoint2D32f* corners = new CvPoint2D32f[board_n];
int corner_count = 0;
int successes = 0;
int step, frame = 0;
// 计算角点
for (int ite = 0; ite < 19; ++ite)
{
src[ite] = cvLoadImage(boardname[ite], CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);
dest[ite] = cvLoadImage(boardname[ite], CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);
assert(src[ite] != nullptr);
IplImage *graysrc = cvCreateImage(cvGetSize(src[ite]), 8, 1);
cvCvtColor(src[ite], graysrc, CV_BGR2GRAY);
cvFindChessboardCorners(graysrc, cvSize(12, 12), corners, &corner_count, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);
if (corner_count == board_n)
{
// 计算亚像素级角点
cvFindCornerSubPix(graysrc,
corners,
corner_count,
cvSize(11, 11),
cvSize(-1, -1), // 精确估计
cvTermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)
);
// 保存角点数据
CV_MAT_ELEM(*point_counts, int, successes, 0) = board_n;
step = successes * board_n;
for (int i = step, j = 0; j < corner_count; ++i, ++j)
{
// 像素坐标
CV_MAT_ELEM(*image_points, float, i, 0) = corners[j].x;
CV_MAT_ELEM(*image_points, float, i, 1) = corners[j].y;
// XY平面物理坐标
CV_MAT_ELEM(*object_points, float, i, 0) = j / board_w;
CV_MAT_ELEM(*object_points, float, i, 1) = j%board_w;
CV_MAT_ELEM(*object_points, float, i, 2) = 0.0f;
}
successes++;
// 绘制角点,按任意键继续
IplImage *cpy = cvCloneImage(src[ite]);
cvDrawChessboardCorners(cpy, board_sz, corners, board_n, board_n);
cout << boardname[ite] << "检测成功!! 按任意键继续 corner_count:" << corner_count<< endl;
cvShowImage(boardname[ite], cpy);
cvWaitKey();
cvDestroyWindow(boardname[ite]);
cvReleaseImage(&graysrc);
} else{
cout << boardname[ite] << "检测失败!! 按任意键继续 corner_count:" << corner_count << endl;
cvShowImage(boardname[ite], src[ite]);
cvWaitKey();
cvDestroyWindow(boardname[ite]);
}
}
CvMat* object_points2 = cvCreateMat(successes*board_n, 3, CV_32FC1);
CvMat* image_points2 = cvCreateMat(successes*board_n, 2, CV_32FC1);
CvMat* point_counts2 = cvCreateMat(successes, 1, CV_32SC1);
for (int i = 0; i < successes*board_n; ++i){
CV_MAT_ELEM(*image_points2, float, i, 0) =
CV_MAT_ELEM(*image_points, float, i, 0);
CV_MAT_ELEM(*image_points2, float, i, 1) =
CV_MAT_ELEM(*image_points, float, i, 1);
CV_MAT_ELEM(*object_points2, float, i, 0) =
CV_MAT_ELEM(*object_points, float, i, 0);
CV_MAT_ELEM(*object_points2, float, i, 1) =
CV_MAT_ELEM(*object_points, float, i, 1);
CV_MAT_ELEM(*object_points2, float, i, 2) =
CV_MAT_ELEM(*object_points, float, i, 2);
}
for (int i = 0; i < successes; ++i){ //These are all the same number
CV_MAT_ELEM(*point_counts2, int, i, 0) =
CV_MAT_ELEM(*point_counts, int, i, 0);
}
// 焦距近似为1.f
CV_MAT_ELEM(*intrinsic_matrix, float, 0, 0) = 1.f;
CV_MAT_ELEM(*intrinsic_matrix, float, 1, 1) = 1.f;
// 标定相机
cvCalibrateCamera2(
object_points2,
image_points2,
point_counts2,
cvSize(800, 600),
intrinsic_matrix,
distortion_coeffs,
NULL, NULL, 0
);
// 打印内参
cout << "intrinsic_matrix: " << endl;
for (int row = 0; row < 3; ++row)
{
for (int col = 0; col < 3; ++col)
{
cout << CV_MAT_ELEM(*intrinsic_matrix, float, row, col) << " " << ends;
}
}cout << endl;
cout << "distortion_coeffs: " << endl;
for (int row = 0; row < 4; ++row)
{
cout << CV_MAT_ELEM(*distortion_coeffs,float, row, 0) << " / " <<ends;
}cout << endl;
// 计算矫正参数
IplImage* mapx = cvCreateImage(cvSize(800, 600), IPL_DEPTH_32F, 1);
IplImage* mapy = cvCreateImage(cvSize(800, 600), IPL_DEPTH_32F, 1);
cvInitUndistortMap( intrinsic_matrix, distortion_coeffs, mapx, mapy );
// 矫正19副图像
for (int ite = 0; ite < 19; ++ite)
{
dest[ite] = cvCloneImage(src[ite]);
cvRemap(src[ite], dest[ite], mapx, mapy);
}
// 循环展示对比图
// 任意键继续,VK_ESCP退出程序
cout << "循环展示对比图,任意键继续,VK_ESCP退出程序!!" << endl;
int showindex = 0;
cvNamedWindow("原始");
cvNamedWindow("矫正");
do {
cvShowImage("原始", src[showindex]);
cvShowImage("矫正", dest[showindex]);
++showindex; showindex %= 19;
} while ( cvWaitKey() != 27 );
cout << "标定结束" << endl;
cvWaitKey(500);
return 0;
}