Code:
/*
* This is a demo to show how to combine opengl, opencv and a Mikrocontroller
* First display a 3d Cube with the camera image on it.
* The mC send a byte and the cube will rotate.
* The drogram displays the FPS from opengl, camera and how many bytes came
* from the mC.
* The function to read the camera und mC run into Threads so the
* opengl render stuff will not be blocked.
* This is just a demo, the code is ugly and my english too
*
* You need g++-4.4 to compile this
* compile with
* g++-4.4 -pthread -std=gnu++0x -Wall `pkg-config --cflags --libs opencv` -I/usr/include/GL -I/usr/X11R6/include -L/usr/X11R6/lib -lglut -lGLU -lGL drehdich.cpp -o drehdich
*
* Copyright (C) 2009 Thomas Huxhorn
* email thomas dot huxhorn at web dot de
*/
/*
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <thread>
// opengl stuff
#include <GL/freeglut.h>
#include <GL/gl.h>
#include <GL/glut.h>
// opencv stuff
#include <cv.h>
#include <highgui.h>
using namespace std;
// GLUT callbacks and functions
void displayFunc(void);
void idleFunc(void);
void reshapeFunc(int width, int height);
void countFrames(void);
void renderBitmapString(float x, float y, void *font, char *string);
// rotate the cube
float rotation = 0;
// OpenCV variables
// Camera capute
CvCapture *capture = 0;
// Image to display
IplImage *frame = 0;
// width & height of the opengl windows
int windowswidth = 800, windowsheight = 600;
// TODO do we need mutex?
int cameraFPS = 0;
int COMcontrolFPS = 0;
// texture for the camera image
GLuint cameraImageTextureID;
// run into thread
// read a byte from the mC for the cube rotation
void COMcontrol()
{
// open the device
// may be this is /dev/ttyS0
FILE *fin = fopen("/dev/ttyUSB0", "r");
// print error by error
if(!fin)
{
cerr << "Cannot open /dev/ttyUSB0\n";
perror("ERROR");
return ;
}
// for storing the byte from the mC
unsigned char input = 0;
while(1)
{
// read one byte & print error if 0 byte was read
if(fread(&input, sizeof(input), 1, fin) == 0)
{
cerr << "Cannot read from /dev/ttyUSB0\n";
perror("ERROR");
}
// cout << "read " << (int) input << "\n";
rotation = (float) input;
// increate paket/s
COMcontrolFPS++;
}
}
// run into thread
// read images from the camera
void readCamera()
{
while(1)
{
// read a frame
frame = cvQueryFrame( capture );
// if there was a error
if(!frame)
{
cerr << "Cannot capture frame\n";
}
// increate frames
cameraFPS++;
}
}
// save a opengl image
// filename is automaticly increased on every call
int saveImage()
{
// buffer for the opengl image
unsigned char *image;
//Allocate our buffer for the image & print error if one happend
if ((image = (unsigned char*)malloc(3* windowswidth * windowsheight * sizeof(char))) == NULL)
{
cerr << "Failed to allocate memory for image\n";
return -1;
}
// filename
char fname[32];
// how many images was actually written
// need this to create the next filename
static int counter = 0;
// create a filename
snprintf(fname, sizeof(fname), "jpg/%05d.jpg", counter);
// Copy the image into our buffer
glReadBuffer(GL_BACK_LEFT);
glReadPixels(0,0,windowswidth, windowsheight,GL_RGB,GL_UNSIGNED_BYTE,image);
// create a new opencv image
// windowswidth & windowsheight ist that what you write
// by glutInitWindowSize (windowswidth, windowsheight);
IplImage *cvimage = cvCreateImageHeader(cvSize(windowswidth, windowsheight), IPL_DEPTH_8U, 3);
// Ugly Stuff
cvimage->imageData = (char*)image;
// flip it vertically & swap BRG -> RGB
cvConvertImage(cvimage, cvimage, CV_CVTIMG_FLIP | CV_CVTIMG_SWAP_RB );
// save it
if(!cvSaveImage(fname , cvimage))
{
cerr << "Cannot write image" << fname << "\n";
}
counter++;
// free the images
free(image);
cvReleaseImage(&cvimage);
return 0;
}
// render the scenen
void displayFunc(void)
{
// copy the camera image into a texture
if(frame->nChannels == 3)
{
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, frame->width, frame->height, 0, GL_BGR, GL_UNSIGNED_BYTE, frame->imageData);
}
else if(frame->nChannels == 4)
{
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, frame->width, frame->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, frame->imageData);
}
// clear the buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// do some opengl stuff
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(50.0, 1.33, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef( 0, 0, -60);
// rotate the cube
glRotatef( 50, 1.0f, 0.0f, 0.0f );
glRotatef( rotation, 0.0f, 1.0f, 0.0f );
// draw 4 rectangles
glBegin(GL_QUADS);
glTexCoord2i(0,frame->height);
glVertex3f(-15.0,-15.0, 15.0);
glTexCoord2i(frame->width,frame->height);
glVertex3f(15.0,-15.0, 15.0);
glTexCoord2i(frame->width,0);
glVertex3f(15.0,15.0, 15.0);
glTexCoord2i(0,0);
glVertex3f(-15.0,15.0, 15.0);
glEnd();
glBegin(GL_QUADS);
glTexCoord2i(0,frame->height);
glVertex3f(15.0,-15.0, -15.0);
glTexCoord2i(frame->width,frame->height);
glVertex3f(15.0,-15.0, 15.0);
glTexCoord2i(frame->width,0);
glVertex3f(15.0,15.0, 15.0);
glTexCoord2i(0,0);
glVertex3f(15.0,15.0, -15.0);
glEnd();
glBegin(GL_QUADS);
glTexCoord2i(0,frame->height);
glVertex3f(15.0,-15.0, -15.0);
glTexCoord2i(frame->width,frame->height);
glVertex3f(-15.0,-15.0, -15.0);
glTexCoord2i(frame->width,0);
glVertex3f(-15.0,15.0, -15.0);
glTexCoord2i(0,0);
glVertex3f(15.0,15.0, -15.0);
glEnd();
glBegin(GL_QUADS);
glTexCoord2i(0,frame->height);
glVertex3f(-15.0,-15.0, -15.0);
glTexCoord2i(frame->width,frame->height);
glVertex3f(-15.0,-15.0, 15.0);
glTexCoord2i(frame->width,0);
glVertex3f(-15.0,15.0, 15.0);
glTexCoord2i(0,0);
glVertex3f(-15.0,15.0, -15.0);
glEnd();
glDisable(GL_TEXTURE_RECTANGLE_ARB);
countFrames();
// uncomment this if you want to make a video
// saveImage();
glutSwapBuffers();
}
void idleFunc(void)
{
glutPostRedisplay();
}
void reshapeFunc(int width, int height)
{
/*
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(height == 0)
height = 1;
float ratio = 1.0f * width / height;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the clipping volume
// gluPerspective(45,ratio,1,1000);
gluPerspective(50.0, 1.33, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
*/
// Set the viewport to be the entire window
glViewport(0, 0, width, height);
}
// count and display FPS from opengl, camera und mC
void countFrames(void)
{
// string to display
static char openglFPSstring[30];
static char cameraFPSstring[30];
static char COMcontrolFPSstring[30];
static int cframe = 0, timebase = 0;
cframe++;
// if one secund was elapsed
// create new string to display
int timenow = glutGet(GLUT_ELAPSED_TIME);
if(timenow - timebase > 1000)
{
snprintf(openglFPSstring, sizeof(openglFPSstring), "opengl fps: %4.2f", cframe*1000.0/(timenow-timebase));
snprintf(cameraFPSstring, sizeof(cameraFPSstring), "camera fps: %4.2f", cameraFPS*1000.0/(timenow-timebase));
snprintf(COMcontrolFPSstring, sizeof(COMcontrolFPSstring), "Pakets from mC / sec: %4.2f", COMcontrolFPS*1000.0/(timenow-timebase));
timebase = timenow;
cframe = 0;
cameraFPS = 0;
COMcontrolFPS = 0;
// cout << pixelstring << endl;
}
glDisable(GL_LIGHTING);
glColor3f(1.0,0,0);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, windowswidth, 0, windowsheight);
// invert the y axis, down is positive
glScalef(1, -1, 1);
// mover the origin from the bottom left corner
// to the upper left corner
glTranslatef(0, -windowsheight, 0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// render the string
renderBitmapString(20, 20 , GLUT_BITMAP_HELVETICA_10, openglFPSstring);
renderBitmapString(20, 40 , GLUT_BITMAP_HELVETICA_10, cameraFPSstring);
renderBitmapString(20, 60 , GLUT_BITMAP_HELVETICA_10, COMcontrolFPSstring);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
// render a string on given position
void renderBitmapString(float x, float y, void *font, char *string)
{
char *c;
glRasterPos2f(x, y);
for(c=string; *c != '\0'; c++)
{
glutBitmapCharacter(font, *c);
}
}
int main(int argc, char **argv)
{
// initialize camera
capture = cvCaptureFromCAM( 0 );
// if the camera cannot init, print error and return
if( !capture )
{
cerr << "Cannot open WebCam!\n";
return 1;
}
// crate a new thread for the COMcontrol
std::thread thr(COMcontrol);
cout << "New COMcontrol Thread with the id " << thr.get_id() << "\n";
glutInit(&argc,argv);
glutInitWindowSize (windowswidth, windowsheight);
glutInitWindowPosition(100, 100);
glutInitDisplayMode ( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Dreh dich");
// Register callbacks:
glutReshapeFunc(reshapeFunc);
glutDisplayFunc(displayFunc);
glutIdleFunc(idleFunc);
// query one frame to determine the image dimensions
frame = cvQueryFrame( capture );
glEnable(GL_DEPTH_TEST);
// initialze OpenGL texture
glGenTextures(1, &cameraImageTextureID);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cameraImageTextureID);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// copy the camera image into the texture
if(frame->nChannels == 3)
{
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, frame->width, frame->height, 0, GL_BGR, GL_UNSIGNED_BYTE, frame->imageData);
}
else if(frame->nChannels == 4)
{
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, frame->width, frame->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, frame->imageData);
}
// now create a thread for the camera
std::thread thr2(readCamera);
cout << "New Camera Thread with the id " << thr2.get_id() << "\n";
// mainloop
glutMainLoop();
glDeleteTextures(1, &cameraImageTextureID);
return 0;
}
Lesezeichen