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.
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:
- Find the folder in which you keep the
.pde
file that you are using. - Drag an image into that folder.
- set
filename
to the name of the image without the ending. For example, if the name of the image wastest_image.jpeg
, then setfilename
to"test_image"
. Add the.jpeg
ending to the second string of theloadImage
function. Down below is thesetup()
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:
- Find the greyscale value of the colors. Converting
RGB
to greyscale follows this formula:0.299R + .587G + .114B
. - Compare the two greyscale values using the
percentDifference
value from earlier. - 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:
Here’s another:
That’s all for this time — see you soon!