Below is the file 'aca319/lab8q1.c' from this revision. You can also download the file.
#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> #define POINTER(img,x,y) (img+(3 * (((x)*width)+(y))) ) unsigned char * load_ppm(const unsigned char *filename, int *width, int *height) { FILE *f = fopen(filename, "r"); int v, mv; unsigned char *rv; if (!f) { fprintf(stderr, "Unable to load input file: %s\n", filename); return NULL; } if ((fscanf(f, "P%d\n", &v) == EOF) || (v != 6)) { fprintf(stderr, "Wrong file version.\n"); return NULL; } if ((fscanf(f, "%d %d\n", width, height) == EOF)) { fprintf(stderr, "Unable to read height and width.\n"); return NULL; } if ((fscanf(f, "%d\n", &mv) == EOF)) { fprintf(stderr, "Unable to max value.\n"); return NULL; } rv = malloc(sizeof(unsigned char) * *height * *width * 3); if (!rv) { fprintf(stderr, "Unable to allocate image buffer\n"); return NULL; } fread(rv, sizeof(unsigned char), *height * *width * 3, f); return rv; } void write_ppm(const unsigned char *filename, int width, int height, const unsigned char *data) { FILE *out; out = fopen(filename, "w"); if (!out) { fprintf(stderr, "Unable to open output file.\n"); return; } fprintf(out, "P6\n%d %d\n255\n", width, height); fwrite(data, sizeof(unsigned char), width*height*3, out); fclose(out); } void minimum(const unsigned char **pixels, int count, char *result) { int i, p; for (p=0;p<3;p++) { result[p] = *(pixels[0] + p); for (i=0;i<count;i++) { if (*(pixels[i] + p) < result[p]) result[p] = *(pixels[i] + p); } } } void maximum(const unsigned char **pixels, int count, char *result) { int i, p; for (p=0;p<3;p++) { result[p] = *(pixels[0] + p); for (i=0;i<count;i++) { if (*(pixels[i] + p) > result[p]) result[p] = *(pixels[i] + p); } } } void average(const unsigned char **pixels, int count, char *result) { int i, p; for (p=0;p<3;p++) { int total = 0; for (i=0;i<count;i++) { total += *(pixels[i] + p); } result[p] = total / count; } } int int_compare(const void *a, const void *b) { int c = *(int *)a; int d = *(int *)b; return d - c; } void median(const unsigned char **pixels, int count, char *result) { int i, p; int median; unsigned char *s = calloc(count, sizeof(unsigned char)); if (!s) { fprintf(stderr, "Out of memory in median()\n"); } for (p=0;p<3;p++) { for (i=0;i<count;i++) { s[i] = *(pixels[i] + p); } qsort(s, count, sizeof(unsigned char), int_compare); if (count % 2) { /* average the two middle values to get median */ median = (s[count/2] + s[(count/2)+1]) / 2; } else { median = s[count/2]; } result[p] = median; } free(s); } unsigned char * run_filter(const unsigned char *clean_image, const unsigned char *dirty_image, int width, int height, void (*filter_function)(const unsigned char **, int, char *), double *error) { unsigned char *rv; int i, j; const unsigned char *cells[9]; assert(clean_image != NULL); assert(dirty_image != NULL); assert(error != NULL); rv = calloc(sizeof(unsigned char), height * width * 3); if (!rv) { fprintf(stderr, "Out of memory in run_filter\n"); return NULL; } fprintf(stderr, "Applying filter to image of size %dx%d\n", width, height); for (i=0;i<height;i++) { for (j=0;j<width;j++) { const unsigned char *clean, *unfiltered; int count; clean = POINTER(clean_image, i, j); unfiltered = POINTER(dirty_image, i, j); count = 0; /* this cell; always should be added */ cells[count] = unfiltered; count++; /* the row below */ if ((i > 0) && (j > 0)) { cells[count] = POINTER(dirty_image, i-1, j-1); count++; } if (i > 0) { cells[count] = POINTER(dirty_image, i-1, j); count++; } if ((i > 0) && (j < (width - 1))) { cells[count] = POINTER(dirty_image, i-1, j+1); count++; } /* this row */ if (j>0) { cells[count] = POINTER(dirty_image, i, j-1); count++; } if (j<width-1) { cells[count] = POINTER(dirty_image, i, j+1); count++; } /* the row above */ if ((i < height - 1) && (j > 0)) { cells[count] = POINTER(dirty_image, i+1, j-1); count++; } if (i < height - 1) { cells[count] = POINTER(dirty_image, i+1, j); count++; } if ((i < height - 1) && (j < (width - 1))) { cells[count] = POINTER(dirty_image, i+1, j+1); count++; } filter_function(cells, count, rv + (3 * ((i*width) + j))); } } return rv; } int main(int argc, char *argv[]) { int height, width; double error; unsigned char *clean, *noisy; unsigned char *result; clean = load_ppm("ViGIR.ppm", &width, &height); noisy = load_ppm("ViGIRnoisy.ppm", &width, &height); // write_ppm("bypass.ppm", width, height, noisy); result = run_filter(clean, noisy, width, height, minimum, &error); write_ppm("minimum.ppm", width, height, result); free(result); result = run_filter(clean, noisy, width, height, maximum, &error); write_ppm("maximum.ppm", width, height, result); free(result); result = run_filter(clean, noisy, width, height, average, &error); write_ppm("average.ppm", width, height, result); free(result); result = run_filter(clean, noisy, width, height, median, &error); write_ppm("median.ppm", width, height, result); free(result); free(clean); free(noisy); return 0; }