Skip to content

Commit 6af2202

Browse files
Merge pull request #29 from swastijain132005/feat/edge-detection
feat: add edge detection (-D flag) using Sobel operator
2 parents fb2260f + 6c56c82 commit 6af2202

File tree

6 files changed

+136
-3
lines changed

6 files changed

+136
-3
lines changed

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,43 @@ Otherwise, it is set to **black** (`R = G = B = 0`).
138138
This results in a high-contrast, two-tone image where all intermediate shades are eliminated — essentially a hard binary “black-and-white” conversion.
139139

140140

141+
### 7.) The Edge Detection (Sobel) Algorithm
142+
143+
The “edge detection” filter highlights sharp changes in pixel intensity, producing a sketch-like outline of the image.
144+
145+
For each pixel, the horizontal and vertical gradients are calculated using a 3×3 Sobel kernel applied to the surrounding pixels:
146+
147+
Horizontal (Gx):
148+
-1 0 1
149+
-2 0 2
150+
-1 0 1
151+
152+
Vertical (Gy):
153+
-1 -2 -1
154+
0 0 0
155+
1 2 1
156+
157+
The gradient magnitude for each color channel is then computed as:
158+
159+
value
160+
=
161+
𝐺
162+
𝑥
163+
2
164+
+
165+
𝐺
166+
𝑦
167+
2
168+
value=
169+
Gx
170+
2
171+
+Gy
172+
2
173+
174+
175+
176+
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.
177+
141178
---
142179

143180
### Usage

filter.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
int main(int argc, char *argv[])
88
{
99
// Define allowable filters
10-
char *filters = "bgrsivB:";
10+
char *filters = "bgrsivtdB:";
1111

1212

1313
char filterArr[argc-3];
@@ -130,6 +130,14 @@ int main(int argc, char *argv[])
130130
vignette(height, width, image);
131131
break;
132132

133+
case 't':
134+
threshold(height, width, image);
135+
break;
136+
137+
case 'd': // Edge Detection
138+
detect_edges(height, width, image);
139+
break;
140+
133141
// Brightness Adjust
134142
case 'B': {
135143
int brightness_value = atoi(optarg);
@@ -138,7 +146,10 @@ int main(int argc, char *argv[])
138146
}
139147
default:
140148
printf("Unknown filter: %c\n", filterArr[i]);
141-
break;
149+
free(image);
150+
fclose(inptr);
151+
fclose(outptr);
152+
return 7;
142153

143154
}
144155
}
@@ -168,4 +179,4 @@ int main(int argc, char *argv[])
168179
fclose(inptr);
169180
fclose(outptr);
170181
return 0;
171-
}
182+
}

filter.exe

54.7 KB
Binary file not shown.

helpers.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,73 @@ void threshold(int height, int width, RGBTRIPLE image[height][width])
214214
}
215215
}
216216
}
217+
void detect_edges(int height, int width, RGBTRIPLE image[height][width])
218+
{
219+
// Temporary copy of the image
220+
RGBTRIPLE **copy = malloc(height * sizeof(RGBTRIPLE *));
221+
for (int i = 0; i < height; i++)
222+
copy[i] = malloc(width * sizeof(RGBTRIPLE));
223+
224+
for (int i = 0; i < height; i++)
225+
for (int j = 0; j < width; j++)
226+
copy[i][j] = image[i][j];
227+
228+
// Sobel kernels
229+
int Gx[3][3] = {
230+
{-1, 0, 1},
231+
{-2, 0, 2},
232+
{-1, 0, 1}
233+
};
234+
int Gy[3][3] = {
235+
{-1, -2, -1},
236+
{ 0, 0, 0},
237+
{ 1, 2, 1}
238+
};
239+
240+
for (int i = 0; i < height; i++)
241+
{
242+
for (int j = 0; j < width; j++)
243+
{
244+
int sumRx = 0, sumGx = 0, sumBx = 0;
245+
int sumRy = 0, sumGy = 0, sumBy = 0;
246+
247+
for (int di = -1; di <= 1; di++)
248+
{
249+
for (int dj = -1; dj <= 1; dj++)
250+
{
251+
int ni = i + di;
252+
int nj = j + dj;
253+
254+
if (ni >= 0 && ni < height && nj >= 0 && nj < width)
255+
{
256+
RGBTRIPLE pixel = copy[ni][nj];
257+
int kx = Gx[di + 1][dj + 1];
258+
int ky = Gy[di + 1][dj + 1];
259+
260+
sumRx += pixel.rgbtRed * kx;
261+
sumGx += pixel.rgbtGreen * kx;
262+
sumBx += pixel.rgbtBlue * kx;
263+
264+
sumRy += pixel.rgbtRed * ky;
265+
sumGy += pixel.rgbtGreen * ky;
266+
sumBy += pixel.rgbtBlue * ky;
267+
}
268+
}
269+
}
270+
271+
// Calculate gradient magnitude and clamp
272+
int red = min(max((int)round(sqrt(sumRx*sumRx + sumRy*sumRy)), 0), 255);
273+
int green = min(max((int)round(sqrt(sumGx*sumGx + sumGy*sumGy)), 0), 255);
274+
int blue = min(max((int)round(sqrt(sumBx*sumBx + sumBy*sumBy)), 0), 255);
275+
276+
image[i][j].rgbtRed = red;
277+
image[i][j].rgbtGreen = green;
278+
image[i][j].rgbtBlue = blue;
279+
}
280+
}
281+
282+
// Free temporary array
283+
for (int i = 0; i < height; i++)
284+
free(copy[i]);
285+
free(copy);
286+
}

helpers.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
#ifndef HELPERS_H
2+
#define HELPERS_H
3+
4+
#include <stdio.h>
5+
#include <math.h>
6+
17
#include "bmp.h"
28

39
// Convert image to grayscale
@@ -15,8 +21,17 @@ void reflect(int height, int width, RGBTRIPLE image[height][width]);
1521
// Blur image
1622
void blur(int height, int width, RGBTRIPLE image[height][width]);
1723

24+
//Threshold Filter(Black & White)
25+
void threshold(int height, int width, RGBTRIPLE image[height][width]);
26+
27+
// *New: Edge Detection filter*
28+
void detect_edges(int height, int width, RGBTRIPLE image[height][width]);
29+
1830
// Brightness adjustment filter
1931
void brightness(int height, int width, RGBTRIPLE image[height][width], int value);
2032

2133
// Vignette filter
2234
void vignette(int height, int width, RGBTRIPLE image[height][width]);
35+
36+
37+
#endif

output.bmp

68.7 MB
Binary file not shown.

0 commit comments

Comments
 (0)