Sunday, November 24, 2013

ARToolkit Sanguniololu Overlay on the circuit board 1.3a


This is a hack of the Artoolkit to provide a see through texture from a png file with alpha channel.
I plan to include a camera tracking and eventually use a LED pico projector in the next expreiment with the ARToolkit.
Some Source Code


#ifdef _WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef __APPLE__
#include <GL/gl.h>
#include <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 <png.h>
#include "stb_image.h"
//
// Camera configuration.
//
#ifdef _WIN32
char *vconf = "Data\\WDM_camera_flipV.xml";
#else
char *vconf = "";
#endif

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

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

char           *patt_name      = "Data/patt.hiro";
int             patt_id;
double          patt_width     = 80.0;
double          patt_center[2] = {0.0, 0.0};
double          patt_center1[2]={0.0,0.0};
double          patt_center2[2]={0.0,0.0};
double          patt_trans[3][4];
GLuint tex;
GLuint png_texture_load(const char * file_name, int * width, int * height);

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( void );

unsigned int counter=0;

GLuint texture;
int x,y,n;

////////////////////////////////////////////////////////////////////////////
    char INBUFFER[500];
    char OUTBUFFER[20];
    DWORD        bytes_read    = 0;    // Number of bytes read from port
    DWORD        bytes_written = 0;    // Number of bytes written to the port
    HANDLE       comport      = NULL;  // Handle COM port
 int   bStatus;
    DCB          comSettings;          // Contains various port settings
    COMMTIMEOUTS CommTimeouts;
    //////////////////////////////////////

int main(int argc, char **argv)
{

// strcpy(&OUTBUFFER[0], "The quick brown fox jumped over the lazy dog. \n\r\0");
    // Open COM port
    if ((comport = 
         CreateFile("\\\\.\\COM11",                // open com5:
                    GENERIC_READ | GENERIC_WRITE, // for reading and writing
                    0,                            // exclusive access
                    NULL,                         // no security attributes
                    OPEN_EXISTING,              
                    FILE_ATTRIBUTE_NORMAL,
                    NULL)) == INVALID_HANDLE_VALUE)
    {
       printf("error1"); // error processing code goes here
    }
    // Set timeouts in milliseconds
    CommTimeouts.ReadIntervalTimeout         = 0; 
    CommTimeouts.ReadTotalTimeoutMultiplier  = 0; 
    CommTimeouts.ReadTotalTimeoutConstant    = 100;
    CommTimeouts.WriteTotalTimeoutMultiplier = 0;
    CommTimeouts.WriteTotalTimeoutConstant   = 100;
    bStatus = SetCommTimeouts(comport,&CommTimeouts);
    if (bStatus != 0)
    {
        printf("error");// error processing code goes here
    }
    // Set Port parameters.
    // Make a call to GetCommState() first in order to fill
    // the comSettings structure with all the necessary values.
    // Then change the ones you want and call SetCommState().
    GetCommState(comport, &comSettings);
    comSettings.BaudRate = 9600;
    comSettings.StopBits = ONESTOPBIT;
    comSettings.ByteSize = 8;
    comSettings.Parity   = NOPARITY;
    comSettings.fParity  = FALSE;
    bStatus = SetCommState(comport, &comSettings);
    if (bStatus == 0)
    {
        printf("error");// error processing code goes here
    }
////////////////////////////////////////////////////////////////////////////////////////////
glutInit(&argc, argv);
init();
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
printf("here\n");
    unsigned char *data = stbi_load("circuit3.png", &x, &y, &n, 0);
printf("(%d, %d, %d)",x,y,n);
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x,y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
stbi_image_free(data);

    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);
    }
}
int angle1=90,angle2=90;
/* main loop */
static void mainLoop(void)
{
    ARUint8         *dataPtr;
    ARMarkerInfo    *marker_info;
    int             marker_num;
    int             j, k;


 count++;


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

    argDrawMode2D();
    if(counter%30==0)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 ) {
        argSwapBuffers();
        return;
    }

    /* get the transformation between the marker and the real camera */
    arGetTransMat(&marker_info[k], patt_center, patt_width, patt_trans);
 
