//*********************************************************************** // convolve.c // author: Matthew Judd and John Karpovich // mrj2p@virginia.edu and jfk3w@Virginia.edu // University of Virginia // December 7, 1992 // // // compilation: // make serial - for serial version // make all - for MENTAT parallel version // // description: // Implements virtual class definitions for convolving example of the // Stenciler base class. // // user responsibility: // Write setRowsAndCols() code - this code initializes the number of rows // and columns in the image. It also initializes the window variables to // include the whole image. // // Write getNextStencil() code - this function both returns the next stencil // to apply to the matrix, and decides whether or not to stop applying // filters. // // Write prepareDest() code - this function prepares the destination file // to receive the final image from the convolvers. Any information // the destination file needs other than that image must be written here. //*********************************************************************** // **************************************************************************** // // Copyright (c) 1992 // University of Virginia // All Rights Reserved // // This software is the property of the University of Virginia. // This software is provided `as is' and without any express or // implied warrenties. // // Send problems & suggestions to: // Andrew Grimshaw (grimshaw@cs.virginia.edu) // // ************************************************************************** #include #include #include #include #include "convolve.h" //************************************************************************ //************************************************************************ // // USER DEFINED CONVOLVER FUNCTIONS // //************************************************************************ //******************+****************************************************** void convolve::workers_alloc(int pieces) { #ifndef SERIAL convolve prototype; // a convolve handle used to create the // vector of workers needed. if (pieces >0) workers = (Stenciler*)mentat_vec_create(prototype, pieces); #else if (pieces >0) workers = new convolve[pieces]; #endif } void convolve::destroy_workers(int pieces) { int i; convolve *tempWorker; #ifndef SERIAL for (i = 0; i < pieces; i++) { tempWorker = (convolve *) &(workers[i]); tempWorker->destroy(); } #else delete workers; #endif } //************************************************************************* // Name of file with source image is sNm // // This code should determine the number of rows and columns in the data // matrix, and set the Stenciler member variables numRows and numCols. // Finally, it should set the Stenciler member variables lr_row_window // and lr_col_window, which designate the lower right point defining the // part of the image which is mutable, to (numRows - 1) and (numCols - 1), // respectively. // Examples of this file for use with .ppx format and user-defined formats // exist with the convolve and pde examples. //************************************************************************* int convolve::setRowsCols() { int ret_val; srcFile = fopen((char *)srcNm, "r"); if (srcFile != NULL) { fseek(srcFile, 3L, 0); numRows = (fgetc(srcFile) & 0377) << 8; numRows |= (fgetc(srcFile) & 0377); numCols = (fgetc(srcFile) & 0377) << 8; numCols |= (fgetc(srcFile) & 0377); ulRow = 0; ulCol = 0; lrRow = numRows; lrCol = numCols; } else { fprintf(stderr, "Cannot open %s\n", srcNm); fflush(stderr); } lr_row_window = numRows - 1; lr_col_window = numCols - 1; ret_val = lr_col_window; return (ret_val); } //************************************************************************ // Determines whether or not to continue applying stencils; if so, // determines what the next stencil is and returns a pointer to it. If // loop is finished, returns a NULL pointer //************************************************************************ stencil* convolve::getNextStencil() { stencil *next; if (currentStencil == NULL) next = NULL; else next = currentStencil->st; if (currentStencil != NULL) currentStencil = currentStencil->next; return (next); } //************************************************************************ // This function is used to prepare the destination file to accept the // data from the workers. For example, if the chosen file format requires // a header, this function should write that header to the output file. // After this function has been called, the output file should need nothing // but the actual matrix data to be complete. //************************************************************************ void convolve::prepareDest() { char hdr[512]; srcFile = fopen ((char*) srcNm, "r"); destFile = fopen ((char*) destNm, "w"); fread (hdr, sizeof(char), 512, srcFile); fwrite (hdr, sizeof(char), 512, destFile); fclose (srcFile); fclose (destFile); } // ************************************************************************** // Output this section of final image to target file. // // This function should open the destination file, copy this workers piece // into that file in the correct place, and then close the output file. // Examples for both image convolution and pde's are in the example files; // both output images into files in .ppx format. // ************************************************************************** void convolve::putMatrixPiece() { DATA_TYPE *rowPtr; int i, j; int hdrSz, offset, colOffset; int ulr, lrr; destFile = fopen((char*) destNm, "r+"); if (destFile == NULL) { fprintf (stderr, "ERROR! Cannot open destination file %s\n", (char*) destNm); fflush (stderr); exit (-1); } hdrSz = 512; offset = hdrSz + (((matrixCols * ulRow) + ulCol) * sizeof (DATA_TYPE)); colOffset = (matrixCols - numCols) * sizeof (DATA_TYPE); fseek (destFile, offset, 0); ulr = maxStencilRows; lrr = ulr + numRows - 1; for (i = ulr; i <= lrr; i++) { rowPtr = srcArray->get_r_ptr(i); rowPtr += maxStencilCols; if (0 == (j=fwrite (rowPtr, sizeof (DATA_TYPE), numCols, destFile))) { fprintf (stderr, "ERROR! Cannot fwrite to %s\n", (char*) destNm); fflush (stderr); exit (-1); } fseek (destFile, colOffset, 1); } fclose (destFile); } // ************************************************************************** // Apply given stencil to workers section of image. // // This function describes the actual work to be done to each piece of the // input matrix with each stencil. Examples for image convolution and // partial differential equations are in the example files. // ************************************************************************** void convolve::doStencilPiece(stencil *sten) { DATA_TYPE *stenr, *srcr, *destr, *currSrcPtr, *currStenPtr; int stenRows, stenCols, stenSum, stenSz; int ulr, ulc, lrr, lrc; int i, j, k, l; int totalCols; long destval; MATRIX_TYPE *tmpArray; float inverseOfDivisor; stenRows = sten->num_row(); stenCols = sten->num_col(); currStRows = stenRows/2; currStCols = stenCols/2; stenSz = stenRows*stenCols; stenr = sten->get_r_ptr(0); // set divisor equal to sum of absolute values of stencil points stenSum = 0; for (i=0; i < stenSz; i++) if (stenr[i] < 0) stenSum -= stenr[i]; else stenSum += stenr[i]; // make sure divisor not zero if (stenSum == 0) stenSum = 1; inverseOfDivisor = 1.0/(float) stenSum; // set region to work on in terms of the source array's coords. // window coords are relative to "real" data, i.e 0,0 = top left corner // of real data, not source array. That's why we need to add in // maxStencilxxx to calc offset. ulr = (w_ulRow - ulRow) + maxStencilRows; ulc = (w_ulCol - ulCol) + maxStencilCols; lrr = ulr + numRows - 1 - (lrRow - w_lrRow); lrc = ulc + numCols - 1 - (lrCol - w_lrCol); totalCols = (maxStencilCols * 2) + numCols; for (i=ulr; i <= lrr; i++) { // point srcr to the beginning of where the data for this stencil // will come from (i.e. to the upper left of the current // destination point) srcr = srcArray->get_r_ptr(i-currStRows); srcr += (ulc - currStCols); destr = destArray->get_r_ptr(i); destr += ulc; for (j=ulc; j <= lrc; j++) { destval = 0; currSrcPtr = srcr; currStenPtr = stenr; for (k=0;k < stenRows; k++) { for (l=0; l < stenCols;l++) destval += currStenPtr[l]*currSrcPtr[l]; currStenPtr += stenCols; currSrcPtr += totalCols; } *destr = (DATA_TYPE) (destval*inverseOfDivisor); destr++; srcr++; } } tmpArray = srcArray; srcArray = destArray; destArray = tmpArray; } // ************************************************************************** // Read workers section of Matrix from given input file, using values sent // from convolver through init(). Called from the init() function. // // This function must get each workers pice from the input file. It should // use Stenciler member variables matrixCols, ulRow, ulCol, and numCols // to determine the offset from the beginning of the file to the start of the // first piece row, and the distance in the input file from the end of one // piece row to the beginning of the next. // ************************************************************************** void convolve::getMatrixPiece() { int hdrSz, offset, colOffset; int ulr, lrr; int i, j; DATA_TYPE *rowPtr; srcFile = fopen ((char*) srcNm, "r"); if (srcFile == NULL) { fprintf (stderr, "ERROR! Cannot open file %s\n", (char*) srcNm); fflush (stderr); exit (-1); } hdrSz = 512; // The size of the header of an image in .ppx format offset = hdrSz + (((matrixCols * ulRow) + ulCol) * sizeof (DATA_TYPE)); colOffset = (matrixCols - numCols) * sizeof(DATA_TYPE); fseek (srcFile, offset, 0); ulr = maxStencilRows; lrr = ulr + numRows - 1; for (i=ulr; i <= lrr; i++) { rowPtr = srcArray->get_r_ptr(i); rowPtr += maxStencilCols; if (0 == (j=fread (rowPtr, sizeof(DATA_TYPE), numCols, srcFile))) { fprintf (stderr, "ERROR! Cannot fread %s\n", (char*)srcNm); fflush (stderr); exit(-1); } fseek (srcFile, colOffset, 1); } fclose (srcFile); }