//------------------------------------------------------------------- // rgb2mono.cpp // // This program demonstrates the use of a matrix multiplication // to transform a graphics image from RGB format to YUV format. // // to compile: $ g++ rgb2mono.cpp -o rgb2mono // to execute: $ ./rgb2mono // // NOTE: This program requires using a customized device-driver // (named 'gateway.c') for the ATI Radeon graphics processor in // the Gateway 53A laptop computer used for in-classroom demos, // because it directly writes to privileged frame-buffer memory // and it reads from a protected graphics processor register. // // NOTE: This program searches the current working directory to // find our 'hawaii.img' image-file. // // programmer: ALLAN CRUSE // written on: 05 MAR 2011 // revised on: 19 MAR 2011 -- to overcome relocation of the fb //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for read(), write(), close() #include // for memcpy() #include // for mmap() #include // for ioctl() #define VRAM_BASE 0x80000000 #define GET_CRTC_START_ADDRESS 0 char devname[] = "/dev/vram"; const unsigned int rowmax = 768; const unsigned int colmax = 1024; const unsigned int hpitch = 1024; unsigned int *fb; char imgname[] = "hawaii.img"; const int hres = 720; const int vres = 512; typedef unsigned int Image[ hres * vres ]; Image tru, mono; typedef double Vector[ 3 ]; typedef double Matrix[ 3 ][ 3 ]; Matrix trans = { 0.18300, 0.61400, 0.06200, -0.10100, -0.33900, 0.43900, 0.43900, -0.39900, -0.04000 }; unsigned int Screensave[ rowmax * hpitch ]; int main( int argc, char **argv ) { // open the device-file int dd = open( devname, O_RDWR ); if ( dd < 0 ) { perror( devname ); exit(1); } // memory-map the frame-buffer int size = lseek( dd, 0, SEEK_END ); int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void *)VRAM_BASE; if ( mmap( mm, size, prot, flag, dd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // obtain the frame-buffer's offset unsigned int crtc_start_address = 0; if ( ioctl( dd , GET_CRTC_START_ADDRESS, &crtc_start_address ) < 0 ) { perror( "ioctl" ); exit(1); } unsigned int fb_offset = crtc_start_address & 0x3FFFFFFF; printf( "\n FRAME_BUFFER_OFFSET = 0x%08X \n", fb_offset ); fb = (unsigned int *)( VRAM_BASE + fb_offset ); // save the screen's contents to restore later memcpy( Screensave, &fb[0], sizeof( Screensave ) ); // open and read the image-capture file int fd = open( imgname, O_RDONLY ); if ( fd < 0 ) { perror( imgname ); exit(1); } int nbytes = read( fd, &tru, sizeof( Image ) ); if ( nbytes < 0 ) { perror( "read" ); exit(1); } close( fd ); // display the unmodified image int above = (rowmax - vres) / 6; int below = above + vres; int indent = (colmax - hres) / 2; int width = hres; unsigned int *src = (unsigned int *)&tru; for (int row = above; row < below; row++) { unsigned int *dst = &fb[ row * hpitch + indent ]; memcpy( dst, src, 4 * width ); src += width; } printf( "\n" ); printf( " Hit to show the monocrome image " ); getchar(); // convert RGB image to YUV for (int row = above; row < below; row++) for (int col = indent; col < indent + width; col++) { unsigned int pel = fb[ row * hpitch + col ]; unsigned char red = (pel >> 16); unsigned char green = (pel >> 8); unsigned char blue = (pel >> 0); Vector rgb, yuv; rgb[0] = red; rgb[1] = green; rgb[2] = blue; for (int i = 0; i < 3; i++) { double sum = 0.0; sum = (i == 0 ) ? 16.0 : 128.0; for (int k = 0; k < 3; k++) sum += trans[ i ][ k ] * rgb[ k ]; yuv[ i ] = sum; } unsigned char luminance = yuv[ 0 ]; pel = luminance; pel |= (pel << 16)|(pel << 8); fb[ row * hpitch + col ] = pel; } printf( "\n" ); printf( " Hit to restore the former desktop image " ); getchar(); // recover the screen's previously saved contents memcpy( &fb[0], Screensave, sizeof( Screensave ) ); }