diff --git a/README.md b/README.md index b918117..030528e 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,43 @@ Otherwise, it is set to **black** (`R = G = B = 0`). This results in a high-contrast, two-tone image where all intermediate shades are eliminated — essentially a hard binary “black-and-white” conversion. +### 7.) The Edge Detection (Sobel) Algorithm + +The “edge detection” filter highlights sharp changes in pixel intensity, producing a sketch-like outline of the image. + +For each pixel, the horizontal and vertical gradients are calculated using a 3×3 Sobel kernel applied to the surrounding pixels: + +Horizontal (Gx): +-1 0 1 +-2 0 2 +-1 0 1 + +Vertical (Gy): +-1 -2 -1 +0 0 0 +1 2 1 + +The gradient magnitude for each color channel is then computed as: + +value += +𝐺 +𝑥 +2 ++ +𝐺 +𝑦 +2 +value= +Gx +2 ++Gy +2 + ​ + + +The result is clamped between 0 and 255 and replaces the original pixel value. This produces a monochrome image where edges are highlighted, giving a pencil-sketch effect. + --- ### Usage diff --git a/filter.c b/filter.c index b642fd8..e3fac2c 100644 --- a/filter.c +++ b/filter.c @@ -7,7 +7,7 @@ int main(int argc, char *argv[]) { // Define allowable filters - char *filters = "bgrsivB:"; + char *filters = "bgrsivtdB:"; char filterArr[argc-3]; @@ -130,6 +130,14 @@ int main(int argc, char *argv[]) vignette(height, width, image); break; + case 't': + threshold(height, width, image); + break; + + case 'd': // Edge Detection + detect_edges(height, width, image); + break; + // Brightness Adjust case 'B': { int brightness_value = atoi(optarg); @@ -138,7 +146,10 @@ int main(int argc, char *argv[]) } default: printf("Unknown filter: %c\n", filterArr[i]); - break; + free(image); + fclose(inptr); + fclose(outptr); + return 7; } } @@ -168,4 +179,4 @@ int main(int argc, char *argv[]) fclose(inptr); fclose(outptr); return 0; -} +} \ No newline at end of file diff --git a/filter.exe b/filter.exe new file mode 100644 index 0000000..505744c Binary files /dev/null and b/filter.exe differ diff --git a/helpers.c b/helpers.c index 5360748..ee56bf1 100644 --- a/helpers.c +++ b/helpers.c @@ -214,3 +214,73 @@ void threshold(int height, int width, RGBTRIPLE image[height][width]) } } } +void detect_edges(int height, int width, RGBTRIPLE image[height][width]) +{ + // Temporary copy of the image + RGBTRIPLE **copy = malloc(height * sizeof(RGBTRIPLE *)); + for (int i = 0; i < height; i++) + copy[i] = malloc(width * sizeof(RGBTRIPLE)); + + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + copy[i][j] = image[i][j]; + + // Sobel kernels + int Gx[3][3] = { + {-1, 0, 1}, + {-2, 0, 2}, + {-1, 0, 1} + }; + int Gy[3][3] = { + {-1, -2, -1}, + { 0, 0, 0}, + { 1, 2, 1} + }; + + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + int sumRx = 0, sumGx = 0, sumBx = 0; + int sumRy = 0, sumGy = 0, sumBy = 0; + + for (int di = -1; di <= 1; di++) + { + for (int dj = -1; dj <= 1; dj++) + { + int ni = i + di; + int nj = j + dj; + + if (ni >= 0 && ni < height && nj >= 0 && nj < width) + { + RGBTRIPLE pixel = copy[ni][nj]; + int kx = Gx[di + 1][dj + 1]; + int ky = Gy[di + 1][dj + 1]; + + sumRx += pixel.rgbtRed * kx; + sumGx += pixel.rgbtGreen * kx; + sumBx += pixel.rgbtBlue * kx; + + sumRy += pixel.rgbtRed * ky; + sumGy += pixel.rgbtGreen * ky; + sumBy += pixel.rgbtBlue * ky; + } + } + } + + // Calculate gradient magnitude and clamp + int red = min(max((int)round(sqrt(sumRx*sumRx + sumRy*sumRy)), 0), 255); + int green = min(max((int)round(sqrt(sumGx*sumGx + sumGy*sumGy)), 0), 255); + int blue = min(max((int)round(sqrt(sumBx*sumBx + sumBy*sumBy)), 0), 255); + + image[i][j].rgbtRed = red; + image[i][j].rgbtGreen = green; + image[i][j].rgbtBlue = blue; + } + } + + // Free temporary array + for (int i = 0; i < height; i++) + free(copy[i]); + free(copy); +} \ No newline at end of file diff --git a/helpers.h b/helpers.h index 88da2ff..770ab49 100644 --- a/helpers.h +++ b/helpers.h @@ -1,3 +1,9 @@ +#ifndef HELPERS_H +#define HELPERS_H + +#include +#include + #include "bmp.h" // Convert image to grayscale @@ -15,8 +21,17 @@ void reflect(int height, int width, RGBTRIPLE image[height][width]); // Blur image void blur(int height, int width, RGBTRIPLE image[height][width]); +//Threshold Filter(Black & White) +void threshold(int height, int width, RGBTRIPLE image[height][width]); + +// *New: Edge Detection filter* +void detect_edges(int height, int width, RGBTRIPLE image[height][width]); + // Brightness adjustment filter void brightness(int height, int width, RGBTRIPLE image[height][width], int value); // Vignette filter void vignette(int height, int width, RGBTRIPLE image[height][width]); + + +#endif diff --git a/output.bmp b/output.bmp new file mode 100644 index 0000000..9301fe8 Binary files /dev/null and b/output.bmp differ