【ARTOOlkit】让标识卡显示自己的旋转角度

严格的来说,我写的这篇是研究了我实验室的学姐的博客写出来的,推荐一下学姐的博https://blog.csdn.net/tupu8617/article/list/2

有很多不错的东西,在已有的知识上补充自己的的学习水平。

       我们这次要做的是,旋转我们的标识卡,在屏幕上显示出我们的旋转角度。具体是我们利用glVertex()画点函数,在标识卡上绘制出一个圆,然后利用atan(double x)函数来求旋转角度,利用函数glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, string[i]),将旋转角度显示在屏幕上,我们这次要实现的功能就是这个。

      话不多说,接下来给大家分享源码

#ifdef _WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef __APPLE__
#include <GL/gl.h>
#include <GL/glut.h>
#else
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#endif
#include <AR/gsub.h>
#include <AR/video.h>
#include <AR/param.h>
#include <AR/ar.h>

#include<math.h>//声明数学函数库
#define PI 3.14159//定义变量PI,用来计算圆时用到
double angle = 0;//旋转角度
const int n =100;
const GLfloat R = 40.0f;//半径

/* set up the video format globals */

#ifdef _WIN32
char            *vconf = "Data\\WDM_camera_flipV.xml";
#else
char            *vconf = "";
#endif

int             xsize, ysize;
int             thresh = 100;
int             count = 0;

int             mode = 1;//标识位

char           *cparam_name    = "Data/camera_para.dat";
ARParam         cparam;

char           *patt_name      = "Data/patt.hiro";
int             patt_id;
int             patt_width     = 80.0;
double          patt_center[2] = {0.0, 0.0};
double          patt_trans[3][4];

static void   init(void);
static void   cleanup(void);
static void   keyEvent( unsigned char key, int x, int y);
static void   mainLoop(void);
static void   draw( double trans[3][4] );

static void DrawCircle();
static void getResultRaw(ARMarkerInfo *marker_info);
static void print_string(char *string);

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    init();

    arVideoCapStart();
    argMainLoop( NULL, keyEvent, mainLoop );
    return (0);
}

static void   keyEvent( unsigned char key, int x, int y)
{
    /* quit if the ESC key is pressed */
    if( key == 0x1b ) {
        printf("*** %f (frame/sec)\n", (double)count/arUtilTimer());
        cleanup();
        exit(0);
    }
    //如果键盘输入c
    if( key == 'c' ) {
        printf("*** %f (frame/sec)\n", (double)count/arUtilTimer());
        count = 0;

        mode = 1 - mode;//让每次键盘输入c都让mode变化
        //此处mode转换为布尔型,如果mode=0,则为假arGetTransMatCont
        if( mode ) printf("Continuous mode: Using arGetTransMatCont.\n");
        //如果mode不为假,输出arGetTransMat
         else      printf("One shot mode: Using arGetTransMat.\n");
    }
}

/* main loop */
static void mainLoop(void)
{
    static int      contF = 0;//静态变量
    ARUint8         *dataPtr;
    ARMarkerInfo    *marker_info;
    int             marker_num;
    int             j, k;

    /* grab a vide frame */
    if( (dataPtr = (ARUint8 *)arVideoGetImage()) == NULL ) {
        arUtilSleep(2);
        return;
    }
    if( count == 0 ) arUtilTimerReset();
    count++;

    argDrawMode2D();
    argDispImage( dataPtr, 0,0 );

    /* detect the markers in the video frame */
    if( arDetectMarker(dataPtr, thresh, &marker_info, &marker_num) < 0 ) {
        cleanup();
        exit(0);
    }

    arVideoCapNext();

    /* check for object visibility */
    k = -1;
    for( j = 0; j < marker_num; j++ ) {
        if( patt_id == marker_info[j].id ) {
            if( k == -1 ) k = j;
            else if( marker_info[k].cf < marker_info[j].cf ) k = j;
        }
    }
    //if( k == -1 ) {
    if(k != -1){
    
        glDisable(GL_DEPTH_TEST);//绘制透明图片时关闭检查
        getResultRaw(  &marker_info[k] );//显示旋转角度

    }
        contF = 0;
        //argSwapBuffers();
        //return;
    


    /*计算摄像头的转移矩阵,标识卡和摄像机之间的转移信息通过使用函数*/
    //mode为0
    if( mode == 0 || contF == 0 ) {
        arGetTransMat(&marker_info[k], patt_center, patt_width, patt_trans);
    }
    else {
        //mode为1
        arGetTransMatCont(&marker_info[k], patt_trans, patt_center, patt_width, patt_trans);
    }
    contF = 1;

    draw( patt_trans );

    argSwapBuffers();
}

