El kernel de una imagen es una pequeña matriz cuadrada de tamaño impar que, por medio de la convolución entre el kernel y la imagen, se utiliza para aplicar distintos efectos en la imagen. La convolución es el proceso en el cual se suma cada píxel de la imagen con sus vecinos locales, teniendo en cuenta los pesos indicados por el kernel. De esta forma, si tenemos la matriz de píxeles y el kernel
y deseamos obtener la convolución del píxel central (195), obtenemos el resultado:
Así, para aplicar el filtro deseado, se toma cada uno de los píxeles de la imagen original y se reemplazan por el píxel obtenido al realizar su respectiva convolución con el kernel.
A continuación se realiza la descripción de 4 kernels y se muestra el resultado de su convolución con una imagen.
Filtro que da la ilusión de profundidad y enfatiza la diferencia entre pixeles.
Filtro que desenfatiza las diferencias entre los pixeles, logrando un efecto borroso en la imagen.
Filtro que resalta diferencias de intensidad importantes entre los pixeles. De esta forma, un píxel cuyos píxeles vecinos tengan una intensidad similar, se verá negro al aplicar el filtro; mientras que un un píxel cuyos vecinos tengan una intensidad bastante diferente, se verá blanco.
Filtro que enfatiza las diferencias entre los píxeles adyacentes. Con esto, se obtiene una imagen más vívida.
1linklet img;
2linklet v = 1.0 / 9.0;
3link
4linklet emboss = [
5link [-2, -1, 0],
6link [-1, 1, 1],
7link [0, 1, 2]
8link];
9link
10linklet blurM = [
11link [v, v, v],
12link [v, v, v],
13link [v, v, v]
14link];
15link
16linklet outline = [
17link [-1, -1, -1],
18link [-1, 8, -1],
19link [-1, -1, -1]
20link];
21link
22linklet sharpen = [
23link [0, -1, 0],
24link [-1, 5, -1],
25link [0, -1, 0]
26link];
27link
28linkfunction preload() {
29link img = loadImage("/vc/docs/sketches/workshops/imaging/BabyYoda.jpg");
30link}
31link
32linkfunction setup() {
33link createCanvas(800, 550);
34link img.resize(400, 275);
35link noLoop();
36link}
37link
38linkfunction draw() {
39link
40link
41link img.loadPixels();
42link
43link eImg = createImage(img.width, img.height);
44link bImg = createImage(img.width, img.height);
45link oImg = createImage(img.width, img.height);
46link sImg = createImage(img.width, img.height);
47link
48link eImg.loadPixels();
49link for (let x = 1; x < img.width; x++) {
50link for (let y = 1; y < img.height; y++) {
51link let c = convolution(x, y, emboss);
52link let index = 4 * (x + img.width * y);
53link
54link eImg.pixels[index] = red(c);
55link eImg.pixels[index + 1] = green(c);
56link eImg.pixels[index + 2] = blue(c);
57link eImg.pixels[index + 3] = alpha(c);
58link }
59link }
60link eImg.updatePixels();
61link image(eImg, 0, 0);
62link
63link bImg.loadPixels();
64link for (let x = 1; x < img.width; x++) {
65link for (let y = 1; y < img.height; y++) {
66link let c = convolution(x, y, blurM);
67link let index = 4 * (x + img.width * y);
68link
69link bImg.pixels[index] = red(c);
70link bImg.pixels[index + 1] = green(c);
71link bImg.pixels[index + 2] = blue(c);
72link bImg.pixels[index + 3] = alpha(c);
73link }
74link }
75link bImg.updatePixels();
76link image(bImg, 400, 0);
77link
78link
79link oImg.loadPixels();
80link for (let x = 1; x < img.width; x++) {
81link for (let y = 1; y < img.height; y++) {
82link let c = convolution(x, y, outline);
83link let index = 4 * (x + img.width * y);
84link
85link oImg.pixels[index] = red(c);
86link oImg.pixels[index + 1] = green(c);
87link oImg.pixels[index + 2] = blue(c);
88link oImg.pixels[index + 3] = alpha(c);
89link }
90link }
91link oImg.updatePixels();
92link image(oImg, 0, 275);
93link
94link sImg.loadPixels();
95link for (let x = 1; x < img.width; x++) {
96link for (let y = 1; y < img.height; y++) {
97link let c = convolution(x, y, sharpen);
98link let index = 4 * (x + img.width * y);
99link
100link sImg.pixels[index] = red(c);
101link sImg.pixels[index + 1] = green(c);
102link sImg.pixels[index + 2] = blue(c);
103link sImg.pixels[index + 3] = alpha(c);
104link }
105link }
106link sImg.updatePixels();
107link image(sImg, 400, 275);
108link
109link fill(255, 255, 255);
110link textSize(32);
111link text('Emboss', 270, 30);
112link text('Outline', 280, 310);
113link text('Blur', 730, 30);
114link text('Sharpen', 665, 310);
115link
116link}
117link
118linkfunction convolution(x, y, matrix) {
119link let rtotal = 0;
120link let gtotal = 0;
121link let btotal = 0;
122link
123link for (kx = -1; kx <= 1; kx++) {
124link for (ky = -1; ky <= 1; ky++) {
125link let xpos = x + kx;
126link let ypos = y + ky;
127link let r = 0;
128link let g = 0;
129link let b = 0;
130link
131link if ((xpos >= 0 && xpos < img.width) && (ypos >= 0 || ypos < img.height)) {
132link let index = 4 * (xpos + img.width * ypos);
133link r = img.pixels[index];
134link g = img.pixels[index + 1];
135link b = img.pixels[index + 2];
136link }
137link
138link rtotal += matrix[kx + 1][ky + 1] * r;
139link gtotal += matrix[kx + 1][ky + 1] * g;
140link btotal += matrix[kx + 1][ky + 1] * b;
141link }
142link }
143link
144link rtotal = constrain(rtotal, 0, 255);
145link gtotal = constrain(gtotal, 0, 255);
146link btotal = constrain(btotal, 0, 255);
147link
148link return color(rtotal, gtotal, btotal);
149link}
La aplicación de filtros no es el único uso que se le da a los kernels, pues estos también se utilizan para la "Extracción de características" de una imagen. Sobel, por ejemplo, es un tipo de kernel que se utiliza en el procesamiento de imágenes, especialmente en algoritmos de detección de bordes. En total existen 4 tipos de sobel, que se describen y se muestran a continuación.
Se utiliza para mostrar únicamente las diferencias entre un píxel con los pixeles superiores adyacentes.
Se utiliza para mostrar únicamente las diferencias entre un píxel con los pixeles posteriores adyacentes.
Se utiliza para mostrar únicamente las diferencias entre un píxel con los pixeles inferiores adyacentes.
Se utiliza para mostrar únicamente las diferencias entre un píxel con los pixeles anteriores adyacentes.
1linklet img;
2link
3linklet topS = [
4link [1, 2, 1],
5link [0, 0, 0],
6link [-1, -2, -1]
7link];
8link
9linklet rigthS = [
10link [-1, 0, 1],
11link [-2, 0, 2],
12link [-1, 0, 1]
13link];
14link
15linklet bottomS = [
16link [-1, -2, -1],
17link [0, 0, 0],
18link [1, 2, 1]
19link];
20link
21linklet leftS = [
22link [1, 0, -1],
23link [2, 0, -2],
24link [1, 0, -1]
25link];
26link
27linkfunction preload() {
28link img = loadImage("/vc/docs/sketches/workshops/imaging/BabyYoda.jpg");
29link}
30link
31linkfunction setup() {
32link createCanvas(800, 550);
33link img.resize(400, 275);
34link noLoop();
35link}
36link
37linkfunction draw() {
38link
39link img.loadPixels();
40link
41link tImg = createImage(img.width, img.height);
42link rImg = createImage(img.width, img.height);
43link bImg = createImage(img.width, img.height);
44link lImg = createImage(img.width, img.height);
45link
46link tImg.loadPixels();
47link for (let x = 1; x < img.width; x++) {
48link for (let y = 1; y < img.height; y++) {
49link let c = convolution(x, y, topS);
50link let index = 4 * (x + img.width * y);
51link
52link tImg.pixels[index] = red(c);
53link tImg.pixels[index + 1] = green(c);
54link tImg.pixels[index + 2] = blue(c);
55link tImg.pixels[index + 3] = alpha(c);
56link }
57link }
58link tImg.updatePixels();
59link image(tImg, 0, 0);
60link
61link rImg.loadPixels();
62link for (let x = 1; x < img.width; x++) {
63link for (let y = 1; y < img.height; y++) {
64link let c = convolution(x, y, rigthS);
65link let index = 4 * (x + img.width * y);
66link
67link rImg.pixels[index] = red(c);
68link rImg.pixels[index + 1] = green(c);
69link rImg.pixels[index + 2] = blue(c);
70link rImg.pixels[index + 3] = alpha(c);
71link }
72link }
73link rImg.updatePixels();
74link image(rImg, 400, 0);
75link
76link
77link bImg.loadPixels();
78link for (let x = 1; x < img.width; x++) {
79link for (let y = 1; y < img.height; y++) {
80link let c = convolution(x, y, bottomS);
81link let index = 4 * (x + img.width * y);
82link
83link bImg.pixels[index] = red(c);
84link bImg.pixels[index + 1] = green(c);
85link bImg.pixels[index + 2] = blue(c);
86link bImg.pixels[index + 3] = alpha(c);
87link }
88link }
89link bImg.updatePixels();
90link image(bImg, 0, 275);
91link
92link lImg.loadPixels();
93link for (let x = 1; x < img.width; x++) {
94link for (let y = 1; y < img.height; y++) {
95link let c = convolution(x, y, leftS);
96link let index = 4 * (x + img.width * y);
97link
98link lImg.pixels[index] = red(c);
99link lImg.pixels[index + 1] = green(c);
100link lImg.pixels[index + 2] = blue(c);
101link lImg.pixels[index + 3] = alpha(c);
102link }
103link }
104link lImg.updatePixels();
105link image(lImg, 400, 275);
106link
107link fill(255, 255, 255);
108link textSize(32);
109link text('Top', 330, 30);
110link text('Bottom', 280, 310);
111link text('Right', 710, 30);
112link text('Left', 730, 310);
113link
114link}
115link
116linkfunction convolution(x, y, matrix) {
117link let rtotal = 0;
118link let gtotal = 0;
119link let btotal = 0;
120link
121link for (kx = -1; kx <= 1; kx++) {
122link for (ky = -1; ky <= 1; ky++) {
123link let xpos = x + kx;
124link let ypos = y + ky;
125link let r = 0;
126link let g = 0;
127link let b = 0;
128link
129link if ((xpos >= 0 && xpos < img.width) && (ypos >= 0 || ypos < img.height)) {
130link let index = 4 * (xpos + img.width * ypos);
131link r = img.pixels[index];
132link g = img.pixels[index + 1];
133link b = img.pixels[index + 2];
134link }
135link
136link rtotal += matrix[kx + 1][ky + 1] * r;
137link gtotal += matrix[kx + 1][ky + 1] * g;
138link btotal += matrix[kx + 1][ky + 1] * b;
139link }
140link }
141link
142link rtotal = constrain(rtotal, 0, 255);
143link gtotal = constrain(gtotal, 0, 255);
144link btotal = constrain(btotal, 0, 255);
145link
146link return color(rtotal, gtotal, btotal);
147link}
Adicionalmente, estos kernel pueden ser utilizados en el procesamiento de videos.
1linklet fingers;
2link
3linklet outline = [
4link [-1, -1, -1],
5link [-1, 8, -1],
6link [-1, -1, -1]
7link];
8link
9linklet topSobel = [
10link [1, 2, 1],
11link [0, 0, 0],
12link [-1, -2, -1]
13link];
14link
15linklet emboss = [
16link [-2, -1, 0],
17link [-1, 1, 1],
18link [0, 1, 2]
19link];
20link
21linklet sharpen = [
22link [0, -1, 0],
23link [-1, 5, -1],
24link [0, -1, 0]
25link];
26link
27link
28linkfunction preload() {
29link fingers = createVideo("/vc/docs/sketches/fingers.webm");
30link}
31link
32linkfunction mousePressed() {
33link fingers.loop();
34link}
35link
36linkfunction setup() {
37link createCanvas(640, 480);
38link fingers.hide();
39link}
40link
41linkfunction draw() {
42link
43link fingers.loadPixels();
44link loadPixels();
45link
46link let count = 0;
47link
48link for (let y = 1; y < fingers.height; y++) {
49link count = count + 1;
50link for (let x = 1; x < fingers.width; x++) {
51link
52link let c = convolution(x, y, emboss);
53link let index = 4 * (x + fingers.width * (y + count));
54link
55link pixels[index] = red(c);
56link pixels[index + 1] = green(c);
57link pixels[index + 2] = blue(c);
58link pixels[index + 3] = alpha(c);
59link }
60link }
61link
62link count = 0;
63link
64link for (let y = 1; y < fingers.height; y++) {
65link count = count + 1;
66link for (let x = 1; x < fingers.width; x++) {
67link
68link let c = convolution(x, y, topSobel);
69link let index = 4 * ((x + 320) + fingers.width * (y + count));
70link
71link pixels[index] = red(c);
72link pixels[index + 1] = green(c);
73link pixels[index + 2] = blue(c);
74link pixels[index + 3] = alpha(c);
75link }
76link }
77link
78link count = 0;
79link
80link for (let y = 1; y < fingers.height; y++) {
81link count = count + 1;
82link for (let x = 1; x < fingers.width; x++) {
83link
84link let c = convolution(x, y, outline);
85link let index = 4 * (x + fingers.width * (y + 500 + count));
86link
87link pixels[index] = red(c);
88link pixels[index + 1] = green(c);
89link pixels[index + 2] = blue(c);
90link pixels[index + 3] = alpha(c);
91link }
92link }
93link
94link count = 0;
95link
96link for (let y = 1; y < fingers.height; y++) {
97link count = count + 1;
98link for (let x = 1; x < fingers.width; x++) {
99link
100link let c = convolution(x, y, sharpen);
101link let index = 4 * ((x + 320) + fingers.width * (y + 500 + count));
102link
103link pixels[index] = red(c);
104link pixels[index + 1] = green(c);
105link pixels[index + 2] = blue(c);
106link pixels[index + 3] = alpha(c);
107link }
108link }
109link updatePixels();
110link
111link fill(255, 255, 255);
112link textSize(25);
113link strokeWeight(0.1);
114link text('Emboss', 220, 40);
115link text('Outline', 230, 280);
116link text('Top Sobel', 520, 40);
117link text('Sharpen', 535, 280);
118link
119link stroke(255, 255, 255);
120link strokeWeight(11);
121link line(0, 246, 640, 246);
122link strokeWeight(5);
123link line(320, 0, 320, 480);
124link
125link}
126link
127linkfunction convolution(x, y, matrix) {
128link let rtotal = 0;
129link let gtotal = 0;
130link let btotal = 0;
131link
132link for (kx = -1; kx <= 1; kx++) {
133link for (ky = -1; ky <= 1; ky++) {
134link let xpos = x + kx;
135link let ypos = y + ky;
136link let r = 0;
137link let g = 0;
138link let b = 0;
139link
140link if ((xpos >= 0 && xpos < fingers.width) && (ypos >= 0 || ypos < fingers.height)) {
141link let index = 4 * (xpos + fingers.width * ypos);
142link r = fingers.pixels[index];
143link g = fingers.pixels[index + 1];
144link b = fingers.pixels[index + 2];
145link }
146link
147link rtotal += matrix[kx + 1][ky + 1] * r;
148link gtotal += matrix[kx + 1][ky + 1] * g;
149link btotal += matrix[kx + 1][ky + 1] * b;
150link }
151link }
152link
153link rtotal = constrain(rtotal, 0, 255);
154link gtotal = constrain(gtotal, 0, 255);
155link btotal = constrain(btotal, 0, 255);
156link
157link return color(rtotal, gtotal, btotal);
158link}