printf("patt_center(%g)\n",patt_trans[1][3]);//,patt_trans[1][1],patt_trans[2][1]);
/// printf("patt_center(%g,%g,%g)\n",patt_trans[0][2],patt_trans[1][2],patt_trans[2][2]);
// printf("patt_center(%g,%g,%g)\n",patt_trans[0][3],patt_trans[1][3],patt_trans[2][3]);
// printf("patt_center(%g,%g,%g)\n",patt_trans[0][0],patt_trans[1][0],patt_trans[2][0]);


double ratio=80.0;
patt_center2[0]=patt_trans[0][3]+50;
patt_center2[1]=patt_trans[1][3]+100;
int x,y;
if(patt_center1[0]==0.0 && patt_center1[1]==0.0){x=0;y=0;}
else {
y=(patt_center2[0])/ratio;
 x=(patt_center2[1])/(2.3*ratio);
}
 patt_center1[0]=patt_center2[0];
patt_center1[1]=patt_center2[1];
//if(x>2 || x<-2)x=0;if(y>2 || y<-2)y=0;
angle1=angle1-x;
angle2=angle2+y;
if(angle2>180)angle2=180;
if(angle2<0)angle2=0;
if(angle1>180)angle1=180;
if(angle1<0)angle1=0;


printf("%d %d",angle1,angle2);
printf("(%d, %d)\n",x,y);
////////////write camera movement x,y
char out[7];
out[0]=(char)((angle1)/100+48);
out[1]=(char)((angle1)/10+48);
out[2]=(char)((angle1)%10+48);
out[3]=(char)((angle2)/100+48);
out[4]=(char)((angle2)/10+48);
out[5]=(char)((angle2)%10+48);
out[6]=0;
printf(":%s",out);
bStatus = WriteFile(comport,              // Handle
       &out,      // Outgoing data
       6,              // Number of bytes to write
       &bytes_written,  // Number of bytes written
       NULL);
        if (bStatus != 0)
        {
            printf("error writing comport %",bytes_written);// error processing code here
        }
        
       


    draw();

    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 draw( void )
{
    double    gl_para[16];
    GLfloat   mat_ambient[]     = {0.0, 0.0, 1.0,0.0};
    GLfloat   mat_flash[]       = {0.0, 0.0, 1.0, 0.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);
glClearColor(0.0,0.0,0.0,0.0);
   if(counter%30==0)glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glBindTexture(GL_TEXTURE_2D, texture);

    /* load the camera transformation matrix */
    argConvGlpara(patt_trans, gl_para);
    glMatrixMode(GL_MODELVIEW);
    
glLoadMatrixd( gl_para );
// glEnable (GL_BLEND);
//glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBindTexture(GL_TEXTURE_2D,tex);
    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);
    glTranslatef( 40.0, -45.0, 0.0 );
    //glutSolidCube(50.0);
glBegin (GL_QUADS);
glTexCoord2f (0.0, 0.0);
glVertex3f (0.0, 0.0, 0.0);
glTexCoord2f(-1.0, 0.0);
glVertex3f (2*x/15.5, 0.0, 0.0);
glTexCoord2f (-1.0,-1.0);
glVertex3f (2*x/15.5, 2*y/15, 0.0);
glTexCoord2f (0.0, -1.0);
glVertex3f (0.0, 2*y/15, 0.0);
glEnd ();
    glDisable( GL_LIGHTING );
glDisable(GL_TEXTURE_2D);
    glDisable( GL_DEPTH_TEST );
}

















