DESARROLLO:




 


C.1.DESARROLLO




C.1.1.Conceptos Aplicados Para El Desarrollo

C.1.1.1.¿Qué es un "Pixel"?

Las DIMENSIONES DE PÍXEL son las medidas horizontales y verticales de una imagen, expresadas en píxeles. Las dimensiones de píxel se pueden determinar multiplicando tanto el ancho como la altura por el dpi.

Este es el motivo por el cual dots-per-inch (puntos por pulgada) (dpi) o pixels-per-inch (píxeles por pulgada) (ppi) son términos comunes y sinónimos utilizados para expresar la resolución de imágenes digitales.

La PROFUNDIDAD DE BITS es determinada por la cantidad de bits utilizados para definir cada píxel. Cuanto mayor sea la profundidad de bits, tanto mayor será la cantidad de tonos (escala de grises o color) que puedan ser representados. Las imágenes digitales se pueden producir en blanco y negro (en forma bitonal), a escala de grises o a color.

Una imagen bitonal está representada por píxeles que constan de 1 bit cada uno, que pueden representar dos tonos, utilizando los valores 0 para el negro y 1 para el blanco.

Una imagen a escala de grises está compuesta por píxeles representados por múltiples bits de información, que típicamente varían entre 2 a 8 bits o más.

Ejemplo: En una imagen de 2 bits, existen cuatro combinaciones posibles: 00, 01, 10 y 11. Si "00" representa el negro, y "11" representa el blanco, entonces "01" es igual a gris oscuro y "10" es igual a gris claro. La profundidad de bits es dos, pero la cantidad de tonos que pueden representarse es 22 ó 4. A 8 bits, pueden asignarse 256 (28) tonos diferentes a cada píxel.

Una imagen a color está típicamente representada por una profundidad de bits entre 8 y 24 o superior a ésta. En una imagen de 24 bits, los bits por lo general están divididos en tres grupos: 8 para el rojo, 8 para el verde, y 8 para el azul. Para representar otros colores se utilizan combinaciones de esos bits. Una imagen de 24 bits ofrece 16,7 millones (224) de valores de color. Cada vez más, los scáners están capturando 10 bits o más por canal de color y por lo general imprimen a 8 bits para compensar el "ruido" del escáner y para presentar una imagen que se acerque en el mayor grado posible a la percepción humana.

Profundidad de bits: De izquierda a derecha - imagen bitonal de 1 bit, a escala de grises de 8 bits, y a color de 24 bits.

Cálculos binarios para la cantidad de tonos representados por profundidades de bits comunes:

1 bit (21) = 2 tonos
2 bits (22) = 4 tonos
3 bits (23) = 8 tonos
4 bits (24) = 16 tonos
8 bits (28) = 256 tonos
16 bits (216) = 65.536 tonos
24 bits (224) = 16,7 millones de tonos

C.1.1.2.¿Qué es RGB?

C.1.1.2.1. Colores primarios de la luz

La luz tiene tres colores primarios: rojo, verde y azul. Combinando esos colores primarios en diversas intensidades podemos conseguir todos los colores visibles.

Si representamos la intensidad de cada color primario con un número, entonces podemos representar los colores con tres números (uno para el rojo, uno para el verde y uno para el azul). Esta forma de representar los colores con números para la intensidad de los componentes rojo, verde y azul de la luz se conoce como el sistema de color RGB (del inglés Red, Green y Blue, que en castellano suele referirse como RVA: Rojo, Verde y Azul).

C.1.1.2.2. El sistema de color RGB (RVA)

Si se utilizan los números enteros en el rango 0..255 (un byte), es decir 256 valores posibles para cada color primario, entonces con tres bytes se puede representar 256 x 256 x 256 combinaciones diferentes de los colores primarios, es decir una gama de más de 16 millones de colores (frecuentemente referida como "color verdadero"). Este sistema de color RGB se conoce como RGB-256.

Algunos programas utilizan un sistema conocido como RGB-100, que utiliza números en el rango 0..100 para indicar un porcentaje de intensidad (0%=apagado; 100%=máximo). En los ejemplos se utiliza RGB-256 porque es el más popular.

C.1.1.2.3. Tonos de grises

El color negro es la ausencia de color (o la ausencia de luz) y se representa como RGB(0,0,0) (Rojo=0, Verde=0, Azul=0). El blanco es la presencia de todos los colores (en su intensidad máxima) y se representa entonces como RGB(255,255,255) (Rojo=255, Verde=255, Azul=255). Todos los tonos de grises del negro al blanco se representan con tres valores iguales para los componentes rojo, verde y azul (ningún color predomina), es decir que tienen la forma RGB(x, x, x). Por ejemplo, el color definido en la jerga como "gris claro" se representa como RGB(192,192,192), y el "gris oscuro" es RGB(128,128,128).

Tabla C.1 :Tonos de Grises

RGB(0,0,0) = Negro

RGB(128,128,128) = Gris oscuro

RGB(192,192,192) = Gris claro

RGB(255,255,255) = Blanco

 

C.1.1.2.4.Colores Primarios

Para comenzar, los colores primarios se representan de esta manera:

Tabla C.2 :Colores Primarios

RGB(255,0,0) = Rojo claro (o rojo brillante, o rojo intenso)

