Edge Detection
edge-detection.pde
/**
* Edge Detection.
*
* This program analyzes every pixel in an image and compares it with the
* neighboring pixels to identify edges.
*
* This is an example of an "image convolution" using a kernel (small matrix)
* to analyze and transform a pixel based on the values of its neighbors.
*
* This kernel describes a "Laplacian Edge Detector". It is effective,
* but sensitive to noise. One common enhancement is to add a Gaussian
* blur to the source image first, as in
* grayImg->filter(BLUR);
* to reduce impact of noise on the output. The combination is often called
* "Laplace of Gaussian", or "LoG" for short.
*
* For weaker detection effect, try this kernel: [ 0 -1 0 ]
* [ -1 4 -1 ]
* [ 0 -1 0 ]
*/
float kernel[3][3] = {{ -1, -1, -1},
{ -1, 8, -1},
{ -1, -1, -1}};
PImage* img;
void setup() {
size(640, 360);
img = loadImage("moon.jpg"); // Load the original image
noLoop();
}
void draw() {
image(img, 0, 0); // Displays the image from point (0,0)
img->loadPixels();
// Edge detection should be done on a grayscale image.
// Create a copy of the source image, and convert to gray.
// PImage's copy CONSTRUCTOR is deleted (see E0002 in Processing.h --
// it owns a GPU texture, so value-style copying isn't supported), but
// PImage::copy() is a real method that duplicates the whole image into
// an independent PImage. It returns by value, so wrap it in `new` to
// fit this codebase's PImage* convention -- the move constructor
// handles the transfer, no pixel data is copied twice.
PImage* grayImg = new PImage(img->copy());
grayImg->filter(GRAY);
// grayImg->filter(BLUR);
// Create an opaque image of the same size as the original
PImage* edgeImg = createImage(grayImg->width, grayImg->height, RGB);
// Loop through every pixel in the image
for (int y = 1; y < grayImg->height - 1; y++) { // Skip top and bottom edges
for (int x = 1; x < grayImg->width - 1; x++) { // Skip left and right edges
// Output of this filter is shown as offset from 50% gray.
// This preserves transitions from low (dark) to high (light) value.
// Starting from zero will show only high edges on black instead.
float sum = 128;
for (int ky = -1; ky <= 1; ky++) {
for (int kx = -1; kx <= 1; kx++) {
// Calculate the adjacent pixel for this kernel point
int pos = (y + ky) * grayImg->width + (x + kx);
// Image is grayscale, red/green/blue are identical
float val = blue(grayImg->pixels[pos]);
// Multiply adjacent pixels based on the kernel values
sum += kernel[ky + 1][kx + 1] * val;
}
}
// For this pixel in the new image, set the output value
// based on the sum from the kernel
edgeImg->pixels[y * edgeImg->width + x] = color(sum);
}
}
// State that there are changes to edgeImg->pixels[]
edgeImg->updatePixels();
image(edgeImg, width / 2, 0); // Draw the new image
}