home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-06-30 | 21.0 KB | 646 lines | [TEXT/R*ch] |
- // This may look like C code, but it is really -*- C++ -*-
- /*
- ************************************************************************
- *
- * Grayscale Image
- * Implementation of the Primitive Operations
- *
- * The image is represented as a Pixmap, i.e. a matrix of pixels
- * each of them specifies the gray level at a particular point
- *
- ************************************************************************
- */
-
- #pragma implementation "image.h"
- #include "image.h"
- #include <builtin.h>
-
-
-
-
- /*
- *------------------------------------------------------------------------
- * Constructors and destructors
- */
-
- void IMAGE::allocate(
- const int no_rows, // No. of rows
- const int no_cols, // No. of cols
- const int depth // No. of bits per pixel
- )
- {
- valid_code = IMAGE_val_code;
-
- assure((ncols=no_cols) > 0, "Zero image width unexpected");
- assure((nrows=no_rows) > 0, "Zero image height unexpected");
- assure((bits_per_pixel=depth) > 0 && depth <= GRAY_MAXBIT,
- "Zero or too large no. of bits per pixel");
-
- name = "";
- npixels = nrows * ncols;
-
- assert( (scanrows = (GRAY **)calloc(nrows,sizeof(GRAY *))) != 0 );
- assert( (pixels = (GRAY *)calloc(npixels,sizeof(GRAY))) != 0 );
-
- register int i;
- for(i=0; i<nrows; i++)
- scanrows[i] = &pixels[i*ncols];
- }
-
- // Set a new image name
- void IMAGE::set_name(const char * new_name)
- {
- if( name != 0 && name[0] != '\0' ) // Dispose of the previous image name
- delete name;
-
- if( new_name == 0 || new_name[0] == '\0' )
- name = ""; // Image is anonymous now
- else
- name = new char[strlen(new_name)+1], strcpy(name,new_name);
- }
-
- // Routing constructor module
- IMAGE::IMAGE(const IMAGE_CREATORS_1op op, const IMAGE& prototype)
- {
- switch(op)
- {
- case Expand:
- _expand(prototype);
- break;
-
- case Shrink:
- _shrink(prototype);
- break;
-
- default:
- _error("Operation %d is not yet implemented",op);
- }
- }
-
-
- IMAGE::~IMAGE(void) // Dispose the image struct
- {
- is_valid();
- if( name != 0 && name[0] != '\0' )
- delete name;
-
- delete scanrows;
- delete pixels;
- valid_code = 0;
- }
-
-
- /*
- *------------------------------------------------------------------------
- * Single Image operations
- */
-
- // Clip pixel values to
- // [0,1<<bits_per_pixel-1].
- // A pixel with the value outside that range
- // (i.e. negative or too big) is set to
- // 0 or 1<<bits_per_pixel-1, resp.
- IMAGE& IMAGE::clip_to_intensity_range(void)
- {
- is_valid();
- const int maxval = (1<<bits_per_pixel)-1;
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)pixels;
- for(; cp < (GRAY_SIGNED *)pixels + npixels; cp++)
- if( *cp < 0 )
- *cp = 0;
- else if( *cp > maxval )
- *cp = maxval;
-
- return *this;
- }
-
- // Perform a transformation
- // pixel = |(signed)pixel|
- // on all the pixels of the image
- IMAGE& IMAGE::abs(void)
- {
- is_valid();
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)pixels;
- for(; cp < (GRAY_SIGNED *)pixels + npixels; cp++)
- if( *cp < 0 )
- *cp = -(*cp);
-
- return *this;
- }
-
- // Perform a transformation
- // pixel = fp((signed)pixel)
- // on all the pixels of the image
- // where fp is a user-defined function
- IMAGE& IMAGE::apply(USER_F * fp)
- {
- is_valid();
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)pixels;
- for(; cp < (GRAY_SIGNED *)pixels + npixels; cp++)
- *cp = fp(*cp);
-
- return *this;
- }
-
- // Perform the histogram equalization
- IMAGE& IMAGE::equalize(const int no_grays)
- {
- is_valid();
- int orig_no_grays = 1 << bits_per_pixel;
- assert( no_grays <= orig_no_grays );
-
- int histogram [orig_no_grays];
- memset(histogram,0,sizeof(histogram));
-
- // Evaluate the histogram of an image
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)pixels;
- for(; cp < (GRAY_SIGNED *)pixels + npixels; cp++)
- {
- if( *cp <= 0 )
- *cp = 0;
- else if( *cp >= orig_no_grays )
- *cp = orig_no_grays-1;
- histogram[*cp]++;
- }
-
- const int pixels_per_bin_optimal = (npixels + no_grays - 1)/no_grays;
- const int gray_shade_subsample_factor =
- (orig_no_grays + no_grays -1)/no_grays;
- register int pixel;
- int new_pixel, new_pixel_old;
- int accumulated = 0;
- int optimal_accumulated = pixels_per_bin_optimal;
- // Mapping from pixels of original
- short look_up_table[orig_no_grays]; // image to [new_pixel_old,new_pixel]
- // (actually, just to the center of
- // this interval)
-
- // Equalizing the histogram
- for(pixel=0,new_pixel=0,new_pixel_old=0; pixel<orig_no_grays; pixel++)
- {
- accumulated += histogram[pixel];
- while( accumulated > optimal_accumulated )
- new_pixel += gray_shade_subsample_factor,
- optimal_accumulated += pixels_per_bin_optimal;
- assert( new_pixel < orig_no_grays );
- look_up_table[pixel] = (new_pixel >
- new_pixel_old+gray_shade_subsample_factor ?
- (new_pixel + new_pixel_old)/2 :
- new_pixel);
- new_pixel_old = new_pixel;
- }
-
- // Update the image according to the LUT
- for(cp = (GRAY_SIGNED *)pixels; cp < (GRAY_SIGNED *)pixels + npixels; cp++)
- *cp = look_up_table[*cp];
-
- return *this;
- }
-
- // Compute the 1. norm of the entire image
- // SUM{ |(signed)pixel[i,j]| }
- double IMAGE::norm_1(void) const
- {
- is_valid();
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)pixels;
- long long sum = 0;
- for(; cp < (GRAY_SIGNED *)pixels + npixels; )
- sum += ::abs(*cp++);
-
- return sum;
- }
-
- // Compute the square of the 2. norm of
- // the entire image
- // SUM{ |(signed)pixel[i,j]|^2 }
- double IMAGE::norm_2_sqr(void) const
- {
- is_valid();
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)pixels;
- register double sum = 0;
- for(; cp < (GRAY_SIGNED *)pixels + npixels; )
- sum += ::sqr(*cp++);
-
- return sum;
- }
-
- // Compute the infinity norm of the
- // entire image
- // MAX{ |(signed)pixel[i,j]| }
- int IMAGE::norm_inf(void) const
- {
- is_valid();
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)pixels;
- register int maxp = 0;
- for(; cp < (GRAY_SIGNED *)pixels + npixels; )
- maxp = ::max(::abs(*cp++),maxp);
-
- return maxp;
- }
-
- // Find extremum values of image pixels
- Extrema::Extrema(const IMAGE& image)
- : max_pixel(0,0), min_pixel(0,0)
- {
- image.is_valid();
- max_value = min_value = image(0,0);
-
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)image.pixels;
- register int i,j;
- for(i=0; i<image.nrows; i++)
- for(j=0; j<image.ncols; j++, cp++)
- if( *cp > max_value )
- max_value = *cp, max_pixel.row_val = i, max_pixel.col_val = j;
- else if( *cp < min_value )
- min_value = *cp, min_pixel.row_val = i, min_pixel.col_val = j;
- }
-
- // Normalize pixel values to be
- // in range 0..1<<bits_per_pixel-1
- IMAGE& IMAGE::normalize_for_display(void)
- {
- is_valid();
- Extrema extrema(*this);
- message("\nImage_normalization:"
- "\n\tmin pixel value %d, max pixel value %d",
- extrema.min(), extrema.max());
- if( extrema.max() != extrema.min() )
- {
- double factor = (double)((1<<bits_per_pixel)-1) /
- ( extrema.max() - extrema.min() );
- message("\n\tNormalization is as follows: (pixel - %d)*%g\n",
- extrema.min(), factor);
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)pixels;
- for(; cp < (GRAY_SIGNED *)pixels + npixels; cp++)
- *cp = (int)( (*cp - extrema.min()) * factor + 0.5 );
- }
-
- return *this;
- }
-
- // Print some info about the image
- void IMAGE::info(void) const
- {
- message("\nimage %dx%dx%d '%s' ",nrows,ncols,bits_per_pixel,name);
- }
- // Print the image as a table of pixel values
- // (zeros are printed as dots)
- void IMAGE::print(const char * title) const
- {
- is_valid();
- message("\nImage %dx%dx%d '%s' is as follows\n\n",nrows,ncols,
- bits_per_pixel,title);
-
- register int i,j;
- for(i=0; i<nrows; i++)
- {
- for(j=0; j<ncols; j++)
- if( (*this)(i,j) == 0 )
- message(" . ");
- else
- message("%4d ",(*this)(i,j));
- message("\n");
- }
- message("Done\n");
- }
-
- /*
- *------------------------------------------------------------------------
- * Image-scalar operations
- * Check to see if the preedicate "(signed)pixel operation scalar"
- * holds for ALL the pixels of the image
- */
-
- // (signed)pixel == val for all pixels?
- int IMAGE::operator == (const int val) const
- {
- is_valid();
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)pixels;
- for(; cp < (GRAY_SIGNED *)pixels + npixels; )
- if( !(*cp++ == val) )
- return 0;
-
- return 1;
- }
-
- // (signed)pixel != val for all pixels?
- int IMAGE::operator != (const int val) const
- {
- is_valid();
- register GRAY_SIGNED * cp = (GRAY_SIGNED *)pixels;
- for(; cp < (GRAY_SIGNED *)pixels + npixels; )
- if( !(*cp++ != val) )
- return 0;
-
- return 1;
- }
-
- // (signed)pixel < val for all pixels?
- int IMAGE::operator < (const int val) const
- {
- is_valid();
- register GRAY_SIGNED