RGB(0,255,0) = Verde claro (o verde brillante, o verde intenso)

RGB(0,0,255) = Azul claro (o azul brillante, o azul intenso)

 

Sus versiones oscuras serían:

Tabla C.3 :Colores Primarios Oscuros

RGB(128,0,0) = Rojo oscuro

RGB(0,128,0) = Verde oscuro

RGB(0,0,128) = Azul oscuro

Las diferentes intensidades de rojo tienen la forma RGB(x,0,0), las de verde tienen la forma RGB(0,x,0) y las de azul son de la forma RGB(0,0,x).

C.1.1.2.5.Colores Secundarios

Los colores secundarios de la luz son cian, magenta y amarillo, y resultan de la combinación de diferentes pares de los colores primarios en iguales intensidades. Por ejemplo, sus versiones brillantes serían:

Tabla C.4 :Colores Secundarios

RGB(0,255,255) = Cian claro = verde claro + azul claro

RGB(255,0,255) = Magenta claro = rojo claro + azul claro

RGB(255,255,0) = Amarillo claro = rojo claro + verde claro

La versiones oscuras de los colores secundarios serían:

Tabla C.5 :Colores Secundarios Oscuros

RGB(0,128,128) = Cian oscuro = verde oscuro + azul oscuro

RGB(128,0,128) = Magenta oscuro = rojo oscuro + azul oscuro

RGB(128,128,0) = Amarillo oscuro = rojo oscuro + verde oscuro

Como puede ver, las diferentes intensidades de cian son de la forma RGB(0,x,x), las de magenta tienen la forma RGB(x,0,x) y las de azul son de la forma RGB(x,x,0).

 

C.1.1.2.6.Colores Puros

Los colores puros o saturados combinan sólo dos colores primarios y tienen la forma RGB(x,y,0), RGB(y,x,0), RGB(0,x,y), RGB(0,y,x), RGB(x,y,0) o RGB(y,x,0) donde x <> 0 y x >= y:

C.1.1.2.7.Matiz y luminosidad

Los colores de la misma forma que tienen la misma relación x/y se dice que tienen el mismo "matiz". Por ejemplo, RGB(255,128,0) y RGB(192,96,0) son de la misma forma (RGB(x,y,0)) y tienen la misma relación x/y (255/128 = 192/96), así que tienen el mismo matiz. El "matiz" es lo que incorrectamente con frecuencia se refieren como "color". Por ejemplo, en este caso el matiz de ambos colores es "naranja", pero es naranja brillante y el otro es naranja oscuro, es decir, comparten el mismo "matiz", pero difieren en la "luminosidad". La luminosidad mide cuán cercano un color está del blanco, y se representa usualmente como un porcentaje. Por ejemplo, RGB(192,96,0) es un naranja con una luminosidad de 75%, y RGB(128,64,0) es un naranja con una luminosidad de 50%.

Tabla C.6 :Colores Puros

RGB(255,128,0) = Naranja 100% luminosidad

RGB(192,96,0) = Naranja 75% luminosidad

RGB(128,64,0) = Naranja 50% luminosidad

El matiz de RGB(0,0,128) y de RGB(0,0,64) es el azul, pero el segundo color tiene un 50% de la luminosidad del primero (tienen una luminosidad de 50% y 25% respectivamente).

C.1.1.2.8.Saturación

Aparte del matiz y la luminosidad, los colores se definen por un tercer parámetro conocido como "saturación", que mide la pureza de un color. Hasta aquí hemos tratado con colores 100% puros. Los colores impuros son colores puros mezclados con gris. Mientras mas mezclado con gris, más saturado es un color. Por ejemplo, RGB(192,128,64) tiene el mismo matiz y luminosidad que el naranja brillante RGB(255,128,0), pero un 50% de saturación, y resulta de mezclar el naranja brillante con el gris medio RGB(128,128,128):

           naranja  gris
  Rojo  = (  255  + 128 ) / 2 = 192
  Verde = (  128  + 128 ) / 2 = 128
  Azul  = (   0   + 128 ) / 2 = 64

Si nuevamente mezclamos el resultado con gris medio, obtendríamos un naranja con 25% de saturación RGB(160,128,96), aún más cercano al gris medio. Si se mezcla gris otra vez, obtiene un naranja con una saturación de sólo un 12,5% RGB(144,128,112), casi un gris medio.

Nótese que un color es más saturado cuando la diferencia entre los valores RGB es más grande. Cuando los valores RGB son más cercanos unos de otros, el color es menos saturado (es decir, es más grisáceo, o se puede decir que es menos "saturado", "vivo", "vívido" o "puro").

La saturación se puede calcular con la siguiente fórmula:

  Saturación = ((máximo-medio) + (medio-mínimo)) / 255 * 100%

Por ejemplo:

  Saturación(160,128,96) = ((160-128) + (128-96)) / 255 * 100%
                  = (32 + 32) / 255 * 100%
                  = 64 / 255 * 100%
  Saturación(160,128,96) = 25%

C.1.1.2.9.Representación Entera

Los tres bytes que representan un color se pueden combinar en una constante entera de 32-bit, representada normalmente en notación hexadecimal. Por ejemplo, RGB(160,128,96) es 6080A0:

  Rojo  (RR) = 160 decimal = A0 hexadecimal
  Verde (GG) = 128 decimal = 80 hexadecimal
  Azul  (BB) =  96 decimal = 60 hexadecimal

