En el artículo anterior se veía cómo detectar tumores en imágenes obtenidas mediante resonancia magnética, lo que no es más que un problema de detección de objetos o «segmentación» de imágenes. Sin embargo, el primer paso a tener en cuenta antes de utilizar cualquiera de los métodos existentes para tal fin, es identificar el tipo de software del que se debe disponer y, evidentemente, conocer el funcionamiento del mismo.
Si queremos trabajar con imágenes bidimensionales e implementar los algoritmos que lleven a cabo su segmentación, podemos utilizar software matemático. Unas de las opciones más populares son: (i) Matlab, un software de pago, que posee un lenguaje de programación propio: M. Está disponible para las plataformas Unix, Windows, Mac OS X y GNU/Linux y (ii) GNU Octave, un software gratuito, considerado el equivalente libre de Matlab. Disponible para GNU/Linux, Mac, BSD, y Windows. La sintaxis es casi idéntica a la de Matlab, y reconoce los ficheros .m escritos por dicho programa.
Ambos tienen sus ventajas y desventajas. Por una parte, Matlab cuenta con la desventaja de ser un software de pago, sin embargo, cuenta con numerosas funciones en la que se encuentran ya implementados diferentes algoritmos y que están agrupadas por diferentes ramas de las ciencias y la ingeniería. Cada uno de esos grupos de funciones recibe el nombre de «librería» o «toolbox». Esto resulta altamente ventajoso, ya que hace innecesario que tengamos que programar las funciones más básicas dentro del campo en el que se esté trabajando; basta con llamar a la función en cuestión dentro de nuestro código. Por ejemplo, en este caso que estamos trabajando con imágenes, usaremos la «toolbox» de «Image Processing Toolbox», y ahí ya tenemos una función que transforma una imagen en color a blanco y negro, otra que nos permite redimensionar imágenes, otra que obtiene el ancho y el alto de la imagen… es decir, las operaciones más básicas cuando estamos dentro del campo del procesamiento de la señal, como indica el nombre de la «toolbox» utilizada.
Por otra parte, Octave es software libre y, por tanto, gratuito. La desventaja es que muchas de las funciones que ya vienen implementadas en Matlab no están en Octave, lo que hace que, al ejecutar un programa creado en Matlab en el que se hagan llamadas a funciones propias de él, se encontrará un error al no estar disponibles en este software lo que supondrá tener que programar más líneas de código.
En el caso de la segmentación resulta muy ventajoso Matlab porque existen varias «toolboxes» dedicadas al procesamiento de imágenes y visión artificial, como por ejemplo: «Image Processing Toolbox», «Computer Vision System Toolbox», «Vision HDL Toolbox», «Image Acquisition Toolbox», «Mapping Toolbox»; dentro de las dos primeras -especialmente- hay infinidad de funciones útiles para llevar a cabo esta técnica, e incluso hay implementados algunos de los métodos de segmentación más conocidos, como el método de Otsu del que se habló en el artículo anterior.
Antes de ver una forma sencilla de llevar a cabo la segmentación con el método de Otsu, se debe entender cómo trabajan estos programas con las imágenes. Cualquier imagen, ya sea obtenida a través de Internet, de un teléfono móvil, de una cámara fotográfica o de una resonancia magnética, está compuesta por una gran cantidad de «cuadraditos» (también pueden ser rectangos) muy pequeños. Cada uno de estos elementos, que son la unidad elemental de la imagen, recibe el nombre de «píxel». Una forma sencilla de observar los píxeles de una imagen es haciendo zoom sobre ella (imagen 2):
Cada píxel se muestra con un color determinado, es decir, contiene un valor de intensidad concreto. En general, existe una importante variación de color entre píxeles, puesto que cada objeto que hay en la imagen suele ser de un color diferente. Los puntos donde la variación de intensidad (la diferencia de color) es mayor, pertenecen a lo que denominamos «bordes de los objetos».
A día de hoy, los tipos de imágenes más comunes son las que están en escala de grises o las que utilizan el sistema de color RGB (Red, Green, Blue). En los primeros, cada píxel contiene un nivel de gris representado por un valor comprendido entre 0 y 255 (imagen 3), mientras que, en las imágenes RGB, los píxeles pueden mostrar cualquier color y su intensidad viene dada como una combinación de rojo, verde y azul (imagen 4), lo que hace que las combinaciones posibles de color sean infinitas ya que hay 256 valores de rojo, 256 valores de verde y otros tantos de azul.
Dicho esto, se puede entender una imagen en escalas de grises como una pared de ladrillos (imagen 2b), donde cada ladrillo («píxel») tiene un valor de intensidad asignado. Esta forma de ordenar los datos en filas y columnas como si fuese una pared de datos, pudiendo realizar sumas y multiplicaciones con ellos, recibe el nombre de «matriz». Cada píxel se corresponde con un elemento de la matriz.
Sin embargo, en el caso de una imagen en RGB tendremos tres matrices una detrás de otra. Como en una imagen en color cada píxel contiene una combinación de rojo, verde y azul, en la primera matriz aparecerá un valor comprendido entre 0 y 255 en función del porcentaje de rojo que contenga cada píxel, en la segunda en función del porcentaje de verde y en la tercera del de azul.
Cuando, en lugar de trabajar con una fotografía, se está trabajando con un modelo 3D, cada unidad elemental recibe el nombre de «voxel» en vez de «píxel», y en vez de ser un cuadrado en un cubo.
A continuación, se detallará un ejemplo de segmentación de una imagen en Matlab. Una vez que se tienen identificadas las imágenes con las que se va a trabajar, debemos asegurarnos de que han sido guardadas en alguno de los formatos permitidos por el programa que vayamos a utilizar. En Matlab por ejemplo, esto no supone mayor problema puesto que soporta todos estos formatos: .bmp, .gif, .hdf, .jpeg, .jpg, .jp2, .jpf, .jpx, .j2c, .j2k, .pbm, .pcx, .pgm, .png, .pnm, .ppm, .ras, .tiff, .tif, .xwd, .cur, .ico.
El primer paso, será «leer» la imagen, es decir, introducir la información procedente de la imagen en el software. Algo similar a seleccionar la imagen con la que queremos trabajar.
La forma de hacer esto es con el comando imread (tanto en Matlab como en Octave, ya que este último cuenta también con una librería de procesamiento de imágenes). Supongamos que tenemos la imagen de una flor, y que tiene por nombre “flor.png”:
imagen = imread(‘flor.png’);
de esta forma, y de acuerdo con lo explicado anteriormente, si I es una imagen es escala de grises tendrá dimensiones MxN, siendo M el número de filas de píxeles que componen la imagen y N en número de columnas. Mientras que si es una imagen en color (RGB) será de dimensiones MxNx3, el 3 corresponde a los colores R,G y B.
Si lo que queremos hacer es una segmentación básica, podemos utilizar uno de los métodos más antiguos que es el de Otsu. Por fortuna, al ser muy utilizado desde hace muchos años, se encuentra implementado en las dos plataformas, bajo el comando graythresh:
umbral = graythresh(imagen);
con este comando obtenemos de forma «automática» un umbral global que se corresponde con un valor de intensidad dentro del rango [0, 1]. Todos los píxeles de la imagen que tengan un valor mayor que ese umbral serán coloreados en blanco y los que tengan una intensidad inferior en negro. Para realizar esta conversión de imagen RGB a imagen binaria, utilizamos el comando im2bw:
imagenBW = im2bw(imagen,umbral);
Por tanto, imagenBW se corresponde con una versión en blanco y negro de la imagen original. Aumentando o disminuyendo el valor de «umbral», podremos añadir o quitar detalles a esta versión imagenBW.
Por último, la forma de mostrar por pantalla una imagen es con el comando imshow:
imshow(imagenBW)
que nos ofrece un resultado similar a (imagen 5B).
De esta forma, con tan sólo 4 líneas de código hemos realizado una segmentación de la imagen original, es decir, se han distinguido dos objetos dentro de una misma imagen. En el ejemplo, los píxeles blancos corresponden a la flor, y los píxeles negros al fondo -aproximadamente-. Como se ha explicado anteriormente, el resultado puede refinarse cambiando el valor del umbral. Además se debe tener en cuenta que este método fue creado en 1979, y desde entonces ya han sido desarrollados otros métodos para llevar a cabo la segmentación de una forma más precisa, e incluso en color.
Evidentemente, no siempre se tendrá la suerte de que el método a utilizar -como en este caso el método de umbralización de Otsu-, esté implementado en el software. Entonces habrá que crear el código, aunque con la ayuda de las librerías existentes resultará más fácil y rápido, y evitaremos la programación de grandes partes de código.
Bibliografía: Annadurai S.: “Fundamentals of digital image processing”. Pearson Education India (2007). Chapman S.J.: “MATLAB programming for engineers”. Cengage Learning (2007). Dougherty E. R.: “Digital image processing methods”. Marcel Dekker, Inc. (1994). Gomes J., Velho, L.: “Image processing for computer graphics”. Springer Science & Business Media (2013). Petrou M., Petrou C.: “Image processing: the fundamentals”. John Wiley & Sons (2010). Rodríguez M. G.: “Introducción rápida a Matlab y Simulink para ciencia e ingeniería”. Ediciones Díaz de Santos (2003).