Last active
January 22, 2021 04:19
-
-
Save teeschorle/3e01a70bd0df2c3261e70e2e061224c7 to your computer and use it in GitHub Desktop.
CS50 Problem Set 4 (edX 2020) - Helpers (to be used in combination with Filters.c provided by CS50)
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
//CS50 Problem Set 4 (edx 2020): Filter (more comfortable) | |
//Author: teeschorle | |
#include "helpers.h" | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <math.h> | |
#include <string.h> | |
// Convert image to grayscale | |
void grayscale(int height, int width, RGBTRIPLE image[height][width]) | |
{ | |
double average; | |
for (int i = 0; i < height; i++) | |
{ | |
for (int j = 0; j < width; j++) | |
{ | |
average = round((image[i][j].rgbtBlue + image[i][j].rgbtGreen + image[i][j].rgbtRed) / 3.0); //3.0 instead of 3 in order to yield a float division result (instead of an int which is just cut off) | |
image[i][j].rgbtBlue = average; | |
image[i][j].rgbtGreen = average; | |
image[i][j].rgbtRed = average; | |
} | |
} | |
return; | |
} | |
// Reflect image horizontally | |
void reflect(int height, int width, RGBTRIPLE image[height][width]) | |
{ | |
RGBTRIPLE(*imagecopy)[width] = calloc(height, width * sizeof(RGBTRIPLE)); | |
for (int i = 0; i < height; i++) | |
{ | |
for (int j = 0; j < width; j++) | |
{ | |
imagecopy[i][j].rgbtBlue = image[i][width - j - 1].rgbtBlue; | |
imagecopy[i][j].rgbtGreen = image[i][width - j - 1].rgbtGreen; | |
imagecopy[i][j].rgbtRed = image[i][width - j - 1].rgbtRed; | |
} | |
for (int j = 0; j < width; j++) | |
{ | |
image[i][j].rgbtBlue = imagecopy[i][j].rgbtBlue; | |
image[i][j].rgbtGreen = imagecopy[i][j].rgbtGreen; | |
image[i][j].rgbtRed = imagecopy[i][j].rgbtRed; | |
} | |
} | |
free(imagecopy); | |
return; | |
} | |
// Blur image | |
void blur(int height, int width, RGBTRIPLE image[height][width]) | |
{ | |
RGBTRIPLE(*imagecopy)[width] = calloc(height, width * sizeof(RGBTRIPLE)); | |
for (int i = 1; i < height - 1; i++) //1 and height - 1 are due to different treatment of the edges | |
{ | |
for (int j = 1; j < width - 1; j++) //1 and height - 1 are due to different treatment of the edges | |
{ | |
imagecopy[i][j].rgbtBlue = round((image[i - 1][j - 1].rgbtBlue + image[i - 1][j].rgbtBlue + image[i - 1][j + 1].rgbtBlue + image[i][j - 1].rgbtBlue + image[i][j].rgbtBlue + image[i][j + 1].rgbtBlue + image[i + 1][j - 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue) / 9.0); | |
imagecopy[i][j].rgbtGreen = round((image[i - 1][j - 1].rgbtGreen + image[i - 1][j].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i][j - 1].rgbtGreen + image[i][j].rgbtGreen + image[i][j + 1].rgbtGreen + image[i + 1][j - 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen) / 9.0); | |
imagecopy[i][j].rgbtRed = round((image[i - 1][j - 1].rgbtRed + image[i - 1][j].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i][j - 1].rgbtRed + image[i][j].rgbtRed + image[i][j + 1].rgbtRed + image[i + 1][j - 1].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed) / 9.0); | |
} | |
} | |
//first and last line | |
for (int j = 1; j < width - 1; j++) //corners treated separately | |
{ | |
imagecopy[0][j].rgbtBlue = round((image[0][j - 1].rgbtBlue + image[0][j].rgbtBlue + image[0][j + 1].rgbtBlue + image[0 + 1][j - 1].rgbtBlue + image[0 + 1][j].rgbtBlue + image[0 + 1][j + 1].rgbtBlue) / 6.0); | |
imagecopy[0][j].rgbtGreen = round((image[0][j - 1].rgbtGreen + image[0][j].rgbtGreen + image[0][j + 1].rgbtGreen + image[0 + 1][j - 1].rgbtGreen + image[0 + 1][j].rgbtGreen + image[0 + 1][j + 1].rgbtGreen) / 6.0); | |
imagecopy[0][j].rgbtRed = round((image[0][j - 1].rgbtRed + image[0][j].rgbtRed + image[0][j + 1].rgbtRed + image[0 + 1][j - 1].rgbtRed + image[0 + 1][j].rgbtRed + image[0 + 1][j + 1].rgbtRed) / 6.0); | |
imagecopy[height - 1][j].rgbtBlue = round((image[height - 1 - 1][j - 1].rgbtBlue + image[height - 1 - 1][j].rgbtBlue + image[height - 1 - 1][j + 1].rgbtBlue + image[height - 1][j - 1].rgbtBlue + image[height - 1][j].rgbtBlue + image[height - 1][j + 1].rgbtBlue) / 6.0); | |
imagecopy[height - 1][j].rgbtGreen = round((image[height - 1 - 1][j - 1].rgbtGreen + image[height - 1 - 1][j].rgbtGreen + image[height - 1 - 1][j + 1].rgbtGreen + image[height - 1][j - 1].rgbtGreen + image[height - 1][j].rgbtGreen + image[height - 1][j + 1].rgbtGreen) / 6.0); | |
imagecopy[height - 1][j].rgbtRed = round((image[height - 1 - 1][j - 1].rgbtRed + image[height - 1 - 1][j].rgbtRed + image[height - 1 - 1][j + 1].rgbtRed + image[height - 1][j - 1].rgbtRed + image[height - 1][j].rgbtRed + image[height - 1][j + 1].rgbtRed) / 6.0); | |
} | |
//first and last column | |
for (int i = 1; i < height - 1; i++) | |
{ | |
imagecopy[i][0].rgbtBlue = round((image[i - 1][0].rgbtBlue + image[i - 1][1].rgbtBlue + image[i][0].rgbtBlue + image[i][1].rgbtBlue + image[i + 1][0].rgbtBlue + image[i + 1][1].rgbtBlue) / 6.0); | |
imagecopy[i][0].rgbtGreen = round((image[i - 1][0].rgbtGreen + image[i - 1][1].rgbtGreen + image[i][0].rgbtGreen + image[i][1].rgbtGreen + image[i + 1][0].rgbtGreen + image[i + 1][1].rgbtGreen) / 6.0); | |
imagecopy[i][0].rgbtRed = round((image[i - 1][0].rgbtRed + image[i - 1][1].rgbtRed + image[i][0].rgbtRed + image[i][1].rgbtRed + image[i + 1][0].rgbtRed + image[i + 1][1].rgbtRed) / 6.0); | |
imagecopy[i][width - 1].rgbtBlue = round((image[i - 1][width - 2].rgbtBlue + image[i - 1][width - 1].rgbtBlue + image[i][width - 2].rgbtBlue + image[i][width - 1].rgbtBlue + image[i + 1][width - 2].rgbtBlue + image[i + 1][width - 1].rgbtBlue) / 6.0); | |
imagecopy[i][width - 1].rgbtGreen = round((image[i - 1][width - 2].rgbtGreen + image[i - 1][width - 1].rgbtGreen + image[i][width - 2].rgbtGreen + image[i][width - 1].rgbtGreen + image[i + 1][width - 2].rgbtGreen + image[i + 1][width - 1].rgbtGreen) / 6.0); | |
imagecopy[i][width - 1].rgbtRed = round((image[i - 1][width - 2].rgbtRed + image[i - 1][width - 1].rgbtRed + image[i][width - 2].rgbtRed + image[i][width - 1].rgbtRed + image[i + 1][width - 2].rgbtRed + image[i + 1][width - 1].rgbtRed) / 6.0); | |
} | |
//corners | |
imagecopy[0][0].rgbtBlue = round((image[0][0].rgbtBlue + image[0][1].rgbtBlue + image[1][0].rgbtBlue + image[1][1].rgbtBlue) / 4.0); | |
imagecopy[0][0].rgbtGreen = round((image[0][0].rgbtGreen + image[0][1].rgbtGreen + image[1][0].rgbtGreen + image[1][1].rgbtGreen) / 4.0); | |
imagecopy[0][0].rgbtRed = round((image[0][0].rgbtRed + image[0][1].rgbtRed + image[1][0].rgbtRed + image[1][1].rgbtRed) / 4.0); | |
imagecopy[0][width - 1].rgbtBlue = round((image[0][width - 2].rgbtBlue + image[0][width - 1].rgbtBlue + image[1][width - 2].rgbtBlue + image[1][width - 1].rgbtBlue) / 4.0); | |
imagecopy[0][width - 1].rgbtGreen = round((image[0][width - 2].rgbtGreen + image[0][width - 1].rgbtGreen + image[1][width - 2].rgbtGreen + image[1][width - 1].rgbtGreen) / 4.0); | |
imagecopy[0][width - 1].rgbtRed = round((image[0][width - 2].rgbtRed + image[0][width - 1].rgbtRed + image[1][width - 2].rgbtRed + image[1][width - 1].rgbtRed) / 4.0); | |
imagecopy[height - 1][0].rgbtBlue = round((image[height - 2][0].rgbtBlue + image[height - 2][1].rgbtBlue + image[height - 1][0].rgbtBlue + image[height - 1][1].rgbtBlue) / 4.0); | |
imagecopy[height - 1][0].rgbtGreen = round((image[height - 2][0].rgbtGreen + image[height - 2][1].rgbtGreen + image[height - 1][0].rgbtGreen + image[height - 1][1].rgbtGreen) / 4.0); | |
imagecopy[height - 1][0].rgbtRed = round((image[height - 2][0].rgbtRed + image[height - 2][1].rgbtRed + image[height - 1][0].rgbtRed + image[height - 1][1].rgbtRed) / 4.0); | |
imagecopy[height - 1][width - 1].rgbtBlue = round((image[height - 2][width - 2].rgbtBlue + image[height - 2][width - 1].rgbtBlue + image[height - 1][width - 2].rgbtBlue + image[height - 1][width - 1].rgbtBlue) / 4.0); | |
imagecopy[height - 1][width - 1].rgbtGreen = round((image[height - 2][width - 2].rgbtGreen + image[height - 2][width - 1].rgbtGreen + image[height - 1][width - 2].rgbtGreen + image[height - 1][width - 1].rgbtGreen) / 4.0); | |
imagecopy[height - 1][width - 1].rgbtRed = round((image[height - 2][width - 2].rgbtRed + image[height - 2][width - 1].rgbtRed + image[height - 1][width - 2].rgbtRed + image[height - 1][width - 1].rgbtRed) / 4.0); | |
for (int i = 0; i < height; i++) | |
{ | |
for (int j = 0; j < width; j++) | |
{ | |
image[i][j].rgbtBlue = imagecopy[i][j].rgbtBlue; | |
image[i][j].rgbtGreen = imagecopy[i][j].rgbtGreen; | |
image[i][j].rgbtRed = imagecopy[i][j].rgbtRed; | |
} | |
} | |
free(imagecopy); | |
return; | |
} | |
// Detect edges | |
void edges(int height, int width, RGBTRIPLE image[height][width]) | |
{ | |
// create framedimage with a 1-pixel black border for corner and border treatment | |
RGBTRIPLE(*framedimage)[width + 2] = calloc(height + 2, (width + 2) * sizeof(RGBTRIPLE)); | |
// black horizontal borders | |
for (int i = 0; i < width + 2; i++) | |
{ | |
framedimage[0][i].rgbtBlue = 0; | |
framedimage[0][i].rgbtGreen = 0; | |
framedimage[0][i].rgbtRed = 0; | |
framedimage[height + 1][i].rgbtBlue = 0; | |
framedimage[height + 1][i].rgbtGreen = 0; | |
framedimage[height + 1][i].rgbtRed = 0; | |
} | |
// black vertical borders | |
for (int i = 0; i < height + 2; i++) | |
{ | |
framedimage[i][0].rgbtBlue = 0; | |
framedimage[i][0].rgbtGreen = 0; | |
framedimage[i][0].rgbtRed = 0; | |
framedimage[0][width + 1].rgbtBlue = 0; | |
framedimage[0][width + 1].rgbtGreen = 0; | |
framedimage[0][width + 1].rgbtRed = 0; | |
} | |
// copy image to rest of framedimage | |
for (int i = 0; i < height; i++) | |
{ | |
for (int j = 0; j < width; j++) | |
{ | |
framedimage[i + 1][j + 1].rgbtBlue = image[i][j].rgbtBlue; | |
framedimage[i + 1][j + 1].rgbtGreen = image[i][j].rgbtGreen; | |
framedimage[i + 1][j + 1].rgbtRed = image[i][j].rgbtRed; | |
} | |
} | |
// allocate memory space for imagecopy (same size as framedimage) | |
RGBTRIPLE(*imagecopy)[width + 2] = calloc(height + 2, (width + 2) * sizeof(RGBTRIPLE)); | |
// create temp variables for pixel channel values | |
int blue = 0; | |
int green = 0; | |
int red = 0; | |
for (int i = 1; i < height + 1; i++) //index from 1 to height + 1 in order to filter the whole original image within the 1-pixel frame | |
{ | |
for (int j = 1; j < width + 1; j++) //see above | |
{ | |
blue = round(pow(pow(gx(i, j, "blue", height, width, framedimage),2) + pow(gy(i, j, "blue", height, width, framedimage),2), 0.5)); | |
green = round(pow(pow(gx(i, j, "green", height, width, framedimage),2) + pow(gy(i, j, "green", height, width, framedimage),2), 0.5)); | |
red = round(pow(pow(gx(i, j, "red", height, width, framedimage),2) + pow(gy(i, j, "red", height, width, framedimage),2), 0.5)); | |
// cap values at 255 | |
if (blue > 255) | |
{ | |
blue = 255; | |
} | |
if (green > 255) | |
{ | |
green = 255; | |
} | |
if (red > 255) | |
{ | |
red = 255; | |
} | |
imagecopy[i][j].rgbtBlue = blue; | |
imagecopy[i][j].rgbtGreen = green; | |
imagecopy[i][j].rgbtRed = red; | |
} | |
} | |
// copy imagecopy back to target image (careful: imagecopy is larger than target image => cut off 1-pixel edge) | |
for (int i = 0; i < height; i++) | |
{ | |
for (int j = 0; j < width; j++) | |
{ | |
image[i][j].rgbtBlue = imagecopy[i + 1][j + 1].rgbtBlue; | |
image[i][j].rgbtGreen = imagecopy[i + 1][j + 1].rgbtGreen; | |
image[i][j].rgbtRed = imagecopy[i + 1][j + 1].rgbtRed; | |
} | |
} | |
free(imagecopy); | |
free(framedimage); | |
return; | |
} | |
int gx(int i, int j, char *channel, int height, int width, RGBTRIPLE image[height + 2][width + 2]) | |
{ | |
int g_x = 0; | |
if(strcmp(channel, "blue") == 0) | |
{ | |
g_x = (image[i - 1][j + 1].rgbtBlue + 2 * image[i][j + 1].rgbtBlue + image[i + 1][j + 1].rgbtBlue) - (image[i - 1][j - 1].rgbtBlue + 2 * image[i][j - 1].rgbtBlue + image[i + 1][j - 1].rgbtBlue); | |
return g_x; | |
} | |
else if (strcmp(channel, "green") == 0) | |
{ | |
g_x = (image[i - 1][j + 1].rgbtGreen + 2 * image[i][j + 1].rgbtGreen + image[i + 1][j + 1].rgbtGreen) - (image[i - 1][j - 1].rgbtGreen + 2 * image[i][j - 1].rgbtGreen + image[i + 1][j - 1].rgbtGreen); | |
return g_x; | |
} | |
else if (strcmp(channel, "red") == 0) | |
{ | |
g_x = (image[i - 1][j + 1].rgbtRed + 2 * image[i][j + 1].rgbtRed + image[i + 1][j + 1].rgbtRed) - (image[i - 1][j - 1].rgbtRed + 2 * image[i][j - 1].rgbtRed + image[i + 1][j - 1].rgbtRed); | |
return g_x; | |
} | |
else | |
{ | |
printf("colour not found"); | |
return 0; | |
} | |
} | |
int gy(int i, int j, char *channel, int height, int width, RGBTRIPLE image[height + 2][width + 2]) | |
{ | |
int g_y = 0; | |
if(strcmp(channel, "blue") == 0) | |
{ | |
g_y = (image[i + 1][j - 1].rgbtBlue + 2 * image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue) - (image[i - 1][j - 1].rgbtBlue + 2 * image[i - 1][j].rgbtBlue + image[i - 1][j + 1].rgbtBlue); | |
return g_y; | |
} | |
else if (strcmp(channel, "green") == 0) | |
{ | |
g_y = (image[i + 1][j - 1].rgbtGreen + 2 * image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen) - (image[i - 1][j - 1].rgbtGreen + 2 * image[i - 1][j].rgbtGreen + image[i - 1][j + 1].rgbtGreen); | |
return g_y; | |
} | |
else if (strcmp(channel, "red") == 0) | |
{ | |
g_y = (image[i + 1][j - 1].rgbtRed + 2 * image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed) - (image[i - 1][j - 1].rgbtRed + 2 * image[i - 1][j].rgbtRed + image[i - 1][j + 1].rgbtRed); | |
return g_y; | |
} | |
else | |
{ | |
printf("colour not found"); | |
return 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for your walk though. Please can you explain the #include "helper.h" line?
I have filter.c:1:10: fatal error: 'helpers.h' file not found
#include "helpers.h"
when i tried compiling.