Nótese que las constantes de color tienen la forma BBGGRR, donde BB es el byte (dos dígitos hexadecimales) para el azul (blue), GG es el byte para el verde (green) y RR es el byte para el rojo (red). La razón es que los enteros se almacenan con el byte menos significativo primero, así que BBGGRR se almacena como RRGGBB, el orden en que se esperan los valores RGB (por ejemplo 6080A0 se almacena internamente como A08060).

C.1.1.2.10.RGB(red-green-blue)

RGB en el sistema de color más utilizado por la mayoría de los formatos actuales. Es un sistema aditivo que variando la cantidad de color rojo, verde y azul agregados al negro, se produce nuevos colores. En los archivos gráficos el sistema RGB se usa para representar cada pixel con un tripleta de la forma (R,G,B).

Representando el modelo en un cubo unitario (Fig.C.1), cada componente de la tripleta toma valores en el rango de 0 a 1. Así un color Cl se expresa:

Cl = RR + GG + BB

(Fig.C.1:Modelo de un Cubo Unitario)

Para los valores de 24-bits la tripleta (0, 0, 0) representa al negro, mientras que (255, 255, 255) representa al blanco. Cuando los tres valores RGB tienen un mismo valor - (63, 63, 63) o (127, 127, 127) o (191, 191, 191) por ejemplo - el color resultante en un tono de gris (Fig.C.2).

(Fig.C.2:Modelo de un Cubo RGB)

Con base en la teoría de tres estímulos de la visión, nuestros ojos perciben los colores mediante el estímulo de tres pigmentos visuales en los conos de la retina. Estos pigmentos visuales tienen la sensibilidad pico en longitudes de onda de alrededor de 630 nm (rojo), 530 nm (verde) y 450 nm (azul).

C.1.1.3.Digitalización de la imagen

Toda imagen encierra una gran cantidad de información acerca del objeto representado. La imagen obtenida con una fotografía o un aparato de rayos X, de una estructura, sin tratamiento informático alguno, se llama imagen analógica, porque es una representación análoga a esa estructura, y contiene una distribución continua de brillos, cuyos límites están dentro de los márgenes de dicha imagen. Con un sistema informático, los diferentes brillos o densidades continuas tienen una representación de sus valores máximo y mínimo, con unos límites concretos, en una escala de tonos o en una escala de grises. Así, en una distribución espacial, esos valores de grises pueden tener una posición definida, con un valor de gris concreto. A cada una de estas posiciones o elementos de la imagen se les denomina pixels, y a este tipo de representación es a lo que se llama imagen digital. Cuando se digitaliza una imagen analógica, se pierde algo de la información, sobre todo en los detalles finos, pero en cambio, se obtiene la posibilidad de actuar sobre ella electrónicamente: se puede cuantificar la información, y modificarla en algunos aspectos para mejorar su visualización. Es una imagen electrónica, y el ordenador la trata, utilizando el sistema binario: el ordenador sólo maneja 2 dígitos (0 y 1), aislados, o en combinaciones que permiten representar cualquier cantidad de que uno desee expresar. La unidad mínima funcional del ordenador es el Bit (binary digit point punt). Los bits se agrupan en ocho posiciones, las cuales constituyen el Byte.

C.1.1.4.Adquisicion de Datos

La adquisición de datos del campo, donde se esta aplicando un sistema de control de imagen, se realiza con una cámara de vídeo, la cual puede transformar las ondas de luz en señales electrónicas que sean reflejo fiel de las imágenes.

Un sistema de lentes de la cámara enfoca la imagen a un traductor que efectúa la conversión. Un tipo de traductor es el CCD (Charge-Coupled Device, Dispositivo acoplado a carga), que es una memoria electrónica que puede ser cargada mediante luz. Son analógicos y están construidos con un tipo especial de transistor CMOS.

Para aprovechar su funcionalidad, se utilizan en combinación con convertidores de señal (ADC) analógica a digital, para cuantificar la carga variable dentro de un número discreto de colores.

Una vez que la señal es digitalizada es enviada a la CPU por un puerto USB.

 

C.1.2.Desarrollo del Software

 

 

 

C.1.2.1.Código de Visual C (Comentado paso por paso):

 

// DetectCambio.cpp : Defines the initialization routines for the DLL.

//

#include "stdafx.h"

#include "DetectCambio.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

//

// Note!

//

// If this DLL is dynamically linked against the MFC

// DLLs, any functions exported from this DLL which

// call into MFC must have the AFX_MANAGE_STATE macro

// added at the very beginning of the function.

//

// For example:

//

// extern "C" BOOL PASCAL EXPORT ExportedFunction()

// {

// AFX_MANAGE_STATE(AfxGetStaticModuleState());

// // normal function body here

// }

//

// It is very important that this macro appear in each

// function, prior to any calls into MFC. This means that

// it must appear as the first statement within the

// function, even before any object variable declarations

// as their constructors may generate calls into the MFC

// DLL.

//

// Please see MFC Technical Notes 33 and 58 for additional

// details.

//

/////////////////////////////////////////////////////////////////////////////

// CDetectCambioApp

BEGIN_MESSAGE_MAP(CDetectCambioApp, CWinApp)

