⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.cpp

📁 2d convolution on image
💻 CPP
字号:
// main.cpp
// ========
// It convolves 2D image with Gaussian smoothing kernel,
// and compare the performance between normal 2D convolution and separable
// convolution.
// The result images will be displayed on the screen using OpenGL.
//
//  AUTHOR: Song Ho Ahn (song.ahn@gmail.com)
// CREATED: 2005-08-31
// UPDATED: 2005-09-12
///////////////////////////////////////////////////////////////////////////////

#include <cstdio>
#include <cstdlib>
#include <GL/glut.h>
#include "convolution.h"
#include "Timer.h"

// image data for openGL
struct ImageData{
    GLint   x;      // resolution X
    GLint   y;      // resolution Y
    GLenum  format; // data format (RGB or INDEX..)
    GLenum  type;   // data type (8bit, 16bit or 32bit..)
    GLvoid  *buf;   // image pixel bits
};

// GLUT CALLBACK functions
void displayCB();
void displaySubWin1CB();
void displaySubWin2CB();
void displaySubWin3CB();
void reshapeCB(int w, int h);
void reshapeSubWin1CB(int w, int h);
void reshapeSubWin2CB(int w, int h);
void reshapeSubWin3CB(int w, int h);
void keyboardHandlerCB(unsigned char key, int x, int y);

void initGL();
int  initGLUT(int argc, char **argv);
bool initSharedMem();
void clearSharedMem();
bool loadRawImage(char *fileName, int x, int y, unsigned char *data);
void drawString(const char *str, int x, int y, void *font);

// constants ////////////////////////
const char *FILE_NAME = "lena.raw";
const int  IMAGE_X = 256;
const int  IMAGE_Y = 256;
const int  MAX_NAME = 1024;

// global variables ////////////////
ImageData       *image;
unsigned char   *inBuf;
unsigned char   *outBuf1;
unsigned char   *outBuf2;
char            fileName[MAX_NAME];
int             imageX;
int             imageY;
void            *font = GLUT_BITMAP_8_BY_13;
int             fontWidth = 8;
int             fontHeight = 13;
int             mainWin, subWin1, subWin2, subWin3, subWin4;
double          time1, time2;



///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
    // use default image file if not specified
    if(argc == 4)
    {
        strcpy(fileName, argv[1]);
        imageX = atoi(argv[2]);
        imageY = atoi(argv[3]);
    }
    else{
        printf("Usage: %s <image-file> <width> <height>\n", argv[0]);
        strcpy(fileName, FILE_NAME);
        imageX = IMAGE_X;
        imageY = IMAGE_Y;
        printf("\nUse default image \"%s\", (%d,%d)\n", fileName, imageX, imageY);
    }

    // allocate memory for global variables
    if(!initSharedMem()) return 0;

    // open raw image file
    if(!loadRawImage(fileName, imageX, imageY, inBuf))
    {
        clearSharedMem();                       // exit program if failed to load image
        return 0;
    }

    // define 5x5 Gaussian kernel
    float kernel[25] = { 1/256.0f,  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f,
                         4/256.0f, 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f,
                         6/256.0f, 24/256.0f, 36/256.0f, 24/256.0f, 6/256.0f,
                         4/256.0f, 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f,
                         1/256.0f,  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f };

    // Separable kernel
    float kernelX[5] = { 1/16.0f,  4/16.0f,  6/16.0f,  4/16.0f, 1/16.0f };
    float kernelY[5] = { 1/16.0f,  4/16.0f,  6/16.0f,  4/16.0f, 1/16.0f };

    // integer kernel
    float kernelFactor = 1 / 256.0f;
    int kernelInt[25] = { 1,  4,  6,  4, 1,
                          4, 16, 24, 16, 4,
                          6, 24, 36, 24, 6,
                          4, 16, 24, 16, 4,
                          1,  4,  6,  4, 1 };

    // perform convolution
    Timer t;
    t.start();
    convolve2D(inBuf, outBuf1, imageX, imageY, kernel, 5, 5);
    t.stop();
    time1 = t.getElapsedTimeInMilliSec();
    printf("Normal Convolution: %f ms\n", time1);

    t.start();
    convolve2DSeparable(inBuf, outBuf2, imageX, imageY, kernelX, 5, kernelY, 5);
    t.stop();
    time2 = t.getElapsedTimeInMilliSec();
    printf("Separable Convolution: %f ms\n", time2);

