Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,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
Expand Down
50 changes: 28 additions & 22 deletions filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,27 @@
int main(int argc, char *argv[])
{
// Define allowable filters
char *filters = "bgrsivt";
char *filters = "bgrsivtd";




char filterArr[argc-3];

// gets all filter flags and checks validity
for(int i=0; i<argc; i++){
char temp = getopt(argc,argv,filters);
if(temp == -1) break;
filterArr[i]= temp;
if(filterArr[i] == '?') {
printf("Invalid filter option");
return 1;
}
}

char filterArr[argc - 3];
int filterCount = 0;

// Ensure proper usage
if (argc < optind + 2)
while ((opt = getopt(argc, argv, filters)) != -1)
{
if (opt == '?')
{
printf("Usage: ./filter [flag] infile outfile\n");
return 3;
printf("Invalid filter option\n");
return 2;
}
filterArr[filterCount++] = (char)opt;
}





// Remember filenames
char *infile = argv[optind];
Expand Down Expand Up @@ -131,10 +129,18 @@ int main(int argc, char *argv[])
case 't':
threshold(height, width, image);
break;
default:
printf("%c", &filterArr[i]);
break;


case 'd': // Edge Detection
detect_edges(height, width, image);
break;

default:
printf("Unknown filter: %c\n", filterArr[i]);
free(image);
fclose(inptr);
fclose(outptr);
return 7;

}
}
// Write outfile's BITMAPFILEHEADER
Expand Down
77 changes: 77 additions & 0 deletions helpers.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "helpers.h"
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include "bmp.h"
int min(int a,int b){
if(a<b) return a;
Expand Down Expand Up @@ -198,3 +200,78 @@ void threshold(int height, int width, RGBTRIPLE image[height][width])
}
}
}


// ----------------------
// EDGE DETECTION (SOBEL)
// ----------------------
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);
}
11 changes: 11 additions & 0 deletions helpers.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#ifndef HELPERS_H
#define HELPERS_H

#include <stdio.h>
#include <math.h>

#include "bmp.h"

// Convert image to grayscale
Expand All @@ -19,3 +25,8 @@ void vignette(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]);

#endif
Loading