摄像头标定

简介:

OPENCV没有提供完整的示例,自己整理了一下,贴出来记录。

步骤如下:

首先自制一张标定图片,用A4纸打印出来,设定距离,再设定标定棋盘的格子数目,如8×6,以下是我做的图片8×8

o_camera_calibration_8_8.JPG

然后利用cvFindChessboardCorners找到棋盘在摄像头中的2D位置,这里cvFindChessboardCorners不太稳定,有时不能工作,也许需要图像增强处理。

计算实际的距离,应该是3D的距离。我设定为21.6毫米,既在A4纸上为两厘米。

再用cvCalibrateCamera2计算内参,

最后用cvUndistort2纠正图像的变形。

结果如下: o_camera_calibration2.JPG

代码下载

代码: <c>#include "stdafx.h"

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <string.h>

// OpenCV

  1. include <cxcore.h>
  2. include <cv.h>
  3. include <highgui.h>
  4. 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 stuff bool 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 ); } } </c>

本文转自博客园知识天地的博客,原文链接:摄像头标定,如需转载请自行联系原博主。

相关文章
|
6天前
|
弹性计算 运维 网络安全
上云“加速器”——基于云效流水线快速上线企业门户网站
阿里云提出使用云效将项目代码部署到ECS,快速构建企业门户网站。该方案融合云原生技术和持续交付,通过云效流水线简化从开发到部署的全过程,实现快速迭代。文章详细阐述了技术架构,包括客户端、云解析DNS、VPC、ECS等组件,以及部署流程,包括准备阶段、部署网站服务、解析域名和可选的静态资源加速。此外,还介绍了如何使用云效平台创建流水线,实现自动化构建与部署,以及如何通过一键部署简化流程。整个方案旨在降低运维成本,提高速度和灵活性,同时提供域名备案和SSL证书配置的指导。
138400 67
上云“加速器”——基于云效流水线快速上线企业门户网站
|
7天前
|
Kubernetes 测试技术 应用服务中间件
基于 Nginx Ingress + 云效 AppStack 实现灰度发布
本文将演示结合云效 AppStack,来看下如何在阿里云 ACK 集群上进行应用的 Ingress 灰度发布。
64443 14
|
7天前
|
SQL 数据采集 DataWorks
DataWorks重磅推出全新资源组2.0,实现低成本灵活付费和动态平滑扩缩容
DataWorks资源组2.0上线,提供低成本、动态扩缩容的数据计算资源服务。
53480 2
DataWorks重磅推出全新资源组2.0,实现低成本灵活付费和动态平滑扩缩容
|
8天前
|
存储 关系型数据库 分布式数据库
突破大表瓶颈|小鹏汽车使用PolarDB实现百亿级表高频更新和实时分析
PolarDB已经成为小鹏汽车应对TB级别大表标注、分析查询的"利器"。
突破大表瓶颈|小鹏汽车使用PolarDB实现百亿级表高频更新和实时分析
|
7天前
|
弹性计算 人工智能 Kubernetes
基于云效 AppStack,5 分钟搞定一个 AI 应用的开发和部署
区别于传统的流水线工具,本实验将带你体验云效应用交付平台 AppStack,从应用视角,完成一个 AI 聊天应用的高效交付。
54745 0
|
8天前
|
分布式计算 Serverless 调度
EMR Serverless Spark:结合实时计算 Flink 基于 Paimon 实现流批一体
本文演示了使用实时计算 Flink 版和 Serverless Spark 产品快速构建 Paimon 数据湖分析的流程,包括数据入湖 OSS、交互式查询,以及离线Compact。Serverless Spark完全兼容Paimon,通过内置的DLF的元数据实现了和其余云产品如实时计算Flink版的元数据互通,形成了完整的流批一体的解决方案。同时支持灵活的作业运行方式和参数配置,能够满足实时分析、生产调度等多项需求。
59576 3
|
11天前
|
人工智能 Linux Docker
一文详解几种常见本地大模型个人知识库工具部署、微调及对比选型(1)
近年来,大模型在AI领域崭露头角,成为技术创新的重要驱动力。从AlphaGo的胜利到GPT系列的推出,大模型展现出了强大的语言生成、理解和多任务处理能力,预示着智能化转型的新阶段。然而,要将大模型的潜力转化为实际生产力,需要克服理论到实践的鸿沟,实现从实验室到现实世界的落地应用。阿里云去年在云栖大会上发布了一系列基于通义大模型的创新应用,标志着大模型技术开始走向大规模商业化和产业化。这些应用展示了大模型在交通、电力、金融、政务、教育等多个行业的广阔应用前景,并揭示了构建具有行业特色的“行业大模型”这一趋势,大模型知识库概念随之诞生。
123646 25
|
9天前
|
云计算 存储 数据可视化
阿里云研发工程师:HPC优化实例动手实验讲解
近日,全球领先的云计算厂商阿里云宣布最新HPC优化实例hpc8ae的正式商业化,该实例依托阿里云自研的「飞天+CIPU」架构体系,搭载第四代AMD EPYC处理器,专为高性能计算应用优化,特别适用于计算流体、有限元分析、多物理场模拟等仿真类应用,CAE场景下的性价比最少提升50%。
阿里云研发工程师:HPC优化实例动手实验讲解
|
8天前
|
存储 人工智能 自然语言处理
LangChain让LLM带上记忆
最近两年,我们见识了“百模大战”,领略到了大型语言模型(LLM)的风采,但它们也存在一个显著的缺陷:没有记忆。在对话中,无法记住上下文的 LLM 常常会让用户感到困扰。本文探讨如何利用 LangChain,快速为 LLM 添加记忆能力,提升对话体验。
49533 6
LangChain让LLM带上记忆
|
13天前
|
存储 SQL 搜索推荐
一站式实时数仓Hologres整体能力介绍—2024实时数仓Hologres公开课 01
一站式实时数仓Hologres整体能力介绍—2024实时数仓Hologres公开课 01

热门文章

最新文章