/*
    t.start();
    convolve2DFast(inBuf, outBuf2, imageX, imageY, kernel, 5, 5);
    //convolve2DSlow(inBuf, outBuf2, imageX, imageY, kernel, 5, 5);
    t.stop();
    time2 = t.getElapsedTimeInMilliSec();
    printf("Fast 2D Convolution: %f ms\n", time2);
*/

    // compare the results of separable convolution with normal convolution, they should be equal.
    for(int i=0; i < imageX*imageY; ++i)
    {
        if(outBuf1[i] != outBuf2[i]) printf("different at %d (%d, %d), out1:%d, out2:%d\n", i, i%imageX, i/imageX, outBuf1[i], outBuf2[i]);
    }


    // drawing graphics from here /////////////////////////////////////////////
    // init GLUT
    mainWin = initGLUT(argc, argv);

    // register GLUT callback functions
    glutDisplayFunc(displayCB);
    glutReshapeFunc(reshapeCB);                 // subwindows do not need reshape call
    glutKeyboardFunc(keyboardHandlerCB);

    // 3 sub-windows
    // each sub-windows has its own openGL context, callbacks
    subWin1 = glutCreateSubWindow(mainWin, 0, 0, imageX, imageY);
    glutDisplayFunc(displaySubWin1CB);
    glutKeyboardFunc(keyboardHandlerCB);

    subWin2 = glutCreateSubWindow(mainWin, imageX, 0, imageX, imageY);
    glutDisplayFunc(displaySubWin2CB);
    glutKeyboardFunc(keyboardHandlerCB);

    subWin3 = glutCreateSubWindow(mainWin, 0, imageX*2, imageX, imageY);
    glutDisplayFunc(displaySubWin3CB);
    glutKeyboardFunc(keyboardHandlerCB);

    // turn off unused features
    initGL();

    // the last GLUT call (LOOP)
    // window will be shown and display callback is triggered by events
    // NOTE: this call never return main().
    glutMainLoop(); /* Start GLUT event-processing loop */

    return 0;
}



///////////////////////////////////////////////////////////////////////////////
// initialize global variables
///////////////////////////////////////////////////////////////////////////////
bool initSharedMem()
{
    image = new ImageData;
    if(!image)
    {
        printf("ERROR: Memory Allocation Failed.\n");
        return false;
    }

    // allocate input/output buffer
    inBuf = new unsigned char[imageX * imageY];
    outBuf1 = new unsigned char[imageX * imageY];
    outBuf2 = new unsigned char[imageX * imageY];

    if(!inBuf || !outBuf1 || !outBuf2)
    {
        printf("ERROR: Memory Allocation Failed.\n");
        return false;
    }

    // set image data
    image->x = imageX;
    image->y = imageY;
    image->format = GL_LUMINANCE;
    image->type = GL_UNSIGNED_BYTE;
    image->buf = (GLvoid*)inBuf;

    return true;
}



///////////////////////////////////////////////////////////////////////////////
// clean up shared memory
///////////////////////////////////////////////////////////////////////////////
void clearSharedMem()
{
    delete image;
    delete [] inBuf;
    delete [] outBuf1;
    delete [] outBuf2;
}



///////////////////////////////////////////////////////////////////////////////
// load 8-bit RAW image
///////////////////////////////////////////////////////////////////////////////
bool loadRawImage(char *fileName, int x, int y, unsigned char *data)
{
    // check params
    if(!fileName || !data)
        return false;

    FILE *fp;
    if((fp = fopen(fileName, "r")) == NULL)
    {
        printf("Cannot open %s.\n", fileName);
        return false;
    }

    // read pixel data
    fread(data, 1, x*y, fp);
    fclose(fp);

    return true;
}



///////////////////////////////////////////////////////////////////////////////
// initialize GLUT for windowing
///////////////////////////////////////////////////////////////////////////////
int initGLUT(int argc, char **argv)
{
    // GLUT stuff for windowing
    // initialization openGL window.
    // it is called before any other GLUT routine
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);    // display mode

    glutInitWindowSize(3*imageX, imageY);           // window size

    glutInitWindowPosition(100, 100);               // window location

    // finally, create a window with openGL context
    // Window will not displayed until glutMainLoop() is called
    // it returns a unique ID
    int handle = glutCreateWindow(argv[0]);            // param is the title of window

    return handle;
}



