You are on page 1of 7

viernes, 23 de marzo de 2007

Intentando aprender manejo de bitmaps - I


Estoy desarrollando una aplicacin para ortodoncia que requiere el procesamiento de
imagenes digitalizadas, sobre las mismas se marcan puntos (cefalomtricos) y luego se
aplican clculos geomtricos. La mayora de estos cclulos son relativamente simples:
distancia entre 2 puntos, proyeccin entre puntos y rectas, interseccin entre rectas,
clculo de ngulos, y algun otro clculo que no es mas que una composicin de los
mencionados.
El manejo por ahora no parece complicado, y lo relacionado con los clculos geomtricos
anda bien. Estoy trabajando con bitmaps, ya que es el formato de archivo que me
permite mayor manipulacin para programar y trabajar sobre imagenes con Delphi, que
es el IDE y lenguaje que estoy utilizando.
Como todo, hacerlo ahora que se algo ms, no fue complicado, pero llegar a obtener y
ordenar toda la informacin que hay sobre .bmp, y el manejo de imgenes con Delphi,
fue una tarea pesada, de muchas lecturas, buscar ayuda en foros, etc.
Mi mayor problema se present al querer calcular la escala, esto es la equivalencia entre
pixeles por mm realde la imgen, es decir por cada mm real de la imagen sin digitalizar,
a cuantos pixeles equivale en la imagen ya digitalizada mediante scanner, cmara digital,
etc. Sabiendo poco o menos que ahora, hice lo siguiente:
1. antes de escanear la imgen, mido una distancia en la misma,
llamemosle distmm, la cual ser un dato ingresado por el usuario.
2. el usuario marca los puntos extremos de la imagen
3. calculo la distancia en pixeles correspondiente, como ya tengo la distancia en
mm, mediante una simple regla de 3, se obtiene la relacin entre mm y pixeles
para la imagen dada.
Esto funciona.
Quise hacerlo mas automtico, que el usuario no tenga que ingresar ningun dato,
simplemente marcar 2 puntos, y obtener la escala desde la informacin guardada en el
bmp. Esto me llev a indagar sobre el tema, busqu en san google e internet y
preguntando en foros.
Conclusin: no encontr forma de hacerlo, pero aprend algo ms sobre bmps y su
informacin interna que quiero compartir porque creo que se abre a un mundo
fascinante y que cada vez gana mas adeptos, el manejo de imgenes. Consideren estos
apuntes de primera mano, una referencia introductoria y rpida, pero espero que util. Al
menos que sirva para entender los cesudos artculos disponibles por toda la web a partir
de esta base, si sirve para eso, me doy por satisfecha.

Bitmaps...poco conocidos
Es el formato ms extendido en los sistemas Windows (aparecido en la versin 3.0) y

OS/2 , siendo el arhivo BMP donde se almacenan las imgenes. Se almacenan en


formato DIB (device independente bitmap, mapa independiente del dispositivo) que
permite a Windows visualizar el contenido del mapa de bits en cualquier dispositivo de
visualizacin. Esto se debe a que el mapa de bits especifica el color de un bit de forma
independiente del mtodo utilizado para representarlo.
Es un formato simple que tiene varios derivados (los .ico por ejemplo), y aunque
tericamente permite compresin no se usa en la prctica. Su desventaja es el gran
tamao de archivo (por ausencia de compresin), y que necesita una mayor velocidad de
carga como consecuencia.

Forma del archivo


Veamos como est organizado:
BITMAPFILEHEADER // contiene datos sobre tipo, tamao y diseo de un archivo del
bitmap.
BITMAPINFOHEADER // cabecera de informacin especifica dimensiones, tipo de
condensacin y formato del color para el bitmap
ACOLORS DE RGBQUAD [] // vector de estructuras, contiene tantos elementos como
colores haya en el bitmap
BYTE EL ABITMAPBITS []
Los colores del vector RGBQUAD suelen aparecer en orden de importancia
para ayudar al driver de visualizacin a dibujar el bitmap en un dispositivo
que no pueda visualizar tantos colores como los que tiene la imagen.
A diferencia de la mayora de los formatos grficos este se organiza en 4,
y no en 3 partes.
Estos datos pertenecen a la API, hay que incluir la Unit Windows en
Delphi para acceder a los mismos.
Me voy a concentrar en la estructura que me interesa para manejar la informacin de mi
problema, BITMAPINFOHEADER, que tiene la forma:
BITMAPINFOHEADER, de forma:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[ 1 ];
}BITMAPINFO;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize; // tamao de la informacin de cabecera
DWORD biWidth; // ancho en pixeles de la imgen
DWORD biHeight; // alto en pxeles
WORD biPlanes; // nro de planos de la imagen
WORD biBitCount; //nro de bits por pixel (puede valer 1, 4, 8 o 24)
DWORD biCompression; // compresion utilizada
DWORD biSizeImage;
// tamao de la imagen en bytes
DWORD biXpelsPerMeter; //pixeles por metro horizontal
DWORD biYPelsPerMeter; // pixeles por metro vertical
DWORD biClrUsed;
// nro de colores utilizados

