/* imgproc.c - by David Blythe, SGI */ /* Examples of various image processing operations coded as OpenGL accumulation buffer operations. This allows extremely fast image processing on machines with hardware accumulation buffers (RealityEngine, InfiniteReality, VGX). */ #include #include #include #include #include "texture.h" static unsigned *image, *null; static int width, height, components; static void (*func) (void); static float alpha = 1.; static float luma = .5; static int reset = 1; static int format = GL_RGBA; void brighten(void) { if (reset) { memset(null, 0, width * height * sizeof *null); reset = 0; } glDrawPixels(width, height, format, GL_UNSIGNED_BYTE, image); glAccum(GL_LOAD, alpha / 2.); glDrawPixels(width, height, format, GL_UNSIGNED_BYTE, null); glAccum(GL_ACCUM, (1 - alpha) / 2.); glAccum(GL_RETURN, 2.0); } void saturate(void) { if (reset) { memset(null, 0xff, width * height * sizeof *null); reset = 0; } glDrawPixels(width, height, format, GL_UNSIGNED_BYTE, image); glAccum(GL_LOAD, alpha / 2.); glDrawPixels(width, height, format, GL_UNSIGNED_BYTE, null); glAccum(GL_ACCUM, (1 - alpha) / 2.); glAccum(GL_RETURN, 2.0); } void contrast(void) { if (reset) { memset(null, luma, width * height * sizeof *null); reset = 0; } glDrawPixels(width, height, format, GL_UNSIGNED_BYTE, image); glAccum(GL_LOAD, alpha / 2.); glDrawPixels(width, height, format, GL_UNSIGNED_BYTE, null); glAccum(GL_ACCUM, (1 - alpha) / 2.); glAccum(GL_RETURN, 2.0); } void balance(void) { if (reset) { memset(null, luma, width * height * sizeof *null); reset = 0; } glDrawPixels(width, height, format, GL_UNSIGNED_BYTE, image); glAccum(GL_LOAD, alpha / 2.); glDrawPixels(width, height, format, GL_UNSIGNED_BYTE, null); glAccum(GL_ACCUM, (1 - alpha) / 2.); glAccum(GL_RETURN, 2.0); } void sharpen(void) { if (reset) { gluScaleImage(format, width, height, GL_UNSIGNED_BYTE, image, width / 4, height / 4, GL_UNSIGNED_BYTE, null); gluScaleImage(format, width / 4, height / 4, GL_UNSIGNED_BYTE, null, width, height, GL_UNSIGNED_BYTE, null); reset = 0; } glDrawPixels(width, height, format, GL_UNSIGNED_BYTE, image); glAccum(GL_LOAD, alpha / 2.); glDrawPixels(width, height, format, GL_UNSIGNED_BYTE, null); glAccum(GL_ACCUM, (1 - alpha) / 2.); glAccum(GL_RETURN, 2.0); } void set_brighten(void) { func = brighten; reset = 1; printf("brighten\n"); } void set_saturate(void) { func = saturate; reset = 1; printf("saturate\n"); } void set_contrast(void) { func = contrast; reset = 1; printf("contrast\n"); } void set_balance(void) { func = balance; reset = 1; printf("balance\n"); } void set_sharpen(void) { func = sharpen; reset = 1; printf("sharpen\n"); } void help(void) { printf("'h' - help\n"); printf("'b' - brighten\n"); printf("'s' - saturate\n"); printf("'c' - contrast\n"); printf("'z' - sharpen\n"); printf("'a' - color balance\n"); printf("left mouse - increase alpha\n"); printf("middle mouse - decrease alpha\n"); } void init(char *filename) { double l = 0; int i; func = brighten; if (filename) { image = read_texture(filename, &width, &height, &components); if (image == NULL) { fprintf(stderr, "Error: Can't load image file \"%s\".\n", filename); exit(1); } else { printf("%d x %d image loaded\n", width, height); } if (components < 3 || components > 4) { printf("must be RGB or RGBA image\n"); exit(1); } } else { int i, j; components = 4; width = height = 512; image = (unsigned *) malloc(width * height * sizeof(unsigned)); for (j = 0; j < height; j++) for (i = 0; i < width; i++) { if (i & 1) image[i + j * width] = 0xff; else image[i + j * width] = 0xff00; if (j & 1) image[i + j * width] |= 0xff0000; } } null = (unsigned *) malloc(width * height * sizeof *image); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glClearColor(.25, .25, .25, .25); /* compute luminance */ for (i = 0; i < width * height; i++) { GLubyte *p = (GLubyte *) (image + i); double r = p[0] / 255.; double g = p[1] / 255.; double b = p[2] / 255.; l += r * .3086 + g * .0820 + b * .114; } luma = l / (width * height); printf("average luminance = %f\n", luma); } void display(void) { printf("alpha = %f\n", alpha); glClear(GL_COLOR_BUFFER_BIT); (*func) (); glutSwapBuffers(); } void reshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0., (GLdouble) width, 0., (GLdouble) height, -1., 1.); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } /* ARGSUSED1 */ void key(unsigned char key, int x, int y) { switch (key) { case 'b': set_brighten(); break; case 's': set_saturate(); break; case 'c': set_contrast(); break; case 'z': set_sharpen(); break; case 'a': set_balance(); break; case 'h': help(); break; case '\033': exit(0); break; default: return; } glutPostRedisplay(); } /* ARGSUSED2 */ void mouse(int button, int state, int x, int y) { if (state == GLUT_DOWN) { switch (button) { case GLUT_LEFT_BUTTON: alpha += .1; break; case GLUT_MIDDLE_BUTTON: alpha -= .1; break; case GLUT_RIGHT_BUTTON: break; } } glutPostRedisplay(); } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitWindowSize(512, 512); glutInitDisplayMode(GLUT_RGBA | GLUT_ACCUM | GLUT_DOUBLE); (void) glutCreateWindow("imgproc"); init(argv[1]); glutDisplayFunc(display); glutKeyboardFunc(key); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutMainLoop(); return 0; /* ANSI C requires main to return int. */ }