5.9. Operaciones aritméticas¶
La familia de dibujo de la sección anterior pinta dentro de una imagen. La familia aritmética combina dos imágenes en una tercera – sumando sus valores de píxeles, restando uno del otro, tomando el mínimo o el máximo en cada posición. Ese pequeño conjunto de operaciones aritméticas píxel a píxel es la base sobre la que se construyen la diferenciación de fotogramas, la sustracción de fondo, el apilamiento de exposiciones y un puñado de otros patrones clásicos.
La familia aritmética en la clase Image es lo bastante pequeña como para enumerarla de una vez:
add()– por píxelself + other, recortado al máximo del formato.sub()– por píxelself - other, recortado a0por abajo.rsub()– por píxelother - self, recortado a0(la misma aritmética quesubcon los operandos invertidos).min()– mínimo por píxel de los dos valores.max()– máximo por píxel.difference()– por píxel|self - other|, la diferencia absoluta.
Además de dos operaciones relacionadas de una sola imagen:
invert()– reemplaza cada píxel por255 - pixel(o el máximo equivalente para el formato).
Dos degradados de origen A y B, y el resultado de cada operación por pares aplicada a ellos. Cada operación se ejecuta posición por posición – lo que se muestra en el resultado en cualquier ubicación depende únicamente de los dos píxeles de origen en esa ubicación.¶
5.9.1. Dos formas de operando¶
Cada uno de los métodos de dos imágenes acepta cualquiera de las dos formas para su segundo operando:
Otra
Imagede las mismas dimensiones. La aritmética se ejecuta posición por posición – el resultado en(x, y)es la operación aplicada a los píxeles de origen en(x, y)de ambas imágenes.Un valor escalar – un entero para escala de grises, una tupla
(r, g, b)para RGB565. El mismo escalar se aplica en todas las posiciones.
La forma escalar es útil cuando la aplicación quiere desplazar cada píxel en una cantidad constante. img.add(40) aclara toda la imagen en 40; img.sub((20, 20, 20)) oscurece cada píxel en 20 por canal; img.max(50) eleva cualquier píxel por debajo de 50 hasta 50 y deja el resto intacto – el tipo de operación que convierte un fondo de sensor casi negro en un gris oscuro plano para que las etapas posteriores trabajen sobre él.
5.9.2. Recorte¶
Los valores de los píxeles permanecen dentro del rango del formato a lo largo de cada operación. Para un canal de 8 bits eso significa 0 – 255: cualquier cosa que se hubiera desbordado por encima de 255 se recorta de nuevo a 255, y cualquier cosa que hubiera caído por debajo de 0 se recorta hasta 0. No hay envolvente.
Esa elección importa en la práctica. add al aclarar píxeles nunca produce un artefacto de oscurecimiento repentino en el extremo brillante donde de otro modo la operación se desbordaría; sub al oscurecer píxeles nunca produce un artefacto de aclaramiento repentino en el extremo oscuro donde de otro modo se produciría un desbordamiento por defecto. Los resultados siguen siendo visualmente significativos a costa de cierta pérdida de información en los extremos saturados.
El recorte es también la razón por la que sub y rsub devuelven resultados diferentes entre sí. img_a.sub(img_b) da la parte de a que es más brillante que b y cero en todas las demás partes; img_a.rsub(img_b) da la parte de b que es más brillante que a. Cualquiera de las dos es útil para la detección de cambios unilateral – si a la aplicación solo le importan los píxeles que se volvieron más brillantes, o solo los que se volvieron más oscuros – pero ninguna captura todo el cambio entre dos fotogramas.
5.9.3. La operación de diferencia¶
Para la detección de cambios bilateral, la operación a la que recurrir es difference(), que calcula |self - other| en cada posición – la diferencia absoluta, sin signo. Cada píxel que cambió en cualquier dirección aparece como un valor distinto de cero en el resultado, con la magnitud proporcional a cuánto cambió en esa posición.
Esa propiedad – distinta de cero exactamente donde las dos imágenes difieren – es lo que convierte a difference en el caballo de batalla de la detección de cambios fotograma a fotograma. Un fotograma de referencia almacenado al inicio y una captura nueva, pasados por difference, producen una imagen cuyos píxeles distintos de cero marcan cada posición donde algo en la escena se movió o cambió de brillo.
5.9.4. Acotar con mask¶
Todos los métodos aritméticos aceptan el argumento de palabra clave mask introducido en la página de regiones y máscaras. Cuando se pasa una máscara, la operación se ejecuta solo en las posiciones donde la máscara es distinta de cero; en todas las demás partes la imagen de destino se deja intacta.
Esa composición aparece en dos patrones. El primero es limitar una operación a un área conocida: sumar dos fotogramas únicamente dentro del cuadro delimitador de un marcador detectado, por ejemplo. El segundo es construir un fotograma compuesto pieza por pieza – min sobre una secuencia de fotogramas dentro de una máscara de primer plano, max sobre la misma secuencia dentro de la máscara complementaria – ese tipo de patrón.
5.9.5. En el sitio, y preservando las entradas¶
Todos los métodos aritméticos siguen la convención de funcionamiento establecida anteriormente: cada uno modifica la imagen de origen en el sitio y devuelve la misma imagen para encadenar. Los píxeles del origen desaparecen tras la llamada – reemplazados por el resultado de la operación contra lo que se pasara como segundo operando.
Cuando la aplicación necesita preservar ambas entradas, el patrón seguro es copiar una de ellas primero:
diff = current.copy() # leaves current intact
diff.difference(reference) # diff now holds the absolute difference
Ese patrón – copiar y luego operar – es la columna vertebral de cualquier canalización de diferenciación de fotogramas, donde el fotograma de referencia tiene que sobrevivir a la comparación para poder reutilizarse en el siguiente fotograma capturado.
Con seis operaciones de combinación, dos operaciones de una sola imagen, un caballo de batalla de diferencia absoluta y la palabra clave mask para acotar, el conjunto de herramientas de aritmética de píxeles cubre las combinaciones de brillo y canal que necesita la visión artificial clásica. Las herramientas restantes de tipo aritmético en la superficie trabajan bit a bit en lugar de valor a valor.