Ir al contenido


Foto

Resta de imágenes


  • Por favor identifícate para responder
6 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 26 marzo 2011 - 05:04

Al trabajar con imágenes se nos puede plantear la necesidad de sustraer dos, con el fín de hacer patente las diferencias entre ambas.

Mediante esta técnica se puede ahorrar espacio al guardar secuencias de vídeo, por ejemplo. También puede indicar movimiento en sistemas de vigilancia. La sustracción digital también tiene utilidades para aislar ciertas diferencias tras realizar un marcado de ciertas estructuras.

Propongo un sencillo código que resta dos imágenes y devuelbe un HBITMAP con el resultado. Está basado en la potente y veloz API BitBlt y su capacidad de realizar operaciones binarias con los pixels de las imágenes.

Un XOR entre imágenes nos pondrán en negro sus semejanzas. A partir del resultado crearemos una máscara bicolor. Esta máscara tendrá en blanco las diferencias de imágenes y en negro las similitudes. Con la mascara realizamos un AND sobre una de las imágenes iniciales con lo que se preservan las diferencias. El resultado será negro en zonas iguales de las dos imágenes y el resto mostrará una imagen que resulta ser lo diferente entre las imágenes que hemos restado.

Unas imágenes de muestra:

post-175-14275693552638.jpg

post-175-14275693551929.jpg




cpp
  1. HBITMAP CreateSubstractBitmap(HDC DC1, HDC DC2)
  2. {
  3.   BITMAP Bitmap;
  4.   HBITMAP hMaskBmp, hResultBmp;
  5.   HDC hScreen = GetDC(0);
  6.   GetObject(GetCurrentObject(DC1, OBJ_BITMAP), sizeof(BITMAP), &Bitmap);
  7.   hMaskBmp = CreateBitmap(Bitmap.bmWidth, Bitmap.bmHeight, 1, 1, NULL);
  8.   hResultBmp = CreateBitmap(Bitmap.bmWidth, Bitmap.bmHeight, 1, 32, NULL);
  9.   HDC hResultDC  = CreateCompatibleDC(0);
  10.   HDC hMaskDC = CreateCompatibleDC(0);
  11.   HGDIOBJ  Old = SelectObject(hResultDC, hResultBmp);
  12.   SelectObject(hMaskDC, hMaskBmp);
  13.  
  14.   SetBkColor(hResultDC, 0);
  15.   BitBlt(hResultDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, DC1, 0, 0, SRCCOPY);
  16.   BitBlt(hResultDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, DC2, 0, 0, SRCINVERT);
  17.   BitBlt(hMaskDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, hResultDC, 0, 0, SRCCOPY);
  18.   BitBlt(hMaskDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, 0, 0, 0, DSTINVERT);
  19.   SetBkColor(hResultDC, clWhite);  //clWhite = 0xFFFFFF
  20.   BitBlt(hResultDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, DC1, 0, 0, SRCCOPY);
  21.   BitBlt(hResultDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, hMaskDC, 0, 0, SRCAND);
  22.  
  23.   SelectObject(hResultDC, Old);
  24.   DeleteObject(hMaskBmp);
  25.   ReleaseDC(0, hScreen);
  26.   DeleteDC(hResultDC);
  27.   DeleteDC(hMaskDC);
  28.  
  29.   return hResultBmp;
  30. }


Ejemplo:


cpp
  1.   Image3->Picture->Bitmap->Handle = CreateSubstractBitmap(Image1->Canvas->Handle, Image2->Canvas->Handle);



