From: mc8860 AT pop DOT ou DOT edu (Jason McCullough) Newsgroups: comp.os.msdos.djgpp Subject: DJGPP behaves differently from GCC. Possible Bug? Help needed....... Date: Thu, 17 Apr 1997 16:55:06 GMT Organization: Maximum Caffination. Lines: 476 Message-ID: <33565468.13125228@ounews.ou.edu> NNTP-Posting-Host: cate0-120.reshall.ou.edu Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp Precedence: bulk Thankfully, I turned this project in already. But a part of the program that isn't graded still doesn't work. I'm reading a P5 pgm image file in, and performing an edge detection operation on it, then dumping it out in P2 pgm format. When I compile it on the University alphas here at school, it works just fine. Compile it with DJGPP, exact same source code, and the edge detection outputs nothing but black pixels after 20k or so. Rather cryptic. Both DJGPP -v on my dos box and g++ -v on the alphas here give version 2.7.2.1. I added a line after the pixel read to dump that pixel to a diagnostic file, and checked; the pixels are screwed up when they're originally read. Can someone *plueeeze* point out what the incompatibility is here, since you *really really* want to waste your time on this? Welp, here's the code. Email me at mc8860 AT pop DOT ou DOT edu if there's any actual followups to this. // start file // image class declarations #include #include #include #include // This class reads, writes, and performs edge an detection operation on // PGM files of either P2 or P5 format. class image { private: int rows, cols, type, maxgrey; int **data; // 2 dimensional array to store PGM // pixel values; to be dynamically // allocated public: image(); // default constructor image(int num_rows, int num_cols, int max_grey, int **&values); // construct image when // passed all values image(image &initimage); // copy constructor ~image(); image edges(int thresholdvalue); image& operator=(const image &initial); // overloaded operators for reading and writing // the images friend ostream& operator<<(ostream&, image&); friend istream& operator>>(istream&, image&); }; // image class definition // --------------------------------------------------------------------- // Description: This is the default constructor for the image class. // Preconditions: None. // Postconditions: The image is created with default values. // Return Value: None. image::image() { type = 0; rows = 0; cols = 0; maxgrey = 0; data = NULL; } // --------------------------------------------------------------------- // Description: This is the constructor for which all values are passed in. // Preconditions: Int r is the number of rows of pixels, int c the number of // columns, int g the maximum grey value of a pixel, and int **& is a // 2 dimensional array of the pixel values in row major order. // Postconditions: The image is created with the passed in values. // Return Value: None. image::image(int r, int c, int g, int **& values) { type = 0; rows = r; cols = c; maxgrey = g; // Allocate storage data = new (int *)[rows]; for (int i=0; i < rows; i++) { data[i]=new (int)[cols]; } // read in values for (int j=0; j < rows; j++) { for (int k=0; k < cols; k++) { data[j][k] = values[j][k]; } } } image::image(image &initimg) { rows = initimg.rows; cols = initimg.cols; type = initimg.type; maxgrey = initimg.maxgrey; // Allocate storage data = new (int *)[rows]; for (int i=0; i < rows; i++) { data[i]=new (int)[cols]; } // read in values for (int j=0; j < rows; j++) { for (int k=0; k < cols; k++) { data[j][k] = initimg.data[j][k]; } } } // --------------------------------------------------------------------- // Description: This is the equals operator for the image class. // Preconditions: A constant reference to the image to be copied. // Postconditions: The image owning the operation now contains the values // of the constant reference image. // Return Value: A reference to the modified image image& image::operator=(const image& initimg) { if (this != &initimg) // check for initimg = initimg or equivalent { for (int z=0; z < rows; z++) // wipe data, making sure to get delete[] data[z]; // all of the 2d array delete[] data; rows = initimg.rows; cols = initimg.cols; type = initimg.type; maxgrey = initimg.maxgrey; // Allocate storage data = new (int *)[rows]; for (int i=0; i < rows; i++) { data[i]=new (int)[cols]; } // read in values for (int j=0; j < rows; j++) { for (int k=0; k < cols; k++) { data[j][k] = initimg.data[j][k]; } } } return(*this); } // --------------------------------------------------------------------- // Description: This is the destructor for the image class. // Preconditions: A created image, which is the owner of the operation. // Postconditions: The owner image has had its allocated space for data[][] // deallocated. // Return Value: None. image::~image() { for (int i=0; i < rows; i++) // wipe data, making sure delete[] data[i]; // to get all of the 2d array delete[] data; } // --------------------------------------------------------------------- // Description: This is the overloaded >> (read) operator for the image class. // Preconditions: A input stream ins, and a reference to a created image. // Postconditions: The owning image now contains the row, column, maximum grey // value, type, and pixel data from the input stream. // Return Value: A reference to the input stream. istream& operator>>(istream& ins, image& current) { int linel = 79; // maximum length of a line unsigned char temp; // temporary variable for reading one P5 pixel char buffer[linel]; if (!ins) { cerr << "Input file does not exist, or is not" << "accessible.\n"; exit (2); } ins.get(temp); // skip to 5 or 2 ins.getline(buffer, linel); current.type = atoi(buffer); ins.getline(buffer, linel, ' '); // change seperator to space // so only one word is read current.rows = atoi(buffer); ins.getline(buffer, linel); current.cols = atoi(buffer); ins.getline(buffer, linel); current.maxgrey = atoi(buffer); // allocate space current.data = new (int *)[current.rows]; for (int i=0; i < current.rows; i++) { current.data[i]=new (int)[current.cols]; } // check for p2 or p5 image, and read in pixel data if (current.type == 2) { for (int j=0; j < current.rows; j++) { for (int k=0; k < current.cols; k++) { ins >> current.data[j][k]; } } } else { for (int j=0; j < current.rows; j++) { for (int k=0; k < current.cols; k++) { ins.get(temp); current.data[j][k] = temp; } } } return ins; } // --------------------------------------------------------------------- // Description: This is the overloaded output(<<) operator for the image class. // Preconditions: An ostream, and a reference to the // image owning the operation. // Postconditions: The values of the image are written to the ostream in // P2 format // Return Value: A reference to the ostream. ostream& operator<<(ostream& outs, image& current) { // output format, rows, cols, and maximum grey value outs << "P2\n"; outs << (current.rows) << " " << (current.cols) << "\n"; outs << (current.maxgrey) << "\n"; // output pixels for (int i=0; i < (current.rows); i++) { for (int j=0; j < (current.cols); j++) { outs << current.data[i][j]; if (j != (current.cols - 1)) outs << " "; } outs << "\n"; } return outs; } // --------------------------------------------------------------------- // Description: This is the edge detection/calculation operation for // the image class. // Preconditions: The image owning the operation and an integer threshold // to compare the edge values with. // Postconditions: None. // Return Value: A copy of the newly created image file with the edges // detected and shown. image image::edges(int threshold) { int xedge, yedge; int **deriv; // allocate space for edge detection results deriv = new (int *)[rows - 2]; for (int i=0; i < (rows - 2); i++) { deriv[i]=new (int)[cols - 2]; } // Calculate derivative values for array, store in temparray array // Derivative algorithm: a b c // d e f // g h i // horiz_edge = a + b + c - g - h - i // vertic_edge = a + d + g - c - f - i // edge = sqrt(sqr(horiz_edge) + sqr(vertic_edge)) // calculate from 1 to rows - 1 and cols - 1 (operation // is undefined for edge pixels) for (int j=1; j < (rows - 1); j++) { for (int k=1; k < (cols - 1); k++) { xedge = data[j-1][k-1] + data[j-1][k] + data[j-1][k+1] - data[j+1][k-1] - data[j+1][k] - data[j+1][k+1]; yedge = data[j-1][k-1] + data[j][k-1] + data[j+1][k-1] - data[j-1][k+1] - data[j][k+1] - data[j+1][k+1]; deriv[j-1][k-1] = (int)sqrt((xedge * xedge) + (yedge * yedge)); } } // Compare derivatives to the threshold; if the derivative is // equal to or larger than the threshold, replace value with maxgrey; // else replace pixel value with 0 for (int m=0; m < (rows - 2); m++) { for (int n=0; n < (cols - 2); n++) { if ((deriv[m][n]) >= threshold) deriv[m][n] = maxgrey; else deriv[m][n] = 0; } } // create new image with edges detected (deriv[][] values) image new_image(rows - 2, cols - 2, maxgrey, deriv); return(new_image); } // Description: This program performs a basic edge detection on either a // P2 or P5 format Portable Grey Map image file. // // Input: The names of the input & output image files, along with the // threshold value, are taken as command line arguments. For both // formats, the first line of the pgm file consists of the letters P2 or // P5 followed by a carriage return. The second line is the row and // column size followed by a carriage return. The third line consists // of the maximum grey value defined followed by a carriage return. // Then, for a P2 file, the grey values of all the pixels in the image are // stored thereafter in ascii format, (1, 5, 255, etc), one row to a line. // For a P5 image, the rest of the file consists of the grey value of all // the pixels listed in top-down left to right format, stored in binary. // The values of the pixels may vary from 255(white) to 0(black) for this // project. // // Error Checking: If filenames for the image files and the threshold are // not provided as command line arguments, the program exits and returns a // value of 1. If the input file does not exist, the program also exits // with a return value of 2. // // Output: A P2 format PGM image file with the edges detected and displayed. // //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //************************************************************************ // Main Program //************************************************************************ // ---------------------------------------------------------------------- // Description: The main program calls member functions of the pgm file to // read the file into the class, calculate the edges, // and then write the new image with edges back to disk. // Error checking of the number of command line parameters and valid open // of the input file is done. // // Input: The number of arguments on the calling command line, and a pointer // to an array of strings holding those arguments. // Output: None // Return value: 0 if successful; 1 if not enough command line arguments; // and 2 if the input file could not be opened. //************************************************************************ int main(int argcnt, char *args[]) { int threshold; image pgmfile, newfile; // Check for command line errors if (argcnt != 4) { cerr << "Please input the correct input, output and threshold " << "filenames again.\n"; exit (1); } // Assign threshold to integer variable from command line string threshold = atoi(args[3]); // Read input file into class ifstream ins(args[1], ios::in); ins >> pgmfile; ins.close(); // Calculate edges for the pgm, store the value in a new pgm newfile = pgmfile.edges(threshold); // Write new image ofstream outs(args[2], ios::out); outs << newfile; outs.close(); return(0); } // End of main program