A. Configurar EmguCV en VS2010 (o un frame en caso de vídeo), pudiendo indicarse el tipo de imagen...

15
Visión Artificial con OpenCV: Un Enfoque Práctico Sesión Práctica 1: Instalación y Configuración del entorno; tratamiento de imágenes A. Configurar EmguCV en VS2010 Nota: Compruebe que posee instalada la extensión de C#. En caso contrario, introduzca el DVD de Visual Studio 2010, seleccione la opción de “Agregar o quitar componentes” y seleccione la extensión de C#. Configurar Visual Studio 2010 para poder trabajar con la librería EmguCV se reduce a hacer uso de una serie de inclusiones de librerías y referencias específicas de ella. Para llevar a cabo este proceso, seguiremos los siguientes pasos: 1. Acceda a la web de EmguCV (http://www.emgu.com/wiki/index.php/Main_Page) 2. En la sección “Latest News” aparecerá un listado de las últimas versiones con sus enlaces correspondientes. Sobre cualquiera de ellas, cliqueamos en el enlace representado por la palabra “sourceforge”.

Transcript of A. Configurar EmguCV en VS2010 (o un frame en caso de vídeo), pudiendo indicarse el tipo de imagen...

Visión Artificial con OpenCV: Un Enfoque Práctico Sesión Práctica 1: Instalación y Configuración del entorno;

tratamiento de imágenes

A. Configurar EmguCV en VS2010

Nota: Compruebe que posee instalada la extensión de C#. En caso contrario, introduzca el

DVD de Visual Studio 2010, seleccione la opción de “Agregar o quitar componentes” y

seleccione la extensión de C#.

Configurar Visual Studio 2010 para poder trabajar con la librería EmguCV se reduce a hacer

uso de una serie de inclusiones de librerías y referencias específicas de ella.

Para llevar a cabo este proceso, seguiremos los siguientes pasos:

1. Acceda a la web de EmguCV (http://www.emgu.com/wiki/index.php/Main_Page)

2. En la sección “Latest News” aparecerá un listado de las últimas versiones con sus

enlaces correspondientes. Sobre cualquiera de ellas, cliqueamos en el enlace

representado por la palabra “sourceforge”.

3. Accedemos al enlace indicado en la siguiente sección.

4. En la página de SourceForge nos aparecerá para descargar la última versión de la

librería. Debido a su continua actualización, la última versión suele presentar

numerosos bugs. Por ello nos descargaremos una versión testeada y en

funcionamiento desde hace varios años (para los objetivos del presente curso no se

necesitará mas). La versión a descargar es la 2.2.

5. Para ello, accedemos a la pestaña “Files”.

6. Dentro de la carpeta “emgucv” aparecerá un listado de todas las versiones hasta la

fecha. Nos introducimos en la carpeta de la versión “2.2.0.0” y encontraremos lo

siguiente:

7. Debido a varios errores (algunos sin explicación por parte de los desarrolladores de la

librería) para el caso de la versión de 64 bits, haremos uso de la versión de 32 bits. Esto

no restringe que el equipo deba ser de 32 bits para su funcionamiento, solo restringe

el tipo de proyecto a crear desde el Visual Studio.

8. Una vez descargado el archiv, lo descomprimiremos en una ruta conocida y a elección

nuestra. Por simplicidad se ha escogido la ruta C:\Emgu. Tras esto, se puede pasar a

configurar el proyecto de Visual Studio.

9. Arrancamos el Visual Studio 2010 y creamos un proyecto nuevo de Windows Forms.

10. En primer lugar, añadiremos las referencias necesarias del wrapper. Para ello,

presionamos con el click derecho sobre la carpeta “References” o, sobre el nombre del

proyecto, click derecho a “Agregar referencia”. Dentro de la pestaña “Examinar”

navegamos hasta la ruta donde se instaló EmguCV. En ella, dentro de la carpeta “bin”,

seleccionamos las siguientes librerías dinámicas: “Emgu.CV.dll”, “Emgu.CV.UI.dll” y

“Emgu.Util.dll”. Tras ello, le damos a aceptar.

11. En segundo lugar, tendremos que añadir las

referencias pertenecientes a la librería OpenCV

nativa. Al no encontrarse en el lenguaje referencia

del proyecto (C#), sino en C++, no se podrán añadir

de igual forma. Para ello, tendremos que

introducirlas directamente a nuestro proyecto

como archivos externos (al igual que cualquier

elemento adicional). Hacemos click con el botón

derecho sobre el nombre del proyecto y accedemos

a la opción “Agregar” ”Elemento existente”.

Tras ello, navegamos hasta la carpeta de instalación

de la librería y, dentro de la subcarpeta “bin”,

seleccionamos todas las dlls relacionadas con

openCV. Estas son: “cvextern.dll”,

“opencv_calib3d220.dll”, “opencv_contrib220.dll”,

“opencv_core220.dll”, “opencv_deatures2d220.dll”,

“opencv_ffmpeg220.dll”, “opencv_flann220.dll”,

“opencv_gpu220.dll”, “opencv_highgui220.dll”,

“opencv_imgproc220.dll”, “opencv_legacy220.dll”,

“opencv_ml220.dll”, “opencv_objdetect220.dll”,

“opencv_video220.dll” y “ZedGraph.dll”. Quedando

finalmente algo similar a lo mostrado a la derecha.

12. Como podemos recordar, estamos haciendo uso de la versión de 32 bits de la librería.

Por ello, para que funcione correctamente, debemos especificar a nuestro proyecto

que genere la solución para un dispositivo x86. Hay que indicarlo en dos lugares

diferentes:

a. Botón secundario sobre el archivo de la solución (el de más arriba)

Propiedades. Propiedades de Configuración Plataforma x86.

b. Botón secundario sobre el proyecto (justo debajo de la solución)

Propiedades. Generar Destino de la Plataforma x86.

13. Como programa de ejemplo, crearemos una ventana que muestre una imagen de

fondo negro y con un texto en el centro.

14. Hacemos doble click en el archivo “Form1.cs” y nos aparecerá el editor gráfico del

formulario en cuestión. Haremos uso de un elemento de tipo “PictureBox”, de forma

que lo arrastraremos al formulario. De entre sus propiedades, le daremos un tamaño

de 400x400 píxeles, quedando algo similar a:

15. En el código del formulario (sobre “Form1.cs”, click derechoVer código), crearemos

dos variables de tipos propios de EmguCV:

- Image<tipo, profundidad>: almacén básico que contiene la información de una

imagen (o un frame en caso de vídeo), pudiendo indicarse el tipo de imagen y la

profundidad del color al crearla.

- MCvFont: tipo de fuente; utilizada para especificar las características de la fuente a

dibujar.

La imagen a crear será a color RGB de un byte por componente. Además, la crearemos

del mismo tamaño que el recipiente utilizado en el formulario para presentarla

(400x400) y le indicaremos que inicialmente todos sus píxeles serán negros: Image<Bgr, Byte> im = new Image<Bgr, Byte>(400, 400, new Bgr(0, 0, 0));

A la fuente le especificaremos el tipo y las escalas (tanto horizontal como vertical): MCvFont f = new MCvFont(FONT.CV_FONT_HERSHEY_TRIPLEX, 1, 1);

16. Para que reconozcan los tipos específicos de esta librería, hay que añadir en la parte

superior del fichero las referencias que se están utilizando: using Emgu.CV;

using Emgu.Util;

using Emgu.CV.Structure;

using Emgu.CV.CvEnum;

17. Se puede apreciar que, aparte de los atributos que acabamos de añadir a la clase, solo

se encuentra visible el constructor, cuyo único contenido es una llamada a la función

InitializeComponent(). Tras dicha llamada, dibujaremos un determinado texto a

nuestra imagen para, posteriormente, mostrarla en el pictureBox creado.

18. El método “Draw” perteneciente a la clase “Image” se encuentra sobrecargado.

Haremos uso de la opción que nos permite dibujar una cadena de texto en la imagen.

Le indicaremos al método el texto a dibujar, la fuente a utilizar (nótese que se indica

con la palabra “ref” delante, para denotar que se le pasa una referencia o un puntero),

el lugar donde dibujar (como un punto con coordenadas x e y) y, por último, el color

con el que se pintará (en nuestro caso, verde). im.Draw("EMGUcv", ref f, new System.Drawing.Point(140, 200), new Bgr(0, 255, 0));

19. Por ultimo, se mostrará el contenido de nuestra imagen sobre el pictureBox creado.

Para ello, el atributo “Image” del pictureBox se modifica con el contenido de nuestra

imagen. Como el pictureBox solo admite bitmaps, hacemos uso del método interno a

la clase “Image” que nos la convierte a bitmaps. Quedaría: pictureBox1.Image = im.ToBitmap();

20. Finalmente, quedaría lo siguiente:

21. Puede compilar y ejecutar el proyecto para comprobar que funciona correctamente.

B. Plantilla de proyecto de EmguCV

Partiremos del proyecto que se ha creado como ejemplo, de forma que crearemos un

template a partir de dicho proyecto y lo instalaremos entre las plantillas predeterminadas de

Visual Studio.

Así, se podrá partir del programa creado de ejemplo, sin necesidad de realizar todos los

pasos indicados anteriormente. Los pasos a seguir son los siguientes:

1. Con el proyecto abierto, seleccionamos la opción “Archivo” ”Exportar plantilla”. En

el asistente, seleccionaremos la opción “Plantilla de proyecto”.

2. A continuación, introducimos la información del proyecto. Excepto el nombre, las

demás opciones son opcionales.

3. IMPORTANTE desmarcar la opción “Importar la plantilla automáticamente en Visual

Studio”.

4. Finalizamos. Se guardará la plantilla en un archivo .zip.

5. Creamos un nuevo proyecto de Visual Studio. En este caso será un proyecto VSIX.

6. El proyecto se creará y nos aparecerá el manifiesto del proyecto para rellenarlo.

7. En primer lugar, rellenaremos los campos informativos: Nombre, descripción, autor,

etc.

8. Posteriormente, en la opción “Supported VS Editions”, seleccionaremos las ediciones

compatibles con nuestro template. Seleccionaremos:

9. Se añadirá el archivo zip (template) creado anteriormente. Dentro de la opción “Add

content”, seleccionamos el tipo “Project Template” y cargamos desde un archivo el

template originado en el proyecto anterior. Opcionalmente, se podrá seleccionar una

subcarpeta para dicho template, que se corresponderá con una subcategoría dentro

de las plantillas del Visual Studio. Para nuestro ejemplo:

10. Quedará finalmente:

11. Por último, se generará la solución del proyecto VSIX (“Generar” “Generar

solución”, o “F7”).

12. Ya se encuentra creado el complemento para añadir al Visual Studio. Cerramos el

entorno y nos dirigimos a la ruta donde se ha generado la solución del proyecto VSIX.

Hacemos doble click en el archivo “.vsix”, que instalará el complemento en el Visual

Studio.

13. Tras ello, ya se puede crear un nuevo proyecto en Visual Studio partiendo de la

plantilla creada:

C. Herramientas gráficas de EmguCV

Como se ha podido comprobar con el ejemplo

detallado, EmguCV hace uso de una serie de clases

propias para definir, almacenar y operar con imágenes.

Es por ello que EmguCV contempla una serie de

herramientas propias (del cuadro de herramientas de

Diseño) para poder mostrar la información en un

formulario.

Si bien, en el proyecto de ejemplo, se hacía uso de un

“pictureBox” para mostrar el contenido de una imagen,

se pudo apreciar que había que realizar una conversión

a bitmap para poder mostrar el contenido de dicha

imagen. Es por esto, y por otros ejemplos similares, que

EmguCV aporta una serie de herramientas para facilitar

el trabajar con dicha librería.

A continuación se detallan los pasos a seguir para

añadir esas herramientas a las predeterminadas de

Visual Studio para poder trabajar con ellas.

1. Nos dirigimos a la pestaña de diseño del formulario. En el cuadro de herramientas

(derecha), cliqueamos con el botón derecho y seleccionamos la opción “Elegir

Elementos”.

2. En la ventana que aparece, dentro de la pestaña “Componentes de .NET Framework”,

cliqueamos en el botón de “Examinar”.

3. Dentro de la ubicación de EmguCV, dentro de la carpeta “bin”, seleccionamos la

librería “Emgu.CV.UI.dll”.

4. Cargará automáticamente las herramientas de EmguCV y aparecerán en la pestaña

“General” del cuadro de herramientas de diseño.

D. Primer proyecto con EmguCV

Haremos uso de la plantilla creada para comenzar nuestro proyecto.

A partir de él, haremos uso de las utilidades para cargar imágenes, mostrarlas y aplicarles

ciertos tratamientos simples.

1. Cargar Imágenes: se realizará de dos formas diferentes.

a. Haciendo uso de una ruta estática, se puede cargar una imagen en la propia

inicialización del objeto “Image”:

Image<Bgr,Byte> im = new Image<Bgr, Byte>(“ruta_de_la_imagen.jpg”);

b. Haciendo uso de los diálogos de apertura de archivos que posee C#:

//Creamos el objeto

OpenFileDialog op = new OpenFileDialog();

//Seleccionamos el filtro utilizado (tipo de archivo)

op.Filter = "Imágenes JPEG (.jpg)|*.jpg";

op.FilterIndex = 0; //Con más de uno, así se seleccionaría la posición

//Abrimos el cuadro de diálogo

if (op.ShowDialog() == DialogResult.OK)

{

//Inicializamos la Imagen con la ruta obtenida del diálogo

im = new Image<Bgr, Byte>(op.FileName);

//Aquí se mostraría la imagen cargada (en el pictureBox)

}

2. Mostrar Imágenes:

Ya se ha visto en el proyecto de ejemplo cómo mostrar una imagen en un pictureBox, de

forma que en el formulario pueda apreciarse el contenido de dicha imagen.

De igual forma, podría mostrarse si se hace uso de la herramienta “ImageBox”, que es una

de las herramientas que nos proporciona EmguCV.

Esta herramienta, al estar pensada para trabajar con objetos de la clase “Image”, no

necesita de conversiones previas. Así pues, para mostrar el contenido de “im” en un

ImageBox, se haría lo siguiente:

imageBox1.Image = im;

3. Tratamientos sobre imágenes

En este apartado se expondrán una serie de tratamientos (simples y complejos) sobre

imágenes, haciendo uso de las funcionalidades que aporta EmguCV.

Para hacer la sesión más interactiva y entretenida, los siguientes apartados se aportan

a modo de “ejercicios” a realizar por el alumnado, con una breve explicación al respecto.

Ante cualquier duda puede consultar la web de EmguCV o, en última instancia, al

profesor.

a. Modifique el diseño del formulario, para mostrar 2 imageBox (elimine el pictureBox)

de 512x512 de tamaño, cada uno. Incluya un botón, que mostrará un cuadro de

diálogo y, de esa forma, poder seleccionar la imagen correspondiente. Incluya otro

botón, que servirá para activar la funcionalidad correspondiente que se pida en cada

apartado.

Puede probar con cargar cualquier imagen que quiera pero, por motivos

históricos, sería muy emotivo trabajar con la imagen clásica de visión artificial

(rostro de Lena Söderberg): puede encontrarla en google imágenes, o en

http://www.kitware.com/blog/files/128_1232259669.jpg.

b. Redimensionar la imagen: cómo ha podido comprobar, utilizar una dimensión de

512x512 abarca buena parte de la pantalla. Intente redimensionar los dos imageBox a

256x256. Al cargar la imagen de Lena, puede apreciar que solo muestra una cuarta

parte de la imagen. Haga uso del método “Resize” de la clase Image para

redimensionar la imagen a un tamaño de 256x256 píxeles. Para ello tendrá que

indicarle como primer y segundo parámetro el ancho y alto, respectivamente, al que se

redimensionará y, como último parámetro, la interpolación utilizada para ello (lineal,

cúbica, etc): se encuentran redefinidas dentro del enumerado “INTER”, de forma que

podrá indicar el tercer parámetro como INTER.CV_INTER_LINEAR (para interpolación

lineal). Pruebe con las otras interpolaciones, por si observa algún cambio

c. Acceso directo a los píxeles de una imagen: como atributo de la clase “Image” se

encuentra un array tridimensional denominado “Data”, al que se puede acceder de

forma pública y modificar el valor de las componentes de color de un determinado

píxel. Pruebe a pintar de color rojo (BGR a 0,0,255) un recuadro de la imagen y aprecie

el resultado.

d. Extraer sub-imagen: Haga uso del método “GetSubRect”, pasándole por parámetros un

rectángulo (clase Rectangle), inicializado con cuatro parámetros: posición ‘x’ inicial,

posición ‘y’ inicial, ancho y alto.

e. Convertir la imagen a escala de grises. Para ello utilice el método “Convert” de la clase

Image.

f. Aplique un filtro tipo “blur” sobre la imagen. Este tipo de filtros lineales, calcula el

nuevo valor de un píxel con respecto al de sus vecinos, de forma que se suelen utilizar

para eliminar el ruido de sal y pimienta. Para ello, haga uso de los métodos:

i. Blur de media: media aritmética del valor de un píxel con el de sus vecinos. Haga

uso del método “MedianBlur” y pasándole por parámetro el tamaño del kernel de

convolución a aplicar.

ii. Blur Gausiano: haga uso de la función “SmoothGaussian” y pasándole por

parámetro el tamaño del kernel de convolución a aplicar. Este no realiza la media

aritmética, sino una ponderada de forma que la participación del píxel depende

de la distancia con el central.

g. Binarizar la imagen: convertirla en una imagen en blanco y negro. Debe partir de la

imagen en escala de grises (si parte desde la imagen a color, lo que obtendrá es una

binarización en cada canal del color). En ambos casos deberá indicar un valor umbral

de binarización. Haga uso del método “ThresholdBinary”, pasándole por parámetro el

umbral y el valor máximo a utilizar en caso de superar dicho umbral.

i. Inserte un control de tipo “ScrollBar” en su aplicación (con un valor entre 0 y 255)

y utilice el valor devuelto para binarizar la imagen con dicho valor. Utilice el

evento generado por la barra de desplazamiento para aplicar la conversión en el

mismo momento. De esa forma, podrá apreciar cómo se modifica la imagen a

medida que mueve la barra de desplazamiento.

h. Transformaciones afines: giros, traslaciones, etc.

i. Dar la vuelta: hacer uso del método “Flip”, al que se le podrá pasar dos

parámetros: FLIP.HORIZONTAL o FLIP.VERTICAL; para efectuar el cambio

horizontal o verticalmente.

ii. Rotación: hacer uso de la función “Rotate”, a la que se le pasa el ángulo de

rotación y un color (el que se utilizará para rellenar el fondo en caso de que

ningún píxel coincida en una posición concreta).

iii. Inserte un control de tipo “ScrollBar” en su aplicación (con un valor entre 0 y 360)

y utilice el valor devuelto para utilizarlo como ángulo giro de la imagen. Utilice el

evento generado por la barra de desplazamiento para aplicar el giro en el mismo

momento. De esta forma, podrá apreciar los cambios mientras mueve la barra.

i. Operadores morfológicos comunes:

i. Erosionar una imagen: obtención del esqueleto de la imagen. Reduce aquellos

patrones gruesos de la imagen. Hacer uso del método “Erode”, pasándole por

parámetros el número de iteraciones utilizadas para erosionar la imagen.

ii. Dilatar la imagen: justamente lo opuesto a la anterior. Hacer uso de la función

“Dilate”, e indicándole por parámetros el número de iteraciones a realizar.

j. Filtros derivativos: utilizados para detectar cambios en una imagen.

i. Operador de Sobel: operador discreto que calcula, aproximadamente, el gradiente

de la intensidad de la imagen. Hay que partir de la imagen monocromática para

obtener buenos resultados. Aplica el gradiente horizontal y el vertical

(dependiendo de los parámetros). Puede utilizarlo, haciendo uso del método

“Sobel”, pasándole por parámetros: un entero (0 o 1) que indica si se realizará la

derivada respecto a X, otro entero (0 o 1) que indica si se realizará la derivada

respecto a Y, y un último entero que indica el tamaño del kernel. Para aplicar uno,

pruebe a llamar al método con los parámetros “1, 0, 3”. Pruebe con otras

combinaciones. Este filtro detecta variaciones significativas en la intensidad de los

píxeles y las acentúa.

ii. Operador Laplaciano: uso de la transformada discreta de Laplace. Derivada de la

intensidad de segundo orden. Se correspondería con aplicar la derivada al

resultado aportado por el operador de Sobel (internamente lo llama). A las

variaciones acentuadas tras aplicar Sobel, este filtro las detecta y se queda

únicamente con estas variaciones para mostrar los bordes de la imagen. Haga uso

de ella con el método “Laplace” y pasándole como argumento el tamaño del

kernel.

iii. Detector de bordes “Canny”: detector óptimo de bordes. Aplica filtro Gaussiano,

Sobel y Laplace con unos kérneles concretos, y de forma iterativa, para obtener de

forma óptima los bordes. Se hace uso de él llamando al método “Canny”, con dos

parámetros que especificarán el mínimo y máximo umbral de binarización,

respectivamente, entre los cuales el método buscará el óptimo.

iv. Modifique su aplicación para que, en el detector “Canny”, los dos parámetros

umbrales vengan aportados por dos barras de desplazamiento (así podrá apreciar

los resultados de hacer las modificaciones en tiempo real).

k. Redimensionar utilizando pirámides: En un comienzo se ha indicado un mecanismo

muy simple para redimensionar imágenes. El problema de dicho mecanismo era que se

basaba en multiplicar la información (al aumentar el tamaño) o en eliminar

información (al disminuir el tamaño). El resultado de este redimensionamiento puede

ocasionar pérdidas graves en el contenido de la imagen o una visualización muy

artificial. Para ello, hay un mecanismo de redimensionamiento de la imagen que hace

uso de las transformadas gaussianas y laplacianas para extrapolar el contenido de los

píxeles con respecto a sus vecinos; obteniendo así un resultado mucho más óptimo al

redimensionar. Haga uso del método “PyrDown” para reducir la imagen de forma

piramidal y “PyrUp” para ampliar la imagen de forma piramidal. ¿Observa algo

interesante?

l. Detección de líneas rectas: para detectar las líneas, se hace uso de un sistema de

coordenadas polares, de forma que un punto viene definido por dos valores (rho y

theta). Para un punto concreto con coordenadas cartesianas, al representarlo con

coordenadas polares (variando ambas), se mostraría una representación sinusoidal.

Esto que quiere decir: que nuestro algoritmo aplicará estas transformaciones a polares

con todos los puntos y, aquellos cuyos senos coincidan en un punto son propensos a

encontrarse en la misma línea. Obviamente, mientras más puntos coincidan se

obtendrá una mayor precisión. Así pues, pasando a la práctica, el método encargado

de buscar líneas rectas es “HoughLines”, al que se le pasa por parámetros: el mínimo y

máximo umbral de binarización (para utilizarlos con “Canny”), la resolución de rho (en

píxeles) y de theta (en grados) en las representaciones sinusoidales (cuantización de

dichos valores), un umbral que denotará el número de puntos cartesianos cuyas

representaciones polares deben converger en un punto (mínimo para denotarlo como

línea), el tamaño mínimo de la línea y la distancia mínima entre puntos para ser

considerados como línea.

Trabajando con la imagen en escala de grises, devuelve un “LineSegment2D[][]”, de

forma que la primera coordenada solo posee un posible valor (0), mientras que la

segunda contiene todas las líneas (una por posición y de tipo Segment2D). Para

pintarlas, podemos hacer uso del método “Draw” de la clase Image.

m. Detección de círculos: para detectar un círculo, se lleva a cabo un proceso análogo al

de detección de líneas. En este caso, un círculo vendrá descrito por dos coordenadas

(punto central) y el radio. Para los círculos, se implementa un método más eficaz y

simple que el de las líneas. Haga uso del método “HoughCircles”, que recibe por

parámetros: el umbral mayor de “Canny”, el umbral para la detección del centro del

círculo, la resolución con la que trabajar (1: 100% de la imagen), mínima distancia

entre círculos, radio mínimo y radio máximo (ambos radios puedes ser 0, y se

encargaría el método de buscar todas las posibilidades). El método devuelve un

“CircleF[][]” que, al igual que pasaba en el apartado anterior, tiene una sola fila (por

ser una imagen en escala de grises) y las columnas indican los diversos círculos.

Igualmente podrá usar el método “Draw” de Image.

n. Operaciones con histogramas: un histograma es una representación gráfica de una

variable, en forma de barras, donde la superficie de la barra es proporcional a la

frecuencia de los valores representados. En visión artificial, se suele utilizar para

denotar la distribución de la luminosidad en una imagen monocromática (frecuencia

de cada posible valor de la escala de grises). Esta información es muy útil para extraer

determinadas características de la imagen, así como para aplicar diversos tratamientos

sobre ella.

i. Ecualizar el histograma: expande homogéneamente las “barras” del

histograma, de forma que amplia el rango de valores de la escala de

grises que aparecen en la imagen, permitiendo aumentar el contraste

de la misma. Haga uso del método “_EqualizeHist()”.

ii. Calcular y mostrar el histograma: Para ello, en primer lugar, hay que

crear un objeto de tipo “DenseHistogram”, e indicarle el valor máximo

y el rango de valores en su inicialización: DenseHistogram Histo = new DenseHistogram(255, new RangeF(0, 255));

Con la imagen en escala de grises, se puede calcular su histograma

hacienda uso del método “Calculate”, que recibe por parámetros: un

vector de Image (por si se quiere mostrar más de un histograma a la

vez – en nuestro caso: new Image<Gray, Byte>[] {im}), el segundo y

tercer parámetros se utilizan para opciones específicas a la hora de

mostrar varios histogramas (en nuestro caso, valdrán “false” y “null”,

respectivamente).

Por último, ¿cómo lo mostramos en nuestra aplicación?... ¿te acuerdas

del HistogramBox del cuadro de herramientas? Tendrás que crear uno

y hacer uso de su método “AddHistogram” (al que se le pasa el

nombre, el color y el histograma) y, por último, utilizar el método

“Refresh” para refrescar el histograma.

o. Correspondencia de patrones: buscar un determinado patrón en la imagen o, lo que es

lo mismo: dada una imagen, detectar las apariciones de ella en otra imagen.

Aparentemente, el uso del método “MatchTemplate” puede parecer simple (debido a

que solo recibe por parámetros la imagen plantilla y el método de normalización de los

coeficientes –que utilizaremos el TM_TYPE.CV_TM_CCOEFF_NORMED-) pero, tras su

ejecución hay que realizar otras tareas. Nos devuelve una imagen, pero cada posición

de esta imagen representa la probabilidad de que ese punto (x e y) sea el punto de

comienzo de la plantilla pasada. Así pues, lo que habrá que hacer a continuación es

buscar sobre todos ellos (con un porcentaje estipulado por nosotros -normalmente

mayor al 70%-) y mostrar un recuadro sobre aquellos que superen nuestro umbral.

Para facilitar la tarea de buscar sobre los elementos de una imagen, la convertiremos a

un array de elementos tipo float haciendo uso de “float[,,] porcentajes = im.Data;”.

Tras ello, haremos una búsqueda secuencial por todas las filas y columnas de este

array (dos primeras componentes), con la tercera componente a 0 (es una imagen en

escala de grises). Para cada valor que supere 0.75 (por ejemplo) lo pintaremos. Puede

hacer uso del método “Draw” de Image o, incluso, crear un “Rectangle” con punto de

inicio en la posición actual y con un ancho y alto igual al de la plantilla.