Edge Detection

Avi Gupta
hackerLog
Published in
5 min readJan 14, 2022

What is an edge?

That statement can be defined in many ways. Maybe you define it geometrically, as the line where two planes intersect. Maybe you define it visually, as a line or curve that separates two objects/faces.

When we talk about Edge Detection, we talk about the visual kinds of edges. These edges can easily be defined by a human — but hard to define by a computer.

Right?

Well, no.

Part 1: How does the human eye perceive an edge?

This is not a hard question to answer, if you think about it.

A rectangular prism.

Take, for example, this conveniently placed rectangular prism. How many edges do you see?

As long as you’re not blind, you would have seen 9 edges.

We can define a visual edge as a noticeable change in color between two pixels.

Using this definition, we can get started on building our edge detector.

Part 2: The Code

To make this program, I used Processing, a Java-based IDE designed for graphics. Each Processing file is saved as a .pde file.

First, let’s setup some variables:

PImage img; //sets the image
String filename; //sets the filename
float percentDifference; //sets the threshold

The variable percentDifference is there to define the difference in percentage two pixels have to be in order to qualify as an edge.

Then, we set up the program. To initialize filename, we have to do three things:

  1. Find the folder in which you keep the .pde file that you are using.
  2. Drag an image into that folder.
  3. set filename to the name of the image without the ending. For example, if the name of the image was test_image.jpeg, then set filename to "test_image". Add the .jpeg ending to the second string of the loadImage function. Down below is the setup() function:
void setup(){
size(<insert image width>, <insert image height>);
filename = "insert-file-name-here"; //insert the name of the file here without the ending
percentDifference = 11.5; //the minimum difference in percentage for it to be an edge
img = loadImage(filename + ".insert-file-ending-here");
noLoop(); //prevents the draw() function from looping
}

We then add the draw() function and load the image img.

void draw() {
image(img, 0, 0, width, height);
}

Next, we need to detect edges horizontally and vertically. This can be done by going pixel by pixel and comparing the color with the pixel next to it.

//find edges on the x axis
for(int x = 0; x < width - 1; x++){
for(int y = 0; y < height; y++){
detectEdge(x, y, x+1, y);
}
}
//find edges on the y axis
for(int x = 0; x < width; x++){
for(int y = 0; y < height - 1; y++){
detectEdge(x, y, x, y+1);
}
}

And so, the entire draw function looks like this:

void draw(){
image(img, 0, 0, width, height);
//find edges on the x axis
for(int x = 0; x < width - 1; x++){
for(int y = 0; y < height; y++){
detectEdge(x, y, x+1, y);
}
}
//find edges on the y axis
for(int x = 0; x < width; x++){
for(int y = 0; y < height - 1; y++){
detectEdge(x, y, x, y+1);
}
}
}

But wait! What about that detectEdge function?

First, initialize the function:

void detectEdge(int x1, int y1, int x2, int y2){
}

Then, add some variables obtaining the colors from the pixels at (x1, y1) and (x2, y2).

  color c1 = get(x1, y1);
color c2 = get(x2, y2);

Now comes the edge detection part. The way this program detects edges is like this:

  1. Find the greyscale value of the colors. Converting RGB to greyscale follows this formula: 0.299R + .587G + .114B.
  2. Compare the two greyscale values using the percentDifference value from earlier.
  3. If there is an edge (meaning that the percent difference between the two greyscale values is greater than the percentDifference value), then mark it by showing a red pixel.

Here is the full detectEndge() function:

void detectEdge(int x1, int y1, int x2, int y2){
//get colors
color c1 = get(x1, y1);
color c2 = get(x2, y2);

//get greyscale valuses
float g1 = .299 * red(c1) + .587 * green(c1) + .114 * blue(c1) + 0.0001;
float g2 = .299 * red(c2) + .587 * green(c2) + .114 * blue(c2) + 0.0001;

//compare edges
if((g2 - g1)/g1 * 100>= percentDifference){
set(x1, y1, color(255, 0, 0)); //set pixel to a red color
}
}

And that’s all you have to do!

If you want to save the version of the file with the edges, here’s what you do:

//save version with edges detected
void mouseClicked(){
saveFrame(filename + "-edges.jpg");
}

Here is the full code:

PImage img;
String filename;
float percentDifference;
void setup(){
size(640, 360);
filename = "test-image-1";
percentDifference = 11.5; //the minimum difference in percentage for it to be an edge
img = loadImage(filename + ".jpeg");
noLoop();
}
void draw(){
image(img, 0, 0, width, height);
//find edges on the x axis
for(int x = 0; x < width - 1; x++){
for(int y = 0; y < height; y++){
detectEdge(x, y, x+1, y);
}
}
//find edges on the y axis
for(int x = 0; x < width; x++){
for(int y = 0; y < height - 1; y++){
detectEdge(x, y, x, y+1);
}
}
}
//edge detection
void detectEdge(int x1, int y1, int x2, int y2){
//get colors
color c1 = get(x1, y1);
color c2 = get(x2, y2);

//get greyscale valuses
float g1 = .299 * red(c1) + .587 * green(c1) + .114 * blue(c1) + 0.0001;
float g2 = .299 * red(c2) + .587 * green(c2) + .114 * blue(c2) + 0.0001;

//compare edges
if((g2 - g1)/g1 * 100>= percentDifference){
set(x1, y1, color(255, 0, 0)); //set pixel to a red color
}
}
//save version with edges detected
void mouseClicked(){
saveFrame(filename + "-edges.jpg");
}

Here is a picture before and after:

Before. Pulled from the internet.
After, with edges detected.

Here’s another:

Before. NOTE: this person does not exist. It was made by the AI who lives by a van down by the river in thispersondoesnotexist.com.
After. Notice all the fine details picked up such as the hair, eyes, and mouth.

That’s all for this time — see you soon!

--

--

Avi Gupta
hackerLog

Named after the first 2 games I got on my xBox, Forza and Minecraft. Also, i have a blog. Real name is Avi.