Blame |
Last modification |
View Log
| RSS feed
/*
*
* This file is part of ARToolKit.
*
* ARToolKit is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* ARToolKit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ARToolKit; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
// ============================================================================
// Includes
// ============================================================================
#ifdef _WIN32
# include <windows.h>
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef __APPLE__
# include <GL/glut.h>
# ifdef GL_VERSION_1_2
# include <GL/glext.h>
# endif
#else
# include <GLUT/glut.h>
# include <OpenGL/glext.h>
#endif
#include <AR/config.h>
#include <AR/ar.h>
#include <AR/video.h>
#include <AR/param.h>
#include <AR/gsub_lite.h>
#include "calib_cparam.h"
// ============================================================================
// Constants
// ============================================================================
#define CALIB_CPARAM_DEBUG 0
// ============================================================================
// Global variables
// ============================================================================
/* set up the video format globals */
#if defined(__sgi)
char *vconf
= "-size=FULL";
#elif defined(__linux)
# if defined(AR_INPUT_GSTREAMER)
char *vconf
= "videotestsrc";
# elif defined(AR_INPUT_V4L)
char *vconf
= "-width=640 -height=480";
# elif defined(AR_INPUT_1394CAM)
char *vconf
= "-mode=640x480_YUV411";
# elif defined(AR_INPUT_DV)
char *vconf
= "";
# endif
#elif defined(_WIN32)
char *vconf
= "Data\\WDM_camera_flipV.xml";
#elif defined(__APPLE__)
char *vconf
= "-width=640 -height=480";
#else
char *vconf
= "";
#endif
static ARUint8
*gARTImage
= NULL
;
static ARParam gARTCparam
; // Dummy parameter, to supply to gsub_lite.
static ARGL_CONTEXT_SETTINGS_REF gArglSettings
= NULL
;
static int gWin
;
static int gXsize
= 0;
static int gYsize
= 0;
int refresh
;
static unsigned char *gSaveARTImage
= NULL
;
static ARGL_CONTEXT_SETTINGS_REF gSaveArglSettings
= NULL
;
static ARParam param
;
static double dist_factor
[4];
int line_num
;
int loop_num
;
int line_mode
[LINE_MAX
];
double inter_coord
[LOOP_MAX
][LINE_MAX
][LINE_MAX
][3];
double line_info
[LOOP_MAX
][LINE_MAX
][4];
int mode
;
int line_num_current
;
int loop_num_current
;
double theta
;
double radius
;
double gStartX
, gStartY
, gEndX
, gEndY
;
// ============================================================================
// Functions
// ============================================================================
int main
(int argc
, char *argv
[]);
static int init
(int argc
, char *argv
[]);
static void Keyboard
(unsigned char key
, int x
, int y
);
static void Special
(int key
, int x
, int y
);
static void Mouse
(int button
, int state
, int x
, int y
);
static void Quit
(void);
static void Idle
(void);
static void Visibility
(int visible
);
static void Reshape
(int w
, int h
);
static void Display
(void);
static void drawPrevLine
(void);
static void drawNextLine
(void);
static void draw_warp_line
(double sx
, double ex
, double sy
, double ey
);
static void getCpara
(void);
static void intersection
( double line1
[4], double line2
[4], double *screen_coord
);
int main
(int argc
, char *argv
[])
{
glutInit
(&argc
, argv
);
if (!init
(argc
, argv
)) exit(-1);
glutInitDisplayMode
(GLUT_RGB
| GLUT_DOUBLE
);
glutInitWindowSize
(gXsize
, gYsize
);
glutInitWindowPosition
(100,100);
gWin
= glutCreateWindow
("Camera calibration");
// Setup argl library for current context.
// Turn off distortion compensation.. we are calibrating.
if ((gArglSettings
= arglSetupForCurrentContext
()) == NULL
) {
fprintf(stderr
, "main(): arglSetupForCurrentContext() returned error.\n");
exit(-1);
}
arglDistortionCompensationSet
(gArglSettings
, FALSE
);
// Make a dummy camera parameter to supply when calling arglDispImage().
gARTCparam.
xsize = gXsize
;
gARTCparam.
ysize = gYsize
;
// Setup a space to save our captured image.
if ((gSaveArglSettings
= arglSetupForCurrentContext
()) == NULL
) {
fprintf(stderr
, "grabImage(): arglSetupForCurrentContext() returned error.\n");
exit(-1);
}
arglDistortionCompensationSet
(gSaveArglSettings
, FALSE
);
arMalloc
(gSaveARTImage
, unsigned char, gXsize
*gYsize
*AR_PIX_SIZE_DEFAULT
);
// Register GLUT event-handling callbacks.
// NB: Idle() is registered by Visibility.
glutDisplayFunc
(Display
);
glutReshapeFunc
(Reshape
);
glutVisibilityFunc
(Visibility
);
glutKeyboardFunc
(Keyboard
);
glutSpecialFunc
(Special
);
glutMouseFunc
(Mouse
);
if (arVideoCapStart
() != 0) {
fprintf(stderr
, "init(): Unable to begin camera data capture.\n");
return (FALSE
);
}
mode
= 0;
line_num_current
= 0;
loop_num_current
= 0;
glutMainLoop
();
return (0);
}
static int init
(int argc
, char *argv
[])
{
printf("Input center coordinates: X = ");
scanf("%lf", &dist_factor
[0]);
while (getchar() != '\n');
printf(" : Y = ");
scanf("%lf", &dist_factor
[1]);
while (getchar() != '\n');
printf("Input distortion ratio: F = ");
scanf("%lf", &dist_factor
[2]);
while (getchar() != '\n');
printf("Input size adjustment factor: S = ");
scanf("%lf", &dist_factor
[3]);
while (getchar() != '\n');
initLineModel
(&line_num
, &loop_num
, line_mode
, inter_coord
);
// Open the video path.
if (arVideoOpen
(vconf
) < 0) {
fprintf(stderr
, "init(): Unable to open connection to camera.\n");
return (FALSE
);
}
// Find the size of the window.
if (arVideoInqSize
(&gXsize
, &gYsize
) < 0) return (FALSE
);
fprintf(stdout
, "Camera image size (x,y) = (%d,%d)\n", gXsize
, gYsize
);
// Allocate space for a save image.
arMalloc
(gSaveARTImage
, unsigned char, gXsize
* gYsize
* AR_PIX_SIZE_DEFAULT
);
param.
xsize = gXsize
;
param.
ysize = gYsize
;
param.
dist_factor[0] = dist_factor
[0];
param.
dist_factor[1] = dist_factor
[1];
param.
dist_factor[2] = dist_factor
[2];
param.
dist_factor[3] = dist_factor
[3];
return (TRUE
);
}
static void thetaRadiusSet
(void) {
if (line_num_current
== 0) {
if (line_mode
[line_num_current
] == L_HORIZONTAL
) {
theta
= 90;
radius
= gYsize
/2;
} else {
theta
= 0;
radius
= gXsize
/2;
}
} else {
if (line_mode
[line_num_current
] == L_HORIZONTAL
) {
if (line_mode
[line_num_current
] == line_mode
[line_num_current
-1]) {
radius
+= 10.0;
} else {
theta
= 90;
radius
= gYsize
/2;
}
} else {
if (line_mode
[line_num_current
] == line_mode
[line_num_current
-1]) {
radius
+= 10.0;
} else {
theta
= 0;
radius
= gXsize
/2;
}
}
}
}
static void eventCancel
(void) {
if (mode
== 0) {
// Cancel from mode 0 should quit program.
arVideoCapStop
();
Quit
();
} else if (mode
== 1) {
if (line_num_current
== 0) {
// Cancel from mode 1, first line, should go back to mode 0.
arVideoCapStart
();
mode
= 0;
} else {
// Cancel from mode 1, non-first line, should go back to first line.
line_num_current
= 0;
thetaRadiusSet
();
glutPostRedisplay
();
}
}
}
static void Mouse
(int button
, int state
, int x
, int y
)
{
ARUint8
*image
;
if (state
== GLUT_DOWN
) {
if (button
== GLUT_RIGHT_BUTTON
) {
eventCancel
();
} else if (button
== GLUT_LEFT_BUTTON
&& mode
== 0) {
// Processing a new image.
// Copy an image to saved image buffer.
do {
image
= arVideoGetImage
();
} while (image
== NULL
);
memcpy(gSaveARTImage
, image
, gXsize
*gYsize
*AR_PIX_SIZE_DEFAULT
);
printf("Grabbed image.\n");
arVideoCapStop
();
mode
= 1;
line_num_current
= 0;
thetaRadiusSet
();
glutPostRedisplay
();
}
}
}
static void Keyboard
(unsigned char key
, int x
, int y
)
{
ARParam iparam
;
double trans
[3][4];
char name
[256];
int k
= 1;
if( mode
== 0 ) return;
switch( key
) {
case 0x1B:
gStartX
= -1.0;
gStartY
= -1.0;
gEndX
= -1.0;
gEndY
= -1.0;
// fall through..
case 0x0D:
line_info
[loop_num_current
][line_num_current
][0] = gStartX
;
line_info
[loop_num_current
][line_num_current
][1] = gStartY
;
line_info
[loop_num_current
][line_num_current
][2] = gEndX
;
line_info
[loop_num_current
][line_num_current
][3] = gEndY
;
line_num_current
++;
if (line_num_current
< line_num
) {
thetaRadiusSet
();
} else {
// Completed placements for this image.
loop_num_current
++;
if (loop_num_current
< loop_num
) {
arVideoCapStart
();
mode
= 0;
} else {
// All done. Calculate parameter, save it, and exit.
getCpara
();
arParamDecomp
( ¶m
, &iparam
, trans
);
arParamDisp
( &iparam
);
printf("Input filename: ");
scanf("%s", name
);
arParamSave
( name
, 1, &iparam
);
Quit
();
}
}
break;
default:
k
= 0;
break;
}
if (k
) glutPostRedisplay
();
}
static void Special
(int key
, int x
, int y
)
{
double mx
, my
;
int k
= 1;
if (mode
== 0) return;
if (line_mode
[line_num_current
] == L_HORIZONTAL
) {
switch (key
) {
case GLUT_KEY_UP
:
radius
-= 1.0;
break;
case GLUT_KEY_DOWN
:
radius
+= 1.0;
break;
case GLUT_KEY_LEFT
:
mx
= (gStartX
+ gEndX
)/ 2.0;
my
= (gStartY
+ gEndY
)/ 2.0;
theta
-= 0.25;
radius
= cos( (double)(theta
*3.141592/180.0) ) * mx
+ sin( (double)(theta
*3.141592/180.0) ) * my
;
break;
case GLUT_KEY_RIGHT
:
mx
= (gStartX
+ gEndX
)/ 2.0;
my
= (gStartY
+ gEndY
)/ 2.0;
theta
+= 0.25;
radius
= cos( (double)(theta
*3.141592/180.0) ) * mx
+ sin( (double)(theta
*3.141592/180.0) ) * my
;
break;
default:
k
= 0;
break;
}
} else {
switch (key
) {
case GLUT_KEY_UP
:
mx
= (gStartX
+ gEndX
)/ 2.0;
my
= (gStartY
+ gEndY
)/ 2.0;
theta
+= 0.25;
radius
= cos( (double)(theta
*3.141592/180.0) ) * mx
+ sin( (double)(theta
*3.141592/180.0) ) * my
;
break;
case GLUT_KEY_DOWN
:
mx
= (gStartX
+ gEndX
)/ 2.0;
my
= (gStartY
+ gEndY
)/ 2.0;
theta
-= 0.25;
radius
= cos( (double)(theta
*3.141592/180.0) ) * mx
+ sin( (double)(theta
*3.141592/180.0) ) * my
;
break;
case GLUT_KEY_LEFT
:
radius
-= 1.0;
break;
case GLUT_KEY_RIGHT
:
radius
+= 1.0;
break;
default:
k
= 0;
break;
}
}
if (k
) glutPostRedisplay
();
}
static void Quit
(void)
{
if (gSaveArglSettings
) arglCleanup
(gSaveArglSettings
);
if (gArglSettings
) arglCleanup
(gArglSettings
);
if (gWin
) glutDestroyWindow
(gWin
);
arVideoClose
();
exit(0);
}
static void Idle
(void)
{
static int ms_prev
;
int ms
;
float s_elapsed
;
ARUint8
*image
;
// Find out how long since Idle() last ran.
ms
= glutGet
(GLUT_ELAPSED_TIME
);
s_elapsed
= (float)(ms
- ms_prev
) * 0.001;
if (s_elapsed
< 0.01f) return; // Don't update more often than 100 Hz.
ms_prev
= ms
;
// Grab a video frame.
if (mode
== 0) {
if ((image
= arVideoGetImage
()) != NULL
) {
gARTImage
= image
;
// Tell GLUT the display has changed.
glutPostRedisplay
();
}
}
}
//
// This function is called on events when the visibility of the
// GLUT window changes (including when it first becomes visible).
//
static void Visibility
(int visible
)
{
if (visible
== GLUT_VISIBLE
) {
glutIdleFunc
(Idle
);
} else {
glutIdleFunc
(NULL
);
}
}
//
// This function is called when the
// GLUT window is resized.
//
static void Reshape
(int w
, int h
)
{
glClear
(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
glViewport
(0, 0, (GLsizei
) w
, (GLsizei
) h
);
glMatrixMode
(GL_PROJECTION
);
glLoadIdentity
();
glMatrixMode
(GL_MODELVIEW
);
glLoadIdentity
();
// Call through to anyone else who needs to know about window sizing here.
}
static void beginOrtho2D
(int xsize
, int ysize
) {
glMatrixMode
(GL_PROJECTION
);
glPushMatrix
();
glLoadIdentity
();
gluOrtho2D
(0.0, xsize
, 0.0, ysize
);
glMatrixMode
(GL_MODELVIEW
);
glPushMatrix
();
glLoadIdentity
();
}
static void endOrtho2D
(void) {
glMatrixMode
(GL_PROJECTION
);
glPopMatrix
();
glMatrixMode
(GL_MODELVIEW
);
glPopMatrix
();
}
static void Display
(void)
{
// Select correct buffer for this context.
glDrawBuffer
(GL_BACK
);
glClear
(GL_COLOR_BUFFER_BIT
);
glDisable
(GL_DEPTH_TEST
);
glDisable
(GL_LIGHTING
);
glDisable
(GL_TEXTURE_2D
);
beginOrtho2D
(gXsize
, gYsize
);
if (mode
== 0) {
arglDispImage
(gARTImage
, &gARTCparam
, 1.0, gArglSettings
); // zoom = 1.0.
arVideoCapNext
();
gARTImage
= NULL
;
} else if (mode
== 1) {
arglDispImage
(gSaveARTImage
, &gARTCparam
, 1.0, gSaveArglSettings
);
drawPrevLine
();
drawNextLine
();
}
endOrtho2D
();
glutSwapBuffers
();
}
static void drawPrevLine
(void)
{
int i
;
glColor3f
(0.0,0.0,1.0);
for (i
= 0; i
< line_num_current
; i
++) {
if (line_info
[loop_num_current
][i
][0] == -1.0) continue;
draw_warp_line
(line_info
[loop_num_current
][i
][0], line_info
[loop_num_current
][i
][2],
line_info
[loop_num_current
][i
][1], line_info
[loop_num_current
][i
][3]);
}
}
static void drawNextLine
(void)
{
double sin_theta
, cos_theta
;
double x1
, x2
;
double y1
, y2
;
sin_theta
= sin( (double)(theta
*3.141592/180.0) );
cos_theta
= cos( (double)(theta
*3.141592/180.0) );
if (cos_theta
!= 0) {
x1
= radius
/ cos_theta
;
x2
= (radius
- (gYsize
-1)*sin_theta
) / cos_theta
;
} else {
x1
= x2
= -1.0;
}
if (sin_theta
!= 0) {
y1
= radius
/ sin_theta
;
y2
= (radius
- (gXsize
-1)*cos_theta
) / sin_theta
;
} else {
y1
= y2
= -1.0;
}
gEndY
= -1;
if (x1
>= 0 && x1
<= gXsize
-1) {
gStartX
= x1
;
gStartY
= 0;
if (x2
>= 0 && x2
<= gXsize
-1) {
gEndX
= x2
;
gEndY
= gYsize
-1;
} else if (y1
>= 0 && y1
<= gYsize
-1) {
gEndX
= 0;
gEndY
= y1
;
} else if (y2
>= 0 && y2
<= gYsize
-1) {
gEndX
= gXsize
-1;
gEndY
= y2
;
} else {
printf("???\n");
}
} else if (y1
>= 0 && y1
<= gYsize
-1) {
gStartX
= 0;
gStartY
= y1
;
if (x2
>= 0 && x2
<= gXsize
-1) {
gEndX
= x2
;
gEndY
= gYsize
-1;
} else if (y2
>= 0 && y2
<= gYsize
-1) {
gEndX
= gXsize
-1;
gEndY
= y2
;
} else {
printf("???\n");
}
} else if (x2
>= 0 && x2
<= gXsize
-1) {
gStartX
= x2
;
gStartY
= gYsize
-1;
if (y2
>= 0 && y2
<= gYsize
-1) {
gEndX
= gXsize
-1;
gEndY
= y2
;
} else {
printf("???\n");
}
}
glColor3f
(1.0,1.0,1.0);
if (gEndY
!= -1) {
draw_warp_line
(gStartX
, gEndX
, gStartY
, gEndY
);
}
}
static void draw_warp_line
(double sx
, double ex
, double sy
, double ey
)
{
double a
, b
, c
;
double x
, y
;
double x1
, y1
;
int i
;
a
= ey
- sy
;
b
= sx
- ex
;
c
= sy
*ex
- sx
*ey
;
glLineWidth
(1.0f);
glBegin
(GL_LINE_STRIP
);
if (a
*a
>= b
*b
) {
for (i
= -20; i
<= gYsize
+20; i
+=10) {
x
= -(b
*i
+ c
)/a
;
y
= i
;
arParamIdeal2Observ
(dist_factor
, x
, y
, &x1
, &y1
);
glVertex2f
(x1
, gYsize
-1-y1
);
}
} else {
for (i
= -20; i
<= gXsize
+20; i
+=10) {
x
= i
;
y
= -(a
*i
+ c
)/b
;
arParamIdeal2Observ
(dist_factor
, x
, y
, &x1
, &y1
);
glVertex2f
(x1
, gYsize
-1-y1
);
}
}
glEnd
();
}
static void getCpara
(void)
{
double *world_coord
;
double *screen_coord
;
int point_num
;
int i
, j
, k
;
point_num
= 0;
for (k
= 0; k
< loop_num
; k
++) {
for (i
= 0; i
< line_num
; i
++) {
for (j
= 0; j
< line_num
; j
++) {
if (inter_coord
[k
][i
][j
][0] != -10000.0) point_num
++;
}
}
}
arMalloc
(world_coord
, double, point_num
* 3);
arMalloc
(screen_coord
, double, point_num
* 2);
point_num
= 0;
for (k
= 0; k
< loop_num
; k
++) {
for (i
= 0; i
< line_num
; i
++) {
if (line_info
[k
][i
][0] == -1.0) continue;
for (j
= 0; j
< line_num
; j
++) {
if (line_info
[k
][j
][0] == -1.0) continue;
if (inter_coord
[k
][i
][j
][0] == -10000.0) continue;
world_coord
[point_num
*3+0] = inter_coord
[k
][i
][j
][0];
world_coord
[point_num
*3+1] = inter_coord
[k
][i
][j
][1];
world_coord
[point_num
*3+2] = inter_coord
[k
][i
][j
][2];
intersection
(line_info
[k
][i
], line_info
[k
][j
],
&(screen_coord
[point_num
*2]));
point_num
++;
}
}
}
printf("point_num = %d\n", point_num
);
if (arParamGet
((double (*)[3])world_coord
, (double (*)[2])screen_coord
, point_num
, param.
mat) < 0) {
printf("ddd error!!\n");
exit(0);
}
free(world_coord
);
free(screen_coord
);
}
static void intersection
(double line1
[4], double line2
[4], double *screen_coord
)
{
double a
, b
, c
, d
, e
, f
, g
;
a
= line1
[1] - line1
[3];
b
= line1
[2] - line1
[0];
c
= line1
[0] * a
+ line1
[1] * b
;
d
= line2
[1] - line2
[3];
e
= line2
[2] - line2
[0];
f
= line2
[0] * d
+ line2
[1] * e
;
g
= a
*e
- b
*d
;
if (g
== 0.0) { printf("???\n"); exit(0); }
screen_coord
[0] = (c
* e
- b
* f
) / g
;
screen_coord
[1] = (a
* f
- c
* d
) / g
;
}