DWORD biClrImportant;
son)
} BITMAPINFOHEADER;

// colores mas importantes (vale 0, si todos lo

Importante: Cabe aclarar que esta informacin no est en todo bitmap, ya que
depender de la manera en que la imagen sea creada: mediante scanner, computadora,
o cmara digital. Pero es importante tenerlo presente, ya que depender de su origen
para determinar si vamos a contar con esta informacin para su posterior
procesamiento.
(Si el origen son imgenes usadas en medicina, es muy probable que s contemos con
estos datos)
De todos modos, no me fue util a mis propsitos por los motivos que ya dir.
Cmo acceder desde Delphi:
procedure GetBitmapInfo(Filename: string;
var
Info: BITMAPINFOHEADER);
begin
FillChar(Info,Sizeof(Info),0);
with TFileStream.Create(Filename,fmOpenRead,
fmShareDenyWrite) do
try
Seek(Sizeof(BITMAPFILEHEADER),soFromBeginning);
ReadBuffer(Info,Sizeof(Info));
finally
Free;
end;
end;
La variable Info devuelve la estructura con los datos mencionados. Veamos como usarla:
// Por ejemplo
var
Info: BITMAPINFOHEADER;
Str: string;
begin
GetBitmapInfo('c:\1.bmp',Info);
Str:=
'Ancho = ' + IntToStr(Info.biWidth) + #13 +
'Alto = ' + IntToStr(Info.biHeight) + #13 +
'Profundidad en bits = ' + IntToStr(Info.biBitCount) + #13 +
'Resolucion horizontal = ' + IntToStr(Info.biXPelsPerMeter) +
' Pixeles por metro' + #13 +
'Resolucion vertical = ' + IntToStr(Info.biYPelsPerMeter) +
' Pixeles por metro' + #13;
case Info.biCompression of
BI_RGB: Str:= Str + 'Compresion = Sin comprimir';
BI_RLE8: Str:= Str + 'Compresion = RL8';
BI_RLE4: Str:= Str + 'Compresion = RLE4';
BI_BITFIELDS: Str:= Str + 'Compresion = BITFIELDS';
end;

ShowMessage(Str);
end;
Pensaba, y estaba en un error, que con los datosInfo.biXPelsPerMeter (pixeles por
metro), podra sacar la escala a mm para el eje Ox y aplicarla a mis medidas en pixeles
(lo mismo para el eje Oy).
No es asi, desconozco aun en base a qu se establece esa referencia a metros, pero lo
cierto es que no se corresponde con las dimensiones reales de la imagen.
Hecho que comprob empricamente con las medidas reales de mi imgen antes de
escanear. Tampoco se refiere a mm de pantalla, a partir de la escala hallada calcule los
mm, y distan de la medida real entre los puntos de pantalla.
(Reeditado) biXPelsPerMeter y biYPelsPerMeterEstos se refieren a los valores del
dispositivo destino, hecho a tener en cuenta si queremos almacenar la imagen que
estamos trabajando, conviene encontrar un dispositivo destino lo mas compatible con
esas magnitudes para evitar distorciones o mejor definicin.
Nota-1: los valores obtenidos en Info, coinciden con los que obtiene Photoshop cuando
nos dice la equivalencia entre pixeles y cms.
Nota-2: los valores de biXPelsPerMeter ybiYPelsPerMeter no cambian con la
resolucin, se mantienen constantes. Por lo que es la informacin que se guarda en el
bitmap al crearse. La misma debe estar relacionada con la resolucin y/o configuracin
del dispositivo que crea la imagen digitalizada. Estos valores, guardan relacin
con biWidth y biHeight (pixeles), valores que tambin se pueden obtener con
Photoshop, asi como la equivalencia en cms, y esta relacin dista de la medida de la
imagen real.
Me pareci interesante para compartir, porque entre otras cosas desconozco toda la
informacin que contiene un bmp y las variantes de uso que puede hacerse con ella.
Esto es solo un (simple) ejemplo.

