Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Gráficos (https://www.clubdelphi.com/foros/forumdisplay.php?f=8)
-   -   Binarización de una imagen (https://www.clubdelphi.com/foros/showthread.php?t=40666)

bosterito 23-02-2007 02:43:35

Binarización de una imagen
 
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é:

Código:

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

Cita:

Empezado por bosterito
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.

Cita:

Empezado por bosterito
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.

Cita:

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
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:

Código Delphi [-]
if P^[k] >= umbral
  then P^[k] := 1
  else P^[k] := 0

Siendo P, el puntero de la linea:
Código Delphi [-]
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

Respuesta
 
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.


La franja horaria es GMT +2. Ahora son las 03:10:37.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi