The unified diff between revisions [8e7fdeec..] and [6327b022..] is displayed below. It can also be downloaded as a raw diff.
#
#
# add_file "aca319/lab8q2.c"
# content [d67ec05875eb3c45773ab8bc2822eb836d6208ea]
#
============================================================
--- aca319/lab8q2.c d67ec05875eb3c45773ab8bc2822eb836d6208ea
+++ aca319/lab8q2.c d67ec05875eb3c45773ab8bc2822eb836d6208ea
@@ -0,0 +1,281 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+
+#include "mpi.h"
+#include "mpe.h"
+
+#define POINTER(img,x,y) (img+(((x)*width)+(y)))
+
+unsigned char *
+load_pgm(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 != 5)) {
+ 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, f);
+ return rv;
+}
+
+void
+write_pgm(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, "P5\n%d %d\n255\n", width, height);
+ fwrite(data, sizeof(unsigned char), width*height, out);
+ fclose(out);
+}
+
+unsigned char
+minimum(const unsigned char **pixels, int count)
+{
+ int i;
+ unsigned char rv;
+
+ rv = *(pixels[0]);
+ for (i=1;i<count;i++) {
+ if (*(pixels[i]) < rv)
+ rv = *(pixels[i]);
+ }
+ return rv;
+}
+
+unsigned char
+maximum(const unsigned char **pixels, int count)
+{
+ int i;
+ unsigned char rv;
+
+ rv = *(pixels[0]);
+ for (i=1;i<count;i++) {
+ if (*(pixels[i]) > rv)
+ rv = *(pixels[i]);
+ }
+ return rv;
+}
+
+unsigned char
+average(const unsigned char **pixels, int count)
+{
+ int i;
+ int total = 0;
+
+ for (i=0;i<count;i++) {
+ total += *(pixels[i]);
+ }
+ return total / count;
+}
+
+int
+char_compare(const void *a, const void *b)
+{
+ unsigned char c = *(int *)a;
+ unsigned char d = *(int *)b;
+ return c - d;
+}
+
+unsigned char
+median(const unsigned char **pixels, int count)
+{
+ int i;
+ int median;
+
+ unsigned char *s = calloc(count, sizeof(unsigned char));
+ if (!s) {
+ fprintf(stderr, "Out of memory in median()\n");
+ }
+
+ for (i=0;i<count;i++) {
+ s[i] = *(pixels[i]);
+ }
+ qsort(s, count, sizeof(unsigned char), char_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];
+ }
+ free(s);
+ return median;
+}
+
+unsigned char *
+run_filter(const unsigned char *clean_image, const unsigned char *dirty_image,
+ int width, int height, int offset, int assigned_length, int rank, int size,
+ unsigned char (*filter_function)(const unsigned char **, int),
+ unsigned long *error)
+{
+ unsigned char *rv;
+ int i, j;
+ const unsigned char *cells[9];
+ unsigned long error_count=0;
+
+ assert(clean_image != NULL);
+ assert(dirty_image != NULL);
+ assert(error != NULL);
+
+ rv = calloc(sizeof(unsigned char), height * width);
+ if (!rv) {
+ fprintf(stderr, "Out of memory in run_filter\n");
+ return NULL;
+ }
+
+ for (i=offset;i<offset+assigned_length;i++) {
+ for (j=0;j<width;j++) {
+ const unsigned char *clean, *unfiltered;
+ unsigned char filtered;
+ 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++;
+ }
+ filtered = filter_function(cells, count);
+ *POINTER(rv, i, j) = filtered;
+ error_count += ((unsigned int)*clean - (unsigned int)filtered) * ((unsigned int)*clean - (unsigned int)filtered);
+ }
+ }
+
+ //*error = error_count / (width * height);
+ *error = error_count;
+
+ return rv;
+}
+
+void
+run_filter_in_mpi(int rank, int size, unsigned char *clean, unsigned char *noisy, int width, int height,
+ const char *output_file,
+ unsigned char (*filter_function)(const unsigned char **, int))
+{
+ unsigned long error_count;
+ unsigned long *error_vector;
+ unsigned char *result;
+ unsigned char *total_result;
+ int my_offset, my_length;
+ int i;
+
+ my_offset = rank * (height / size);
+ my_length = height / size;
+ if (rank < height % size) {
+ my_offset += rank;
+ my_length++;
+ }
+ result = run_filter(clean, noisy, width, height, my_offset, my_length, rank, size, filter_function, &error_count);
+ memmove(result, result+(my_offset*width), my_length*width);
+
+ total_result = malloc(sizeof(unsigned char) * height * width);
+ MPI_Gather(result, my_length * width, MPI_CHAR, total_result, my_length * width, MPI_CHAR, 0, MPI_COMM_WORLD);
+ if (rank == 0) {
+ write_pgm(output_file, width, height, total_result);
+ }
+
+ error_vector = calloc(sizeof(unsigned long), size);
+ MPI_Gather(&error_count, 1, MPI_LONG, error_vector, 1, MPI_LONG, 0, MPI_COMM_WORLD);
+ if (rank == 0) {
+ double error_result;
+ error_count = 0;
+ for (i=0; i<size; i++) {
+ error_count += error_vector[i];
+ }
+ error_result = error_count / (width * height);
+ printf("%s: mean squared error=%f\n", output_file, error_result);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ unsigned char *clean, *noisy;
+ int height, width;
+ int rank, size;
+
+ MPI_Init(&argc, &argv);
+
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+ clean = load_pgm("ViGIR.pgm", &width, &height);
+ noisy = load_pgm("ViGIRnoisy.pgm", &width, &height);
+
+ run_filter_in_mpi(rank, size, clean, noisy, width, height, "minimum.pgm", minimum);
+ run_filter_in_mpi(rank, size, clean, noisy, width, height, "maximum.pgm", maximum);
+ run_filter_in_mpi(rank, size, clean, noisy, width, height, "average.pgm", average);
+ run_filter_in_mpi(rank, size, clean, noisy, width, height, "median.pgm", median);
+
+ free(clean);
+ free(noisy);
+
+ MPI_Finalize();
+
+ return 0;
+}
+