#include #include #include #include #include "args.h" #include "ppm.h" static Image image_convolution(Image input, float kernel[9]); static void split_rgb(Image input, uint8_t *r, uint8_t *g, uint8_t *b); static void merge_rgb(Image *out, uint8_t *r, uint8_t *g, uint8_t *b); static uint8_t kernel_op(uint8_t *data, float kernel[9], int i, int j, int w, int h); static void usage(void); void usage(void) { fprintf(stderr, "Usage: dsco [INPUT] -f [edge|blur] [-o OUTPUT]\n"); exit(1); } Image image_convolution(Image input, float kernel[9]) { Image out; out.width = input.width; out.height = input.height; out.pixel_bits = input.pixel_bits; size_t n_pixels = out.width * out.height * 3; out.data = calloc(n_pixels, sizeof(uint8_t)); if (out.data == NULL) { perror("image_convolution() Error"); exit(1); } uint8_t *r, *g, *b; uint8_t red, green, blue; r = calloc(input.width * input.height, sizeof(uint8_t)); g = calloc(input.width * input.height, sizeof(uint8_t)); b = calloc(input.width * input.height, sizeof(uint8_t)); split_rgb(input, r, g, b); int i, j, index; for (i = 0; i < input.height; i++) { for (j = 0; j < input.width; j++) { index = i * input.width + j; red = kernel_op(r, kernel, i, j, input.width, input.height); green = kernel_op(g, kernel, i, j, input.width, input.height); blue = kernel_op(b, kernel, i, j, input.width, input.height); out.data[index * 3] = red; out.data[index * 3 + 1] = green; out.data[index * 3 + 2] = blue; } } //merge_rgb(&out, r, g, b); free(r); free(g); free(b); return out; } void merge_rgb(Image *out, uint8_t *r, uint8_t *g, uint8_t *b) { int i; for (i = 0; i < out->width * out->height; i++) { out->data[3 * i] = r[i]; out->data[3 * i + 1] = g[i]; out->data[3 * i + 2] = b[i]; } } uint8_t kernel_op(uint8_t *data, float kernel[9], int i, int j, int w, int h) { float kernel_value = 0; int ki, kj, img_index, index_i, index_j, index_k; for (ki = 0; ki < 3; ki++) { for (kj = 0; kj < 3; kj++) { index_i = i + ki - 1; //height index_j = j + kj - 1; //width index_k = 3 * ki + kj; if (index_i < 0 || index_i >= h || index_j < 0 || index_j >= w) kernel_value += data[i * w + j] * kernel[index_k]; else { img_index = index_i * w + index_j; kernel_value += data[img_index] * kernel[index_k]; } } } kernel_value = (kernel_value > 255) ? 255: kernel_value; kernel_value = (kernel_value < 0) ? 0: kernel_value; return (uint8_t)kernel_value; } void split_rgb(Image input, uint8_t *r, uint8_t *g, uint8_t *b) { if (!r || !g || !b) { perror("rgb_split() Error"); exit(1); } int i; for (i = 0; i < input.width * input.height; i++) { r[i] = input.data[3 * i]; g[i] = input.data[3 * i + 1]; b[i] = input.data[3 * i + 2]; } } int main(int argc, char *argv[]) { int opt; char *cli_arg; char *filter, *out_file, *in_file; cli_arg = in_file = filter = out_file = NULL; while ((opt = args_getopt(argc, argv, "hf:o:", &cli_arg)) != -1) { switch (opt) { case 'f': filter = cli_arg; break; case 'o': out_file = cli_arg; break; case 0: in_file = cli_arg; break; default: usage(); } } char default_input[] = "/dev/stdin"; char default_output[] = "/dev/stdout"; if (!in_file) in_file = default_input; if (!in_file) in_file = default_output; float edge[9] = { -1, -1, -1, -1, 8, -1, -1, -1, -1, }; float blur[9] = { 1, 2, 1, 2, 4, 2, 1, 2, 1, }; int i; for (i = 0; i < 9; i++) blur[i] /= 16; float sharpen[9] = { 0, -1, 0, -1, 5, -1, 0, -1, 0, }; float *kernel = NULL; if (!strcmp(filter, "edge")) kernel = edge; else if (!strcmp(filter, "blur")) kernel = blur; else if (!strcmp(filter, "sharpen")) kernel = sharpen; else usage(); Image img, out; ppm_read(in_file, &img); out = image_convolution(img, kernel); ppm_write(out_file, &out); return 0; }