Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
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
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,58 @@ 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.



### Pixelate Filter

The “Pixelate” filter divides the image into small square blocks (default 5x5) and replaces each block with the average color of its pixels. This creates a mosaic-like effect, useful for artistic rendering or obscuring parts of an image for privacy.

Algorithm Steps:

1. Divide the image into blocks of size blockSize x blockSize.
2. For each block:
a. Compute the average Red, Green, and Blue values of all pixels in the block.
b. Replace all pixels in the block with the computed average color.
3. Repeat until all blocks are processed.


---

### Usage
Expand Down
56 changes: 34 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 = "bgrsivtdp";




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,24 @@ 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;



case 'p':
apply_pixelate(height, width, image, 5); // default block size = 5
break;

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

}
}
// Write outfile's BITMAPFILEHEADER
Expand Down
130 changes: 130 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,131 @@ 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;
}
}



// Pixelate Filter
void apply_pixelate(int height, int width, RGBTRIPLE image[height][width], int blockSize)
{
for (int i = 0; i < height; i += blockSize)
{
for (int j = 0; j < width; j += blockSize)
{
int sumRed = 0, sumGreen = 0, sumBlue = 0;
int count = 0;

// Compute average color in the block
for (int bi = 0; bi < blockSize; bi++)
{
for (int bj = 0; bj < blockSize; bj++)
{
int ni = i + bi;
int nj = j + bj;
if (ni < height && nj < width)
{
sumRed += image[ni][nj].rgbtRed;
sumGreen += image[ni][nj].rgbtGreen;
sumBlue += image[ni][nj].rgbtBlue;
count++;
}
}
}

int avgRed = sumRed / count;
int avgGreen = sumGreen / count;
int avgBlue = sumBlue / count;

// Set all pixels in the block to the average color
for (int bi = 0; bi < blockSize; bi++)
{
for (int bj = 0; bj < blockSize; bj++)
{
int ni = i + bi;
int nj = j + bj;
if (ni < height && nj < width)
{
image[ni][nj].rgbtRed = avgRed;
image[ni][nj].rgbtGreen = avgGreen;
image[ni][nj].rgbtBlue = avgBlue;
}
}
}
}
}
}


// Free temporary array
for (int i = 0; i < height; i++)
free(copy[i]);
free(copy);
}
15 changes: 15 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,12 @@ 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]);

// Pixelate filter
void apply_pixelate(int height, int width, RGBTRIPLE image[height][width], int blockSize);


#endif