//{{AFX_MSG_MAP(CDetectCambioApp)

// NOTE - the ClassWizard will add and remove mapping macros here.

// DO NOT EDIT what you see in these blocks of generated code!

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

// CDetectCambioApp construction

CDetectCambioApp::CDetectCambioApp()

{

// TODO: add construction code here,

// Place all significant initialization in InitInstance

m_nTamX=0;

m_nTamY=0;

m_nUmbral=0;

}

/////////////////////////////////////////////////////////////////////////////

// The one and only CDetectCambioApp object

bool LeerMat();

void GuardarMat();

bool bInicio=false;

bool bFirst=true;

CDetectCambioApp dllApp;

CMatrixRGB g_Mat;

bool CDetectCambioApp::GetBMPInfo(CString pszFile, BYTE ** pByte,DWORD &dwWidth,DWORD &dwHeight,DWORD &dwSizeImage)

{

bool bRet=false;

HANDLE hf; // handle a archivo

BITMAPFILEHEADER hdr; // bitmap file-header

BITMAPINFO bi;

PBITMAPINFOHEADER pbih; //bitmap info-header

DWORD dwTmp=0;

*pByte=NULL;

hf = CreateFile((LPCTSTR)pszFile, //levanto archivo

GENERIC_READ,

(DWORD) 0,

NULL,

OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL,

(HANDLE) NULL);

try

{

if (hf != INVALID_HANDLE_VALUE) //si el handle no es invalido por algún error al tomar el archivo

{

if(ReadFile(hf,(LPVOID) &hdr, sizeof(BITMAPFILEHEADER), //lee la cabezera del BITMAP FILE HEADER

(LPDWORD) &dwTmp, NULL))

{

dwSizeImage=hdr.bfSize - hdr.bfOffBits; //tamaño en bytes de la imagen

if(!dwSizeImage)

AfxMessageBox("SizeImage es cero",MB_OK | MB_ICONSTOP,NULL);

if(ReadFile(hf,(LPVOID) &bi,(hdr.bfSize - (dwSizeImage + sizeof(BITMAPFILEHEADER))), //lee cabecera de BMP

(LPDWORD) &dwTmp, NULL))

{

pbih = (PBITMAPINFOHEADER) &bi;

if(pbih->biCompression==BI_RGB && pbih->biBitCount==24) //si el formato es BMP de 24 bit

{

dwWidth=pbih->biWidth;

dwHeight=pbih->biHeight;

*pByte=new BYTE[dwSizeImage];

if(!ReadFile(hf,(LPVOID) *pByte,dwSizeImage,&dwTmp,NULL)) //lee información de la imagen en un array

{

AfxMessageBox("Error al leer la imagen | MB_ICONSTOP",MB_OK,NULL);

if(*pByte)

{

delete *pByte;

*pByte=NULL;

}

}

else

bRet=true;

}

else

AfxMessageBox("Formato invalido en archivo bmp",MB_OK | MB_ICONSTOP,NULL);

}

else

AfxMessageBox("Error al leer la info de bmp",MB_OK | MB_ICONSTOP,NULL);

}

else

AfxMessageBox("Error al leer encabezado de bmp",MB_OK | MB_ICONSTOP,NULL);

CloseHandle(hf);

}

else

AfxMessageBox("Error en Handle de archivo",MB_OK | MB_ICONSTOP,NULL);

}

catch(CException * Ex)

{

AfxMessageBox("Error Inesperado en GetBMPInfo",MB_OK | MB_ICONSTOP,NULL);

Ex->Delete();

}

return bRet;

}

 

bool CDetectCambioApp::MakeMatrixRGB(LPBYTE pInfo, DWORD dwWidth, DWORD dwHeigth, DWORD dwSizeImage, CMatrixRGB &Mat)

