calib_dist用于测量图像中心点坐标和镜头畸变参数,而程序calib_cparam用于测量摄像机实际焦距。
本文主要介绍 calib_dist 程序的源码
主要文件有 calib_dist.c、calib_dist.h、check_dist.c
calib_dist.c
Part1 参数
static ARUint8 *gARTImage = NULL;
// 处理的图像
static ARParam gARTCparam;
// 给 gsub_lite.c 提供的 AR参数
static ARGL_CONTEXT_SETTINGS_REF gArglSettings = NULL;
//设置 setting
//GL的相关设置
static int gWin; //gl窗口
static int gXsize = 0; //窗大小
static int gYsize = 0;
static int gThresh = THRESH;
//keyboard 和 motion 中用到
static unsigned char *gClipImage = NULL;
static int gStatus; //状态变量 0等待抓取图像,1绘制包围盒,2放置经线。
//------------------------------------------------待定----
static CALIB_PATT_T gPatt;
static double dist_factor[4];
static int point_num;
static int gDragStartX = -1, gDragStartY = -1, gDragEndX = -1, gDragEndY = -1;
static int check_num;
PART2 Main函数
int main(int argc, char *argv[])
{
//glut初始化
glutInit(&argc, argv);
//init()函数
if (!init(argc, argv)) exit(-1);
//glut窗口名称、大小、模式设置
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(gXsize, gYsize);
glutInitWindowPosition(100,100);
gWin = glutCreateWindow("Calibrate distortion");
/* arglSetupForCurrentContext()函数
主要包括arglDrawModeSet()、arTextmapModeSet()、argTexRectangleModeSet()
这三个函数分别进行如下操作:
gArglSettings->arglDrawMode =AR_DRAW_BY_TEXTURE
gArglSettings->arTextmapMode =AR_DRAW_TEXTURE_FULL_IMAGE
gArglSettings->arglTexRectangle =TRUE
*/
if ((gArglSettings = arglSetupForCurrentContext()) == NULL) {
fprintf(stderr, "main(): arglSetupForCurrentContext() returned error.\n");
exit(-1);
}
//arglDistortionCompensationSet()函数
//主要是将 gArglSettings->disableDistortionCompensation=TRUE
arglDistortionCompensationSet(gArglSettings, FALSE);
gARTCparam.xsize = gXsize;
gARTCparam.ysize = gYsize;
//glut对应的事件设置
glutDisplayFunc(Display);//用于注册一个绘图函数
glutReshapeFunc(Reshape);//当你改变窗口大小时的回调(CallBack)函数
glutVisibilityFunc(Visibility);//设置当前窗口的可视回调函数
glutKeyboardFunc(Keyboard);//注册当前窗口的键盘回调函数
glutMouseFunc(Mouse);//注册当前窗口的鼠标回调函数
glutMotionFunc(Motion);
//arVideoCapStart()函数 对init()函数中的vid->graphManger,调用run()函数
//arVideoCapStart():打开相机线程,与arVideoCapStop对应,合理运用可减少CPU负载。
if (arVideoCapStart() != 0) {
fprintf(stderr, "init(): Unable to begin camera data capture.\n");
return (FALSE);
}
point_num = 0;
gStatus = 0;
print_comment(0);
//进入GLUT事件处理循环,让所有的与“事件”有关的函数调用无限循环。在一个GLUT程序中,这个例程被调用一次 。一旦被调用,这个程序将永远不会返回 。它将调用必要的任何已注册的回调。
glutMainLoop();
return (0);
}
PART3 init()函数
static int init(int argc, char *argv[])
{
char line[512];
int i;
gPatt.h_num = H_NUM;
gPatt.v_num = V_NUM;
gPatt.loop_num = 0;
if (gPatt.h_num < 3 || gPatt.v_num < 3) exit(0);
strcpy_s(line, vconf);
for (i = 1; i < argc; i++) {
strcat_s(line, " ");
strcat_s(line, argv[i]);
}
//本程序中 line =vconf
//char *vconf = "Data\\WDM_camera_flipV.xml";
if (arVideoOpen(line) < 0) {
//arVideoOpen()函数的源码 下面具体讲
fprintf(stderr, "init(): Unable to open connection to camera.\n");
return (FALSE);
}
//获取arVideo的width 和height
//vid->graphManager->GetCurrentMediaFormat(&frame_width, &frame_height,null,null)
if (arVideoInqSize(&gXsize, &gYsize) < 0) return (FALSE);
fprintf(stdout, "Camera image size (x,y) = (%d,%d)\n", gXsize, gYsize);
//arMalloc ar的空间分配函数
arMalloc(gClipImage, unsigned char, gXsize * gYsize);
return (TRUE);
}
arVideoOpen()函数 与 ar2VideoOpen(char *config)函数
arVideoOpen()
int arVideoOpen(char *config)
{
if (gVid != NULL) {
fprintf(stderr, "arVideoOpen(): Error, device is already open.\n");
return (-1);
}
gVid = ar2VideoOpen(config);
if (gVid == NULL) return (-1);
return (0);
}
ar2VideoOpen()
AR2VideoParamT *ar2VideoOpen(char *config)
{
AR2VideoParamT *vid = NULL;
char config_default[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><dsvl_input><camera show_format_dialog=\"true\" friendly_name=\"\"><pixel_format><RGB32 flip_h=\"false\" flip_v=\"true\"/></pixel_format></camera></dsvl_input>";
//分配参数空间并将其填充。
arMalloc(vid, AR2VideoParamT, 1);
memset(vid, 0, sizeof(AR2VideoParamT));
// win函数 以单线程的方式创建com对象
CoInitialize(NULL);
//新建 vid->graphManager 用DSVL new的对象
vid->graphManager = new DSVL_VideoSource();
//用config 参数 也就是上文的line 对vid->graphManger 赋值
//如果config不存在 就用config_default;如果存在 则有 fromXMLString 和fromXMLFile 两种不同的方式
if (!config) {
if (FAILED(vid->graphManager->BuildGraphFromXMLString(config_default))) return(NULL);
} else {
if (strncmp(config, "<?xml", 5) == 0) {
if (FAILED(vid->graphManager->BuildGraphFromXMLString(config))) return(NULL);
} else {
if (FAILED(vid->graphManager->BuildGraphFromXMLFile(config))) return(NULL);
}
}
//内存缓冲区
if (FAILED(vid->graphManager->EnableMemoryBuffer())) return(NULL);
return (vid);
}
PART4 Display()函数
static void Display(void)
{
double x, y;
int ssx, eex, ssy, eey;
int i;
// GL buffer set
glDrawBuffer(GL_BACK);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
beginOrtho2D(); // beginOrtho2D() 一些gl的操作
if (gStatus == 0) {
arglDispImage(gARTImage, &gARTCparam, 1.0, gArglSettings);
arVideoCapNext();//接着将获取下一帧图像
gARTImage = NULL;
}
else if (gStatus == 1) {
//在mouse事件后 gStatus 0->1 gARTImage 通过 grabImage()函数 赋值给gPatt.savedImage
arglDispImage(gPatt.savedImage[gPatt.loop_num - 1], &gARTCparam, 1.0, gPatt.arglSettings[gPatt.loop_num - 1]);
for (i = 0; i < point_num; i++) {
x = gPatt.point[gPatt.loop_num - 1][i].x_coord;
y = gPatt.point[gPatt.loop_num - 1][i].y_coord;
//在鼠标点击位置 画一个红色的“十”字
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_LINES);
glVertex2d(x - 10.0, (GLdouble)(gYsize - 1) - y);
glVertex2d(x + 10.0, (GLdouble)(gYsize - 1) - y);
glVertex2d(x, (GLdouble)(gYsize - 1) - (y - 10.0));
glVertex2d(x, (GLdouble)(gYsize - 1) - (y + 10.0));
glEnd();
}
// 绘制当前鼠标拖动剪辑区域。
if (gDragStartX != -1 && gDragStartY != -1
&& gDragEndX != -1 && gDragEndY != -1) {
if (gDragStartX < gDragEndX) { ssx = gDragStartX; eex = gDragEndX; }
else { ssx = gDragEndX; eex = gDragStartX; }
if (gDragStartY < gDragEndY) { ssy = gDragStartY; eey = gDragEndY; }
else { ssy = gDragEndY; eey = gDragStartY; }
if (gClipImage) {
glPixelZoom(1.0f, -1.0f); // ARToolKit bitmap 0.0 is at upper-left, OpenGL bitmap 0.0 is at lower-left.
glRasterPos2f((GLfloat)(ssx), (GLfloat)(gYsize - 1 - ssy));
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//框选位置的图片 画成GL_LUMINANCE
glDrawPixels(eex - ssx + 1, eey - ssy + 1, GL_LUMINANCE, GL_UNSIGNED_BYTE, gClipImage);
}
}
}
else if (gStatus == 2) {
glDispImage(gPatt.savedImage[check_num], &gARTCparam, 1.0, gPatt.arglSettings[check_num]);
for (i = 0; i < gPatt.h_num*gPatt.v_num; i++) {
x = gPatt.point[check_num][i].x_coord;
y = gPatt.point[check_num][i].y_coord;
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_LINES);
glVertex2d(x - 10.0, (GLdouble)(gYsize - 1) - y);
glVertex2d(x + 10.0, (GLdouble)(gYsize - 1) - y);
glVertex2d(x, (GLdouble)(gYsize - 1) - (y - 10.0));
glVertex2d(x, (GLdouble)(gYsize - 1) - (y + 10.0));
glEnd();
}
draw_line();
}
endOrtho2D();
glutSwapBuffers();
}
arglDispImage()函数
void arglDispImage(ARUint8 *image, const ARParam *cparam, const double zoom, ARGL_CONTEXT_SETTINGS_REF contextSettings)
{
GLint texEnvModeSave;
GLboolean lightingSave;
GLboolean depthTestSave;
if (!image) return;
// Prepare an orthographic projection, set camera position for 2D drawing, and save GL state.
// Save GL texture environment mode.
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &texEnvModeSave);
if (texEnvModeSave != GL_REPLACE) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// Save enabled state of lighting.
lightingSave = glIsEnabled(GL_LIGHTING);
if (lightingSave == GL_TRUE) glDisable(GL_LIGHTING);
// Save enabled state of depth test.
depthTestSave = glIsEnabled(GL_DEPTH_TEST);
if (depthTestSave == GL_TRUE) glDisable(GL_DEPTH_TEST);
//GL操作:将当前矩阵指定为 投影矩阵
glMatrixMode(GL_PROJECTION);
//GL操作:将当前矩阵存入堆栈
glPushMatrix();
//GL操作:重置当前指定矩阵为 单位矩阵
glLoadIdentity();
//GL操作:通过正交投影,把景物1:1绘制到一个剪切面
gluOrtho2D(0, cparam->xsize, 0, cparam->ysize);
//GL操作:将当前矩阵指定为 模型视景的操作
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// Restore previous projection, camera position, and GL state.
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
// Restore enabled state of depth test.
if (depthTestSave == GL_TRUE) glEnable(GL_DEPTH_TEST);
// Restore enabled state of lighting.
if (lightingSave == GL_TRUE) glEnable(GL_LIGHTING);
// Restore GL texture environment mode.
if (texEnvModeSave != GL_REPLACE) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texEnvModeSave);
}