Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Segmentacion PDF
Segmentacion PDF
IMÁGENES BASADA EN EL
HISTOGRAMA
GONZALO LUZARDO M.
gluzardo@espol.edu.ec
gonchalox@gmail.com
1. Introducción
Este trabajo consiste en tratar de resolver un problema clásico del campo de la visión artificial, que
se denomina segmentación de imágenes. La segmentación en visión artificial consiste en identificar
individualmente cada uno de los objetos o elementos presentes en una escena. En nuestro caso en
particular, lo que buscamos es identificar una puerta y discriminarla de los demás objetos que
pudieran estar presentes. Las imágenes que vamos a analizar, las cuales son claros ejemplos de los
cuatro problemas a los que nos podríamos enfrentar al momento de tratar de identificar la puerta,
son las siguientes:
CASO 1: CASO 2:
Puerta cerrada vista de frente(imagen1.jpg) Puerta cerrada vista desde un lado
(imagen2.jpg)
CASO 3: CASO 4:
Puerta abierta (imagen3.jpg) Puerta semiabierta (imagen4.jpg)
Para resolver nuestro problema de identificar la puerta en cada una de nuestras imágenes, las
técnicas de segmentación que vamos a utilizar serán las siguientes:
4000
6000
3500
5000
3000
4000
2500
3000 2000
1500
2000
1000
1000
500
0 0
0 50 100 150 200 250 0 50 100 150 200 250
CASO 1 CASO 2
3500
4000
3000
3000 2500
2000
2000
1500
1000
1000
500
0 0
0 50 100 150 200 250 0 50 100 150 200 250
CASO 3 CASO 4
Observando los histogramas podemos notar claramente la naturaleza altamente ruidosa de los
mismos. Podemos identificar algunos picos que podrían considerarse como objetos identificables
dentro de la imagen, así como una multitud de falsos mínimos y falsos máximos. Esta información
obtenida servirá para realizar nuestra primera aproximación de segmentación para cada una de las
imágenes.
La primera segmentación que vamos a hacer será la siguiente: aplicar un filtro de la mediana sobre
el histograma para tratar de eliminar los falsos máximos y falsos mínimos, para luego considerar los
picos (modas) como el número de objetos (clases) presentes en nuestra imagen y el umbral de
separación entre dos clases como la media suma de sus picos.
Utilizando el código MATLAB para segmentar una imagen de la sección 6.2, para cada caso
obtuvimos los siguientes resultados.
6000
5000
4000
3000
2000
1000
0
0 50 100 150 200 250
*Numero de clases identificadas: 7
*Tamaño de la ventana: 11
4000
3500
3000
2500
2000
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 11
*Tamaño de la ventana: 11
5000
4500
4000
3500
3000
2500
2000
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 9
*Tamaño de la ventana: 11
4000
3500
3000
2500
2000
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 15
*Tamaño de la ventana: 11
Los datos que obtuvimos para cada uno de los casos fueron los siguientes:
Podemos notar que esta primera segmentación que hemos aplicado resulta ser bastante buena,
claramente podemos apreciar como los diferentes elementos presentes en la imagen han sido “por
así decirlo” identificados. Adicionalmente esta primera segmentación nos ayuda a poder estimar de
manera heurística el intervalo en niveles de gris que corresponde a la puerta la cual queremos
identificar, en nuestro caso este intervalo se encuentra cercano a 50. Esta información la
utilizaremos para poder etiquetar dentro del histograma a aquellos pixeles que corresponden a la
puerta.
Otra manera de estimar el umbral o fronteras entre dos clases es mediante restitución sucesiva del
umbral, el cual, dada dos clases con una distribución normal de los pixeles en cada una, y una misma
varianza entre clases, estima el umbral de manera reiterada a través de la media suma de sus
medias estimadas utilizando las muestra presentes en la clase hasta que el umbral se estabilice
(Umbralización Semi-Bayes).
Lo que vamos hacer es implementar esta técnica de umbralización y comparar con los resultados
obtenidos mediante la umbralización a través de media suma de los picos.
Utilizando el código de MATLAB 6.3 que contiene un algoritmo para de umbralización mediante
restituciones sucesivas del umbral, para cada caso obtuvimos los siguientes resultados:
6000
5000
4000
3000
2000
1000
0
0 50 100 150 200 250
*Numero de clases identificadas: 7
*Tamaño de la ventana: 11
4000
3500
3000
2500
2000
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 11
*Tamaño de la ventana: 11
Histograma con maximos y fronteras (Semi Bayes)
5000
4500
4000
3500
3000
2500
2000
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 9
*Tamaño de la ventana: 11
4000
3500
3000
2500
2000
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 15
*Tamaño de la ventana: 11
Si observamos los resultados obtenidos notamos que no son muy buenos e incluso son peores a los
que obtuvimos estimando los umbrales como las medias sumas de los picos. Al parecer considerar
que cada una de las clases posee la misma varianza, algo que en realidad claramente no sucede,
ocasiona que las fronteras entre clases se inclinen más hacia la clase con mayor número de
muestras. Una manera de corregir este error sería utilizando una estimación del umbral con Bayes
completo el cual si considera la varianza en cada una de las clases. El problema de aplicar un Bayes
completo radica en el incremento de la cantidad de cálculos que debemos realizar.
En vez de utilizar Bayes-completo, hemos optado por estimar los umbrales de una manera diferente:
el umbral entre dos clases dadas estará ubicado en el valor mínimo presente entre los picos de
ambas clases. Como vemos esta estimación resulta ser más sencilla y mucho más fácil de calcular.
Adicionalmente vamos a etiquetar el histograma utilizando el valor obtenido del nivel de gris donde
puede localizarse la puerta, de tal forma que aquella clase que contenga dentro el valor de gris igual
a 50 corresponderá a la puerta.
Utilizando el código de MATLAB 6.4 el cual establece el umbral entre las clases como el valor mínimo
entre sus picos, para cada caso obtuvimos los siguientes resultados:
Histograma con maximos y fronteras
6000
Clase Puerta
5000
4000
3000
2000
1000
0
0 50 100 150 200 250
*Numero de clases identificadas: 7
*Tamaño de la ventana: 11
4000
Clase Puerta
3500
3000
2500
2000
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 11
*Tamaño de la ventana: 11
5000
4500
4000
3500
3000
2500
2000
Clase Puerta
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 9
*Tamaño de la ventana: 11
4000
3500
3000
Clas e Puerta
2500
2000
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 15
*Tamaño de la ventana: 11
Analizando los resultados podemos darnos cuenta de algunas mejoras respecto a los resultados
obtenidos anteriormente. Podemos observar que existen regiones de la puerta que en un principio
fueron clasificadas erróneamente, esta vez clasificadas de manera correcta; estas regiones
corresponden a las zonas oscuras correspondientes al marco de la puerta. Aun podemos mejorar
nuestros resultados realizando un preprocesamiento sobre la imagen.
Este preprocesamiento consistirá en aplicar un filtro gausiano sobre la imagen original. De esta
forma eliminaremos las frecuencias altas presentes en la imagen, y en teoría una mejor clasificación.
Adicionalmente vamos a marcar sobre la imagen sólo aquellos pixeles que según el histograma
corresponden a la puerta. Utilizando el código MATLAB de la sección 6.5 donde realizamos
preprocesado de imágenes, obtuvimos los siguientes resultados:
6000
Clase Puerta
5000
4000
3000
2000
1000
0
0 50 100 150 200 250
*Numero de clases identificadas: 8
*Tamaño de la ventana: 11
3500
3000
2500
2000
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 15
*Tamaño de la ventana: 11
5000
4000
3000
2000
Clase Puerta
1000
0
0 50 100 150 200 250
*Numero de clases identificadas: 13
*Tamaño de la ventana: 11
Histograma con maximos y fronteras
4000
3500
3000
Clase Puerta
2500
2000
1500
1000
500
0
0 50 100 150 200 250
*Numero de clases identificadas: 13
*Tamaño de la ventana: 11
Como vemos también existen pixeles o regiones mal clasificadas (regiones que no forman parte de la
puerta marcados como parte de ella), esto se debe a que a que dichos pixeles poseen una intensidad
en niveles de gris igual o similar a aquellos pixeles que si forman parte de la puerta. Para mejorar
aún más nuestra segmentación podríamos optar por:
Una posible desventaja de utilizar algunas de estas “mejoras” radica en la necesidad de hacer
cálculos adicionales a los que hemos hecho hasta el momento, lo que no podría ser un
inconveniente para una aplicación montada sobre un robot que en tiempo real está
constantemente buscando una puerta para luego dirigirse hacia ella.
Para la detección de bordes vamos a utilizar los operadores de derivación (filtros del gradiente y
laplacianos) los cuales se ha comprobado que dan muy buenos resultados.
La detección de bordes puede ser particularmente útil en nuestro caso ya que la puerta (con niveles
de intensidad bajos) tiene los bordes muy bien definidos debido a que se encuentra sobre la pared
que tiene un nivel de intensidad mucho más altos.
Utilizando el código MATLAB de la sección 6.6 la cual realiza una extracción de bordes aplicando el
filtro del gradiente de Prewitt, obtuvimos los siguientes resultados:
Si observamos los resultados notamos la eficacia del filtro aplicado. Los bordes de los objetos,
especialmente los de la puerta, han sido identificados muy bien.
Podríamos detenernos aquí, pero por cuestiones de curiosidad, aplicaremos un filtro laplaciano para
la extracción de bordes. Utilizando el código MATLAB de la sección 6.7 pudimos obtener los
siguientes resultados:
Si observamos los resultados obtenidos al aplicar ambos filtros podemos notar que ambos son igual
de buenos, de tal forma que cualquiera de los dos se los podría considerar como válido.
Adicionalmente, se investigaron los filtros de Canny para la detección de bordes. El filtro de Canny
combina un operador diferencial con un filtro gausiano para la detección de bordes. Utilizando el
código MATLAB de la sección 6.8 pudimos obtener los siguientes resultados:
Podemos observar que el filtro de Canny nos da mejores resultados, esto es, el aplicar un filtro
gausiano antes de la detección de bordes nos ayudará a eliminar las altas frecuencias presentes en la
señal y que pueden ser consideradas como falsos bordes, obteniendo al final mejores resultados.
4. Conclusiones
Una vez culminado el presente trabajo podemos sacar las siguientes conclusiones:
• Mientras más complejo resulta ser un algoritmo, más difícil es su implementación y los
resultados no necesariamente serán mucho mejores a los obtenidos por un algoritmo mucho
más simple.
• Es mejor tener algoritmos simples que den buenos resultados a algoritmos complejos que den
resultados un poco mejores (algo parecido a la Ley de Parsimonia1). El menor rendimiento
obtenido con los algoritmos simples es recompensado con la simplicidad y rapidez que estos nos
proporcionan.
• No podemos tener un algoritmo que funcione perfectamente en todos los casos. Si mejoramos
cada vez más un algoritmo, este funcionará muy bien para los casos objetos de de nuestro
estudio y muy mal para los demás casos, esto quiere decir que el algoritmo se vuelve específico
y es incapaz de generalizar.
• La segmentación se vuelve mucho más dificultosa con imágenes de naturaleza compleja, donde
existen una multitud de objetos a ser identificados, ruido ocasionado por la luz, por texturas
complejas en los objetos, entre otros.
• La segmentación basada en histograma en muy potente en imágenes no complejas y bajo
condiciones preestablecidas que favorezcan a la detección. Por ejemplo detección de objetos
sobre un fondo de un color prefijado. Sería muy útil por ejemplo para contar elementos sobre
una banda transportadora.
5. Referencias
• GONZALEZ, WOODS, EDDINS. “Digital Image Processing using MATLAB”. Prentice Hall. 2004.
• MARAVALL DARIO. ``Reconocimiento de formas y visión artificial''. RAMA. 1993.
1
Determina que, entre dos soluciones, es probable que la correcta sea la más sencilla.
6. Código MATLAB
6.1. Extracción y Trazado del histograma de una imagen
image_name = 'imagen1.jpg';
img = imread(image_name);
[counts,x]=imhist(img);
maxcounts = max(counts);
h = bar(x,counts);
set(h,'FaceColor',[102/255,153/255,102/255],'EdgeColor',[102/255,153/255,102/255]
);
title 'Histograma Original';
axis([0 255 0 maxcounts+300]);
function[frontier,findex]=FindFrontiers(values,maxindex)
findex = zeros(1,length(maxindex)+1);
frontier = zeros(1,length(maxindex)+1);
findex(1)= 1;
frontier(1)= values(1);
for N=1:length(maxindex)-1
findex(N+1) = round(maxindex(N) + (maxindex(N+1) - maxindex(N))/2);
frontier(N+1) = values(findex(N+1));
end
findex(length(maxindex)+1)= 256; %Maximo valor de un pixel
frontier(length(maxindex)+1) = values(256)
function[hills,xhills,climbs,xclimbs]=FindFrontiersSemiBayes(values,xmodes)
xhills = zeros(1,length(xmodes)+1);
hills = zeros(1,length(xmodes)+1);
xclimbs = xmodes;
climbs = values(xmodes);
xhills(1)= 1;
hills(1)= values(1);
%Inicializacion
for N=1:length(xmodes)-1
xhills(N+1) = round(xmodes(N) + (xmodes(N+1) - xmodes(N))/2);
hills(N+1) = values(xhills(N+1));
end
xhills(length(xmodes)+1)= 256; %Maximo valor de un pixel
hills(length(xmodes)+1) = values(256);
%Comenzamos con cada una de las clases
%Para cada una de las clases
for N=1:length(xmodes)-2
fprintf('Estabilizando clases: %i y %i\n',N,N+1);
min_sec = xhills(N);
uf = xhills(N+1); %la que iremos modificando paulatinamente
fprintf('Frontera inicial: %i\n',uf);
max_sec = xhills(N+2);
stable = 0; %establece si se stabilizo la busqueda
while(stable == 0)
m1 = sum((values(min_sec:uf) .* [min_sec:uf]))/sum(values(min_sec:uf));
m2 = sum((values(uf:max_sec) .* [uf:max_sec]))/sum(values(uf:max_sec));
mc = round((m1+m2)/2);
fprintf('Frontera obtenida: %i\n',mc);
if(mc==uf)
stable = 1;
else
uf = mc;
end
end
xhills(N+1)=uf;
end
6.4. Segmentación basada en histograma con filtrado de bordes y
estimación de fronteras mediante la localización de los mínimos entre los
picos
%<image_name> es el nombre del a imagen que vamos a procesar
gray_level_element = 50; %nivel de gris de la puerta
image_name = 'imagen1.jpg'; %nombre de la imagen que vamos a tratar
hist_mean_filter = 11; %debe ser impar, filtro de histograma, minimo 1 maximo 256
filter_text = '';
img = imread(image_name);
[m,n] = size(img);
%Convertir a blanco y negro
img = rgb2gray(img);
bar_width = hist_mean_filter;
[shist, err] = sprintf('Tamaño de la ventana: %i\n',bar_width);
%Obtenemos el histograma de la imagen original
[counts,x]=imhist(img);
maxcounts = max(counts);
%Aplicamos un filtro de la media sobre el histograma
counts_filtered = smooth(counts,bar_width);
%Buscamos los mayores locales dentro de la imagen
fprintf('Identificando las clases (objetos) en la imagen\n');
[climbs,xclimbs] = FindLocalMax(counts_filtered);
fprintf('Clases (objetos) identificadas');
climbs
clases = length(climbs); %numero de clases
fprintf('Numero de clases identificadas: %i\n',clases);
[sclases, err] = sprintf('*Numero de clases identificadas: %i\n *',clases);
fprintf('Buscando las fronteras como los minimos\n');
[hills,xhills]=FindFrontiersMin(counts_filtered,xclimbs);
fprintf('Fronteras encontradas\n');
tit_s = 'Histograma con maximos y fronteras';
hills
figure
%Dibujamos el histograma
fprintf('Dibujamos el histograma identificando las clases encontradas\n');
color_clases = DrawHistClases(x,counts_filtered,xhills); %Dibujamos el histograma
de clases
title(tit_s);
hold on;
%Dibujamos los maximos en el histograma
h = stem(xclimbs,climbs);
set(h,'Color','r','LineStyle','--
','Marker','s','MarkerEdgeColor','r','MarkerFaceColor','r','MarkerSize',2);
axis([0 255 0 maxcounts+300]);
xlabel(strcat(sclases, shist));
[xpos,yval] = FindPrototype(gray_level_element,xhills,xclimbs,climbs);
text(xpos,yval + 200, 'Clase Puerta',
'HorizontalAlignment','center','BackgroundColor',[.7 .9 .7],'FontSize', 9);
hold off;
figure
%Dibujamos la imagen original;
fprintf('Identificando las clases en la imagen original\n');
img_clases = GetImgClases(img,xhills,color_clases); %imagen en nivel de gris,
fronteras, colores para cada clase
fprintf('Clases identificadas...Dibujando\n');
imshow(img_clases);
title 'Imagen Segmentada';
function[frontier,findex]=FindFrontiersMin(values,maxindex)
findex = zeros(1,length(maxindex)+1);
frontier = zeros(1,length(maxindex)+1);
findex(1)= 1;
frontier(1)= values(1);
for N=1:length(maxindex)-1
fin = maxindex(N+1);
inicio = maxindex(N);
%Obtengo los valores presentes entre los intervalos
reg = values(inicio:fin);
h = min(reg);
p = find(reg == h);
f = round(inicio + p(1));
findex(N+1) = f ;
frontier(N+1) = values(findex(N+1));
end
findex(length(maxindex)+1)= 256; %Maximo valor de un pixel
frontier(length(maxindex)+1) = values(256);
end
end
img_clases = cast(img_clases,'uint8');