{

bool bNeg=true,bRet=true;

int x,y,aux;

DWORD i,j,PixX,ResX,LongX,OffSetX,PixY,ResY,LongY,OffSetY,OffSet;

sRGB rgb,zero;

zero.nBlue=0;

zero.nGreen=0;

zero.nRed=0;

if(dwHeigth<0) // recorrida de la imagen desde arriba hacia abajo

dwHeigth=abs(dwHeigth); //lo hace positivo

else // recorrida de la imagen desde abajo hacia arriba

bNeg=false;

PixX=dwWidth/m_nTamX;

ResX=dwWidth%m_nTamX;

PixY=dwHeigth/m_nTamY;

ResY=dwHeigth%m_nTamY;

try

{

for(y=0;y<m_nTamY;y++) //recorrido vertical de los cuadros

{

for(x=0;x<m_nTamX;x++) //recorrido horizontal de los cuadros

{

OffSet=dwWidth * PixY * y + PixX * x;

rgb=zero;

if(y==(m_nTamY-1))

LongY=PixY+ResY;

else

LongY=PixY;

for(j=0;j<LongY;j++) //recorrido vertical de pixeles del cuadro elegido

{

OffSetY=OffSet + (dwWidth * j);

if(x==(m_nTamX-1))

LongX=PixX+ResX;

else

LongX=PixX;

for(i=0;i<LongX;i++) //recorrido horizontal de los pixeles del cuadro elegido

{

OffSetX=i; // un Pixel equivale a 3 BYTES(24 bits) del RGB

if(dwSizeImage>(sizeof(RGBTRIPLE)*(OffSetY + OffSetX)+2))

{

rgb.nRed+=(int) pInfo[sizeof(RGBTRIPLE)*(OffSetY + OffSetX)]; //acumula RED

rgb.nGreen+=(int) pInfo[sizeof(RGBTRIPLE)*(OffSetY + OffSetX)+1]; //acumula GREEN

rgb.nBlue+=(int) pInfo[sizeof(RGBTRIPLE)*(OffSetY + OffSetX)+2]; //acumula BLUE

}

}

}

if(LongX*LongY) //si la cantidad de pixeles no es cero

{

rgb.nRed=rgb.nRed/(int)(LongX*LongY); //saca promedio por cada color

rgb.nGreen=rgb.nGreen/(int)(LongX*LongY);

rgb.nBlue=rgb.nBlue/(int)(LongX*LongY);

}

else

return false;

if(bNeg) //imagen top-down

Mat.SetPos(x,y); //posiciona la matriz en el cuadro analizado

else

{ //imagen bottom-up

Mat.SetPos(x,(m_nTamY-y)-1); //posiciona la matriz en el cuadro analizado

aux=rgb.nRed; //intercambia RED por BLUE porque la información esta al revés

rgb.nRed=rgb.nBlue;

rgb.nBlue=aux;

}

Mat.SetRGB(rgb); //coloca promedio del cuadro RGB en la matriz

}

}

}

catch(CMemoryException * MEx)

{

bRet=false;

AfxMessageBox("Error de Memoria en MakeMatrixRGB",MB_OK | MB_ICONSTOP,NULL);

MEx->Delete();

}

catch(CException * Ex)

{

bRet=false;

AfxMessageBox("Error Inesperado en MakeMatrixRGB",MB_OK | MB_ICONSTOP,NULL);

Ex->Delete();

}

return bRet;

}

bool CDetectCambioApp::DetectarMovimiento(CMatrixRGB &MatOld, CMatrixRGB &MatNew)

{

bool bRet=false;

sRGB rgbA,rgbB;

CString str;

int Red=0,Green=0,Blue=0;

int x,y;

for(x=0;x<m_nTamX;x++) //recorrida de la matrix horizontal

{

for(y=0;y<m_nTamY;y++) //recorrida de la matriz vertical

{

MatOld.SetPos(x,y); //posiciona

rgbA=MatOld.GetRGB(); //obtiene RGB

MatNew.SetPos(x,y);

rgbB=MatNew.GetRGB();

Red=abs(rgbA.nRed-rgbB.nRed); //valor absoluto de la diferencia de color entre ambas matrices

Green=abs(rgbA.nGreen-rgbB.nGreen);

Blue=abs(rgbA.nBlue-rgbB.nBlue);

if(Red>=m_nUmbral || Green>=m_nUmbral || Blue>=m_nUmbral) //si algún valor absoluto de cada

bRet=true; //color es mayor igual al umbral detecta cambio

}

}

MatOld=MatNew; //asigna como matriz vieja a la nueva matriz ingresada

return bRet;

}

 

__declspec(dllexport) short int __stdcall Iniciar(short TamX,short TamY, short Umbral) //Inicia Tamaño de matriz RGB

{

dllApp.m_nTamX=TamX; //Asignación de valores globales

dllApp.m_nTamY=TamY;

dllApp.m_nUmbral=Umbral;

g_Mat.Create(dllApp.m_nTamX,dllApp.m_nTamY); //Crea objeto Matriz RGB

bInicio=true; //Matrix iniciada

bFirst=true; //Primera imagen

return 0;

}

 

__declspec(dllexport) short int __stdcall Detectar(VARIANT vtFile) //Detecta cambio de la imagen nueva con respecto a la anterior

{

short int ret=0; //retorno por defecto

BYTE * pByte=NULL;

DWORD dwWidth,dwHeight,dwSizeImage;

CString strFile;

CMatrixRGB Mat;

strFile=vtFile.bstrVal;

if(!bInicio) //Si no esta iniciada la matriz retorna error

return -1;

Mat.Create(dllApp.m_nTamX,dllApp.m_nTamY); //Crea matriz nueva.

if(dllApp.GetBMPInfo(strFile,&pByte,dwWidth,dwHeight,dwSizeImage)) //Obtiene los datos de la imagen BMP de 24 bits de color

{

if((DWORD)dllApp.m_nTamX<=dwWidth && (DWORD)dllApp.m_nTamY<=dwHeight) //si el tamaño de la imagen en pixeles es menor al

{ //de la cantidad de cuadros a analizar da error

if(dllApp.MakeMatrixRGB((LPBYTE) pByte,dwWidth,dwHeight,dwSizeImage,Mat)) //crea matriz según la imagen de entrada

{

if(dllApp.DetectarMovimiento(g_Mat,Mat)) //Detecta cambios entre la matriz nueva y la anterior y la guarda

ret=1; //valor si detecto cambios.

if(bFirst) //si es la primera imagen a partir de la inicialización

{

ret=1; //Fuerza el valor de retorno como si hubiera cambios

bFirst=false; //la primera ya pasó

}

}

}

else

ret=-3; //retorna error en tamaño de imagen con respecto a la de cuadros

}

if(pByte)

delete pByte;

else

ret=-2; //Error al tomar la imagen (Error de archivo o de formato)

return ret; //Respuesta a la detección.

}

 

 

 

// MatrixRGB.cpp : implementation file

//

#include "StdAfx.h"

#include "MatrixRGB.h"

CMatrixRGB::CMatrixRGB()

{

m_bInit=false;

m_nX=0;

m_nY=0;

m_nMaxX=0;

m_nMaxY=0;

m_Mat=NULL;

}

CMatrixRGB::CMatrixRGB(int x,int y)

{

int i;

m_nX=0;

m_nY=0;

m_nMaxX=x;

m_nMaxY=y;

m_Mat=NULL;

if(x>0 && y>0)

{

m_bInit=true;

try

{

m_Mat=new sRGB * [y];

if(m_Mat)

{

for(i=0;i<y;i++)

{

m_Mat[i]=NULL;

m_Mat[i]=new sRGB[x];

if(!m_Mat[i])

m_bInit=false;

}

}

else

m_bInit=false;

}

catch(CMemoryException * MEx)

{

m_bInit=false;

MEx->Delete();

}

if(m_bInit)

InitAll();

else

Destroy();

}

else

m_bInit=false;

}

CMatrixRGB::~CMatrixRGB()

{

Destroy();

}

void CMatrixRGB::Create(int x, int y)

{

int i;

if(m_bInit)

Destroy();

m_nX=0;

m_nY=0;

m_nMaxX=x;

m_nMaxY=y;

if(x>0 && y>0)

{

m_bInit=true;

try

{

m_Mat=new sRGB * [y];

if(m_Mat)

{

for(i=0;i<y;i++)

{

m_Mat[i]=NULL;

m_Mat[i]=new sRGB[x];

if(!m_Mat[i])

m_bInit=false;

}

}

else

m_bInit=false;

}

catch(CMemoryException * MEx)

{

m_bInit=false;

MEx->Delete();

}

if(m_bInit)

InitAll();

}

else

m_bInit=false;

}

 

bool CMatrixRGB::SetPos(int x, int y)

{

bool bRet=false;

if(m_bInit)

{

if(x<m_nMaxX && y<m_nMaxY)

{

m_nX=x;

m_nY=y;

bRet=true;

}

}

return bRet;

}

void CMatrixRGB::GetPos(int &x,int &y)

{

x=m_nX;

y=m_nY;

}

void CMatrixRGB::SetRGB(sRGB rgb)

{

if(m_bInit)

m_Mat[m_nY][m_nX]=rgb;

}

sRGB CMatrixRGB::GetRGB(void)

{

sRGB rgb;

if(m_bInit)

rgb=m_Mat[m_nY][m_nX];

else

{

rgb.nBlue=0;

rgb.nGreen=0;

rgb.nRed=0;

}

return rgb;

}

void CMatrixRGB::InitAll()

{

int i,j;

sRGB rgb;

rgb.nBlue=0;

rgb.nGreen=0;

rgb.nRed=0;

if(m_bInit)

{

for(i=0;i<m_nMaxY;i++)

for(j=0;j<m_nMaxX;j++)

m_Mat[i][j]=rgb;

}

}

void CMatrixRGB::operator=(CMatrixRGB &Mat)

{

int x,y;

if(m_nMaxX!=Mat.m_nMaxX || m_nMaxY!=Mat.m_nMaxY)

Create(Mat.m_nMaxX,Mat.m_nMaxY);

if(m_bInit)

{

for(x=0;x<m_nMaxX;x++)

{

for(y=0;y<m_nMaxY;y++)

{

if(SetPos(x,y) && Mat.SetPos(x,y))

SetRGB(Mat.GetRGB());

}

}

}

}

void CMatrixRGB::Destroy()

{

int i;

try

{

if(m_Mat)

{

for(i=0;i<m_nMaxY;i++)

{

if(m_Mat[i])

delete []m_Mat[i];

}

delete []m_Mat;

}

m_bInit=false;

m_nX=0;

m_nMaxX=0;

m_nY=0;

m_nMaxY=0;

m_Mat=NULL;

}

catch(CMemoryException * MEx)

{

MEx->Delete();

}

}

 

 

void CMatrixRGB::Serialize(CArchive &ar)

{

int i,j,aux;

sRGB rgb;

if(ar.IsStoring())

{

ar<<m_nX;

ar<<m_nY;

ar<<m_nMaxX;

ar<<m_nMaxY;

aux=(int) m_bInit;

ar<<aux;

if(m_bInit)

{

for(i=0;i<m_nMaxX;i++)

{

for(j=0;j<m_nMaxY;j++)

{

if(SetPos(i,j))

{

rgb=GetRGB();

ar<<rgb.nRed;

ar<<rgb.nGreen;

ar<<rgb.nBlue;

}

}

}

}

}

else

{

if(m_bInit)

Destroy();

ar>>m_nX;

ar>>m_nY;

ar>>m_nMaxX;

ar>>m_nMaxY;

ar>>aux;

m_bInit=(bool) aux;

if(m_bInit)

{

try

{

m_Mat=new sRGB * [m_nMaxY];

if(m_Mat)

{

for(i=0;i<m_nMaxY;i++)

{

m_Mat[i]=NULL;

m_Mat[i]=new sRGB[m_nMaxX];

if(!m_Mat[i])

m_bInit=false;

}

}

else

m_bInit=false;

}

catch(CMemoryException * MEx)

{

m_bInit=false;

MEx->Delete();

}

if(m_bInit)

{

for(i=0;i<m_nMaxX;i++)

{

for(j=0;j<m_nMaxY;j++)

{

ar>>rgb.nRed;

ar>>rgb.nGreen;

ar>>rgb.nBlue;

if(SetPos(i,j))

SetRGB(rgb);

}

}

}

else

Destroy();

}

}

}

 