static void init( void )
{
    ARParam  wparam;

    /* open the video path */
    if( arVideoOpen( vconf ) < 0 ) exit(0);
    /* find the size of the window */
    if( arVideoInqSize(&xsize, &ysize) < 0 ) exit(0);
    printf("Image size (x,y) = (%d,%d)\n", xsize, ysize);

    /* set the initial camera parameters */
    if( arParamLoad(cparam_name, 1, &wparam) < 0 ) {
        printf("Camera parameter load error !!\n");
        exit(0);
    }
    arParamChangeSize( &wparam, xsize, ysize, &cparam );
    arInitCparam( &cparam );
    printf("*** Camera Parameter ***\n");
    arParamDisp( &cparam );

    if( (patt_id=arLoadPatt(patt_name)) < 0 ) {
        printf("pattern load error !!\n");
        exit(0);
    }

    /* open the graphics window */
    argInit( &cparam, 1.0, 0, 0, 0, 0 );
}

/* cleanup function called when program exits */
static void cleanup(void)
{
    arVideoCapStop();
    arVideoClose();
    argCleanup();
}

//画图函数
static void DrawCircle()
{
    int i;
    glLineWidth(5);//线宽为5
    glBegin(GL_LINE_LOOP); //利用GL_LINE_LOOP这一函数来画图
    glColor3f(1, 1, 0);//线的颜色
    for(i=0; i<n; i++)
        glVertex2f(R*cos(2*PI/n*i), R*sin(2*PI/n*i));//利用循环画圆
    glEnd();
 
    glPointSize(5);//设置点的大小
    glBegin(GL_POINTS); 
    for(i=0; i<12; i++)
        glVertex2f((R-5)*cos(2*PI/12*i),(R-5)*sin(2*PI/12*i));//画12个点
    glEnd();
 
    glColor3f(1,0,0);
           
    glBegin(GL_TRIANGLES);//画在圆内的箭头
        glVertex3f(0,40,0);
        glVertex3f(3,0,0);
        glVertex3f(-3,0,0);
    glEnd();
    return;
}


//计算角度
static void getResultRaw(ARMarkerInfo *marker_info )
{  
    char        string[256];
    //得到角度
    angle= atan(-marker_info->line[0][0]/marker_info->line[0][1])/PI*180;
 
 
    glRasterPos3f(-0.7f, 0.4f,0.3f);//改变光栅位置
    sprintf(string,"ANGLE:  %3.1f\n",angle);//将字符串赋给string
    print_string( string );
 
        return;
}


//显示angel和角度
static void print_string(char *string)
{
    int i;

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    /*display the position data*/
    glTranslatef(-0.95,-0.20,0.0);//平移
    /*draw red text*/
    glColor3f(0.75,0.0,0.0);
    glRasterPos2i(0.0,0.0);//改变光栅位置
    for( i=0; i<(int)strlen(string); i++)
    {
        if(string[i] != '\n' ){//当读到/n时,就不显示字符,因为原字符串为"ANGLE:  %3.1f\n",其末尾为/n
        
            glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, string[i]);//用于在glut窗口某位置显示字符,只能显示英文字符,而且字体,大小都不能任意设置

        }
        else{
            glTranslatef(0.0,-0.07,0.0);//平移
            glRasterPos2i(0.0,0.0);//光栅位置
        }
    }
    return;
}


static void draw( double trans[3][4] )
{
    double    gl_para[16];
    GLfloat   mat_ambient[]     = {0.0, 0.0, 1.0, 1.0};
    GLfloat   mat_flash[]       = {0.0, 0.0, 1.0, 1.0};
    GLfloat   mat_flash_shiny[] = {50.0};
    GLfloat   light_position[]  = {100.0,-200.0,200.0,0.0};
    GLfloat   ambi[]            = {0.1, 0.1, 0.1, 0.1};
    GLfloat   lightZeroColor[]  = {0.9, 0.9, 0.9, 0.1};
    
    argDrawMode3D();
    argDraw3dCamera( 0, 0 );
    glClearDepth( 1.0 );
    glClear(GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    
    /* load the camera transformation matrix */
    argConvGlpara(trans, gl_para);
    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixd( gl_para );

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambi);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_flash);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_flash_shiny);    
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMatrixMode(GL_MODELVIEW);

    DrawCircle();
    glRotatef(90,1,0,0);//旋转函数

    
    glTranslatef( 25.0, 25.0, 10.0 );//平移函数
    //glutSolidTeapot(25.0);//茶壶
    
    //glLineWidth(10.0);//设置线宽


    glDisable( GL_LIGHTING );

    glDisable( GL_DEPTH_TEST );
}
其中画红色的部分是在simple2.c的基础上添加的,接下来给大家讲解一下添加的代码是什么意思。glDisable(GL_DEPTH_TEST);//绘制透明图片时关闭检查。

