#include /* gettimeofday() */ #include #include #include #include #include "BMP.h" using namespace std; void usage(const char * progName); void squashAndPadData(unsigned char * raw_data, unsigned char * padded_data, int width, int height); void applyEdgeDetection(unsigned char * padded_data, unsigned char * edge_data, int width, int height, int threshold); /************************************************************************** * Print some basic usage information for the program * *************************************************************************/ void usage(const char * progName) { cout << "Usage: " << progName << " [options] " << endl; cout << " Options:" << endl; cout << " -l level : apply threshold at level" << endl; exit(42); } /************************************************************************** * The main method is the entry point of our program * *************************************************************************/ int main(int argc, char * argv[]) { int argi; string inputFileName; string outputFileName; int threshold_level = -1; for (argi = 0; argi < argc; argi++) { if (!strcmp(argv[argi], "-l")) { if (argi >= argc - 1) usage(argv[0]); argi++; threshold_level = atoi(argv[argi]); } else { inputFileName = argv[argi]; outputFileName = string(argv[argi], strlen(argv[argi]) - 4); outputFileName += "-edges.bmp"; } } if (inputFileName == "") usage(argv[0]); BMP inputImage(inputFileName.c_str()); int width = inputImage.getWidth(); int height = inputImage.getHeight(); int num_pixels = width * height; unsigned char * bmp_data = new unsigned char[num_pixels * 3]; inputImage.read(bmp_data); unsigned char * padded_data = new unsigned char[(width + 2) * (height + 2)]; squashAndPadData(bmp_data, padded_data, width, height); delete[] bmp_data; unsigned char * edge_data = new unsigned char[width * height * 3]; struct timeval before, after; gettimeofday(&before, NULL); /* Start timing */ applyEdgeDetection(padded_data, edge_data, width, height, threshold_level); gettimeofday(&after, NULL); /* Stop timing */ /* Write the output BMP image */ BMP outputImage(outputFileName.c_str(), width, height, edge_data); double time_before = before.tv_sec + before.tv_usec / 1000000.0; double time_after = after.tv_sec + after.tv_usec / 1000000.0; double diff = time_after - time_before; cout << "Elapsed time: " << diff << " seconds." << endl; delete[] padded_data; delete[] edge_data; } /************************************************************************** * Convert the 24-bpp BMP data pointed to by raw_data to a 8-bpp * * grayscale representation * *************************************************************************/ void squashAndPadData(unsigned char * raw_data, unsigned char * padded_data, int width, int height) { for (int i = 0; i < width + 2; i++) *padded_data++ = 0; for (int i = 0; i < height; i++) { *padded_data++ = 0; for (int j = 0; j < width; j++) { *padded_data++ = (raw_data[0] + raw_data[1] + raw_data[2]) / 3; raw_data += 3; } *padded_data++ = 0; } for (int i = 0; i < width + 2; i++) *padded_data++ = 0; } /************************************************************************** * Apply the actual edge detection algorithm on the grayscale data * *************************************************************************/ void applyEdgeDetection(unsigned char * padded_data, unsigned char * edge_data, int width, int height, int threshold) { unsigned char (*in)[height+2][width+2] = (unsigned char (*)[height+2][width+2]) padded_data; unsigned char (*out)[height][width][3] = (unsigned char (*)[height][width][3]) edge_data; #pragma omp parallel for for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { /* Apply the Sobel operator on the in to * produce an out value. */ int gradY = (*in)[y][x] + 2 * (*in)[y][x+1] + (*in)[y][x+2] - (*in)[y+2][x] - 2 * (*in)[y+2][x+1] - (*in)[y+2][x+2]; int gradX = (*in)[y][x+2] + 2 * (*in)[y+1][x+2] + (*in)[y+2][x+2] - (*in)[y][x] - 2 * (*in)[y+1][x] - (*in)[y+2][x]; int grad = gradX + gradY; if (grad < 0) grad = 0; else if (grad > 255) grad = 255; if (threshold >= 0) grad = grad < threshold ? 0 : 255; (*out)[y][x][0] = grad; (*out)[y][x][1] = grad; (*out)[y][x][2] = grad; } } }