// stdafx.cpp : source file that includes just the standard includes

// DetectCambio.pch will be the pre-compiled header

// stdafx.obj will contain the pre-compiled type information

#include "stdafx.h"

 

C.1.2.2.Código de Visual Basic (Comentado paso por paso):

FrmPictDiff(FrmPictDiff.frm):

 

Option Explicit

Dim filephat As String

Private Sub cmdComp_Click()

Dim cont As Integer

Dim vrFile As String

Dim intRet As Integer

Dim intResp As Integer

'---------------------------------------------------------------

'Verificación de la existencia de imágenes en la lista de comparación

'---------------------------------------------------------------

If List2.ListCount = 0 Then

If List1.ListCount <> 0 Then

If List1.ListCount > 1 Then

' ------------------------------------------------------------

'|Llamada a la función de inicialización de la DLL ("Iniciar")|

' ------------------------------------------------------------

intRet = Iniciar(TamX, TamY, Umbral)

For cont = 0 To List1.ListCount - 1

vrFile = filephat & List1.List(cont)

'------------------------------------------------------------------------------

'|Llamada a la función de control de cambios de imágenes de la DLL ("Detectar")|

'------------------------------------------------------------------------------

intResp = Detectar(vrFile)

If intResp < 0 Then

MsgBox "Error al querer comparar imagenes", vbCritical

Exit For

End If

' ------------------------------------------------------------------

'|Realiza carga de archivos .BMP distintos en la lista de resultados

' ------------------------------------------------------------------

If intResp = 1 Then

List2.AddItem List1.List(cont)

End If

DoEvents

Next

lblResumen = "Imagenes Analizadas: " & List1.ListCount & Space(6) & "Imagenes Distintas: " & List2.ListCount

Else

MsgBox "Se necesitan 2 imágenes como mínimo para realizar la comparación", vbExclamation, "Imposible Comparar"

End If

End If

End If

End Sub

Private Sub cmdEnd_Click()

Dim decision As Byte

decision = MsgBox("Está seguro de finalizar con la aplicación", vbYesNo + vbDefaultButton2 + vbQuestion, "Cierre del Programa")

If decision = vbYes Then

End

End If

End Sub

Private Sub cmdSettings_Click()

Me.Enabled = False

frmSetings.Show

End Sub

Private Sub cmdVer_Click()

Text1 = Get_Path(Text1.Text, CommonDialog1, True)

End Sub

Private Sub Command1_Click()

Dim fdd As New FileSystemObject

Dim fil As file

Dim clnn

Dim fold As Folder

If Right(Text1, 1) <> "\" And Text1 <> "" Then

Text1 = Text1 & "\"

End If

List1.Clear

List2.Clear

Image1.Picture = Nothing

Image2.Picture = Nothing

lblResumen = ""

On Error GoTo errHandle

' ---------------------------------------------------------

'|Realiza carga de archivos .BMP en la lista de comparación

' ---------------------------------------------------------

Set fold = fdd.GetFolder(Text1)

Set clnn = fold.Files

For Each fil In clnn

If UCase(ExtractExt(fil.Name)) = "BMP" Then

List1.AddItem fil.Name

End If

Next

' --------------------------------

'|Asigna la ruta de trabajo actual

' --------------------------------

filephat = Text1

Set fold = Nothing

Set clnn = Nothing

List1.Selected(0) = True

errHandle:

Exit Sub

End Sub

Private Sub Form_Load()

Dim fdd As New FileSystemObject

Dim fil As file

Dim clnn

Dim fold As Folder

If Mid(App.Path, Len(App.Path), 1) = "\" Then

Text1.Text = App.Path

Else

Text1.Text = App.Path & "\"

End If

' ------------------------------------------------------------------------

'| Inicialización de los parámetros por defecto de configuración de la DLL

' ------------------------------------------------------------------------

TamX = 10

TamY = 10

Umbral = 75

' -------------------------------------

'|Asigna la ruta de trabajo por defecto

' -------------------------------------

filephat = Text1

Set fold = fdd.GetFolder(Text1)

Set clnn = fold.Files

' -----------------------------------------------------------------

'|Realiza carga inicial de archivos .BMP en la lista de comparación

' -----------------------------------------------------------------

For Each fil In clnn

If UCase(ExtractExt(fil.Name)) = "BMP" Then

List1.AddItem fil.Name

End If

Next

Set fold = Nothing

Set clnn = Nothing

End Sub

Private Sub List1_Click()

Image1.Picture = LoadPicture(filephat & List1.List(List1.ListIndex))

End Sub

Private Sub List2_Click()

Image2.Picture = LoadPicture(filephat & List2.List(List2.ListIndex))

End Sub

 

 

FrmSetings(FrmSetings.frm):

Private Sub cmdAceptar_Click()

