Last active
June 25, 2016 21:03
-
-
Save geekskick/42ffe03b607ab6bb1dce9fcc1c5e7491 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <limits.h> | |
#include <errno.h> | |
#include <math.h> | |
/// Uses luminosity to convert colour to greyscale | |
#define LUM_R 0.21F | |
#define LUM_G 0.72F | |
#define LUM_B 0.07F | |
/// Show message on terminal instead of in the stdout file | |
#define DEBUG_PRINT(msg) fprintf(stderr,"[DEBUG %d]: %s\n", __LINE__, msg) | |
struct pixel{ | |
int red; | |
int green; | |
int blue; | |
}; | |
void print_header(const unsigned int width, const unsigned int height, const unsigned int max_rgb, const char* magic_num, FILE *fd){ | |
fprintf(fd, "%s\n", magic_num); | |
fprintf(fd, "%d %d\n", width, height); | |
if(max_rgb > 1){ | |
fprintf(fd, "%d\n", max_rgb); | |
} | |
} | |
void print_image(float **image, const unsigned int width, const unsigned int height, FILE *fp){ | |
for(int h = 0; h < height; h++){ | |
for(int w = 0; w < width; w++){ | |
fprintf(fp, "%d ", (int)image[h][w]); | |
} | |
fprintf(fp, "\n"); | |
} | |
} | |
/// Colours range from 1 (black) to 0 (white) in a P1 format image | |
/// round the greyscale byte value to a 0 or 1 as required. | |
float find_closest_colour(const int pixel_value, const int rgb_max, const int max_val, const int min_val){ | |
int mid_point = rgb_max / 2.0; | |
return pixel_value >= mid_point ? max_val: min_val; | |
} | |
void dither_image(float **image, const unsigned int width, const unsigned int height, const unsigned int rgb_max){ | |
DEBUG_PRINT("Floyding"); | |
unsigned int x, y; ///< For traversing through the image's rows and cols | |
float old_pixel, ///< The pixel removed from the image | |
new_pixel, ///< The manipulated pixel to add | |
q_err; ///< The quantisation error could be a -ve number so sign this | |
for(y = 0; y < height; y++){ | |
for(x = 0; x < width; x++){ | |
old_pixel = image[y][x]; | |
/// Get new pixel value by thresholding 0 or whatever the max brightness was in the | |
/// original image | |
new_pixel = find_closest_colour(old_pixel, rgb_max, rgb_max, 0.0); | |
/// Calculate the difference between | |
q_err = old_pixel - new_pixel; | |
/* | |
char t[70]; | |
sprintf(t, "q_err: (y: %d, x: %d) \t(o:%d n: %d)\t %d\n", y, x, old_pixel, new_pixel, q_err); | |
DEBUG_PRINT(t); | |
*/ | |
/// change the Value into a range to either 0 or 1, then put it in the pixel | |
image[y][x] = find_closest_colour(new_pixel, rgb_max, 0.0, 1.0); | |
/// Check bounds of the memory to prevent segfault | |
if(x < (width - 1)){ | |
image[y ][x + 1] += q_err * (7.0/16.0); | |
} | |
if(y < (height - 1)){ | |
image[y + 1][x ] += q_err * (5.0/16.0); | |
if(x > 0){ | |
image[y + 1][x - 1] += q_err * (3.0/16.0); | |
} | |
if(y < (height - 1)){ | |
image[y + 1][x + 1] += q_err * (1.0/16.0); | |
} | |
} | |
} | |
} | |
} | |
float scale_number(const float number, const unsigned int max_rgb, const int max_scale){ | |
float ratio = (float)max_scale/(float)max_rgb; | |
return ratio * number; | |
} | |
void bayer(float** image, const unsigned int width, const unsigned int height, const int max_rgb){ | |
DEBUG_PRINT("Bayering"); | |
static const int matrix_size = 4; | |
static const int b_matrix[matrix_size][matrix_size] = { | |
{ 1, 9, 3, 11 }, | |
{ 13, 5, 15, 7 }, | |
{ 4, 12, 2, 10 }, | |
{ 16, 8, 14, 6 } | |
}; | |
int matrix_scale = (int)pow((float)matrix_size, 2.0); | |
for(unsigned int h = 0; h < height; h++){ | |
for(unsigned int w = 0; w < width; w++){ | |
float scaled_pix = scale_number(image[h][w], max_rgb, matrix_scale); | |
int mat_number = b_matrix[h % matrix_size][w % matrix_size]; | |
float new_pix = scaled_pix > mat_number? 0.0: 1.0; | |
image[h][w] = new_pix; | |
} | |
} | |
} | |
int main(int argc, const char **argv){ | |
if(argc != 2){ | |
printf("Usage:./ditherimage < <input_imagepath>.ppm > <output_imagepath>.pbm\n"); | |
} | |
char b_m = argv[argc - 1][0]; | |
unsigned int width, height, max_rgb; | |
char id[3], t[70]; | |
struct pixel temp; | |
FILE *fp; | |
scanf("%s\n", id); | |
DEBUG_PRINT(id); | |
scanf("%d %d\n", &width, &height); | |
scanf("%d\n", &max_rgb); | |
sprintf(t, "(w: %d h: %d)", width, height); | |
DEBUG_PRINT(t); | |
/// Heap memory needed for the image | |
/// Get the rows | |
float **image; | |
image = calloc(height, sizeof(image)); | |
if(!image){ | |
DEBUG_PRINT("Error in calloc outer"); | |
exit(1); | |
} | |
/// Get the columns | |
for(unsigned int h = 0; h < height; h++){ | |
image[h] = calloc(width, sizeof(image[h])); | |
if(!image[h]) { | |
DEBUG_PRINT("Error in calloc inner"); | |
exit(1); | |
} | |
} | |
DEBUG_PRINT("Reading image"); | |
//go over the rows | |
for(unsigned int h = 0; h < height; h++){ | |
for(unsigned int w = 0; w < width; w++){ | |
scanf("%d %d %d\n", &temp.red, &temp.green, &temp.blue); | |
//greyscale it | |
image[h][w] = (LUM_R * temp.red) + (LUM_G * temp.green) + (LUM_B * temp.blue); | |
} | |
} | |
DEBUG_PRINT("Image read in and is now luminescent"); | |
/// Save the luminsecent image - just to see what it looks like | |
fp = fopen("lum.pgm", "w"); | |
if(!fp){ | |
DEBUG_PRINT("Error opening file to write to"); | |
perror("File IO"); | |
} | |
else{ | |
print_header(width, height, max_rgb, "P2", fp); | |
print_image(image, width, height, fp); | |
fclose(fp); | |
} | |
if(b_m == 'b'){ | |
bayer(image, width, height, max_rgb); | |
} | |
else if(b_m == 'f'){ | |
dither_image(image, width, height, max_rgb); | |
} | |
else{ | |
DEBUG_PRINT("Error in args"); | |
exit(1); | |
} | |
DEBUG_PRINT("Printing Image"); | |
print_header(width, height, 0, "P1", stdout); | |
print_image(image, width, height, stdout); | |
DEBUG_PRINT("Image printed"); | |
/// Finally free used Heap memory | |
for(int h = height; h < height; h++){ | |
free(image[h]); | |
image[h] = NULL; | |
} | |
free(image); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment