opencv学习笔记--标定与矫正

这篇博客详细记录了使用OpenCV进行相机标定的过程,通过19张不同角度的棋盘格图案,展示了标定后的图像矫正效果,使图像直线更直,改善了因镜头畸变造成的图像变形。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值