///////////////////////////////////////////////////////////////////////////////
// initialize OpenGL
// disable unused features
///////////////////////////////////////////////////////////////////////////////
void initGL()
{
    glClearColor(0, 0, 0, 0);
    glShadeModel(GL_FLAT);  // shading mathod: GL_SMOOTH or GL_FLAT
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // TUNNING IMAGING PERFORMANCE
    // turn off  all pixel path and per-fragment operation
    // which slow down OpenGL imaging operation (glDrawPixels glReadPixels...).
    glDisable(GL_ALPHA_TEST);
    glDisable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_DITHER);
    glDisable(GL_FOG);
    glDisable(GL_LIGHTING);
    glDisable(GL_LOGIC_OP);
    glDisable(GL_STENCIL_TEST);
    glDisable(GL_TEXTURE_1D);
    glDisable(GL_TEXTURE_2D);
}



///////////////////////////////////////////////////////////////////////////////
// write 2d text using GLUT
///////////////////////////////////////////////////////////////////////////////
void drawString(const char *str, int x, int y, void *font)
{
    glRasterPos2i(x, y);

    // loop all characters in the string
    while(*str)
    {
        glutBitmapCharacter(font, *str);
        ++str;
    }
}



//=============================================================================
// CALLBACKS
//=============================================================================

void displayCB()
{
    glutSetWindow(mainWin);
    glClear(GL_COLOR_BUFFER_BIT);
    glutSwapBuffers();
}

void displaySubWin1CB(void)
{
    glutSetWindow(subWin1);
    glClear(GL_COLOR_BUFFER_BIT); // clear canvas

    // specify current raster position(coordinate)
    glRasterPos2i(0, imageY);  // upper-left corner in openGL coordinates
    glPixelZoom(1.0, -1.0);

    glDrawPixels(image->x, image->y, image->format, image->type, image->buf);
    glPixelZoom(1.0, 1.0);

    glColor3f(0,0,1);
    drawString("Original Image", fontWidth, imageY - fontHeight, font);

    glutSwapBuffers();
}

void displaySubWin2CB()
{
    glutSetWindow(subWin2);
    glClear(GL_COLOR_BUFFER_BIT); // clear canvas

    // specify current raster position(coordinate)
    glRasterPos2i(0, imageY);
    glPixelZoom(1.0, -1.0);

    glDrawPixels(image->x, image->y, image->format, image->type, outBuf1);
    glPixelZoom(1.0, 1.0);

    glColor3f(0,0,1);
    char str[64];
    sprintf(str, "Normal Convolution: %5.3f ms", time1);
    drawString(str, fontWidth, imageY - fontHeight, font);

   glutSwapBuffers();
}

void displaySubWin3CB(void)
{
    glutSetWindow(subWin3);
    glClear(GL_COLOR_BUFFER_BIT); // clear canvas

    // specify current raster position(coordinate)
    glRasterPos2i(0, imageY);
    glPixelZoom(1.0, -1.0);

    glDrawPixels(image->x, image->y, image->format, image->type, outBuf2);
    glPixelZoom(1.0, 1.0);

    glColor3f(0,0,1);
    char str[64];
    sprintf(str, "Separable Convolution: %5.3f ms", time2);
    drawString(str, fontWidth, imageY - fontHeight, font);

    glutSwapBuffers();
}

void reshapeCB(int w, int h)
{
    // set viewport to be the entire window
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);

    // left sub-window
    glutSetWindow(subWin1);
    glutPositionWindow(0,0);
    glutReshapeWindow(imageX, imageY);
    glViewport(0, 0, imageX, imageY);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, imageX, 0, imageY);

    // middle sub-window
    glutSetWindow(subWin2);
    glutPositionWindow(imageX, 0);
    glutReshapeWindow(imageX, imageY);
    glViewport(0, 0, imageX, imageY);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, imageX, 0, imageY);

    //right sub-window
    glutSetWindow(subWin3);
    glutPositionWindow(imageX*2, 0);
    glutReshapeWindow(imageX, imageY);
    glViewport(0, 0, imageX, imageY);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, imageX, 0, imageY);


    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}


void keyboardHandlerCB(unsigned char key, int x, int y)
{
    switch(key)
    {
    case 27: // ESCAPE
        clearSharedMem();
        exit(0);
        break;

    case 'r':
    case 'R':
        break;

    default:
        ;
    }
    glutPostRedisplay();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -