PDA

Ver la Versión Completa : Binarización de una imagen


bosterito
23-02-2007, 02:43:35
Hola amigos foristas.
Les cuento que estoy desarrollando un sistema que trata sobre imagenes digitales. En el mismo consta de una sección en la cual maneja imagenes en escala de grises y la transforma a blanco y negro (binarización). Investigando en la web, di que el mejor método es el que trata el umbral de Otsu. Esta binarización también emplea una interpolación bilineal, la cual no se como acoplarla al sistema. A continuación les envío el código que desarrollé:


Type TmatrizB = array[1..16, 1..16] of Integer;
Type VectorReal = array[0..256] of Real;
Type VectorEntero = array[0..256] of Integer;


function DistribucionProbabilidad( Histograma : VectorEntero; Ancho, Alto : Integer ) : VectorReal;
Var
Probabilidad : VectorReal;
i : Integer;
begin
for i := 1 to 256 do
Probabilidad[i] := (Histograma[i]/(Ancho*Alto));
Result := Probabilidad;
end;
procedure MomentoAcumulado( Probabilidad : VectorReal; var Omega : VectorReal; var Mu : VectorReal );
Var
i : Integer;
begin
Omega[1] := Probabilidad[1];
Mu[1] := Probabilidad[1];
for i := 2 to 256 do
begin
Omega[i] := Omega[i-1] + Probabilidad[i];
Mu[i] := Mu[i-1] + ((i-1)*Probabilidad[i]){i * Probabilidad[i]};
end;
end;
function UmbralOptimo( Omega, Mu : VectorReal ) : Integer;
Var
Sigma, SigmaMax, MuTotal, Omega1, Omega2, Mu1, Mu2 : Real;
Umbral, i : Integer;
begin
Sigma := 0; SigmaMax := 0; MuTotal := Mu[256]; Umbral := 0;
for i := 1 to 256 do
begin
Omega1 := Omega[i];
Omega2 := 1 - Omega1;
if ( ( Omega1 <> 0 ) and ( Omega2 <> 0 ) ) then
begin
Mu1 := Mu[i]/Omega1;
Mu2 := (( MuTotal - Mu[i] )/Omega2);
Sigma := ((Omega1 * sqr( Mu1 - MuTotal )) + (Omega2 * sqr( Mu2 - MuTotal )));
if ( Sigma > SigmaMax ) then
begin
SigmaMax := Sigma;
Umbral := i - 1;
end;
end;
end;
Result := Umbral;
end;
function Segmentacion( Bloque : Integer; Imagen : TImage ) : TMatrizB;
var
i, j, Alto, Ancho, Umbral : Integer;
Histograma : VectorEntero;
Omega, Mu, DP : VectorReal;
Matriz : TMatrizB;
begin
FillChar(Matriz, sizeof(Matriz), 0);
Alto := 0;
While( Alto <= Form1.Image1.Picture.Bitmap.Height -1 ) do
begin
Ancho := 0;
While( Ancho <= Form1.Image1.Picture.Bitmap.Width -1 ) do
begin
FillChar(Histograma, sizeof(Histograma), 0);
for j:= Alto to Alto + (Bloque - 1) do
begin
for i:= Ancho to Ancho + (Bloque - 1) do
begin
inc (Histograma[Imagen.Canvas.Pixels[i,j] and $FF + 1]);
end;
end;
Ancho := Ancho + Bloque;
FillChar(DP, sizeof(DP), 0);
DP := DistribucionProbabilidad( Histograma, 16, 16 );
FillChar(Omega, sizeof(Omega), 0); FillChar(Mu, sizeof(Mu), 0);
MomentoAcumulado( DP, Omega, Mu );
Umbral := UmbralOptimo( Omega, Mu );
Matriz[(((Alto+Bloque)) div Bloque), ((Ancho) div Bloque)] := Umbral;
end;
Alto := Alto + Bloque;
end;
Result := Matriz;
end;

procedure Bina( M : TMatrizB; Imagen : TImage; Bloque : Integer );
var
i, j, Alto, Ancho, Fila, Columna : Integer;
begin
Alto := 0;
Fila := 1;
While( Alto <= Form1.Image1.Picture.Bitmap.Height -1 ) do
begin
Ancho := 0;
Columna := 1;
While( Ancho <= Form1.Image1.Picture.Bitmap.Width -1 ) do
begin
for j:= Alto to Alto + (Bloque - 1) do
begin
for i:= Ancho to Ancho + (Bloque - 1) do
begin
if ( Form1.Image1.Canvas.Pixels[i,j] and $FF >= M[Fila, Columna] ) then
Imagen.Canvas.Pixels[i,j] := RGB(255,255,255)
else
Imagen.Canvas.Pixels[i,j] := RGB(0,0,0);
end;
end;
Ancho := Ancho + Bloque ;
inc(Columna);
end;
Alto := Alto + Bloque;
inc(Fila);
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
Var
M : TMatrizB;
begin
M := Segmentacion( 16, Image1 );
Bina( M, Image1, 16 );
end;





Saludos:)

Delphius
23-02-2007, 07:09:02
Esta binarización también emplea una interpolación bilineal, la cual no se como acoplarla al sistema

En estos momentos no tengo abierto el Delphi... y el código la verdad no lo entiendo bien. Deberías encerrar el código entre etiquetas DELPHI en vez de CODE

Si nos puede indicar de que manera estas tratando de acoplar al sistema te podemos ser más útil.

Investigando en la web, di que el mejor método es el que trata el umbral de Otsu
¿Podrías indicarnos el enlace? A muchos les pueda servir. Además, es una buena manera de entender el código que expones.

Me voy a poner a ver el código... pero como te dije anteriormente: explicate bien a que te refieres cuando tratas de acoplarlo a tu sistema... ¿Te da un error?

Saludos,

bosterito
23-02-2007, 18:01:14
Hola.


Originalmente Escrito por Delphius
Si nos puede indicar de que manera estas tratando de acoplar al sistema te podemos ser más útil.


El umbral calculado se lo asigna a cada región de la imagen y se lo extiende a través de una interpolación bilineal. El problema es que no consigo interpretar bien la interpolación bilineal para aplicarla al código. A continuación estan las referencias en las que más me guié:

http://www.gpi.tsc.uvigo.es/research-theses.html, cápitulo 1 y 2.
iaci.unq.edu.ar/.../archivos/apuntes/Segmentación%20por%20umbralización%20-%20Método%20de%20Otsu.pdf (http://www.clubdelphi.com/foros/iaci.unq.edu.ar/.../archivos/apuntes/Segmentación%20por%20umbralización%20-%20Método%20de%20Otsu.pdf)
www.freewebs.com/pdi2005/field_rectificacion.pdf (http://www.clubdelphi.com/foros/www.freewebs.com/pdi2005/field_rectificacion.pdf)



Saludos

Delphius
24-02-2007, 04:12:39
bosterito, en mi tiempo libre voy a ver los pdf que indicas. No te prometo nada, pero voy a hacer lo posible (en lo que mis tiempos y ritmos me lo permitan) para ayudarte.

El tema me gusta, y yo también estoy metiendome en el tema de tratamiento de imagenes. Tengo que admitir que es la primera vez que escucho de este método para generar imagenes binarias.

Yo empleo otra técnica:

1. Transformar la imagen a escala de grises (si es necesario) ya sea mediante el método de la intensidad o el método de brillo.
2. A dicha imagen se la escanea linea a linea (con Scanline):
2.1. Por cada línea, se cambia el valor del pixel apuntado, de acuerdo a una simple ecuación:


if P^[k] >= umbral
then P^[k] := 1
else P^[k] := 0


Siendo P, el puntero de la linea:

P := Image.Bitmap.Scanline(j);


Claro está... que para que funcione apropiadamente, a cada canal (rojo: k = 3, verde: k = 2, y azul: k = 1) se le deba pasar el valor 1 o 0 según la condición.

Y ¡Listo! se obtiene una imagen binaria. Guardandola mejor con un formato de pf8bit.

No se cual será mejor... pero si te sirve, puede ser como una alternativa.;)

Saludos,

Delphius
24-02-2007, 10:16:49
bosterito, los dos ultimos enlaces no funcionan.

He visto un poco lo que pretendes, pero todavia no he logrado entenderlo del todo. Si hay una mente más cultivada en este tema a lo mejor puede ayudarte...

En los unicos pdf que me permite bajar (los que indicaste del enlace 1) No habla nada de un algoritmo de interpolación bilineal.

A manera simple, y por analogía al método de interpolación lineal... lo que trata de hacer la interpolación es predecir (léase calcular) un/os valor/es medio o promedio entre dos puntos A y B. Por ejemplo, si quieres calcular un sólo valor entre dos pixeles puedes hacer: (A+B)/2

Si quieres calcular dos valores:
x1 = (2A + B)/3
x2 = (A + 2B)/3

Ahora, al tratarse de un método bilineal... la cosa se complica. Pues (si nom me equivoco), el valor a calcular no se realiza mediante una función lineal sino polimonial con un grado 2. Una forma, parecida a, por poner ejemplo: A^2 + B.

No se mucho, yo ando investigando a la par tuya:eek::rolleyes:, espero que con esta info puedas seguir avanzando.
Saludos,

Delphius
06-03-2007, 20:49:52
Bueno, he visto los pdf de todos los links y no encuentro algo como para decir que el algoritmo necesita de una interpolación bilineal.

Ha decir verdad entiendo lo que dice el método del umbral de Otsu, y de lo que pude ver en tu código está bien. Funciona.:)

Solo puedo decirte que te conviene emplear la función scanline() en vez de acceder por pixeles. Es mucho más rápido.

Disculpa pero no más no puedo ayudarte:(. Yo he investigado acerca de esto también debido a que en mi tesis se trata un poquito del tema... y me ando poniendo al corriente en diferentes técnicas. Reconozco que es la primera vez que leo algo de Otsu... y lo que leí me parece interesante como para continuar.

Lo que me parece raro es que no te hayas dado una vuelta por aqui para ver si las otras cosas que te puse te sirven.

Saludos,

PD: si llego a saber de otras investigaciones y métodos sobre el asunto te aviso.