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;
+}
+