Skip to content

Commit eadc6c4

Browse files
authored
Merge pull request processing#12 from greg-kennedy/image-processing
Updates to "Image Processing" topic.
2 parents 473a340 + 32490ea commit eadc6c4

File tree

5 files changed

+267
-55
lines changed

5 files changed

+267
-55
lines changed

Topics/Image Processing/Blur/Blur.pde

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,85 @@
11
/**
2-
* Blur.
3-
*
4-
* A low-pass filter blurs an image. This program analyzes every
5-
* pixel in an image and blends it with the neighboring pixels
6-
* to blur the image.
2+
* Blur.
3+
*
4+
* This program analyzes every pixel in an image and blends it with the
5+
* neighboring pixels to blur the image.
6+
*
7+
* This is an example of an "image convolution" using a kernel (small matrix)
8+
* to analyze and transform a pixel based on the values of its neighbors.
9+
*
10+
* Image blur is also called a "low-pass filter". Pixels of low frequency
11+
* change (similar brightness as neighbors) are left mostly unchanged, while
12+
* those with high frequency change (sharply different values) are smoothed
13+
* out.
14+
*
15+
* The kernel here is a Box Blur, in which all components are equally valued.
16+
* Another common blur is "Gaussian Blur", in which pixels nearer the center
17+
* of the kernel have more weight than those further away.
18+
*
19+
* An example 3x3 Gaussian kernel might be: [ 1 2 1 ]
20+
* 1/16 * [ 2 4 2 ]
21+
* [ 1 2 1 ]
22+
*
23+
* An example 5x5 kernel, which creates a greater blur effect:
24+
* [ 1 4 6 4 1 ]
25+
* [ 4 16 24 16 4 ]
26+
* 1/256 * [ 6 24 36 24 6 ]
27+
* [ 4 16 24 16 4 ]
28+
* [ 1 4 6 4 1 ]
729
*/
830

931
float v = 1.0 / 9.0;
10-
float[][] kernel = {{ v, v, v },
11-
{ v, v, v },
32+
float[][] kernel = {{ v, v, v },
33+
{ v, v, v },
1234
{ v, v, v }};
13-
35+
1436
PImage img;
1537

1638
void setup() {
1739
size(640, 360);
1840
img = loadImage("moon.jpg"); // Load the original image
1941
noLoop();
20-
}
42+
}
2143

2244
void draw() {
23-
image(img, 0, 0); // Displays the image from point (0,0)
45+
image(img, 0, 0); // Displays the image from point (0,0)
2446
img.loadPixels();
2547

2648
// Create an opaque image of the same size as the original
27-
PImage edgeImg = createImage(img.width, img.height, RGB);
49+
PImage blurImg = createImage(img.width, img.height, RGB);
2850

2951
// Loop through every pixel in the image
3052
for (int y = 1; y < img.height-1; y++) { // Skip top and bottom edges
3153
for (int x = 1; x < img.width-1; x++) { // Skip left and right edges
32-
float sum = 0; // Kernel sum for this pixel
54+
float sumRed = 0; // Kernel sums for this pixel
55+
float sumGreen = 0;
56+
float sumBlue = 0;
3357
for (int ky = -1; ky <= 1; ky++) {
3458
for (int kx = -1; kx <= 1; kx++) {
3559
// Calculate the adjacent pixel for this kernel point
3660
int pos = (y + ky)*img.width + (x + kx);
37-
// Image is grayscale, red/green/blue are identical
38-
float val = red(img.pixels[pos]);
61+
62+
// Process each channel separately, Red first.
63+
float valRed = red(img.pixels[pos]);
3964
// Multiply adjacent pixels based on the kernel values
40-
sum += kernel[ky+1][kx+1] * val;
65+
sumRed += kernel[ky+1][kx+1] * valRed;
66+
67+
// Green
68+
float valGreen = green(img.pixels[pos]);
69+
sumGreen += kernel[ky+1][kx+1] * valGreen;
70+
71+
// Blue
72+
float valBlue = blue(img.pixels[pos]);
73+
sumBlue += kernel[ky+1][kx+1] * valBlue;
4174
}
4275
}
43-
// For this pixel in the new image, set the gray value
76+
// For this pixel in the new image, set the output value
4477
// based on the sum from the kernel
45-
edgeImg.pixels[y*img.width + x] = color(sum);
78+
blurImg.pixels[y*blurImg.width + x] = color(sumRed, sumGreen, sumBlue);
4679
}
4780
}
48-
// State that there are changes to edgeImg.pixels[]
49-
edgeImg.updatePixels();
81+
// State that there are changes to blurImg.pixels[]
82+
blurImg.updatePixels();
5083

51-
image(edgeImg, width/2, 0); // Draw the new image
84+
image(blurImg, width/2, 0); // Draw the new image
5285
}
53-

