首页 > 代码库 > 对摄像头进行标定
对摄像头进行标定
转自 http://wiki.opencv.org.cn/index.php/%E6%91%84%E5%83%8F%E5%A4%B4%E6%A0%87%E5%AE%9A
摄像头标定
目录[隐藏]
|
[编辑]
标定原理介绍
- 摄像机小孔模型 Cv照相机定标和三维重建#针孔相机模型和变形
[编辑]
标定程序1(opencv自带的示例程序)
[编辑]
简介
读者可以直接使用Opencv自带的摄像机标定示例程序,该程序位于 “\OpenCV\samples\c目录下的calibration.cpp”,程序的输入支持直接从USB摄像机读取图片标定,或者读取avi文件或者已经存放于电脑上图片进行标定。
[编辑]
使用说明
编译运行程序,如果未设置任何命令行参数,则程序会有提示,告诉你应该在你编译出来的程序添加必要的命令行,比如你的程序是calibration.exe(以windows操作系统为例)。则你可以添加如下命令行(以下加粗的字体所示):
calibration -w 6 -h 8 -s 2 -n 10 -o camera.yml -op -oe [<list_of_views.txt>]
[编辑]
调用命令行和参数介绍
Usage: calibration
-w <board_width> # 图片某一维方向上的交点个数 -h <board_height> # 图片另一维上的交点个数 [-n <number_of_frames>] # 标定用的图片帧数 # (if not specified, it will be set to the number # of board views actually available) [-d <delay>] # a minimum delay in ms between subsequent attempts to capture a next view # (used only for video capturing) [-s <square_size>] # square size in some user-defined units (1 by default) [-o <out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters [-op] # write detected feature points [-oe] # write extrinsic parameters [-zt] # assume zero tangential distortion [-a <aspect_ratio>] # fix aspect ratio (fx/fy) [-p] # fix the principal point at the center [-v] # flip the captured images around the horizontal axis [input_data] # 输入数据,是下面三种之中的一种: # - 指定的包含图片列表的txt文件 # - name of video file with a video of the board # if input_data not specified, a live view from the camera is used
标定图片示例
上图中,横向和纵向分别为9个交点和6个交点,对应上面的命令行的命令参数应该为: -w 9 -h 6。
- 经多次使用发现,不指定 -p参数时计算的结果误差较大,主要表现在对u0,v0的估计误差较大,因此建议使用时加上-p参数
[编辑]
list_of_views.txt
该txt文件表示的是你在电脑上面需要用以标定的图片列表。
view000.pngview001.png#view002.pngview003.pngview010.pngone_extra_view.jpg
上面的例子中,前面加“井号”的图片被忽略。
- 在windows的命令行中,有一种简便的办法来产生此txt文件。在CMD窗口中输入如下命令(假设当前目录里面的所有jpg文件都用作标定,并且生成的文件为a.txt)。
dir *.jpg /B >> a.txt
[编辑]
输入为摄像机或者avi文件时
"When the live video from camera is used as input, the following hot-keys may be used:\n" " <ESC>, ‘q‘ - quit the program\n" " ‘g‘ - start capturing images\n" " ‘u‘ - switch undistortion on/off\n";
[编辑]
代码
请直接复制 calibration.cpp 中的相关代码。
[编辑]
标定程序2
OPENCV没有提供完整的示例,自己整理了一下,贴出来记录。
- 首先自制一张标定图片,用A4纸打印出来,设定距离,再设定标定棋盘的格子数目,如8×6,以下是我做的图片8×8
- 然后利用cvFindChessboardCorners找到棋盘在摄像头中的2D位置,这里cvFindChessboardCorners不太稳定,有时不能工作,也许需要图像增强处理。
- 计算实际的距离,应该是3D的距离。我设定为21.6毫米,既在A4纸上为两厘米。
- 再用cvCalibrateCamera2计算内参,
- 最后用cvUndistort2纠正图像的变形。
结果如下:
[编辑]
代码
代码下载
具体的函数使用,请参考Cv照相机定标和三维重建#照相机定标
#include "stdafx.h"#include <stdio.h>#include <stdlib.h>#include <string.h>// OpenCV#include <cxcore.h>#include <cv.h>#include <highgui.h>#include <cvaux.h> void InitCorners3D(CvMat *Corners3D, CvSize ChessBoardSize, int Nimages, float SquareSize);void makeChessBoard();int myFindChessboardCorners( const void* image, CvSize pattern_size, CvPoint2D32f* corners, int* corner_count=NULL, int flags=CV_CALIB_CB_ADAPTIVE_THRESH ); inline int drawCorssMark(IplImage *dst,CvPoint pt)/************************************************* Function: main_loop Description: 绘制一个十字标记 Calls: Called By: Input: RGB image, pt Output: Return: Others: 需要检查坐标是否越界 to do list*************************************************/{ const int cross_len = 4; CvPoint pt1,pt2,pt3,pt4; pt1.x = pt.x; pt1.y = pt.y - cross_len; pt2.x = pt.x; pt2.y = pt.y + cross_len; pt3.x = pt.x - cross_len; pt3.y = pt.y; pt4.x = pt.x + cross_len; pt4.y = pt.y; cvLine(dst,pt1,pt2,CV_RGB(0,255,0),2,CV_AA, 0 ); cvLine(dst,pt3,pt4,CV_RGB(0,255,0),2,CV_AA, 0 ); return 0;} /* declarations for OpenCV */IplImage *current_frame_rgb,grid;IplImage *current_frame_gray;IplImage *chessBoard_Img; int Thresholdness = 120; int image_width = 320;int image_height = 240; bool verbose = false; const int ChessBoardSize_w = 7;const int ChessBoardSize_h = 7;// Calibration stuffbool calibration_done = false;const CvSize ChessBoardSize = cvSize(ChessBoardSize_w,ChessBoardSize_h);//float SquareWidth = 21.6f; //实际距离 毫米单位 在A4纸上为两厘米float SquareWidth = 17; //投影实际距离 毫米单位 200 const int NPoints = ChessBoardSize_w*ChessBoardSize_h;const int NImages = 20; //Number of images to collect CvPoint2D32f corners[NPoints*NImages];int corner_count[NImages] = {0};int captured_frames = 0; CvMat *intrinsics;CvMat *distortion_coeff;CvMat *rotation_vectors;CvMat *translation_vectors;CvMat *object_points;CvMat *point_counts;CvMat *image_points;int find_corners_result =0 ; void on_mouse( int event, int x, int y, int flags, void* param ){ if( event == CV_EVENT_LBUTTONDOWN ) { //calibration_done = true; }} int main(int argc, char *argv[]){ CvFont font; cvInitFont( &font, CV_FONT_VECTOR0,5, 5, 0, 7, 8); intrinsics = cvCreateMat(3,3,CV_32FC1); distortion_coeff = cvCreateMat(1,4,CV_32FC1); rotation_vectors = cvCreateMat(NImages,3,CV_32FC1); translation_vectors = cvCreateMat(NImages,3,CV_32FC1); point_counts = cvCreateMat(NImages,1,CV_32SC1); object_points = cvCreateMat(NImages*NPoints,3,CV_32FC1); image_points = cvCreateMat(NImages*NPoints,2,CV_32FC1); // Function to fill in the real-world points of the checkerboard InitCorners3D(object_points, ChessBoardSize, NImages, SquareWidth); CvCapture* capture = 0; if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - ‘0‘ : 0 ); else if( argc == 2 ) capture = cvCaptureFromAVI( argv[1] ); if( !capture ) { fprintf(stderr,"Could not initialize capturing...\n"); return -1; } // Initialize all of the IplImage structures current_frame_rgb = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3); IplImage *current_frame_rgb2 = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3); current_frame_gray = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 1); chessBoard_Img = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3); current_frame_rgb2->origin = chessBoard_Img->origin = current_frame_gray->origin = current_frame_rgb->origin = 1; makeChessBoard(); cvNamedWindow( "result", 0); cvNamedWindow( "Window 0", 0); cvNamedWindow( "grid", 0); cvMoveWindow( "grid", 100,100); cvSetMouseCallback( "Window 0", on_mouse, 0 ); cvCreateTrackbar("Thresholdness","Window 0",&Thresholdness, 255,0); while (!calibration_done) { while (captured_frames < NImages) { current_frame_rgb = cvQueryFrame( capture ); //current_frame_rgb = cvLoadImage( "c:\\BoardStereoL3.jpg" ); //cvCopy(chessBoard_Img,current_frame_rgb); if( !current_frame_rgb ) break; cvCopy(current_frame_rgb,current_frame_rgb2); cvCvtColor(current_frame_rgb, current_frame_gray, CV_BGR2GRAY); //cvThreshold(current_frame_gray,current_frame_gray,Thresholdness,255,CV_THRESH_BINARY); //cvThreshold(current_frame_gray,current_frame_gray,150,255,CV_THRESH_BINARY_INV); /* int pos = 1; IplConvKernel* element = 0; const int element_shape = CV_SHAPE_ELLIPSE; element = cvCreateStructuringElementEx( pos*2+1, pos*2+1, pos, pos, element_shape, 0 ); cvDilate(current_frame_gray,current_frame_gray,element,1); cvErode(current_frame_gray,current_frame_gray,element,1); cvReleaseStructuringElement(&element);*/ find_corners_result = cvFindChessboardCorners(current_frame_gray, ChessBoardSize, &corners[captured_frames*NPoints], &corner_count[captured_frames], 0); cvDrawChessboardCorners(current_frame_rgb2, ChessBoardSize, &corners[captured_frames*NPoints], NPoints, find_corners_result); cvShowImage("Window 0",current_frame_rgb2); cvShowImage("grid",chessBoard_Img); if(find_corners_result==1) { cvWaitKey(2000); cvSaveImage("c:\\hardyinCV.jpg",current_frame_rgb2); captured_frames++; } //cvShowImage("result",current_frame_gray); intrinsics->data.fl[0] = 256.8093262; //fx intrinsics->data.fl[2] = 160.2826538; //cx intrinsics->data.fl[4] = 254.7511139; //fy intrinsics->data.fl[5] = 127.6264572; //cy intrinsics->data.fl[1] = 0; intrinsics->data.fl[3] = 0; intrinsics->data.fl[6] = 0; intrinsics->data.fl[7] = 0; intrinsics->data.fl[8] = 1; distortion_coeff->data.fl[0] = -0.193740; //k1 distortion_coeff->data.fl[1] = -0.378588; //k2 distortion_coeff->data.fl[2] = 0.028980; //p1 distortion_coeff->data.fl[3] = 0.008136; //p2 cvWaitKey(40); find_corners_result = 0; } //if (find_corners_result !=0) { printf("\n"); cvSetData( image_points, corners, sizeof(CvPoint2D32f)); cvSetData( point_counts, &corner_count, sizeof(int)); cvCalibrateCamera2( object_points, image_points, point_counts, cvSize(image_width,image_height), intrinsics, distortion_coeff, rotation_vectors, translation_vectors, 0); // [fx 0 cx; 0 fy cy; 0 0 1]. cvUndistort2(current_frame_rgb,current_frame_rgb,intrinsics,distortion_coeff); cvShowImage("result",current_frame_rgb); float intr[3][3] = {0.0}; float dist[4] = {0.0}; float tranv[3] = {0.0}; float rotv[3] = {0.0}; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 3; j++) { intr[i][j] = ((float*)(intrinsics->data.ptr + intrinsics->step*i))[j]; } dist[i] = ((float*)(distortion_coeff->data.ptr))[i]; tranv[i] = ((float*)(translation_vectors->data.ptr))[i]; rotv[i] = ((float*)(rotation_vectors->data.ptr))[i]; } dist[3] = ((float*)(distortion_coeff->data.ptr))[3]; printf("-----------------------------------------\n"); printf("INTRINSIC MATRIX: \n"); printf("[ %6.4f %6.4f %6.4f ] \n", intr[0][0], intr[0][1], intr[0][2]); printf("[ %6.4f %6.4f %6.4f ] \n", intr[1][0], intr[1][1], intr[1][2]); printf("[ %6.4f %6.4f %6.4f ] \n", intr[2][0], intr[2][1], intr[2][2]); printf("-----------------------------------------\n"); printf("DISTORTION VECTOR: \n"); printf("[ %6.4f %6.4f %6.4f %6.4f ] \n", dist[0], dist[1], dist[2], dist[3]); printf("-----------------------------------------\n"); printf("ROTATION VECTOR: \n"); printf("[ %6.4f %6.4f %6.4f ] \n", rotv[0], rotv[1], rotv[2]); printf("TRANSLATION VECTOR: \n"); printf("[ %6.4f %6.4f %6.4f ] \n", tranv[0], tranv[1], tranv[2]); printf("-----------------------------------------\n"); cvWaitKey(0); calibration_done = true; } } exit(0); cvDestroyAllWindows();} void InitCorners3D(CvMat *Corners3D, CvSize ChessBoardSize, int NImages, float SquareSize){ int CurrentImage = 0; int CurrentRow = 0; int CurrentColumn = 0; int NPoints = ChessBoardSize.height*ChessBoardSize.width; float * temppoints = new float[NImages*NPoints*3]; // for now, assuming we‘re row-scanning for (CurrentImage = 0 ; CurrentImage < NImages ; CurrentImage++) { for (CurrentRow = 0; CurrentRow < ChessBoardSize.height; CurrentRow++) { for (CurrentColumn = 0; CurrentColumn < ChessBoardSize.width; CurrentColumn++) { temppoints[(CurrentImage*NPoints*3)+(CurrentRow*ChessBoardSize.width + CurrentColumn)*3]=(float)CurrentRow*SquareSize; temppoints[(CurrentImage*NPoints*3)+(CurrentRow*ChessBoardSize.width + CurrentColumn)*3+1]=(float)CurrentColumn*SquareSize; temppoints[(CurrentImage*NPoints*3)+(CurrentRow*ChessBoardSize.width + CurrentColumn)*3+2]=0.f; } } } (*Corners3D) = cvMat(NImages*NPoints,3,CV_32FC1, temppoints);} int myFindChessboardCorners( const void* image, CvSize pattern_size, CvPoint2D32f* corners, int* corner_count, int flags ) { IplImage* eig = cvCreateImage( cvGetSize(image), 32, 1 ); IplImage* temp = cvCreateImage( cvGetSize(image), 32, 1 ); double quality = 0.01; double min_distance = 5; int win_size =10; int count = pattern_size.width * pattern_size.height; cvGoodFeaturesToTrack( image, eig, temp, corners, &count, quality, min_distance, 0, 3, 0, 0.04 ); cvFindCornerSubPix( image, corners, count, cvSize(win_size,win_size), cvSize(-1,-1), cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03)); cvReleaseImage( &eig ); cvReleaseImage( &temp ); return 1;} void makeChessBoard(){ CvScalar e; e.val[0] =255; e.val[1] =255; e.val[2] =255; cvSet(chessBoard_Img,e,0); for(int i = 0;i<ChessBoardSize.width+1;i++) for(int j = 0;j<ChessBoardSize.height+1;j++) { int w =(image_width)/2/(ChessBoardSize.width); int h = w; //(image_height)/2/(ChessBoardSize.height); int ii = i+1; int iii = ii+1; int jj =j+1; int jjj =jj+1; int s_x = image_width/6; if((i+j)%2==1) cvRectangle( chessBoard_Img, cvPoint(w*i+s_x,h*j+s_x),cvPoint(w*ii-1+s_x,h*jj-1+s_x), CV_RGB(0,0,0),CV_FILLED, 8, 0 ); }}
对摄像头进行标定
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。