Off Topic - Html: us los tags <pre> y </pre> desde el modo de edicin en HTML de
blogger para formatear el cdigo en Object Pascal de Delphi.

Intentando aprender manejo de bitmaps - II


Esto fue otras de las cosas que hice, usar la funcion de las API GetDeviceCaps , da
informacin especfica sobre cierto dispositivo, para identificarlo lo hacemos mediante un
handler, en mi caso el de la imagenimg.Bitmap.Canvas.Handle.
Estos son los parmetros de la funcin que cre necesarios para mis clculos:

HORZSIZE Anchura, en milmetros, de la pantalla fsica.

VERTSIZE Altura, en milmetros, de la pantalla fsica.

HORZRES Anchura, en pixels, de la pantalla.

VERTRES Altura, en lneas, de la pantalla.

Retomando la idea del post previo, la idea es calcular la correspondencia entre pixeles y
mm en la imgen real (sin digitalizar). Entonces dados 2 puntos, calculo la distancia en X
y en Y que los separa en pixels. Esas distancias corresponden a los catetos de un
tringulo rectngulo, luego convierto las mismas a mm, obteniendo los 'catetos en mm'.
Aplico Pitgoras para obtener la distancia en pixels y mm, ah tengo la relacin
mm/pixels.
Este mtodo no da el resultado que buscaba, pero si otro interesante: la medida de la
distancia real entre dos puntos de pantalla en mm.
img:TImage // contiene al bitmap
// Relacin horizontal y vertical entre pixels y mm
function TCmdCalcEscala.PixelHorizToMM(deltaX: Double): Double;
var
hdcDesk:HDC;
Begin
hdcDesk:= img.Bitmap.Canvas.Handle; //
Antes hdcDesk:= img.Canvas.Handle;
try
result:= deltaX * (GetDeviceCaps(hdcDesk, HORZSIZE) /
GetDeviceCaps(hdcDesk,HORZRES));
finally
ReleaseDC(hdcDesk, hdcDesk);
end;
End;>
// Relacin vertical entre pixels y mm
function TCmdCalcEscala.PixelVertiToMM(deltaY: Double): Double;
var
hdcDesk:HDC;
Begin
hdcDesk:= img.Bitmap.Canvas.Handle;
try
result:= deltaY * (GetDeviceCaps(hdcDesk, VERTSIZE) /
GetDeviceCaps(hdcDesk,VERTRES));
finally
ReleaseDC(hdcDesk, hdcDesk);
end;
End;
function TCmdCalcEscala.distancia(X,Y:Double): Double;
Begin
// X distancia horizontal, Y distancia vertical

result:=Abs(Sqrt(Sqr(x) + Sqr(y)));
End;
function TCmdCalcEscala.deltaPixels(X,Y:Double):Double;
Begin
result := Abs(X - Y);
End;
//Calcula la relacin entre pixels y mm.
procedure TCmdCalcEscala.ejecutar(Pto1:TPuntoVisual;Pto2:TPuntoVisual);
Var
distXpixel,distYpixel:Double;
distXmm,distYmm:Double;
Begin
distXpixel := deltaPixels(pto1.x,pto2.x); // Distancia horizontal
distYpixel := deltaPixels(pto1.y,pto2.y); // Distancia vertical
//Paso a mm esas distancias
distXmm := PixelHorizToMM(distXpixel);
distYmm := PixelVertiToMM(distYpixel);
//DistPixel, Distmm, FactorEscala son
propiedades de TCmdCalcEscala
DistPixels := distancia(distXpixel,distYpixel);
Distmm := distancia(distXmm,distYmm);
FactorEscala := Distmm/DistPixels;
End;
Ahi obtengo el factor escala que ser aplicado a todas las medidas posteriores, para las
medidas de los puntos en pantalla, creo que puede ser un resultado interesante.
No verifiqu si depende de la resolucin, pero es de esperar que asi sea ya que los
pixeles por pulgada estn en proporcin a la letra de la fuente.
Nota: el handler es el Canvas del objeto imagen TImage, pero podra ser la pantalla, y
para ello usamos la funcin API GetDC , nos devuelve el handler al dispositivo para el
rea de cliente de la ventana especificada.
Por rog a las 8:37 p. m.
Etiquetas: API, Bitmaps, Delphi, desarrollo

NO HAY COMENTARIOS.:
Publicar un comentario

VNCULOS A ESTA PUBLICACIN


Crear un vnculo
Entrada ms recienteEntrada antiguaPgina Principal

Suscribirse a: Comentarios de la entrada (Atom)

You might also like