Topics/Image Processing/Convolution/Convolution.pde

Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,103 @@
11
/**
22
* Convolution
3-
* by Daniel Shiffman.
4-
*
5-
* Applies a convolution matrix to a portion of an image. Move mouse to
6-
* apply filter to different parts of the image.
3+
* by Daniel Shiffman.
4+
*
5+
* Applies a convolution matrix to a portion of an image. Move mouse to
6+
* apply filter to different parts of the image. Click mouse to cycle
7+
* through different effects (kernels).
78
*/
89

910
PImage img;
11+
int effect = 0;
1012
int w = 120;
1113

12-
// It's possible to convolve the image with many different
13-
// matrices to produce different effects. This is a high-pass
14-
// filter; it accentuates the edges.
15-
float[][] matrix = { { -1, -1, -1 },
16-
{ -1, 9, -1 },
17-
{ -1, -1, -1 } };
14+
// It's possible to convolve the image with many different
15+
// matrices to produce different effects. Here are some
16+
// example kernels to try.
17+
float[][] identity = { { 0, 0, 0 },
18+
{ 0, 1, 0 },
19+
{ 0, 0, 0 } };
1820

21+
float[][] darken = { { 0, 0, 0 },
22+
{ 0, 0.5, 0 },
23+
{ 0, 0, 0 } };
24+
25+
float[][] lighten = { { 0, 0, 0 },
26+
{ 0, 2, 0 },
27+
{ 0, 0, 0 } };
28+
29+
float[][] sharpen = { { 0, -1, 0 },
30+
{ -1, 5, -1 },
31+
{ 0, -1, 0 } };
32+
33+
float[][] sharpen2 = { { -1, -1, -1 },
34+
{ -1, 9, -1 },
35+
{ -1, -1, -1 } };
36+
37+
float[][] box_blur = { { 1.0/9.0, 1.0/9.0, 1.0/9.0 },
38+
{ 1.0/9.0, 1.0/9.0, 1.0/9.0 },
39+
{ 1.0/9.0, 1.0/9.0, 1.0/9.0 } };
40+
41+
float[][] edge_det = { { 0, 1, 0 },
42+
{ 1, -4, 1 },
43+
{ 0, 1, 0 } };
44+
45+
float[][] emboss = { { -2, -1, 0 },
46+
{ -1, 1, 1 },
47+
{ 0, 1, 2 } };
48+
49+
// collect the kernels and names into arrays for our program
50+
float[][][] kernels = {
51+
identity,
52+
darken,
53+
lighten,
54+
sharpen,
55+
sharpen2,
56+
box_blur,
57+
edge_det,
58+
emboss
59+
};
60+
61+
String[] effect_names = {
62+
"Identity (no change)",
63+
"Darken",
64+
"Lighten",
65+
"Sharpen",
66+
"Sharpen More",
67+
"Box Blur",
68+
"Edge Detect",
69+
"Emboss"
70+
};
71+
72+
//
1973
void setup() {
2074
size(640, 360);
21-
img = loadImage("moon-wide.jpg");
75+
img = loadImage("moon-wide.jpg");
76+
77+
noLoop();
78+
}
79+
80+
// Clicking the mouse advances to the next effect
81+
void mousePressed() {
82+
effect++;
83+
if (effect >= effect_names.length) effect = 0;
84+
85+
redraw();
86+
}
87+
88+
// Moving the mouse triggers a screen redraw
89+
void mouseMoved() {
90+
redraw();
91+
}
92+
void mouseDragged() {
93+
redraw();
2294
}
2395

2496
void draw() {
2597
// We're only going to process a portion of the image
2698
// so let's set the whole image as the background first
2799
image(img, 0, 0);
28-
100+
29101
// Calculate the small rectangle we will process
30102
int xstart = constrain(mouseX - w/2, 0, img.width);
31103
int ystart = constrain(mouseY - w/2, 0, img.height);
@@ -36,12 +108,15 @@ void draw() {
36108
// Begin our loop for every pixel in the smaller image
37109
for (int x = xstart; x < xend; x++) {
38110
for (int y = ystart; y < yend; y++ ) {
39-
color c = convolution(x, y, matrix, matrixsize, img);
111+
color c = convolution(x, y, kernels[effect], matrixsize, img);
40112
int loc = x + y*img.width;
41113
pixels[loc] = c;
42114
}
43115
}
44116
updatePixels();
117+
118+
textSize(24);
119+
text(effect_names[effect], 4, 24);
45120
}
46121

47122
color convolution(int x, int y, float[][] matrix, int matrixsize, PImage img)
@@ -71,4 +146,3 @@ color convolution(int x, int y, float[][] matrix, int matrixsize, PImage img)
71146
// Return the resulting color
72147
return color(rtotal, gtotal, btotal);
73148
}
74-

Topics/Image Processing/EdgeDetection/EdgeDetection.pde

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,74 @@
11
/**
2-
* Edge Detection.
3-
*
4-
* A high-pass filter sharpens an image. This program analyzes every
5-
* pixel in an image in relation to the neighboring pixels to sharpen
6-
* the image. This example is currently not accurate in JavaScript mode.
2+
* Edge Detection.
3+
*
4+
* This program analyzes every pixel in an image and compares it with thee
5+
* neighboring pixels to identify edges.
6+
*
7+
* This is an example of an "image convolution" using a kernel (small matrix)
8+
* to analyze and transform a pixel based on the values of its neighbors.
9+
*
10+
* This kernel describes a "Laplacian Edge Detector". It is effective,
11+
* but sensitive to noise. One common enhancement is to add a Gaussian
12+
* blur to the source image first, as in
13+
* grayImg.filter(BLUR);
14+
* to reduce impact of noise on the output. The combination is often called
15+
* "Laplace of Gaussian", or "LoG" for short.
16+
*
17+
* For weaker detection effect, try this kernel: [ 0 -1 0 ]
18+
* [ -1 4 -1 ]
19+
* [ 0 -1 0 ]
720
*/
821

9-
float[][] kernel = {{ -1, -1, -1},
10-
{ -1, 9, -1},
22+
float[][] kernel = {{ -1, -1, -1},
23+
{ -1, 8, -1},
1124
{ -1, -1, -1}};
12-
25+
1326
PImage img;
1427

15-
void setup() {
28+
void setup() {
1629
size(640, 360);
1730
img = loadImage("moon.jpg"); // Load the original image
1831
noLoop();
1932
}
2033

2134
void draw() {
22-
image(img, 0, 0); // Displays the image from point (0,0)
35+
image(img, 0, 0); // Displays the image from point (0,0)
2336
img.loadPixels();
37+
38+
// Edge detection should be done on a grayscale image.
39+
// Create a copy of the source image, and convert to gray.
40+
PImage grayImg = img.copy();
41+
grayImg.filter(GRAY);
42+
// grayImg.filter(BLUR);
43+
2444
// Create an opaque image of the same size as the original
25-
PImage edgeImg = createImage(img.width, img.height, RGB);
26-
// Loop through every pixel in the image.
27-
for (int y = 1; y < img.height-1; y++) { // Skip top and bottom edges
28-
for (int x = 1; x < img.width-1; x++) { // Skip left and right edges
29-
float sum = 0; // Kernel sum for this pixel
45+
PImage edgeImg = createImage(grayImg.width, grayImg.height, RGB);
46+
47+
// Loop through every pixel in the image
48+
for (int y = 1; y < grayImg.height-1; y++) { // Skip top and bottom edges
49+
for (int x = 1; x < grayImg.width-1; x++) { // Skip left and right edges
50+
// Output of this filter is shown as offset from 50% gray.
51+
// This preserves transitions from low (dark) to high (light) value.
52+
// Starting from zero will show only high edges on black instead.
53+
float sum = 128;
3054
for (int ky = -1; ky <= 1; ky++) {
3155
for (int kx = -1; kx <= 1; kx++) {
3256
// Calculate the adjacent pixel for this kernel point
33-
int pos = (y + ky)*img.width + (x + kx);
57+
int pos = (y + ky)*grayImg.width + (x + kx);
58+
3459
// Image is grayscale, red/green/blue are identical
35-
float val = red(img.pixels[pos]);
60+
float val = blue(grayImg.pixels[pos]);
3661
// Multiply adjacent pixels based on the kernel values
3762
sum += kernel[ky+1][kx+1] * val;
3863
}
3964
}
40-
// For this pixel in the new image, set the gray value
65+
// For this pixel in the new image, set the output value
4166
// based on the sum from the kernel
42-
edgeImg.pixels[y*img.width + x] = color(sum, sum, sum);
67+
edgeImg.pixels[y*edgeImg.width + x] = color(sum);
4368
}
4469
}
4570
// State that there are changes to edgeImg.pixels[]
4671
edgeImg.updatePixels();
72+
4773
image(edgeImg, width/2, 0); // Draw the new image
4874
}
49-

0 commit comments

Comments
 (0)