' -------------------------------------------------------

'Asignación de los parámetros de configuración de la DLL|

' -------------------------------------------------------

Dim aux As Integer

aux = Val(txt1.Text)

If aux > 0 Then TamX = aux

aux = Val(txt2.Text)

If aux > 0 Then TamY = aux

aux = Val(txt3.Text)

If aux > 0 Then

If aux > 255 Then aux = 255

Umbral = aux

End If

Me.Hide

frmPictDiff.Show

frmPictDiff.Enabled = True

End Sub

Private Sub cmdCancelar_Click()

frmPictDiff.Enabled = True

frmPictDiff.Show

Me.Hide

End Sub

Private Sub Form_Load()

txt1.Text = CStr(TamX)

txt2.Text = CStr(TamY)

txt3.Text = CStr(Umbral)

End Sub

Private Sub Form_Unload(Cancel As Integer)

frmPictDiff.Enabled = True

End Sub

 

Módulo: MdlMAin(MdlMain.bas):

Option Explicit

' --------------------------------------------------------

'Declaración de los parámetros de configuración de la DLL|

' --------------------------------------------------------

Public TamX As Integer

Public TamY As Integer

Public Umbral As Integer

' -----------------------------------------------------------------------

'Declaración de las funciones de entrada a la DLL ("Iniciar","Detectar")|

' -----------------------------------------------------------------------

Declare Function Iniciar Lib "DetectCambio.dll" (ByVal TamX As Integer, ByVal TamY As Integer, ByVal Umbral As Integer) As Integer

Declare Function Detectar Lib "DetectCambio.dll" (ByVal varFile As Variant) As Integer

Public Function Get_Path(strDefPath As String, CmmDialog As Object, OnlyFolder As Boolean)

' ---------------------------------------------------------------

'|Obtiene el path de un cuadro de diálogo de apertura de archivos

' ---------------------------------------------------------------

On Error GoTo errHandle

If Right(strDefPath, 1) <> "\" And strDefPath <> "" Then

strDefPath = strDefPath & "\"

End If

CmmDialog.FileName = strDefPath & "*.bmp"

CmmDialog.Filter = "Archivos (*.bmp)|*.*"

CmmDialog.CancelError = True

CmmDialog.ShowOpen

If OnlyFolder Then

Get_Path = ExtractFolder(CmmDialog.FileName)

Else

Get_Path = CmmDialog.FileName

End If

Exit Function

errHandle:

Get_Path = strDefPath

End Function

Function ExtractFolder(ByVal file As String) As String

' -------------------------------------------------

'|Trunca el nombre de archivo del phat seleccionado

' -------------------------------------------------

Dim i As Integer

ExtractFolder = ""

For i = Len(file) To 1 Step -1

If Mid(file, i, 1) = "\" Then

ExtractFolder = Trim(Mid(file, 1, i))

Exit For

End If

Next

End Function

 

Function ExtractExt(ByVal file As String) As String

' -----------------------------------

'|Devuelve la extensión de un archivo

' -----------------------------------

Dim i As Integer

ExtractExt = ""

For i = Len(file) To 1 Step -1

If Mid(file, i, 1) = "." Then

ExtractExt = Trim(Mid(file, i + 1))

Exit For

End If

Next

End Function

 

 

C.1.2.3.EXPLICACIÓN DE LOS ELEMENTOS DE INTERACCIÓN DEL USUARIO EN LA APLICACIÓN VISUAL BASIC

C.1.2.3.1.Carpeta de Imágenes:

Especifica la ruta de ubicación donde se encuentran almacenados los archivos bitmap, que serán cargados posteriormente para ser procesados. Esta operación puede hacerse por medio de un cuadro de diálogo o simplemente introduciendo el path manualmente en un cuadro de texto.

C.1.2.3.2.Cargar:

Realiza la carga de archivos .bmp en la lista de comparación, de acuerdo a la ubicación de la carpeta de imágenes anteriormente especificada, pudiendo desplazarse y visualizar las imágenes forma de lista .

C.1.2.3.3.Configurar:

Esta opción permite el seteo de los parámetros de configuración de la DLL por medio de un cuadro de diálogo de configuración:

 

C.1.2.3.4.Parámetros de Configuración

C.1.2.3.4.1.Definición Horizontal: Establece el número de filas que tendrá la matriz de la imagen.

(10 por default).

C.1.2.3.4.2.Definición Vertical: Establece el número de columnas que tendrá la matriz de la imagen.

(10 por default).

C.1.2.3.4.3.Umbral de cambio: Establece la sensibilidad de cambio del RGB de las filas de la matriz de la imagen. (75 por default).

 

C.1.2.3.5.Comparar:

En esta opción si hay imágenes cargadas en la lista de comparación, procede a ejecutar las funciones de inicialización y detección de la DLL, con las cuales se podrá establecer las imágenes que no presentan similitud alguna supeditadas al umbral de cambio establecido.

Posteriormente si hay imágenes distintas serán almacenadas en la lista de resultados, pudiendo desplazarse y visualizar las imágenes en la lista.

Si con solo alguna de las imágenes a ser procesadas de la lista de comparación, no es válida por no cumplir con el requisito de ser de 24 bits, la aplicación finalizará de inmediato.

C.1.2.3.6.Salir:

Realiza el cierre de la aplicación.