/******************************************** * * absird.c * * Version 1.0. October 6th, 1995 * * * * This program creates an auto-stereogram from a depth image, either * by tiling an image or creating a random-dot pattern. * * It is designed to be linked with release 6 of the IJG jpeg library. * That library and all the source for it are available at ftp.uu.net * (Internet address 192.48.96.9) in the directory graphics/jpeg. * (If you don't already have it, get it. You won't be sorry.) * * If you don't want to use that library, simply write your own * read & write routines in place of the ones which I have. The * stereogram part of the program will not mind. * * Compile with -I set to the location of the jpeg library include * files, and link with libjpeg and -lm. It should compile under C++ * just fine. (Famous last words.) * * * * Copyright (c) 1995 Bark of Delight. This source may be used * for nonprofit purposes only, and only compiled under and for * use with non-Microsoft operating systems, unless under license * from the author. This notice must remain in the source. * * Portions Copyright (c) Garlic Software, Olive Starlight Orchestra, * Keith Goldfarb * * Thanks to Greg Turk, Rhythm & Hues Studios, and IJG. * * * * Questions? Comments? Write to me anytime. * * Keith Goldfarb Rhythm & Hues * keith@rhythm.com http://www.rhythm.com/~keith * I got nothing. Too bad. Some pink toes * But I'm happy 'cause that's all I have. Some black toes * */ static char sccsid[] = "$Id: absird.c 1.0 1995/10/06$"; #include #include #include #include #include #include /* Here are two typedefs to make the code a bit more brief. * They define the types which I use to communicate with the * image read & write routines. */ typedef struct jpeg_compress_struct JPEG_CS; typedef struct jpeg_decompress_struct JPEG_DS; /* This is the structure used by the parsing routines. */ typedef struct { char *flagName; int minItems; int maxItems; char **items; char **itemNames; int *hit; int *numItems; } PARSETABLE; /* Here are all the function prototypes. */ /* First the parsing/util routines. */ /* Bail, leave the program will an error message. */ void bail( char *progname, char *message ); /* FindInterp, looks up a value in an array of values with interpolation. */ float findInterp( float *vals, float location ); /* ParseArgs, does the actual parsing of the command line. */ int parseArgs( int argc, char **argv, int numParseTable, PARSETABLE *parseTable ); /* PrintUsage, prints the usage and exits. */ void printUsage( char *progName, int numParseTable, PARSETABLE *parseTable, char *extraMessage ); /* Next, we have the JPEG file routines (which call the JPEG library. */ /* Open routines */ JPEG_DS *openJPEGRead( FILE *infile, int *width, int *height, int *numChans ); JPEG_CS *openJPEGWrite( FILE *outfile, int width, int height, int numChans ); /* Scanline read/write. */ void readJPEGScanline( JPEG_DS *dInfo, unsigned char *dest ); void writeJPEGScanline( JPEG_CS *cInfo, unsigned char *src ); /* And close. */ void closeJPEGRead( JPEG_DS *dInfo ); void closeJPEGWrite( JPEG_CS *cInfo ); /* Finally, the routines which actually deal with depth data. */ /* DepthToOffset, converts a depth value into a pixel offset. */ float depthToOffset( float depth, float screenDistance, float dpi, float io ); /* FindIndex, given a location and an array of depth data, finds the * location in the range 0-1 to assign to this pixel. */ float findIndex( float location, float *depthData, float minDepth, float maxDepth, float zeroDepth, float screenDistance, float dpi, float io ); /* End of prototypes */ /*---------------------------------------------------------------------- | main *---------------------------------------------------------------------- | | Function: Main entry point. | | Usage: | progname depthFile outFile [tileFile]] | [-depthVals minDepth maxDepth [zeroDepth]] | [-dpi pixelsPerUnit] | [-interOcular iodistance] | [-screen distanceToScreen] | [-verbose] | | depthFile is the input file, contains depth data. | | outFile will be the file created (slightly larger!) | | tileFile is an optional tile image. If not given, | a random-dot black & white pattern will be used | as the tile pattern. | | -depthVals specifies the distances (in real units) that | the depthFile specifies. minDepth will be what the | value "1.0" (or 255 for 8-bit files) means, maxDepth | will be what the smallest value means, and zeroDepth | will be what zero means. (Often, the user wants a | jump between the smallest value and zero.) | | -dpi specifies the number of pixels per unit on the viewing | screen. Yes, it matters quite a bit. Default is 72, | as it's a reasonable guess. | | -interOcular is the distance between the viewer's eyes. | I don't know why I provide this option. Default is 2.5. | | -screen specifies the distance from the viewer to the screen. | Default is 15. | | -verbose sets verbose mode. | | Measurements can be in whatever units you'd like. I use | inches since I live in the USA. | | | Notes: There are three parts here: | 1: Parse the input parameters. | 2: Open the files. | 3: Generate the sterogram. */ void main( int argc, char **argv ) { /* This is all parsing stuff. We see for each option * The defaults for that option, the names of the items * (for printing the usage) and the two variables "count" * and "hitCount". HitCount is 1 if the option was selected, * 0 otherwize. Count is the number of parameters found. * The actual parameters are stored in the item array (which * must be large enough to hold them) as character pointers. */ static char *regItems[3] = { NULL, NULL, NULL }; static char *regNames[3] = { "depthFile", "outFile", "tileFile" }; static int regCount = 0; static int regHitCount = 0; static char *depItems[3] = { "15.0", "25.0", "30.0" }; static char *depNames[3] = { "minDepth", "maxDepth", "zeroDepth" }; static int depCount = 0; static int depHitCount = 0; static char *dpiItems[1] = { "72.0" }; static char *dpiNames[1] = { "pixelsPerUnit" }; static int dpiCount = 0; static int dpiHitCount = 0; static char *ioItems[1] = { "2.5" }; static char *ioNames[1] = { "iodistance" }; static int ioCount = 0; static int ioHitCount = 0; static char *dstItems[1] = { "15.0" }; static char *dstNames[1] = { "distanceToScreen" }; static int dstCount = 0; static int dstHitCount = 0; static int verCount = 0; static int verHitCount = 0; static PARSETABLE pTable[] = { { "", 2, 3, regItems, regNames, ®HitCount, ®Count }, { "depthVals", 2, 3, depItems, depNames, &depHitCount, &depCount }, { "dpi", 1, 1, dpiItems, dpiNames, &dpiHitCount, &dpiCount }, { "interOcular", 1, 1, ioItems, ioNames, &ioHitCount, &ioCount }, { "screen", 1, 1, dstItems, dstNames, &dstHitCount, &dstCount }, { "verbose", 0, 0, NULL, NULL, &verHitCount, &verCount }, }; /* Here are our local variables. */ /* This stuff for reading/writing files. */ JPEG_DS *iFile, *tFile; JPEG_CS *oFile; FILE *fIn, *fOut, *fTile; /* Stuff related to the file data & size. */ unsigned char *inData, *outData, *tileFullData; float *tileData[4]; char *inFilename, *outFilename, *tileFilename; int across, down, numInChans, numTileChans; int tileWidth, tileHeight; /* And stuff related to the actual SIRD algorithm. */ float minDepth, maxDepth, zeroDepth; float screenDistance, dpi, io; float *infloatData, *outfloatData, result; int zeroSize; /* Misc */ char *progname; int i, j, scan, numFlags, tileLine; /* * 1: Parse the arguments. */ numFlags = sizeof(pTable)/sizeof(PARSETABLE); progname = argv[0]; if(parseArgs(argc, argv, numFlags, pTable)) printUsage(progname, numFlags, pTable, "(C) Copyright 1995 Bark of Delight"); /* Parsing ok, set our parameters from it. */ inFilename = regItems[0]; outFilename = regItems[1]; tileFilename = regItems[2]; minDepth = atof(depItems[0]); maxDepth = atof(depItems[1]); /* Default zeroDepth to a reasonable value, namely the maxDepth. */ if(depCount == 2) zeroDepth = maxDepth; else zeroDepth = atof(depItems[2]); /* dpi, io, screen */ dpi = atof(dpiItems[0]); io = atof(ioItems[0]); screenDistance = atof(dstItems[0]); if(verHitCount) { fprintf(stderr, "Input %s, output %s", inFilename, outFilename); if(tileFilename != NULL) fprintf(stderr, " tile %s", tileFilename); fprintf(stderr, "\nDepths are %g, %g, and %g\n", minDepth, maxDepth, zeroDepth); fprintf(stderr, "To screen is %g, interocular is %g, dpi is %g\n", screenDistance, io, dpi); } /* if verbose */ /* * 2: Open the files */ /* We compute the zeroSize here. It's the number of pixels which * correspond to the zeroDepth. We need it because we're going to * output a file which is larger than the input depth, by this amount. */ zeroSize = (int)(depthToOffset(zeroDepth, screenDistance, dpi, io) + 1.0); /* If we have a tile file, we read it entirely first. */ if(tileFilename != NULL) { /* Open the raw file. */ if((fTile = fopen(tileFilename, "r")) == NULL) bail(progname, "Cannot open tile file."); /* Call the jpeg read routines. */ tFile = openJPEGRead(fTile, &tileWidth, &tileHeight, &numTileChans); /* Get some space to put the whole image. */ tileFullData = (unsigned char *)malloc(tileHeight * tileWidth * numTileChans); /* Read the whole image into memory. */ for(scan=0; scanhit) = 1; } else { fprintf(stderr, "Parsing error, unrecognized flag '%s'.\n", curString); return(-1); } } /* if a flag. */ /* A regular thing. Add it to our current entry, if it fits. */ else { /* If we can add this item, do so */ if(*(curFlagEntry->numItems) < curFlagEntry->maxItems) curFlagEntry->items[(*(curFlagEntry->numItems))++] = curString; /* If not, try to add it to the default (first item). */ else if(*(parseTable[0].numItems) < parseTable[0].maxItems) parseTable[0].items[(*(parseTable[0].numItems))++] = curString; else { fprintf(stderr, "Parsing error, extra parameter, '%s'.\n", curString); return(-1); } } /* if a regular string. */ } /* for each item given */ /* Now loop through and make sure that we got our minimums. */ for(j=0; j 0) fprintf(stderr, " [-%s", curFlag->flagName); /* Print the names which are required. */ for(j=0; jminItems; ++j) fprintf(stderr, " %s", curFlag->itemNames[j]); /* If any more, print them inside brackets. */ if(curFlag->maxItems > curFlag->minItems) { fprintf(stderr, " [%s", curFlag->itemNames[curFlag->minItems]); for(j=curFlag->minItems+1; jmaxItems; ++j) fprintf(stderr, " %s", curFlag->itemNames[j]); fprintf(stderr, "]]\n"); } else fprintf(stderr, "]\n"); } /* for i */ fprintf(stderr, "\n"); if(extraMessage != NULL) fprintf(stderr, "%s\n\n", extraMessage); exit(-1); } /* printUsage */ /*---------------------------------------------------------------------- | bail *---------------------------------------------------------------------- | | Name: bail | | Function: | | usage: | void bail( | char *progname, Program name | char *message Message to print | | Notes: This routine exits the program. It also prints out | any error encountered if errno is not zero. */ void bail( char *progname, char *message ) { extern int errno; fprintf(stderr, "%s : %s\n", progname, message); if(errno) perror("Error encountered"); exit(-1); } /* bail */ /* * From here down are image read & write routines. * These routines are cleanup of the examples provided * with the IJG JPEG package. * * * These routines stand alone -- they only "talk" to the * main program via returned pointers, which are allocated * here. So you can replace all of the routines below this * point with any other image read/write routines if you'd like. */ #ifdef __cplusplus extern "C" { #endif #include "jpeglib.h" #ifdef __cplusplus } #endif /* These routines are required by the jpeg error handlers. */ static struct jpeg_error_mgr ReadJerr, WriteJerr; /*---------------------------------------------------------------------- | openJPEGWrite *---------------------------------------------------------------------- | | Name: openJPEGWrite | | Function: Open a jpeg file for write. | | usage: | JPEG_CS *openJPEGWrite( | FILE *outfile, File pointer | int width, Width (x resolution) | int height, Height (y resolution) | int numChans Number of color channels | | Return: A pointer to the JPEG_CS structure for later use when | writing scanlines. | | Notes: numChans can only be 1 or 3, really. 1 for a grayscale | image, and 3 for a color image. The jpeg libraries don't | return error codes; you can define your own error handlers | but I'm using the default ones here which will just print | out error messages and exit. */ JPEG_CS *openJPEGWrite( FILE *outfile, int width, int height, int numChans ) { JPEG_CS *cInfo; /* Create a structure to be returned. */ cInfo = (JPEG_CS *)malloc(sizeof(JPEG_CS)); /* Use the standard error routines. */ cInfo->err = jpeg_std_error(&WriteJerr); jpeg_create_compress(cInfo); jpeg_stdio_dest(cInfo, outfile); /* Set some parameters. */ cInfo->image_width = width; cInfo->image_height = height; cInfo->input_components = numChans; /* Choose our color space appropriately */ if(numChans == 1) cInfo->in_color_space = JCS_GRAYSCALE; else cInfo->in_color_space = JCS_RGB; /* Call the library routines. */ jpeg_set_defaults(cInfo); jpeg_start_compress(cInfo, TRUE); /* And return the structure. */ return(cInfo); } /* openJPEGWrite */ /*---------------------------------------------------------------------- | writeJPEGScanline *---------------------------------------------------------------------- | | Name: writeJPEGScanline | | Function: Write a single scanline. | | usage: | void writeJPEGScanline( | JPEG_CS *cInfo, The open JPEG file pointer | unsigned char *src Pointer to the data. */ void writeJPEGScanline( JPEG_CS *cInfo, unsigned char *src ) { /* Just call the library routine. */ jpeg_write_scanlines(cInfo, &src, 1); } /* writeJPEGScanline */ /*---------------------------------------------------------------------- | closeJPEGWrite *---------------------------------------------------------------------- | | Name: closeJPEGWrite | | Function: Close a jpeg file previously opened for writing. | | usage: | void closeJPEGWrite( | JPEG_CS *cInfo The open JPEG file pointer */ void closeJPEGWrite( JPEG_CS *cInfo ) { /* Just call the library routines. */ jpeg_finish_compress(cInfo); jpeg_destroy_compress(cInfo); } /* closeJPEGWrite */ /*---------------------------------------------------------------------- | openJPEGRead *---------------------------------------------------------------------- | | Name: openJPEGRead | | Function: Open a jpeg file for write. | | usage: | JPEG_DS *openJPEGRead( | FILE *infile File pointer | int *width, Width of image (returned) | int *height, Height of image (returned) | int *numChans Number of channels (returned) | | Return: A pointer to the JPEG_DS structure for later use when | reading scanlines, and the width, height, and numChans filled. | | Notes: The jpeg libraries don't return error codes; you can | define your own error handlers but I'm using the default | ones here which will just print out error messages and exit. */ JPEG_DS *openJPEGRead( FILE *infile, int *width, int *height, int *numChans ) { JPEG_DS *dInfo; /* Create a structure to be returned. */ dInfo = (JPEG_DS *)malloc(sizeof(JPEG_DS)); /* Use the standard error routines. */ dInfo->err = jpeg_std_error(&ReadJerr); /* Call the library routines. */ jpeg_create_decompress(dInfo); jpeg_stdio_src(dInfo, infile); jpeg_read_header(dInfo, TRUE); jpeg_start_decompress(dInfo); /* Fill the width, height, & numChans. */ *width = dInfo->image_width; *height = dInfo->image_height; *numChans = dInfo->output_components; /* And return the structure. */ return(dInfo); } /* openJPEGRead */ /*---------------------------------------------------------------------- | readJPEGScanline *---------------------------------------------------------------------- | | Name: readJPEGScanline | | Function: Read a single scanline. | | usage: | void readJPEGScanline( | JPEG_DS *dInfo, The open JPEG file pointer | unsigned char *dest Pointer to destination */ void readJPEGScanline( JPEG_DS *dInfo, unsigned char *dest ) { /* Just call the library routine. */ jpeg_read_scanlines(dInfo, &dest, 1); } /* readJPEGScanline */ /*---------------------------------------------------------------------- | closeJPEGRead *---------------------------------------------------------------------- | | Name: closeJPEGRead | | Function: Close a jpeg file previously opened for reading. | | usage: | void closeJPEGRead( | JPEG_DS *dInfo The open JPEG file pointer */ void closeJPEGRead( JPEG_DS *dInfo ) { /* Just call the library routines. */ jpeg_finish_decompress(dInfo); jpeg_destroy_decompress(dInfo); } /* closeJPEGRead */