#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <math.h> /* Do not modify write_pgm() or read_pgm() */ int write_pgm(char *file, void *image, uint32_t x, uint32_t y) { FILE *o; if (!(o = fopen(file, "w"))) { perror(file); return -1; } fprintf(o, "P5\n%u %u\n255\n", x, y); /* Assume input data is correctly formatted. * * There's no way to handle it, otherwise. */ if (fwrite(image, 1, x * y, o) != (x * y)) { perror("fwrite"); fclose(o); return -1; } fclose(o); return 0; } /* A better implementation of this function would read the image dimensions * * from the input and allocate the storage, setting x and y so that the * * user can determine the size of the file at runtime. In order to * * minimize complication, I've written this version to require the user to * * know the size of the image in advance. */ int read_pgm(char *file, void *image, uint32_t x, uint32_t y) { FILE *f; char s[80]; unsigned i, j; if (!(f = fopen(file, "r"))) { perror(file); return -1; } if (!fgets(s, 80, f) || strncmp(s, "P5", 2)) { fprintf(stderr, "Expected P6\n"); return -1; } /* Eat comments */ do { fgets(s, 80, f); } while (s[0] == '#'); if (sscanf(s, "%u %u", &i, &j) != 2 || i != x || j != y) { fprintf(stderr, "Expected x and y dimensions %u %u\n", x, y); fclose(f); return -1; } /* Eat comments */ do { fgets(s, 80, f); } while (s[0] == '#'); if (strncmp(s, "255", 3)) { fprintf(stderr, "Expected 255\n"); fclose(f); return -1; } if (fread(image, 1, x * y, f) != x * y) { perror("fread"); fclose(f); return -1; } fclose(f); return 0; } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <filename>\n", argv[0]); return -1; } uint8_t image[1024][1024]; uint8_t out[1024][1024]; /* This assumes that the file is a pgm image of size 1024 by 1024 */ read_pgm(argv[1], image, 1024, 1024); int8_t Ox[3][3] = { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } }; int8_t Oy[3][3] = { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } }; int r, c, j, i; for (r = 0; r < 1024; r++) { for (c = 0; c < 1024; c++) { /* Handle the cases where the kernel only partially covers the matrix */ if (r == 0 || r == 1023 || c == 0 || c == 1023) { out[r][c] = 0; continue; } int x_accumulator = 0; int y_accumulator = 0; for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) { int img_value = image[r + (j - 1)][c + (i - 1)]; x_accumulator = x_accumulator + Ox[j][i] * img_value; y_accumulator = y_accumulator + Oy[j][i] * img_value; } } int result = round(sqrt((x_accumulator * x_accumulator) + (y_accumulator * y_accumulator))); if (result > 255) result = 255; out[r][c] = result; } } /* After processing the image and storing your output in "out", write * * to sobel.pgm. */ write_pgm("sobel.pgm", out, 1024, 1024); return 0; }