glDisable函数的意思是在InitGL() 或者类似的初始化OpenGL的地方,会有glEnable(GL_DEPTH_TEST);启用了之后,OpenGL在绘制的时候就会检查,当前像素前面是否有别的像素,如果别的像素挡道了它,那它就不会绘制,也就是说,OpenGL就只绘制最前面的一层。当我们需要绘制透明图片时,就需要关闭它glDisable(GL_DEPTH_TEST);

 getResultRaw(  &marker_info[k] );//显示旋转角度

因为重要的计算旋转角度,将角度显示在屏幕上的函数都包括在了 getResultRaw(  &marker_info[k] )函数里面,所以只用执行此函数即可
static void DrawCircle()//画图函数,其中函数中最重要的部分就是:

 for(i=0; i<n; i++)
        glVertex2f(R*cos(2*PI/n*i), R*sin(2*PI/n*i))

这个函数用到for循环,并设置n=100,利用R*cos(2*PI/n*i), R*sin(2*PI/n*i)这一函数来置于画点函数之中,画出了一个圆型。

for(i=0; i<12; i++)
        glVertex2f((R-5)*cos(2*PI/12*i),(R-5)*sin(2*PI/12*i));//画12个点

这段函数画了圆内的12个点。

最后画出的圆如下图所示:

//显示angel和角度
static void print_string(char *string)

接下来给大家介绍如何将字符显示在屏幕上面,这段函数里面的核心点就是

 for( i=0; i<(int)strlen(string); i++)
    {
        if(string[i] != '\n' ){//当读到\n时,就不显示字符,因为原字符串为"ANGLE:  %3.1f\n",其末尾为\n
        
            glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, string[i]);//用于在glut窗口某位置显示字符,只能显示英文字符,而且字体,大小都不能任意设置

(int)strlen(string)s此处利用strlen函数求出了string的长度,并强制转换为int类型,在上面的函数中,string里面的内容是

"ANGLE:  %3.1f\n",其中,%3.1f是angle,也就是求到的角度,末尾为\n。

 if(string[i] != '\n' ){
        
            glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, string[i]);

一个一个的读string,如果读到不是\n,就将字符显示出来,这里在stirng最后添加了一个\n,其实是做了一个标志位,让这个标志在函数print_string中被识别出来。

 glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, string[i])用于在glut窗口某位置显示字符,只能显示英文字符,而且字体,大小都不能任意设置,将字符显示在窗口屏幕。

最后给大家介绍此篇程序的核心函数

//计算角度
static void getResultRaw(ARMarkerInfo *marker_info )
{  
    char        string[256];
    //得到角度
    angle= atan(-marker_info->line[0][0]/marker_info->line[0][1])/PI*180);
 
 
    glRasterPos3f(-0.7f, 0.4f,0.3f);//改变光栅位置
    sprintf(string,"ANGLE:  %3.1f\n",angle);//将字符串赋给string
    print_string( string );//让string显示在屏幕上
 
        return;
}

开篇设置了变量类型为char string,string是为了存储,"ANGLE:  %3.1f\n",angle。这一字符串,将来显示在屏幕上的也是这一字符串。

 angle= atan(-marker_info->line[0][0]/marker_info->line[0][1])/PI*180);

然后是利用atan函数得到旋转角度,并赋予给angle。

atan(double x)是math.h里面的数学函数,用来计算反正切角。

函数double atan(double x);

参数 x 为任意值,返回值以弧度表示,范围为  -π/2 到 +π/2 (-1.57079 到 1.57079)

弧度与角度的关系为:

弧度 = 180 / π 角度

atan(y/x) 仅仅根据正切值为y/x求出对应的角度,此时的double x中的X为计算好的弧度y/x。

其中-marker_info->line[0][0]表示atan(y/x)中的y,marker_info->line[0][1])表示atan(y/x)中的x,-marker_info->line[0][0]/marker_info->line[0][1])表示求出的反正切角度,然后将角度/PI*180表示求出的弧度,因为atan(double x)中的x的返回值必须为弧度值

-marker_info->line[0][0]/marker_info->line[0][1])中line是make_info结构体里面的一个参数,之前有介绍过make_info结构体里面的具体内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值