delphi
  1. function CreateSubstractBitmap(hDC1, hDC2: HDC): HBITMAP;
  2. var
  3.   hMaskBmp, Old: HBITMAP;
  4.   hScreenDC, hMaskDC, hResultDC: HDC;
  5.   Bitmap: TagBITMAP;
  6. begin
  7.   hScreenDC:= GetDC(0);
  8.   GetObject(GetCurrentObject(hDC1, OBJ_BITMAP), sizeof(BITMAP), @Bitmap);
  9.   hMaskBmp:= CreateBitmap(Bitmap.bmWidth, Bitmap.bmHeight, 1, 1, nil);
  10.   Result:= CreateBitmap(Bitmap.bmWidth, Bitmap.bmHeight, 1, 32, nil);
  11.   hResultDC:= CreateCompatibleDC(0);
  12.   hMaskDC:= CreateCompatibleDC(0);
  13.   Old:= SelectObject(hResultDC, Result);
  14.   SelectObject(hMaskDC, hMaskBmp);
  15.  
  16.   SetBkColor(hResultDC, 0);
  17.   BitBlt(hResultDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, hDC1, 0, 0, SRCCOPY);
  18.   BitBlt(hResultDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, hDC2, 0, 0, SRCINVERT);  // XOR
  19.   BitBlt(hMaskDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, hResultDC, 0, 0, SRCCOPY);
  20.   BitBlt(hMaskDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, 0, 0, 0, DSTINVERT);        // NOT
  21.   SetBkColor(hResultDC, clWhite); //clWhite:= $FFFFFF
  22.   BitBlt(hResultDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, hDC1, 0, 0, SRCCOPY);
  23.   BitBlt(hResultDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, hMaskDC, 0, 0, SRCAND);  // AND
  24.  
  25.   SelectObject(hResultDC, Old);
  26.   DeleteObject(hMaskBmp);
  27.   ReleaseDC(0, hScreenDC);
  28.   DeleteDC(hResultDC);
  29.   DeleteDC(hMaskDC);
  30. end;


Ejemplo:

delphi
  1.   Image3.Picture.Bitmap.Handle:= CreateSubstractBitmap(Image1.Canvas.Handle, Image2.Canvas.Handle);




Espero que os sea de utilidad.




Saludos.

Archivos adjuntos


  • 0

#2 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 26 marzo 2011 - 05:15

Gracias maestro Escafandra, como siempre excelente código.    (y) (y)

PD: No puedo ver las imágenes, solo 2 ranas. Debe ser alguna cookie que se obtiene al registrarse o visitar bit.ly/imageshack-domain.

Googleando obtuve esto.

If you don't want to wait, you can also register and login to ImageShack, and all images will be visible for you.
Register your domain with ImageShack so that all images are visible on it. Only Owners, Administrators, Operators, or Moderators may register the domain.


  • 0

#3 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 26 marzo 2011 - 05:31

Bueno, las he subido al foro, así no se pierden.  :)


Saludos.


  • 0

#4 Caral

Caral

    Advanced Member

  • Moderador
  • PipPipPip
  • 4.266 mensajes
  • LocationCosta Rica

Escrito 26 marzo 2011 - 05:55

Hola
Muy bueno Maestro.
Me parece interesantisimo para muchas aplicaciones. (y) (b)
Saludos
  • 0

#5 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 26 marzo 2011 - 06:07

Bueno, las he subido al foro, así no se pierden. 
Saludos.


Ahora las puedo ver, muy buen efecto. Una pregunta ¿Es posible la operación inversa? Osea obtener las 2 imágenes originales a partir de la tercera?

Muchas gracias.
  • 0

#6 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.111 mensajes
  • LocationMadrid - España

Escrito 27 marzo 2011 - 04:36

Ahora las puedo ver, muy buen efecto. Una pregunta ¿Es posible la operación inversa? Osea obtener las 2 imágenes originales a partir de la tercera?



Pues tal y como está planteada la función, no. Sería como pretender encontrar los dos operandos de una resta sabiendo sólo el resultado... ;)




Saludos.
  • 0

#7 andres1569

andres1569

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 431 mensajes

Escrito 28 marzo 2011 - 12:00

Muy interesante, Escafandra(y)  recuerdo que hace unos cuantos años programé algo parecido para obtener la diferencia entre dos imágenes en una tercera, pintando de color rojo la parte diferente, lo hice "a pelo", mediante scanlines, con bastante más código que éste. A propósito del uso de los códigos ROP (SRCINVERT, SRCCOPY ... etc) de mapeo de píxels empleado por la función BitBlt, hace apenas unos días revisando un libro del API gráfico de Windows, flipé viendo que había documentados casi 300 de estos códigos  :| , los hay para todos los gustos, aunque normalmente en las ayudas se muestran unos 15 como los más comunes.

Comentario chorra: Ahora cuando veamos un pasatiempo de esos de encontrar las diferencias lo tenemos muy fácil (si está en papel lo escaneamos) le pasamos este código y no se nos escapará ni una.  ;)

Saludos
  • 0




IP.Board spam blocked by CleanTalk.