#!/bin/bash gcc improc.c main.c -O3 -g -Wall -Wpedantic -lm -Wextra -o main #!/bin/bash gcc improc.c main.c -O3 -g -Wall -Wpedantic -lm -Wextra -o main Stack Exchange network consists of 183 Q&A communities including Stack Overflow, the largest, most trusted online community for developers to learn, share their knowledge, and build their careers.
Visit Stack ExchangeStack Internal
Knowledge at work
Bring the best of human thought and AI automation together at your work.
Explore Stack Internal#!/bin/bash gcc improc.c main.c -O3 -g -Wall -Wpedantic -lm -Wextra -o main #!/bin/bash gcc improc.c main.c -O3 -g -Wall -Wpedantic -lm -Wextra -o main #!/bin/bash gcc improc.c main.c -O3 -g -Wall -Wpedantic -lm -Wextra -o main #!/bin/bash gcc improc.c main.c -O3 -g -Wall -Wpedantic -lm -Wextra -o main #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <math.h> #include <unistd.h> #include <errno.h> #include "improc.h" Image *create_image(int width, int height) { Image *image = malloc(sizeof(Image)); if (image == NULL) { fprintf(stderr, "Could not allocate memory to Image: %s\n", strerror(errno)); return NULL; } image->width = width; image->height = height; image->pixels = malloc(width*height*sizeof(Pixel)); if (image->pixels == NULL) { free(image); fprintf(stderr, "Could not allocate memory to pixels: %s\n", strerror(errno)); return NULL; } return image; } void free_image(Image *image) { if (image != NULL) { if (image->pixels != NULL) free(image->pixels); free(image); } } Image *load_image(char *filename) { char magic[3]; int maxval, width, height; FILE *fp = fopen(filename, "rb"); if (fp == NULL) { fprintf(stderr, "Error opening file: %s\n", strerror(errno)); return NULL; } fscanf(fp, "%2s", magic); if (magic[0] != 'P' || magic[1] != '6') { fprintf(stderr, "Not a valid P6 ppm file: %s\n", strerror(errno)); fclose(fp); return NULL; } fscanf(fp, "%d%d%*c", &width, &height); Image *image = create_image(width, height); fscanf(fp, "%d%*c", &maxval); fread(image->pixels, sizeof(Pixel),image->width*image->height, fp); fclose(fp); return image; } int save_image(char *filename, Image image) { FILE *fp = fopen(filename, "wb"); if (fp == NULL) { fprintf(stderr, "Error opening file: %s\n", strerror(errno)); return -1; } fprintf(fp, "P6\n%d %d\n255\n", image.width, image.height); fwrite(image.pixels, sizeof(Pixel), image.width*image.height, fp); fclose(fp); return 0; } Image *grayscale(Image image) { Image *gray = create_image(image.width, image.height); Pixel pix; int index; uint8_t avg; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { index = row*image.width + col; pix = image.pixels[index]; avg = (uint8_t) ((pix.r + pix.g + pix.b)/3.0); gray->pixels[index] = (Pixel) {avg, avg, avg}; } } return gray; } Image *perceptual_grayscale(Image image) { Image *gray = create_image(image.width, image.height); Pixel pix; uint8_t bt_601; int index; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { index = row*image.width + col; pix = image.pixels[index]; bt_601 = (uint8_t) (0.2126*pix.r + 0.7152*pix.g + 0.0722*pix.b); gray->pixels[index] = (Pixel) {bt_601, bt_601, bt_601}; } } return gray; } double kernel_min(Kernel kernel) { double min = 0; for (int index = 0; index < kernel.size*kernel.size; index++) { if (kernel.weights[index] < 0) min += kernel.weights[index]; } return min*255; } double kernel_max(Kernel kernel) { double max = 0; for (int index = 0; index < kernel.size*kernel.size; index++) { if (kernel.weights[index] > 0) max += kernel.weights[index]; } return max*255; } Accumulator convolve(Image image, Kernel kernel, int row, int col) { Accumulator accumulator = {0, 0, 0}; for (int r_off = -kernel.size/2; r_off <= kernel.size/2; r_off++) { for (int c_off = -kernel.size/2; c_off <= kernel.size/2; c_off++) { int ir = modulo(row + r_off, image.height); int ic = modulo(col + c_off, image.width); int kr = r_off + kernel.size/2; int kc = c_off + kernel.size/2; int index = ir*image.width + ic; Pixel pixel = image.pixels[index]; accumulator.r += pixel.r*kernel.weights[kr*kernel.size + kc]; accumulator.g += pixel.g*kernel.weights[kr*kernel.size + kc]; accumulator.b += pixel.b*kernel.weights[kr*kernel.size + kc]; } } return accumulator; } Image *apply_kernel(Image image, Kernel kernel) { Image *conv = create_image(image.width, image.height); double max = kernel_max(kernel); double min = kernel_min(kernel); double alpha = max - min; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { Accumulator accumulator = convolve(image, kernel, row, col); accumulator.r = 255*(accumulator.r - min)/alpha; accumulator.g = 255*(accumulator.g - min)/alpha; accumulator.b = 255*(accumulator.b - min)/alpha; conv->pixels[row*image.width + col].r = accumulator.r; conv->pixels[row*image.width + col].g = accumulator.g; conv->pixels[row*image.width + col].b = accumulator.b; } printf("%lf\r", 100.0*(1.0*row)/image.height); fflush(stdout); } return conv; } Kernel sobel_x(int n) { Kernel sx; sx.size = 3; sx.weights = malloc(sizeof(double)*sx.size*sx.size); sx.weights[0] = -1; sx.weights[1] = -2; sx.weights[2] = -1; sx.weights[3] = 0; sx.weights[4] = 0; sx.weights[5] = 0; sx.weights[6] = 1; sx.weights[7] = 2; sx.weights[8] = 1; return sx; } Kernel sobel_y(int n) { Kernel sy; sy.size = 3; sy.weights = malloc(sy.size*sy.size*sizeof(double)); sy.weights[0] = -1; sy.weights[1] = 0; sy.weights[2] = 1; sy.weights[3] = -2; sy.weights[4] = 0; sy.weights[5] = 2; sy.weights[6] = -1; sy.weights[7] = 0; sy.weights[8] = 1; return sy; } Image *sobel(Image image) { Image *conv = create_image(image.width, image.height); Image *sobx, *soby; Kernel sx = sobel_x(3); Kernel sy = sobel_y(3); sobx = apply_kernel(image, sx); soby = apply_kernel(image, sy); save_image("sobel_x.ppm", *sobx); save_image("sobel_y.ppm", *soby); double max = kernel_max(sx); double min = kernel_min(sx); double alpha = max - min; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { Accumulator x = convolve(image, sx, row, col); Accumulator y = convolve(image, sy, row, col); x.r = 255*(x.r)/alpha; x.g = 255*(x.g)/alpha; x.b = 255*(x.b)/alpha; y.r = 255*(y.r)/alpha; y.g = 255*(y.g)/alpha; y.b = 255*(y.b)/alpha; Accumulator gradient = { sqrt(x.r*x.r + y.r*y.r), sqrt(x.g*x.g + y.g*y.g), sqrt(x.b*x.b + y.b*y.b), }; /* gradient.r = (gradient.r > 255)? 255: gradient.r; gradient.g = (gradient.g > 255)? 255: gradient.g; gradient.b = (gradient.b > 255)? 255: gradient.b; printf("\n"); printf("x.r: %lf, y.r: %lf, gradient.r: %lf\n", x.r, y.r, gradient.r); printf("x.g: %lf, y.g: %lf, gradient.g: %lf\n", x.g, y.g, gradient.g); printf("x.b: %lf, y.b: %lf, gradient.b: %lf\n", x.b, y.b, gradient.b); printf("\n"); sleep(1); */ conv->pixels[row*image.width + col].r = (uint8_t) gradient.r; conv->pixels[row*image.width + col].g = (uint8_t) gradient.g; conv->pixels[row*image.width + col].b = (uint8_t) gradient.b; } printf("%lf\r", 100.0*(1.0*row)/image.height); fflush(stdout); } return conv; } unsigned modulo(int value, unsigned m) { int mod = value % (int) m; if (mod < 0) mod += m; return mod; } improc.h
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <math.h> #include <unistd.h> #include <errno.h> #include "improc.h" Image *create_image(int width, int height) { Image *image = malloc(sizeof(Image)); if (image == NULL) { fprintf(stderr, "Could not allocate memory to Image: %s\n", strerror(errno)); return NULL; } image->width = width; image->height = height; image->pixels = malloc(width*height*sizeof(Pixel)); if (image->pixels == NULL) { free(image); fprintf(stderr, "Could not allocate memory to pixels: %s\n", strerror(errno)); return NULL; } return image; } void free_image(Image *image) { if (image != NULL) { if (image->pixels != NULL) free(image->pixels); free(image); } } Image *load_image(char *filename) { char magic[3]; int maxval, width, height; FILE *fp = fopen(filename, "rb"); if (fp == NULL) { fprintf(stderr, "Error opening file: %s\n", strerror(errno)); return NULL; } fscanf(fp, "%2s", magic); if (magic[0] != 'P' || magic[1] != '6') { fprintf(stderr, "Not a valid P6 ppm file: %s\n", strerror(errno)); fclose(fp); return NULL; } fscanf(fp, "%d%d%*c", &width, &height); Image *image = create_image(width, height); fscanf(fp, "%d%*c", &maxval); fread(image->pixels, sizeof(Pixel),image->width*image->height, fp); fclose(fp); return image; } int save_image(char *filename, Image image) { FILE *fp = fopen(filename, "wb"); if (fp == NULL) { fprintf(stderr, "Error opening file: %s\n", strerror(errno)); return -1; } fprintf(fp, "P6\n%d %d\n255\n", image.width, image.height); fwrite(image.pixels, sizeof(Pixel), image.width*image.height, fp); fclose(fp); return 0; } Image *grayscale(Image image) { Image *gray = create_image(image.width, image.height); Pixel pix; int index; uint8_t avg; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { index = row*image.width + col; pix = image.pixels[index]; avg = (uint8_t) ((pix.r + pix.g + pix.b)/3.0); gray->pixels[index] = (Pixel) {avg, avg, avg}; } } return gray; } Image *perceptual_grayscale(Image image) { Image *gray = create_image(image.width, image.height); Pixel pix; uint8_t bt_601; int index; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { index = row*image.width + col; pix = image.pixels[index]; bt_601 = (uint8_t) (0.2126*pix.r + 0.7152*pix.g + 0.0722*pix.b); gray->pixels[index] = (Pixel) {bt_601, bt_601, bt_601}; } } return gray; } double kernel_min(Kernel kernel) { double min = 0; for (int index = 0; index < kernel.size*kernel.size; index++) { if (kernel.weights[index] < 0) min += kernel.weights[index]; } return min*255; } double kernel_max(Kernel kernel) { double max = 0; for (int index = 0; index < kernel.size*kernel.size; index++) { if (kernel.weights[index] > 0) max += kernel.weights[index]; } return max*255; } Accumulator convolve(Image image, Kernel kernel, int row, int col) { Accumulator accumulator = {0, 0, 0}; for (int r_off = -kernel.size/2; r_off <= kernel.size/2; r_off++) { for (int c_off = -kernel.size/2; c_off <= kernel.size/2; c_off++) { int ir = modulo(row + r_off, image.height); int ic = modulo(col + c_off, image.width); int kr = r_off + kernel.size/2; int kc = c_off + kernel.size/2; int index = ir*image.width + ic; Pixel pixel = image.pixels[index]; accumulator.r += pixel.r*kernel.weights[kr*kernel.size + kc]; accumulator.g += pixel.g*kernel.weights[kr*kernel.size + kc]; accumulator.b += pixel.b*kernel.weights[kr*kernel.size + kc]; } } return accumulator; } Image *apply_kernel(Image image, Kernel kernel) { Image *conv = create_image(image.width, image.height); double max = kernel_max(kernel); double min = kernel_min(kernel); double alpha = max - min; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { Accumulator accumulator = convolve(image, kernel, row, col); accumulator.r = 255*(accumulator.r - min)/alpha; accumulator.g = 255*(accumulator.g - min)/alpha; accumulator.b = 255*(accumulator.b - min)/alpha; conv->pixels[row*image.width + col].r = accumulator.r; conv->pixels[row*image.width + col].g = accumulator.g; conv->pixels[row*image.width + col].b = accumulator.b; } printf("%lf\r", 100.0*(1.0*row)/image.height); fflush(stdout); } return conv; } Kernel sobel_x(int n) { Kernel sx; sx.size = 3; sx.weights = malloc(sizeof(double)*sx.size*sx.size); sx.weights[0] = -1; sx.weights[1] = -2; sx.weights[2] = -1; sx.weights[3] = 0; sx.weights[4] = 0; sx.weights[5] = 0; sx.weights[6] = 1; sx.weights[7] = 2; sx.weights[8] = 1; return sx; } Kernel sobel_y(int n) { Kernel sy; sy.size = 3; sy.weights = malloc(sy.size*sy.size*sizeof(double)); sy.weights[0] = -1; sy.weights[1] = 0; sy.weights[2] = 1; sy.weights[3] = -2; sy.weights[4] = 0; sy.weights[5] = 2; sy.weights[6] = -1; sy.weights[7] = 0; sy.weights[8] = 1; return sy; } Image *sobel(Image image) { Image *conv = create_image(image.width, image.height); Image *sobx, *soby; Kernel sx = sobel_x(3); Kernel sy = sobel_y(3); sobx = apply_kernel(image, sx); soby = apply_kernel(image, sy); save_image("sobel_x.ppm", *sobx); save_image("sobel_y.ppm", *soby); double max = kernel_max(sx); double min = kernel_min(sx); double alpha = max - min; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { Accumulator x = convolve(image, sx, row, col); Accumulator y = convolve(image, sy, row, col); x.r = 255*(x.r)/alpha; x.g = 255*(x.g)/alpha; x.b = 255*(x.b)/alpha; y.r = 255*(y.r)/alpha; y.g = 255*(y.g)/alpha; y.b = 255*(y.b)/alpha; Accumulator gradient = { sqrt(x.r*x.r + y.r*y.r), sqrt(x.g*x.g + y.g*y.g), sqrt(x.b*x.b + y.b*y.b), }; /* gradient.r = (gradient.r > 255)? 255: gradient.r; gradient.g = (gradient.g > 255)? 255: gradient.g; gradient.b = (gradient.b > 255)? 255: gradient.b; printf("\n"); printf("x.r: %lf, y.r: %lf, gradient.r: %lf\n", x.r, y.r, gradient.r); printf("x.g: %lf, y.g: %lf, gradient.g: %lf\n", x.g, y.g, gradient.g); printf("x.b: %lf, y.b: %lf, gradient.b: %lf\n", x.b, y.b, gradient.b); printf("\n"); sleep(1); */ conv->pixels[row*image.width + col].r = (uint8_t) gradient.r; conv->pixels[row*image.width + col].g = (uint8_t) gradient.g; conv->pixels[row*image.width + col].b = (uint8_t) gradient.b; } printf("%lf\r", 100.0*(1.0*row)/image.height); fflush(stdout); } return conv; } unsigned modulo(int value, unsigned m) { int mod = value % (int) m; if (mod < 0) mod += m; return mod; } #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <math.h> #include <unistd.h> #include <errno.h> #include "improc.h" Image *create_image(int width, int height) { Image *image = malloc(sizeof(Image)); if (image == NULL) { fprintf(stderr, "Could not allocate memory to Image: %s\n", strerror(errno)); return NULL; } image->width = width; image->height = height; image->pixels = malloc(width*height*sizeof(Pixel)); if (image->pixels == NULL) { free(image); fprintf(stderr, "Could not allocate memory to pixels: %s\n", strerror(errno)); return NULL; } return image; } void free_image(Image *image) { if (image != NULL) { if (image->pixels != NULL) free(image->pixels); free(image); } } Image *load_image(char *filename) { char magic[3]; int maxval, width, height; FILE *fp = fopen(filename, "rb"); if (fp == NULL) { fprintf(stderr, "Error opening file: %s\n", strerror(errno)); return NULL; } fscanf(fp, "%2s", magic); if (magic[0] != 'P' || magic[1] != '6') { fprintf(stderr, "Not a valid P6 ppm file: %s\n", strerror(errno)); fclose(fp); return NULL; } fscanf(fp, "%d%d%*c", &width, &height); Image *image = create_image(width, height); fscanf(fp, "%d%*c", &maxval); fread(image->pixels, sizeof(Pixel),image->width*image->height, fp); fclose(fp); return image; } int save_image(char *filename, Image image) { FILE *fp = fopen(filename, "wb"); if (fp == NULL) { fprintf(stderr, "Error opening file: %s\n", strerror(errno)); return -1; } fprintf(fp, "P6\n%d %d\n255\n", image.width, image.height); fwrite(image.pixels, sizeof(Pixel), image.width*image.height, fp); fclose(fp); return 0; } Image *grayscale(Image image) { Image *gray = create_image(image.width, image.height); Pixel pix; int index; uint8_t avg; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { index = row*image.width + col; pix = image.pixels[index]; avg = (uint8_t) ((pix.r + pix.g + pix.b)/3.0); gray->pixels[index] = (Pixel) {avg, avg, avg}; } } return gray; } Image *perceptual_grayscale(Image image) { Image *gray = create_image(image.width, image.height); Pixel pix; uint8_t bt_601; int index; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { index = row*image.width + col; pix = image.pixels[index]; bt_601 = (uint8_t) (0.2126*pix.r + 0.7152*pix.g + 0.0722*pix.b); gray->pixels[index] = (Pixel) {bt_601, bt_601, bt_601}; } } return gray; } double kernel_min(Kernel kernel) { double min = 0; for (int index = 0; index < kernel.size*kernel.size; index++) { if (kernel.weights[index] < 0) min += kernel.weights[index]; } return min*255; } double kernel_max(Kernel kernel) { double max = 0; for (int index = 0; index < kernel.size*kernel.size; index++) { if (kernel.weights[index] > 0) max += kernel.weights[index]; } return max*255; } Accumulator convolve(Image image, Kernel kernel, int row, int col) { Accumulator accumulator = {0, 0, 0}; for (int r_off = -kernel.size/2; r_off <= kernel.size/2; r_off++) { for (int c_off = -kernel.size/2; c_off <= kernel.size/2; c_off++) { int ir = modulo(row + r_off, image.height); int ic = modulo(col + c_off, image.width); int kr = r_off + kernel.size/2; int kc = c_off + kernel.size/2; int index = ir*image.width + ic; Pixel pixel = image.pixels[index]; accumulator.r += pixel.r*kernel.weights[kr*kernel.size + kc]; accumulator.g += pixel.g*kernel.weights[kr*kernel.size + kc]; accumulator.b += pixel.b*kernel.weights[kr*kernel.size + kc]; } } return accumulator; } Image *apply_kernel(Image image, Kernel kernel) { Image *conv = create_image(image.width, image.height); double max = kernel_max(kernel); double min = kernel_min(kernel); double alpha = max - min; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { Accumulator accumulator = convolve(image, kernel, row, col); accumulator.r = 255*(accumulator.r - min)/alpha; accumulator.g = 255*(accumulator.g - min)/alpha; accumulator.b = 255*(accumulator.b - min)/alpha; conv->pixels[row*image.width + col].r = accumulator.r; conv->pixels[row*image.width + col].g = accumulator.g; conv->pixels[row*image.width + col].b = accumulator.b; } printf("%lf\r", 100.0*(1.0*row)/image.height); fflush(stdout); } return conv; } Kernel sobel_x(int n) { Kernel sx; sx.size = 3; sx.weights = malloc(sizeof(double)*sx.size*sx.size); sx.weights[0] = -1; sx.weights[1] = -2; sx.weights[2] = -1; sx.weights[3] = 0; sx.weights[4] = 0; sx.weights[5] = 0; sx.weights[6] = 1; sx.weights[7] = 2; sx.weights[8] = 1; return sx; } Kernel sobel_y(int n) { Kernel sy; sy.size = 3; sy.weights = malloc(sy.size*sy.size*sizeof(double)); sy.weights[0] = -1; sy.weights[1] = 0; sy.weights[2] = 1; sy.weights[3] = -2; sy.weights[4] = 0; sy.weights[5] = 2; sy.weights[6] = -1; sy.weights[7] = 0; sy.weights[8] = 1; return sy; } Image *sobel(Image image) { Image *conv = create_image(image.width, image.height); Image *sobx, *soby; Kernel sx = sobel_x(3); Kernel sy = sobel_y(3); sobx = apply_kernel(image, sx); soby = apply_kernel(image, sy); save_image("sobel_x.ppm", *sobx); save_image("sobel_y.ppm", *soby); double max = kernel_max(sx); double min = kernel_min(sx); double alpha = max - min; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { Accumulator x = convolve(image, sx, row, col); Accumulator y = convolve(image, sy, row, col); x.r = 255*(x.r)/alpha; x.g = 255*(x.g)/alpha; x.b = 255*(x.b)/alpha; y.r = 255*(y.r)/alpha; y.g = 255*(y.g)/alpha; y.b = 255*(y.b)/alpha; Accumulator gradient = { sqrt(x.r*x.r + y.r*y.r), sqrt(x.g*x.g + y.g*y.g), sqrt(x.b*x.b + y.b*y.b), }; gradient.r = (gradient.r > 255)? 255: gradient.r; gradient.g = (gradient.g > 255)? 255: gradient.g; gradient.b = (gradient.b > 255)? 255: gradient.b; conv->pixels[row*image.width + col].r = (uint8_t) gradient.r; conv->pixels[row*image.width + col].g = (uint8_t) gradient.g; conv->pixels[row*image.width + col].b = (uint8_t) gradient.b; } printf("%lf\r", 100.0*(1.0*row)/image.height); fflush(stdout); } return conv; } unsigned modulo(int value, unsigned m) { int mod = value % (int) m; if (mod < 0) mod += m; return mod; } I'm making a image processing application in c from scratch using P6 ppm images, I want some input on my code before I start adding more features to prevent it from falling apart if it's not well structured
improc.h
#ifndef IMPROC_H #define IMPROC_H #include <stdint.h> typedef struct { int size; double *weights; } Kernel; typedef struct { uint8_t r; uint8_t g; uint8_t b; } Pixel; typedef struct { double r; double g; double b; } Accumulator; typedef struct { int height; int width; Pixel *pixels; } Image; typedef struct { double re; double im; } Complex; Image *create_image(int width, int height); void free_image(Image *image); Image *load_image(char *filename); int save_image(char *filename, Image image); Image *grayscale(Image image); Image *perceptual_grayscale(Image image); double kernel_min(Kernel kernel); double kernel_max(Kernel kernel); Accumulator convolve(Image image, Kernel kernel, int row, int col); Image *apply_kernel(Image image, Kernel kernel); Image *sobel(Image image); Kernel sobel_y(int n); Kernel sobel_x(int n); unsigned modulo(int value, unsigned m); #endif improc.c
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <math.h> #include <unistd.h> #include <errno.h> #include "improc.h" Image *create_image(int width, int height) { Image *image = malloc(sizeof(Image)); if (image == NULL) { fprintf(stderr, "Could not allocate memory to Image: %s\n", strerror(errno)); return NULL; } image->width = width; image->height = height; image->pixels = malloc(width*height*sizeof(Pixel)); if (image->pixels == NULL) { free(image); fprintf(stderr, "Could not allocate memory to pixels: %s\n", strerror(errno)); return NULL; } return image; } void free_image(Image *image) { if (image != NULL) { if (image->pixels != NULL) free(image->pixels); free(image); } } Image *load_image(char *filename) { char magic[3]; int maxval, width, height; FILE *fp = fopen(filename, "rb"); if (fp == NULL) { fprintf(stderr, "Error opening file: %s\n", strerror(errno)); return NULL; } fscanf(fp, "%2s", magic); if (magic[0] != 'P' || magic[1] != '6') { fprintf(stderr, "Not a valid P6 ppm file: %s\n", strerror(errno)); fclose(fp); return NULL; } fscanf(fp, "%d%d%*c", &width, &height); Image *image = create_image(width, height); fscanf(fp, "%d%*c", &maxval); fread(image->pixels, sizeof(Pixel),image->width*image->height, fp); fclose(fp); return image; } int save_image(char *filename, Image image) { FILE *fp = fopen(filename, "wb"); if (fp == NULL) { fprintf(stderr, "Error opening file: %s\n", strerror(errno)); return -1; } fprintf(fp, "P6\n%d %d\n255\n", image.width, image.height); fwrite(image.pixels, sizeof(Pixel), image.width*image.height, fp); fclose(fp); return 0; } Image *grayscale(Image image) { Image *gray = create_image(image.width, image.height); Pixel pix; int index; uint8_t avg; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { index = row*image.width + col; pix = image.pixels[index]; avg = (uint8_t) ((pix.r + pix.g + pix.b)/3.0); gray->pixels[index] = (Pixel) {avg, avg, avg}; } } return gray; } Image *perceptual_grayscale(Image image) { Image *gray = create_image(image.width, image.height); Pixel pix; uint8_t bt_601; int index; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { index = row*image.width + col; pix = image.pixels[index]; bt_601 = (uint8_t) (0.2126*pix.r + 0.7152*pix.g + 0.0722*pix.b); gray->pixels[index] = (Pixel) {bt_601, bt_601, bt_601}; } } return gray; } double kernel_min(Kernel kernel) { double min = 0; for (int index = 0; index < kernel.size*kernel.size; index++) { if (kernel.weights[index] < 0) min += kernel.weights[index]; } return min*255; } double kernel_max(Kernel kernel) { double max = 0; for (int index = 0; index < kernel.size*kernel.size; index++) { if (kernel.weights[index] > 0) max += kernel.weights[index]; } return max*255; } Accumulator convolve(Image image, Kernel kernel, int row, int col) { Accumulator accumulator = {0, 0, 0}; for (int r_off = -kernel.size/2; r_off <= kernel.size/2; r_off++) { for (int c_off = -kernel.size/2; c_off <= kernel.size/2; c_off++) { int ir = modulo(row + r_off, image.height); int ic = modulo(col + c_off, image.width); int kr = r_off + kernel.size/2; int kc = c_off + kernel.size/2; int index = ir*image.width + ic; Pixel pixel = image.pixels[index]; accumulator.r += pixel.r*kernel.weights[kr*kernel.size + kc]; accumulator.g += pixel.g*kernel.weights[kr*kernel.size + kc]; accumulator.b += pixel.b*kernel.weights[kr*kernel.size + kc]; } } return accumulator; } Image *apply_kernel(Image image, Kernel kernel) { Image *conv = create_image(image.width, image.height); double max = kernel_max(kernel); double min = kernel_min(kernel); double alpha = max - min; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { Accumulator accumulator = convolve(image, kernel, row, col); accumulator.r = 255*(accumulator.r - min)/alpha; accumulator.g = 255*(accumulator.g - min)/alpha; accumulator.b = 255*(accumulator.b - min)/alpha; conv->pixels[row*image.width + col].r = accumulator.r; conv->pixels[row*image.width + col].g = accumulator.g; conv->pixels[row*image.width + col].b = accumulator.b; } printf("%lf\r", 100.0*(1.0*row)/image.height); fflush(stdout); } return conv; } Kernel sobel_x(int n) { Kernel sx; sx.size = 3; sx.weights = malloc(sizeof(double)*sx.size*sx.size); sx.weights[0] = -1; sx.weights[1] = -2; sx.weights[2] = -1; sx.weights[3] = 0; sx.weights[4] = 0; sx.weights[5] = 0; sx.weights[6] = 1; sx.weights[7] = 2; sx.weights[8] = 1; return sx; } Kernel sobel_y(int n) { Kernel sy; sy.size = 3; sy.weights = malloc(sy.size*sy.size*sizeof(double)); sy.weights[0] = -1; sy.weights[1] = 0; sy.weights[2] = 1; sy.weights[3] = -2; sy.weights[4] = 0; sy.weights[5] = 2; sy.weights[6] = -1; sy.weights[7] = 0; sy.weights[8] = 1; return sy; } Image *sobel(Image image) { Image *conv = create_image(image.width, image.height); Image *sobx, *soby; Kernel sx = sobel_x(3); Kernel sy = sobel_y(3); sobx = apply_kernel(image, sx); soby = apply_kernel(image, sy); save_image("sobel_x.ppm", *sobx); save_image("sobel_y.ppm", *soby); double max = kernel_max(sx); double min = kernel_min(sx); double alpha = max - min; for (int row = 0; row < image.height; row++) { for (int col = 0; col < image.width; col++) { Accumulator x = convolve(image, sx, row, col); Accumulator y = convolve(image, sy, row, col); x.r = 255*(x.r)/alpha; x.g = 255*(x.g)/alpha; x.b = 255*(x.b)/alpha; y.r = 255*(y.r)/alpha; y.g = 255*(y.g)/alpha; y.b = 255*(y.b)/alpha; Accumulator gradient = { sqrt(x.r*x.r + y.r*y.r), sqrt(x.g*x.g + y.g*y.g), sqrt(x.b*x.b + y.b*y.b), }; /* gradient.r = (gradient.r > 255)? 255: gradient.r; gradient.g = (gradient.g > 255)? 255: gradient.g; gradient.b = (gradient.b > 255)? 255: gradient.b; printf("\n"); printf("x.r: %lf, y.r: %lf, gradient.r: %lf\n", x.r, y.r, gradient.r); printf("x.g: %lf, y.g: %lf, gradient.g: %lf\n", x.g, y.g, gradient.g); printf("x.b: %lf, y.b: %lf, gradient.b: %lf\n", x.b, y.b, gradient.b); printf("\n"); sleep(1); */ conv->pixels[row*image.width + col].r = (uint8_t) gradient.r; conv->pixels[row*image.width + col].g = (uint8_t) gradient.g; conv->pixels[row*image.width + col].b = (uint8_t) gradient.b; } printf("%lf\r", 100.0*(1.0*row)/image.height); fflush(stdout); } return conv; } unsigned modulo(int value, unsigned m) { int mod = value % (int) m; if (mod < 0) mod += m; return mod; } main.c
#include <stdio.h> #include <stdlib.h> #include <math.h> #include "improc.h" int main(int argc, char **argv) { (void) argc; Image *ema = load_image(argv[1]); save_image("identity.ppm", *ema); Image *sob = sobel(*ema); save_image("sobel.ppm", *sob); } build script
#!/bin/bash gcc improc.c main.c -O3 -g -Wall -Wpedantic -lm -Wextra -o main