GLuint png_texture_load(const char * file_name, int * width, int * height)
{
    png_byte header[8];
printf("Opening file...");
    FILE *fp = fopen(file_name, "rb");
    if (fp == 0)
    {
        printf("FILE_ERROR");
perror(file_name);
        return 0;
    }

    // read the header
    fread(header, 1, 8, fp);

    if (png_sig_cmp(header, 0, 8))
    {
        printf( "error: %s is not a PNG.\n", file_name);
        fclose(fp);
        return 0;
    }

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
    {
        printf( "error: png_create_read_struct returned 0.\n");
        fclose(fp);
        return 0;
    }

    // create png info struct
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        printf( "error: png_create_info_struct returned 0.\n");
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
        fclose(fp);
        return 0;
    }

    // create png info struct
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info)
    {
        printf( "error: png_create_info_struct returned 0.\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
        fclose(fp);
        return 0;
    }

    // the code in this if statement gets called if libpng encounters an error
    if (setjmp(png_jmpbuf(png_ptr))) {
        printf("error from libpng\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        fclose(fp);
        return 0;
    }
printf("init png reading");
    // init png reading
    png_init_io(png_ptr, fp);
printf("png_read8bytes");
    // let libpng know you already read the first 8 bytes
    png_set_sig_bytes(png_ptr, 8);
printf("png_read_info");
    // read all the info up to the image data
    //png_read_info(png_ptr, info_ptr);
printf("here2");
    // variables to pass to get info
    int bit_depth=8, color_type=PNG_COLOR_TYPE_RGB_ALPHA;
    png_uint_32 temp_width=*width, temp_height=*height;
printf("here2");
    // get info about png
    //png_get_IHDR(png_ptr, info_ptr, &temp_width, &temp_height, &bit_depth, &color_type,
    //    NULL, NULL, NULL);
printf("here2");
    //if (width){ *width = temp_width; }
    //if (height){ *height = temp_height; }
printf("here2\n");
    printf("%s: %lux%lu %d\n", file_name, temp_width, temp_height, color_type);

    if (bit_depth != 8)
    {
        printf( "%s: Unsupported bit depth %d.  Must be 8.\n", file_name, bit_depth);
        return 0;
    }

    GLint format;
    switch(color_type)
    {
    case PNG_COLOR_TYPE_RGB:
        format = GL_RGB;
        break;
    case PNG_COLOR_TYPE_RGB_ALPHA:
        format = GL_RGBA;
        break;
    default:
        printf("%s: Unknown libpng color type %d.\n", file_name, color_type);
        return 0;
    }

    // Update the png info struct.
    png_read_update_info(png_ptr, info_ptr);

    // Row size in bytes.
    int rowbytes = png_get_rowbytes(png_ptr, info_ptr);

    // glTexImage2d requires rows to be 4-byte aligned
    rowbytes += 3 - ((rowbytes-1) % 4);

    // Allocate the image_data as a big block, to be given to opengl
    png_byte * image_data = (png_byte *)malloc(rowbytes * temp_height * sizeof(png_byte)+15);
    if (image_data == NULL)
    {
        printf("error: could not allocate memory for PNG image data\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        fclose(fp);
        return 0;
    }

    // row_pointers is for pointing to image_data for reading the png with libpng
    png_byte ** row_pointers = (png_byte **)malloc(temp_height * sizeof(png_byte *));
    if (row_pointers == NULL)
    {
        printf( "error: could not allocate memory for PNG row pointers\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        free(image_data);
        fclose(fp);
        return 0;
    }

    // set the individual row_pointers to point at the correct offsets of image_data
    for (unsigned int i = 0; i < temp_height; i++)
    {
        row_pointers[temp_height - 1 - i] = image_data + i * rowbytes;
    }

    // read the png into image_data through row_pointers
    png_read_image(png_ptr, row_pointers);

    // Generate the OpenGL texture object
printf("binding");
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, format, temp_width, temp_height, 0, format, GL_UNSIGNED_BYTE, image_data);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    // clean up
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
    free(image_data);
    free(row_pointers);
    fclose(fp);
    return texture;
}