|
@@ -0,0 +1,636 @@
|
|
1
|
+[English](#markdown-header-arrays-green-screen) | [Espaรฑol](#markdown-header-arreglos-pantalla-verde)
|
|
2
|
+
|
|
3
|
+#Arreglos - Pantalla Verde
|
|
4
|
+
|
|
5
|
+![main1.png](images/main1.png)
|
|
6
|
+![main2.png](images/main2.png)
|
|
7
|
+![main3.png](images/main3.png)
|
|
8
|
+
|
|
9
|
+Los arreglos de datos (*arrays*) nos facilitan guardar y trabajar con grupos de datos del mismo tipo. Los datos se guardan en espacios de memoria consecutivos a los que se puede acceder utilizando el nombre del arreglo e รญndices o suscritos que indican la posiciรณn en que se encuentra el dato. Las estructuras de repeticiรณn nos proveen una manera simple de acceder a los datos de un arreglo. En la experiencia de laboratorio de hoy practicarรกs el uso de ciclos anidados en la manipulaciรณn de arreglos bi-dimensionales usando tรฉcnicas de "pantalla verde".
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+##Objetivos:
|
|
13
|
+
|
|
14
|
+1. Practicar el acceso y manipulaciรณn de datos en un arreglo.
|
|
15
|
+
|
|
16
|
+2. Aplicar ciclos anidados para implementar tรฉcnicas de "pantalla verde".
|
|
17
|
+
|
|
18
|
+3. Utilizar expresiones aritmรฉticas y estructuras de selecciรณn para transformar colores de pรญxeles.
|
|
19
|
+
|
|
20
|
+4. Acceder pรญxeles en una imagen y descomponerlos en sus componentes rojo, azul y verde.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+##Pre-Lab:
|
|
24
|
+
|
|
25
|
+Antes de llegar al laboratorio debes:
|
|
26
|
+
|
|
27
|
+1. Haber repasado los conceptos bรกsicos relacionados a estructuras de repeticiรณn, ciclos anidados y arreglos bi-dimensionales.
|
|
28
|
+
|
|
29
|
+2. Conocer los mรฉtodos bรกsicos de `QImage` para manipular los pixeles de las imรกgenes.
|
|
30
|
+
|
|
31
|
+3. Haber estudiado los conceptos e instrucciones para la sesiรณn de laboratorio.
|
|
32
|
+
|
|
33
|
+4. Haber tomado el quiz Pre-Lab que se encuentra en Moodle.
|
|
34
|
+
|
|
35
|
+---
|
|
36
|
+
|
|
37
|
+---
|
|
38
|
+
|
|
39
|
+##Tecnologรญa de pantalla verde ("Green Screen")
|
|
40
|
+
|
|
41
|
+En esta experiencia de laboratorio, aprenderรกs los conceptos y destrezas bรกsicas de la tecnologรญa de pantalla verde que se usa en boletines informativos de televisiรณn, pelรญculas, juegos de video y otros. La composiciรณn de pantalla verde, o composiciรณn cromรกtica, es una tรฉcnica que se usa para combinar dos imรกgenes o cuadros de video [1]. Esta tรฉcnica de post-producciรณn crea efectos especiales al componer dos imรกgenes o transmisiones de video sustituyendo el รกrea de un color sรณlido por otra imรกgen [2]. La composiciรณn cromรกtica se puede hacer con imรกgenes de objetos sobre fondos de cualquier color que sean uniformes y diferentes a los de la imagen. Los fondos azules y verdes son los que se usan con mรกs frecuencia porque se distinguen con mรกs facilidad de los tonos de la mayorรญa de los colores de piel humanos.
|
|
42
|
+
|
|
43
|
+Para esta experiencia de laboratorio te proveemos un interfaz grรกfico (GUI) simple que permite al usuario cargar una imagen con un objeto sobre un fondo de color sรณlido (preferiblemente azul o verde) y una imagen para sustituir el fondo. Tu tarea es crear e implementar una funciรณn que cree una tercera imagen compuesta en la cual, a la imagen del objeto con el fondo de color sรณlido se le removerรก el color de fondo y el objeto aparecerรก sobre la imagen que serรก el nuevo fondo. La Figura 1 muestra un ejemplo de los resultados esperados.
|
|
44
|
+
|
|
45
|
+---
|
|
46
|
+
|
|
47
|
+![figure1.png](images/figure1.png)
|
|
48
|
+
|
|
49
|
+**Figura 1.** Ejemplo de los resultados esperados. El objeto de interรฉs es la mano con las gafas.
|
|
50
|
+
|
|
51
|
+---
|
|
52
|
+
|
|
53
|
+Con el propรณsito de ilustrar el procedimiento, llamemos la imagen del objeto con el fondo de color sรณlido *imagen A*, y supongamos que el color sรณlido en el fondo tiene un "RGB" `0x00ff00` (verde puro). Llamemos *imagen B* a la imagen que usaremos para el fondo, un fondo que resulte interesante. Para este ejemplo, supongamos tambiรฉn que los tamaรฑos de ambas imรกgenes son iguales (mismo ancho y alto).
|
|
54
|
+
|
|
55
|
+Para producir la imagen compuesta (*imagen C*), podrรญamos comenzar copiando toda la *imagen B* que usaremos de fondo a la *imagen C*. Luego, para insertar solo el objeto que nos interesa en la imagen compuesta podemos recorrer la *imagen A* pรญxel por pรญxel. Compararรญamos el color de cada pรญxel *p* en la *imagen A* con el color de fondo `0x00ff00`. Si son *similares*, el pรญxel de la *imagen A* corresponde al color sรณlido de fondo y dejamos el pรญxel de la *imagen C* como estรก (el fondo nuevo). Si el color de *p* no es *similar* a `0x00ff00`, modificamos el pรญxel correspondiente en la *imagen C*, copiando el color del pรญxel del objeto a la imagen compuesta. Esto se ilustra en la Figura 2.
|
|
56
|
+
|
|
57
|
+---
|
|
58
|
+
|
|
59
|
+![figure2.png](images/figure2.png)
|
|
60
|
+
|
|
61
|
+**Figura 2.** Ilustraciรณn de cรณmo el algoritmo decide cuรกles pรญxeles de la *imagen A* incluir en la *imagen C*.
|
|
62
|
+
|
|
63
|
+---
|
|
64
|
+
|
|
65
|
+---
|
|
66
|
+
|
|
67
|
+##Pรญxeles
|
|
68
|
+
|
|
69
|
+Al elemento mรกs pequeรฑo de una imagen se le llama un *pรญxel*. Esta unidad consiste de un solo color. Como cada color es una combinaciรณn de tonalidades de los colores primarios rojo, verde y azul, se codifica como un entero sin signo cuyos bytes representan los tonos de rojo, verde y azul del pixel (Figura 3). A esta combinaciรณn se le llama el *RGB* del color por las siglas de "Red-Green-Blue". Por ejemplo un pรญxel de color rojo (puro) tiene una representaciรณn RGB `0x00ff0000`, mientras que un pรญxel de color blanco tiene una representaciรณn RGB de `0x00FFFFFF` (ya que el color blanco es la combinaciรณn de los tonos rojo, verde y azul en toda su intensidad).
|
|
70
|
+
|
|
71
|
+---
|
|
72
|
+
|
|
73
|
+![figure3.png](images/figure3.png)
|
|
74
|
+
|
|
75
|
+**Figura 3.** Distribuciรณn de bits para las tonalidades de rojo, verde y azul dentro de la representaciรณn RGB. Cada tonalidad puede tener valores entre 0x00 (los ocho bits en 0) y 0xFF (los 8 bits en 1).
|
|
76
|
+
|
|
77
|
+---
|
|
78
|
+
|
|
79
|
+En `Qt` se utiliza el tipo `QRgb` para representar valores `RGB`. Utilizando ciertas funciones que describimos abajo podemos obtener los componentes rojo, verde y azul del valor `QRgb` del pรญxel y asรญ manipular imรกgenes.
|
|
80
|
+
|
|
81
|
+###Biblioteca
|
|
82
|
+
|
|
83
|
+La experiencia de laboratorio de hoy utilizarรก la clase `QImage`. Esta clase permite acceder a los datos de los pixeles de una imagen para poder manipularla. La documentaciรณn de la clase `QImage` se encuentra en http://doc.qt.io/qt-4.8/qimage.html.
|
|
84
|
+
|
|
85
|
+El cรณdigo que te proveemos contiene los siguiente objetos de la clase `QImage`:
|
|
86
|
+
|
|
87
|
+* `originalImage` // contiene la informaciรณn de la imagen original que vas a editar
|
|
88
|
+* `editedImage` // contendrรก la imagen editada
|
|
89
|
+
|
|
90
|
+Los objetos de clase `QImage` tienen los siguiente mรฉtodos que serรกn รบtiles para la experiencia de laboratorio de hoy:
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+* `width()` // devuelve el valor entero del ancho de la imagen
|
|
94
|
+* `height()` // devuelve el valor entero de la altura de la imagen
|
|
95
|
+* `pixel(i, j)` // devuelve el `QRgb` del pรญxel en la posiciรณn `(i,j)`
|
|
96
|
+* `setPixel(i,j, pixel)` // modifica el valor del pรญxel en la posiciรณn `(i, j)` al valor pรญxel `QRgb`
|
|
97
|
+
|
|
98
|
+Las siguientes funciones son รบtiles para trabajar con datos de tipo `QRgb`:
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+* `qRed(pixel)` // devuelve el tono del color rojo del pรญxel
|
|
102
|
+* `qGreen(pixel)` // devuelve el tono del color verde del pรญxel
|
|
103
|
+* `qBlue(pixel)` // devuelve el tono del color azul del pรญxel
|
|
104
|
+* `qRgb(int red, int green, int blue)` // devuelve un pรญxel `QRgb` compuesto de los valores de rojo, verde y azul recibidos.
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+####Ejemplos:
|
|
108
|
+
|
|
109
|
+1. `QRgb myRgb = qRgb(0xff, 0x00, 0xff);`: Asigna a `myRgb` el valor `0xff00ff` que representa el color ![figure4.png](images/figure4.png)
|
|
110
|
+
|
|
111
|
+ Nota que el valor `0xff00ff` representa los valores `0xff`, `0x0`, `0xff`, que corresponden a los componentes rojo, verde y azul de `myRgb`.
|
|
112
|
+
|
|
113
|
+2. Si la siguiente imagen `4 x 4` de pรญxeles representa el objeto `originalImage`,
|
|
114
|
+
|
|
115
|
+ ![ejemplo.png](images/ejemplo.png)
|
|
116
|
+
|
|
117
|
+ entonces `originalImage.pixel(2,1)` devuelve un valor `rgb` que representa el color azul (`0x0000ff`).
|
|
118
|
+
|
|
119
|
+3. La siguiente instrucciรณn asigna el color rojo al pรญxel en posiciรณn `(2,3)` en la imagen editada:
|
|
120
|
+
|
|
121
|
+ `editedImage.setPixel(2,3,qRgb(0xff,0x00,0x00));`.
|
|
122
|
+
|
|
123
|
+4. La siguiente instrucciรณn le asigna a `greenContent` el valor del tono de verde que contiene el pixel `(1,1)` de `originalImage`:
|
|
124
|
+
|
|
125
|
+ `int greenContent = qGreen(originalImage.pixel(1,1));`.
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+5. El siguiente programa crea un objeto de clase `QImage` e imprime los componentes rojo, verde y azul del pixel en el centro de la imagen. La imagen utilizada es la que se especifica dentro del parรฉntesis durante la creaciรณn del objeto, esto es, el archivo `chuck.png`.
|
|
129
|
+
|
|
130
|
+---
|
|
131
|
+
|
|
132
|
+```cpp
|
|
133
|
+#include <QImage>
|
|
134
|
+#include <iostream>
|
|
135
|
+
|
|
136
|
+using namespace std;
|
|
137
|
+int main() {
|
|
138
|
+ QImage myImage(โ/Users/rarce/Downloads/chuck.pngโ);
|
|
139
|
+ QRgb centralPixel;
|
|
140
|
+
|
|
141
|
+ centralPixel = myImage.pixel(myImage.width() / 2, myImage.height() / 2);
|
|
142
|
+
|
|
143
|
+ cout << hex;
|
|
144
|
+
|
|
145
|
+ cout << โLos componentes rojo, verde y azul del pixel central son: โ
|
|
146
|
+ << qRed(centralPixel) << โ, โ
|
|
147
|
+ << qGreen(centralPixel) << โ, โ
|
|
148
|
+ << qBlue(centralPixel) << endl;
|
|
149
|
+ return 0;
|
|
150
|
+}
|
|
151
|
+```
|
|
152
|
+
|
|
153
|
+---
|
|
154
|
+
|
|
155
|
+### Midiendo la similaridad de los colores de los pixeles
|
|
156
|
+
|
|
157
|
+Observa la Figura 4 abajo. Aunque el fondo en la *imagen A* parece uniforme, realmente incluye pรญxeles de diferentes colores (aunque parecidos).
|
|
158
|
+
|
|
159
|
+---
|
|
160
|
+
|
|
161
|
+![figure5.png](images/figure5.png)
|
|
162
|
+
|
|
163
|
+**Figura 4.** Lo que puede parecer un color *sรณlido*, realmente no lo es.
|
|
164
|
+
|
|
165
|
+---
|
|
166
|
+
|
|
167
|
+Por esto, en lugar de solo considerar como parte del fondo sรณlido los pรญxeles cuyo color es **exactamente** `0x00FF00`, medimos la *distancia* del valor del color del pรญxel al valor del color *puro*. Una distancia pequeรฑa significa que el color es *casi* verde puro. La ecuaciรณn para la *distancia* es:
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+$$distancia = \sqrt{(P_R-S_R)^2+(P_G-S_G)^2+(P_B-S_B)^2},$$
|
|
171
|
+
|
|
172
|
+donde $$P_R, P_G, P_B$$ son los valores de los componentes rojo, verde y azul del pรญxel bajo consideraciรณn, y $$S_R, S_G, S_B$$ son los valores de los componentes rojo, verde y azul del fondo sรณlido. En nuestro ejemplo, $$S_R=S_B=0$$ y $$S_G=255$$.
|
|
173
|
+
|
|
174
|
+---
|
|
175
|
+
|
|
176
|
+---
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+##Sesiรณn de laboratorio:
|
|
180
|
+
|
|
181
|
+En el laboratorio de hoy, comenzando con una imagen con un objeto de interรฉs sobre un fondo de color sรณlido y una imagen para utilizar como fondo, definirรกs e implantarรกs una funciรณn que cree una tercera imagen compuesta en la cual, a la imagen del objeto de interรฉs se le removerรก el color de fondo y aparecerรก sobre la imagen para el fondo.
|
|
182
|
+
|
|
183
|
+Estarรกs trabajando con el archivo `Filter.cpp`. Lo que sigue es un resumen de las variables en este archivo.
|
|
184
|
+
|
|
185
|
+* `objectImage`: referencia a la imagen del objeto de interรฉs y fondo sรณlido
|
|
186
|
+* `backgroundImage`: referencia a la imagen para el fondo
|
|
187
|
+* `mergedImage`: referencia a la imagen compuesta
|
|
188
|
+* `threshold`: valor umbral usado para comparar las distancias entre el valor del color del pรญxel de la imagen con el objeto sobre fondo sรณlido. En el cรณdigo que se provee, el valor del umbral se lee del valor de la barra deslizable.
|
|
189
|
+* `ghost`: valor Booleano utilizado para aplicar el filtro "fantasma" a los pixeles.
|
|
190
|
+* `(x, y)`: coordenadas de un pixel de la imagen del objeto sobre fondo sรณlido. El valor por defecto es `(0,0)`.
|
|
191
|
+* `(offset_x, offset_y)`: coordenadas de la imagen compuesta en donde la esquina superior izquierda de la imagen del objeto sobre fondo sรณlido serรก insertada. El valor por defecto es `(0,0)`.
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+###Ejercicio 1: Crear imagen compuesta
|
|
195
|
+
|
|
196
|
+####Instrucciones
|
|
197
|
+
|
|
198
|
+1. Carga a QtCreator el proyecto `GreenScreen` haciendo doble "click" en el archivo `GreenScreen.pro` en el directorio `Documents/eip/Arrays-GreenScreen` de tu computadora. Tambiรฉn puedes ir a `http://bitbucket.org/eip-uprrp/arrays-greenscreen` para descargar la carpeta `Arrays-GreenScreen` a tu computadora.
|
|
199
|
+
|
|
200
|
+2. Compila y corre el programa. El cรณdigo que te proveemos crea la interfaz de la Figura 5. Los botones *Select Image* y *Select Background Image* ya han sido programados.
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+ ---
|
|
204
|
+
|
|
205
|
+ ![figure6.png](images/figure6.png)
|
|
206
|
+
|
|
207
|
+ **Figura 5.** Interfaz de la aplicaciรณn GreenScreen.
|
|
208
|
+
|
|
209
|
+ ---
|
|
210
|
+
|
|
211
|
+3. Marca el botรณn para cargar una imagen del objeto de interรฉs sobre fondo sรณlido, luego marca el botรณn para seleccionar la imagen para el fondo. El directorio con los archivos fuente contiene una carpeta llamada `landscapes` que contiene imรกgenes de fondo, y una carpeta llamada `green_background` que contiene imรกgenes de objetos sobre fondo de color sรณlido.
|
|
212
|
+
|
|
213
|
+4. Tu primera tarea es completar la funciรณn `MergeImages` en el archivo `Filter.cpp`. La funciรณn `MergeImages` se invoca cuando el usuario marca el botรณn `Merge Images` y cuando se desliza la barra. La funciรณn `MergeImages` recibe las referencias a la imagen con objeto de interรฉs y fondo sรณlido, la imagen para el fondo y la imagen compuesta, un valor umbral, las coordenadas `(x,y)` de un pรญxel de la imagen del objeto sobre fondo sรณlido, y las coordenadas `(offset_x, offset_y)` de la imagen compuesta.
|
|
214
|
+
|
|
215
|
+Para este ejercicio puedes ignorar el filtro "fantasma" `ghost` y las coordenadas `(offset_x, offset_y)`, y solo componer la imagen con el objeto de interรฉs en la imagen de fondo, comenzando en la posiciรณn `(0,0)`.
|
|
216
|
+
|
|
217
|
+**Algoritmo**
|
|
218
|
+
|
|
219
|
+1. Adquiere el valor del color sรณlido. El color sรณlido serรก el color del pรญxel en la posiciรณn `(x,y)` en la imagen del objeto sobre fondo sรณlido. El valor por defecto para `(x,y)` es `(0,0)`.
|
|
220
|
+
|
|
221
|
+2. Para todas las posiciones `(i,j)`, adquiere el valor del color del pรญxel en la posiciรณn `(i,j)` de la imagen con el objeto. Computa la distancia entre el color de la imagen con el objeto y el valor del color sรณlido. Si la distancia entre el color sรณlido y el color del pรญxel de la imagen es mayor que que el valor umbral, cambia el valor del color del pรญxel en la posiciรณn `(i,j)` de la imagen de fondo al valor del color de la imagen con el objeto.
|
|
222
|
+
|
|
223
|
+Prueba tu implantaciรณn cargando imรกgenes de objetos e imรกgenes para el fondo y verificando la imagen compuesta.
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+###Ejercicio 2: Crear imagen compuesta usando filtro `ghost`
|
|
227
|
+
|
|
228
|
+En este ejercicio modificarรกs el Ejercicio 1 para aplicar el filtro fantasma a cada uno de los pรญxeles que se compondrรกn sobre la imagen de fondo en el caso de que la variable `ghost` sea cierta. El filtro fantasma crearรก el efecto de que el objeto en la imagen compuesta se verรก como un "fantasma" sobre la imagen de fondo, como en la Figura 6.
|
|
229
|
+
|
|
230
|
+---
|
|
231
|
+
|
|
232
|
+![figure7.png](images/figure7.png)
|
|
233
|
+
|
|
234
|
+**Figura 6.** Imagen con filtro fantasma. En este ejemplo, el perro en la imagen con el fondo sรณlido se compone sobre la imagen de fondo utilizando el filtro fantasma.
|
|
235
|
+
|
|
236
|
+---
|
|
237
|
+
|
|
238
|
+El efecto fantasma se consigue promediando el valor del color del pรญxel del fondo con el valor del color del pรญxel correspondiente del objeto, en lugar de solo reemplazar el valor del color del pรญxel del fondo por el del objeto. Calculamos el promedio de cada uno de los componentes (rojo, verde y azul)
|
|
239
|
+
|
|
240
|
+$$N_R=\frac{S_R+B_R}{2}$$
|
|
241
|
+$$N_G=\frac{S_G+B_G}{2}$$
|
|
242
|
+$$N_B=\frac{S_B+B_B}{2},$$
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+en donde $$N_R, N_G, N_B$$ son los componentes rojo, verde y azul del nuevo pรญxel fantasma, $$S_R, S_G, S_B$$ son los componentes de la imagen del objeto, y $$B_R, B_G, B_B$$ son los componentes de la imagen de fondo.
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+###Ejercicio 3: Crear imagen compuesta colocando el objeto en una posiciรณn especรญfica
|
|
249
|
+
|
|
250
|
+El "widget" que despliega el fondo fue programado para que detecte la posiciรณn marcada por el usuario. En este ejercicio programarรกs la funciรณn `MergeImages` para que el objeto sea desplegado en la posiciรณn marcada por el usuario en la imagen de fondo, en lugar de ser desplegado en la esquina superior izquierda. Las Figuras 7 y 8 muestran el efecto. Nota los valores de `Selected Coord` bajo la imagen del medio.
|
|
251
|
+
|
|
252
|
+---
|
|
253
|
+
|
|
254
|
+![figure8.png](images/figure8.png)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+**Figura 7.** En este ejemplo, la imagen del fondo no ha sido marcada y `Selected Coord` tiene `(0,0)` que es su valor por defecto. El perro se inserta en la imagen compuesta con su esquina superior izquierda en el lugar `(0,0)`.
|
|
258
|
+
|
|
259
|
+---
|
|
260
|
+
|
|
261
|
+![figure9.png](images/figure9.png)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+**Figura 8.** En este ejemplo, la imagen del fondo fue marcada en las coordenadas `(827,593)`. La imagen del perro se inserta en la imagen compuesta con su esquina superior izquierda en la posiciรณn `(827,593)`.
|
|
265
|
+
|
|
266
|
+---
|
|
267
|
+
|
|
268
|
+Tu tarea en este ejercicio es la misma que en el Ejercicio 1, pero esta vez debes ajustar la imagen del objeto dentro de la composiciรณn con las cantidades especificadas en los parรกmetros `x_offset` y `y_offset`. Recuerda tomar en consideraciรณn los lรญmites de la imagen compuesta cuando insertes el objeto; el usuario pudiera especificar unos parรกmetros que se salgan de los lรญmites y el objeto se cortarรก, como sucede en la Figura 9.
|
|
269
|
+
|
|
270
|
+---
|
|
271
|
+
|
|
272
|
+![figure10.png](images/figure10.png)
|
|
273
|
+
|
|
274
|
+**Figura 9.** En este ejemplo, el usuario seleccionรณ una posiciรณn que asignรณ valores muy grandes para `x_offset` y `y_offset`; la implementaciรณn hizo el ajuste para que parte de la imagen del perro saliera en la imagen compuesta.
|
|
275
|
+
|
|
276
|
+---
|
|
277
|
+
|
|
278
|
+El ejemplo de la Figura 10 muestra cรณmo se comportarรก la imagen del objeto al sobreponerla en la imagen que queremos de fondo. Las variables `offset_x, offset_y` representan el punto en la imagen de fondo en el que se colocarรก la esquina superior izquierda de la imagen del objeto. Nota que si se escoge un punto muy cerca del borde para la composiciรณn, parte de la imagen del objeto se sale de los lรญmites de la imagen de fondo. Como hemos visto en la manipulaciรณn de arreglos, si se intenta acceder o alterar elementos que estan fuera del rango de tamaรฑo del arreglo, al compilar occurre un error fatal. Lo mismo sucede con las imรกgenes.
|
|
279
|
+
|
|
280
|
+Debes asegurarte de que tu implementaciรณn toma en cuenta los valores de `offset x` y `offset y` para que la composiciรณn no intente acceder o alterar pรญxeles fuera del lรญmite de la imagen de fondo. Si intentas acceder o alterar pรญxeles fuera de esos lรญmites, resulta en un error fatal.
|
|
281
|
+
|
|
282
|
+---
|
|
283
|
+
|
|
284
|
+![figure11.png](images/figure11.png)
|
|
285
|
+
|
|
286
|
+**Figura 10.** Ilustraciรณn de la imagen del objeto de interรฉs con pรญxeles que se salen de los lรญmites de la imagen de fondo. Si no se toma en consideraciรณn esta posibilidad en la implementaciรณn, ocurrirรก un error fatal.
|
|
287
|
+
|
|
288
|
+---
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+Valida tu implantaciรณn seleccionando varios valores para el ajuste de "offset" y observando el efecto que tienen en la imagen compuesta. Asegรบrate de tratar casos en los que tus valores para `x_offset` y `y_offset` ocasionarรญan que la imagen fuera cortada como ocurriรณ en la imagen compuesta de la Figura 9.
|
|
292
|
+
|
|
293
|
+---
|
|
294
|
+
|
|
295
|
+---
|
|
296
|
+
|
|
297
|
+##Entrega
|
|
298
|
+
|
|
299
|
+Utiliza "Entrega" en Moodle para entregar el archivo `filter.cpp` que contiene la funciรณn `MergeImages`. Recuerda utilizar buenas prรกcticas de programaciรณn, incluir el nombre de los programadores y documentar tu programa.
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+---
|
|
303
|
+
|
|
304
|
+---
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+## Referencias
|
|
308
|
+
|
|
309
|
+[1] http://en.wikipedia.org/wiki/Green_screen_(disambiguation)
|
|
310
|
+
|
|
311
|
+[2] http://en.wikipedia.org/wiki/Chroma_key
|
|
312
|
+
|
|
313
|
+[3] http://doc.qt.io/qt-4.8/qimage.html.
|
|
314
|
+
|
|
315
|
+---
|
|
316
|
+
|
|
317
|
+---
|
|
318
|
+
|
|
319
|
+---
|
|
320
|
+
|
|
321
|
+[English](#markdown-header-arrays-green-screen) | [Espaรฑol](#markdown-header-arreglos-pantalla-verde)
|
|
322
|
+
|
|
323
|
+#Arrays - Green Screen
|
|
324
|
+
|
|
325
|
+![main1.png](images/main1.png)
|
|
326
|
+![main2.png](images/main2.png)
|
|
327
|
+![main3.png](images/main3.png)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+Arrays help us to store and work with groups of data of the same type. The data is stored in consecutive memory spaces which can be accessed by using the name of the array and indexes or subscripts that indicate the position where the data is stored. Repetition structures provide us a simple way of accessing the data within an array. In this laboratory experience, you will be using nested loops to process bi-dimensional arrays and implement the functionality of a green-screen.
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+##Objectives:
|
|
334
|
+
|
|
335
|
+1. Practice accessing and modifying elements in an array.
|
|
336
|
+
|
|
337
|
+2. Use nested loops to implement greens-screen techniques.
|
|
338
|
+
|
|
339
|
+3. Use arithmetic expressions and selection structures to transform pixel colors.
|
|
340
|
+
|
|
341
|
+4. Read pixels from an image and decompose them in their red, green and blue components.
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+##Pre-Lab:
|
|
345
|
+
|
|
346
|
+Before coming to the laboratory you should have:
|
|
347
|
+
|
|
348
|
+1. Reviewed the basic concepts about repetition structures, nested loops, and bi-dimensional arrays.
|
|
349
|
+
|
|
350
|
+2. Understood the methods of the `QImage` class for pixel manipulation.
|
|
351
|
+
|
|
352
|
+3. Studied the concepts and instructions for the laboratory session.
|
|
353
|
+
|
|
354
|
+4. Taken the Pre-Lab quiz that is found in Moodle.
|
|
355
|
+
|
|
356
|
+---
|
|
357
|
+
|
|
358
|
+---
|
|
359
|
+
|
|
360
|
+## Green-screen technology
|
|
361
|
+
|
|
362
|
+In this laboratory experience the student will be exposed to the basics of the green screen technology used in newscasting, motion pictures, video games, and others. Green screen compositing, or more generally chroma key compositing, is a technique for combining two still images or video frames[1]. Chroma key compositing, or chroma keying, is a special effects / post-production technique for compositing (layering) two images or video streams together based on color hues (range)[2]. Chroma keying can be done with backgrounds of any color that are uniform and distinct, but green and blue backgrounds are more commonly used because they differ most distinctly in hue from most human skin colors.
|
|
363
|
+
|
|
364
|
+With this laboratory we provide a simple GUI that allows the user to load an image with any solid background (although green or blue are preferred), and a background image. Your task is to implement a function that creates a third, merged image, in which the image with the solid background appears over the background image (with the solid background removed). Figure 1 shows an example of the expected results.
|
|
365
|
+
|
|
366
|
+---
|
|
367
|
+
|
|
368
|
+![figure1.png](images/figure1.png)
|
|
369
|
+
|
|
370
|
+Figure 1: Example of the expected results. The object of interest is the hand carrying the sunglasses.
|
|
371
|
+
|
|
372
|
+---
|
|
373
|
+
|
|
374
|
+For illustration purposes, let's call the image with the solid background *image A* and let's say that the solid color in the background has an RGB `0x00ff00` (pure green). We will refer to the image with the interesting background as *image B*. Let's also assume that both images are the same size (width and height).
|
|
375
|
+
|
|
376
|
+To produce the merged image (*image C*), we could start by completely copying *image B* to *image *C*. Then, to insert only the object of interest into the merged image we could traverse *image A* pixel by pixel. We would compare the color of each pixel *p* in *image A* to the color `0x00FF00`, if they are *similar* we do nothing (because it means that this pixel is part of the solid color background). If the color of *p* is not *similar* to `0x00FF00`, we modify the corresponding pixel in *image C*, copying the color of the object's pixel to the merged image.
|
|
377
|
+
|
|
378
|
+---
|
|
379
|
+
|
|
380
|
+![figure2.png](images/figure2.png)
|
|
381
|
+
|
|
382
|
+**Figure 2** - Illustration of how the algorithm decides which pixels to include from *image A* into *image C*.
|
|
383
|
+
|
|
384
|
+---
|
|
385
|
+
|
|
386
|
+---
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+###Pixels
|
|
390
|
+
|
|
391
|
+The smallest element in an image is called a *pixel*. This unit consists of a single color. Since each color is a combination of tones for the primary red, green and blue colors, it is coded as an unsigned integer whose bytes represent the tones of red, green and blue of the pixel (Figure 3). This combination is called the color's *RGB* which is an acronym for "Red-Green-Blue". For example, a pure red pixel has an RGB representation of `0x00ff0000`, while a white pixel has an RGB representation of `0x00FFFFFF` (since the color white is a combination of tones of red, green and blue in all of their intensity).
|
|
392
|
+
|
|
393
|
+---
|
|
394
|
+
|
|
395
|
+![figure3.png](images/figure3.png)
|
|
396
|
+
|
|
397
|
+**Figure 3.** Bit distribution for the tones of red, green and blue in an RGB representation. Each tone can have values between 0x00 (the eight bits in 0) and (0xFF (the 8 bits in 1).
|
|
398
|
+
|
|
399
|
+---
|
|
400
|
+
|
|
401
|
+`Qt` uses the `QRgb` type to represent `RGB` values. Using certain functions that are described below we can obtains the red, green and blue components of the `QRgb` value of the pixel and manipulate the images.
|
|
402
|
+
|
|
403
|
+###Library
|
|
404
|
+
|
|
405
|
+In today's laboratory experience you will use the `QImage` class. This class permits access to the data in the pixels of an image to manipulate it. The documentation for the `QImage` class can be found in http://doc.qt.io/qt-4.8/qimage.html.
|
|
406
|
+
|
|
407
|
+The code provided in this project contains the following objects of the `QImage` class:
|
|
408
|
+
|
|
409
|
+* `originalImage` // contains the information of the original image that you will edit
|
|
410
|
+* `editedImage` // will contain the edited image
|
|
411
|
+
|
|
412
|
+The objects of the `QImage` class have the following methods that will be useful for today's laboratory experience:
|
|
413
|
+
|
|
414
|
+* `width()` // returns the integer value for the image's width
|
|
415
|
+* `height()` // returns the integer value for the image's height
|
|
416
|
+* `pixel(i, j)` // returns the `QRgb` for the pixel in position `(i,j)`
|
|
417
|
+* `setPixel(i,j, pixel)` // modifies the value for the pixel in position `(i,j)` to the value of pixel `QRgb`
|
|
418
|
+
|
|
419
|
+The following functions are useful to work with data of type `QRgb`:
|
|
420
|
+
|
|
421
|
+* `qRed(pixel)` // returns the tone for the pixel's red color
|
|
422
|
+* `qGreen(pixel)` // returns the tone for the pixel's green color
|
|
423
|
+* `qBlue(pixel)` // returns the tone for the pixel's blue color
|
|
424
|
+* `qRgb(int red, int green, int blue)` // returns the `QRgb` pixel composed of the red, green and blue values received.
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+####Examples:
|
|
428
|
+
|
|
429
|
+1. `QRgb myRgb = qRgb(0xff, 0x00, 0xff);`: Assigns the value `0xff00ff` to `myRgb` which represents the color ![figure2.jpg](images/figure4.jpg)
|
|
430
|
+
|
|
431
|
+ Notice that the value `0xff00ff` represents the values `0xff`, `0x0`, and `0xff`, that correspond to the red, green and blue components in `myRgb`.
|
|
432
|
+
|
|
433
|
+2. If the following `4 x 4` image of pixels represents the object `originalImage`,
|
|
434
|
+
|
|
435
|
+ ![ejemplo.png](images/ejemplo.png)
|
|
436
|
+
|
|
437
|
+then `originalImage.pixel(2,1)` returns the `rgb` value that represents the color blue ( `0x0000ff`).
|
|
438
|
+
|
|
439
|
+3. The following instruction assigns the color red to the pixel in position `(2,3)` in the edited image:
|
|
440
|
+
|
|
441
|
+`editedImage.setPixel(2,3,qRgb(0xff,0x00,0x00));`.
|
|
442
|
+
|
|
443
|
+4. The following instruction assigns to `greenContent` the value of the green tone that is contained in the pixel `(1,1)` of `originalImage`:
|
|
444
|
+
|
|
445
|
+ `int greenContent = qGreen(originalImage.pixel(1,1));`.
|
|
446
|
+
|
|
447
|
+5. The following program creates an object of the `QImage` class and prints the red, green and blue components of the pixel in the center of the image. The image used is the one specified within the parenthesis during the creation of the object, that is, the file `chuck.png`
|
|
448
|
+
|
|
449
|
+---
|
|
450
|
+
|
|
451
|
+```cpp
|
|
452
|
+#include <QImage>
|
|
453
|
+#include <iostream>
|
|
454
|
+
|
|
455
|
+using namespace std;
|
|
456
|
+int main() {
|
|
457
|
+ QImage myImage(โ/Users/rarce/Downloads/chuck.pngโ);
|
|
458
|
+ QRgb centralPixel;
|
|
459
|
+
|
|
460
|
+ centralPixel = myImage.pixel(myImage.width() / 2, myImage.height() / 2);
|
|
461
|
+
|
|
462
|
+ cout << hex;
|
|
463
|
+
|
|
464
|
+ cout << โThe red, green and blue components of the middle pixel are: โ
|
|
465
|
+ << qRed(centralPixel) << โ, โ
|
|
466
|
+ << qGreen(centralPixel) << โ, โ
|
|
467
|
+ << qBlue(centralPixel) << endl;
|
|
468
|
+ return 0;
|
|
469
|
+}
|
|
470
|
+```
|
|
471
|
+
|
|
472
|
+---
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+### Measuring similarity of pixel colors
|
|
477
|
+
|
|
478
|
+Look at Figure 4, although the background in *image A* looks uniform, it really includes pixels of diverse (although similar) colors.
|
|
479
|
+
|
|
480
|
+---
|
|
481
|
+
|
|
482
|
+![figure5.png](images/figure5.png)
|
|
483
|
+
|
|
484
|
+**Figure 4** - What may seem as a *solid* color, really is not. Thus, we use the color *distance*.
|
|
485
|
+
|
|
486
|
+---
|
|
487
|
+
|
|
488
|
+Instead of only considering as part of the solid background the pixels whose color is **exactly** `0x00FF00`, we measure a color's *distance* from the *pure* color. A small *distance* means that the color is *almost* a pure green. A large *distance* means that the color is very different from green. The equation for *distance* is:
|
|
489
|
+
|
|
490
|
+$$distance = \sqrt{(P_R-S_R)^2+(P_G-S_G)^2+(P_B-S_B)^2},$$
|
|
491
|
+
|
|
492
|
+where $$P_R$$, $$P_G$$, and $$P_B$$ are the red, green and blue components of the pixel being considered. $$S_R$$, $$S_G$$, and $$S_B$$ are the components of the solid background, e.g. in our example $$S_R=S_B=0$$ y $$S_G=255$$.
|
|
493
|
+
|
|
494
|
+---
|
|
495
|
+
|
|
496
|
+---
|
|
497
|
+
|
|
498
|
+##Laboratory Session
|
|
499
|
+
|
|
500
|
+In this laboratory experience, starting with an image with an object of interest over a solid color background and an image to use as a background, you will define and implement a function that creates a third merged image where the image with the object of interest will have its background color removed and will appear over the image chosen to be the background.
|
|
501
|
+
|
|
502
|
+You will be working with the `Filter.cpp` file. The following is a review of the variables in this file:
|
|
503
|
+
|
|
504
|
+* objectImage: reference to the object image with the solid background
|
|
505
|
+* backgroundImage: reference to the background image object
|
|
506
|
+* mergedImage: reference to the merged image
|
|
507
|
+* threshold: is a theshold value used to compare the distances between the object pixel and the solid background pixel. In the provided code, the threshold value is read from the slideBar.
|
|
508
|
+* ghost: is a boolean value used to apply ghost filter to pixels.
|
|
509
|
+* (x, y): contains the coordinate of the pixel whose color will be used as solid background. The default value is (0,0).
|
|
510
|
+* (offset_x, offset_y): the coordinate of the merged image where the upper-left corner of the objectImage should be inserted. The default value is (0,0).
|
|
511
|
+
|
|
512
|
+### Exercise 1: Create a composite image
|
|
513
|
+
|
|
514
|
+####Instructions
|
|
515
|
+
|
|
516
|
+1. Load the Qt project called `GreenScreenLab` by double-clicking on the `GreenScreenLab.pro` file in the `Documents/eip/Arrays-GreenScreen` folder of your computer. You may also go to `http://bitbucket.org/eip-uprrp/arrays-greenscreen` to download the `Arrays-GreenScreen` folder to your computer.
|
|
517
|
+
|
|
518
|
+2. Build and run the program. The provided code creates the interface shown in Figure 5. The buttons *Select Image* and *Select Background Image* have already been programmed to perform their actions.
|
|
519
|
+
|
|
520
|
+ ---
|
|
521
|
+
|
|
522
|
+ ![figure6.png](images/figure6.png)
|
|
523
|
+
|
|
524
|
+ **Figure 5.**Interface for the green screen application.
|
|
525
|
+
|
|
526
|
+ ---
|
|
527
|
+
|
|
528
|
+3. Click the *Select Image* button to load the image that contains the solid background, the click *Select Background Image* to load the image that contains the interesting background. The folders called `green_background` and `landscapes` contain some images that are suitable as the first and second images.
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+4. Your first task is to complete the function `MergeImages` in file `Filter.cpp`.`MergeImages` is the function that is called when the user presses the button captioned `Merge Images` or when he slides the slide bar. The function `MergeImages` receives the image with the solid background, the background image, a reference to the merged image, a threshold value, and the coordinates `(x,y)` of the pixel from which we will extract the sample *green* background color, and the coordinates `(offset_x, offset_y)` from the merged image.
|
|
532
|
+
|
|
533
|
+For this first exercise you can ignore the following parameters: ghost, x_offset, y_offset. Your implementation should place the `objectImage` into the `mergedImage` starting at position (0,0).
|
|
534
|
+
|
|
535
|
+**The algorithm**
|
|
536
|
+
|
|
537
|
+1. Acquire the value of the solid color. The solid color will be the color of the pixel in the coordinate `(x,y)` of the object image with the solid background. The default value for `(x,y)` is `(0,0)`.
|
|
538
|
+
|
|
539
|
+2. For every position `(i,j)`, read the color of the corresponding pixel in the objectImage. Compute the distance of the pixel colors to the solid color. If the distance between the solid color and the color of the pixel of the image is greater than the threshold, set the corresponding `(i,j)` pixel in the merged image to the objectImage pixel color.
|
|
540
|
+
|
|
541
|
+Test your implementation by loading object and background images and verifying the merged image.
|
|
542
|
+
|
|
543
|
+## Exercise 2: Creating a composite image using a ghost filter
|
|
544
|
+
|
|
545
|
+In this exercise you will modify Exercise 1 to apply a ghost filter to each of the pixels that will be composed over the background image (if the `ghost` variable is true). The filter creates a ghost like effect on the objects composed over the background image, as in Figure 6.
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+---
|
|
549
|
+
|
|
550
|
+![figure7.png](images/figure7.png)
|
|
551
|
+
|
|
552
|
+**Figure 6** - In this example, the dog in the image with the solid background is composed in the background image with the ghost filter.
|
|
553
|
+
|
|
554
|
+---
|
|
555
|
+
|
|
556
|
+The ghost effect is achieved by *averaging* the background color with the object's color (instead of simply *replacing* the background with the object's color). The average is performed for each of the components (red, green and blue).
|
|
557
|
+
|
|
558
|
+$$N_R=\frac{S_R+B_R}{2}$$
|
|
559
|
+$$N_G=\frac{S_G+B_G}{2}$$
|
|
560
|
+$$N_B=\frac{S_B+B_B}{2},$$
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+where $$N_R$$, $$N_G$$, and $$N_B$$ are the red, green and blue components of the new ghost pixel. $$S_R$$, $$S_G$$, and $$S_B$$ are the components of the object image. $$B_R$$, $$B_G$$, $$B_B$$ are the components of the background image.
|
|
564
|
+
|
|
565
|
+## Exercise 3: Create a composite image placing the object in a specified position
|
|
566
|
+
|
|
567
|
+The widget that displays the background has been programmed to register the position where the user clicks. In this exercise you will program the `MergeImages` function so that the position that user clicks in the background image is used as the *top left* corner where the *object* image will be displayed in the merged image. The following figures illustrates the effect. Note the *Selected Coord* values under the images.
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+---
|
|
571
|
+
|
|
572
|
+![figure8.png](images/figure8.png)
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+**Figure 7.** In this example, the background image has not been clicked. Thus the "Selected Coord" is at its default value of (0,0). The dog image is inserted with its top-left corner at (0,0) in the merged image.
|
|
576
|
+
|
|
577
|
+---
|
|
578
|
+
|
|
579
|
+![figure9.png](images/figure9.png)
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+**Figure 8.** In this example, the background image has been clicked at coordinate `(827,593)`. The dog image is inserted with its top-left corner at `(827,593)` in the merged image.
|
|
583
|
+
|
|
584
|
+---
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+In this exercise your task will be the same as in Exercise 1, but this time you will need to offset the *object* image inside the *merged* image by the amount specified in the `x_offset` and `y_offset` parameters. Please take into consideration the merged image boundaries when you are inserting the object image. The user may specify an offset where the boundaries are exceeded and the object will be cut, as in Figure 9.
|
|
588
|
+
|
|
589
|
+---
|
|
590
|
+
|
|
591
|
+![figure10.png](images/figure10.png)
|
|
592
|
+
|
|
593
|
+**Figure 9**. In this example, the user selected a position that assigned values that are too large for `x_offset` and `y_offset`; the implementation made the adjustment so part of the dog appeared in the merged image.
|
|
594
|
+
|
|
595
|
+---
|
|
596
|
+
|
|
597
|
+The example in Figure 10 shows how the object image will behave when merging it with the background image. The `x_offset` and `y_offset` variables represent the point in the background image where the upper left corner of the object image will be placed. Notice that if a point too close to the image border is chosen, part of the object image will be outside of the limits of the background image. As we have seen when manipulating arrays, if one tries to access or alter elements that are outside of the size range of the array, we get a fatal compilation error. The same thing happens with the images.
|
|
598
|
+
|
|
599
|
+You should make sure that your implementation takes into account the `x_offset` and `y_offset` values so the composition does not try to access or alter pixels outside of the limits of the background image. If you try to access or alter pixels outside of these limits, it will result in a fatal error.
|
|
600
|
+
|
|
601
|
+---
|
|
602
|
+
|
|
603
|
+![figure11.png](images/figure11.png)
|
|
604
|
+
|
|
605
|
+**Figure 10.** Illustration of the object image with pixels that are outside of the background image limits. If the possibility of this happening is not taken into account in the implementation, there will be a fatal error.
|
|
606
|
+
|
|
607
|
+---
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+Validate your implementation by choosing several offsets and observing the merged image. Be sure to try cases in which you choose x and y offsets that result in the object being cropped in the merged image (as in Figure 9).
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+---
|
|
614
|
+
|
|
615
|
+---
|
|
616
|
+
|
|
617
|
+### Deliverables
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+Use "Deliverables" in Moodle to upload the `filter.cpp` file that contains the `MergeImages` function. Remember to use good programming techniques, include the names of the programmers involved, and to document your program.
|
|
621
|
+
|
|
622
|
+---
|
|
623
|
+
|
|
624
|
+---
|
|
625
|
+
|
|
626
|
+### References
|
|
627
|
+
|
|
628
|
+[1] http://en.wikipedia.org/wiki/Green_screen_(disambiguation)
|
|
629
|
+
|
|
630
|
+[2] http://en.wikipedia.org/wiki/Chroma_key
|
|
631
|
+
|
|
632
|
+[3] http://doc.qt.io/qt-4.8/qimage.html.
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
|