Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 15-10-2014
REVINFOR REVINFOR is offline
Miembro
NULL
 
Registrado: may 2011
Posts: 19
Poder: 0
REVINFOR Va por buen camino
Como optimizar la conversion de hexadecimales a enteros decimales

Buenas noches, en estos momentos estoy trabajando en un sistema de control de asistencia con un lector de huella...
Este lector al momento de capturar la huella (para tener el template de comparacion) genera un array de tipo byte, el cual lo convierto todos a hexadecimal y lo guardo como una cadena en la base de datos, por ejemplo:

Array = [1,2,3,...,20,30,40,...255]
Hex = 01,02,03,...14,1E,28....FF]
cadena a guardar = 010203...141E28....FF

Luego, para controlar la asistencia del usuario, tengo que convertir esta cadena en el array de bytes que tenia al principio...
para ello, lo que hago es contar las posiciones de la cadena de 2 en 2, anteponiendo el caracter $ y usando la funcion strtoint.

strtoint($01)
strtoint($02)
strtoint($03)
...

Este proceso se tiene que realizar por cada huella, hasta encontrar una coincidencia, y de no existir ninguna indicar un error ....

Los primeros dias, estaba con una velocidad de <1 seg, (tenia registrados 200 huellas) pero a la fecha tengo 1420, y noto que la velocidad esta disminuyendo...

Mi pregunta es: es posible optimizar el proceso de conversion de una cadena de numeros hexadecimales a enteros, o quizas el proceso que utilizo esta mal... me refiero talvez puedo guardar los datos directamente en formato numerico o algo asi....

Gracias de antemano.
Responder Con Cita
  #2  
Antiguo 15-10-2014
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola REVINFOR.

Cita:
Empezado por REVINFOR Ver Mensaje
...
Luego, para controlar la asistencia del usuario, tengo que convertir esta cadena en el array de bytes que tenia al principio...
para ello, lo que hago es contar las posiciones de la cadena de 2 en 2, anteponiendo el caracter $ y usando la funcion strtoint.
...
A partir de aquí no me queda del todo claro la secuencia de acciones que sigues...

Sin embargo pareciera, que una vez obtenida la huella y pasada a cadena, te podrías ahorrar esa última conversión comparándola directamente con las almacenadas en la tabla.

A modo de ejemplo:
Código Delphi [-]
function BytesToString(v: array of byte): string;
const
  DIGHEX = '0123456789ABCDEF';
var
  i: Integer;
begin
  SetLength(Result, Length(v) shl 1);
  for i :=  Low(v) to High(v) do
  begin
    Result[1+2*i]:= DIGHEX[(v[i] shr  4)+1];
    Result[2+2*i]:= DIGHEX[(v[i] and 15)+1];
  end;
end;

...
var
  Huella: array of Byte;
  ...
begin
  SetLength(Huella, N); // (N igual a tamaño_leido + 1)

  // CapturarHuella sería una función que devuelve verdadero si la lectura resulta bién
  // y en el parámetro Huella los Bytes enviados por el lector
  if CapturarHuella(Huella) then  
    with tuQuery do
    begin
      Close;
      SQL.Clear;
      SQL.Add('SELECT COUNT(*) AS ASISTENCIAS FROM TU_TABLA');
      SQL.Add('WHERE SIGNATURE = :PSIGNAT');
      SQL.Add('AND FECHA BETWEEN :DESDE AND :HASTA');
      ParamByName('PSIGNAT').AsString:= BytesToString(Huella);
      ...

      Open;
      //... acciones que desees
      if not IsEmpty then
        ShowMessage(Format('Asistencias: %d', [FieldByName('ASISTENCIAS').AsInteger]))
      ... 
    end;
  ...

Saludos
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #3  
Antiguo 15-10-2014
REVINFOR REVINFOR is offline
Miembro
NULL
 
Registrado: may 2011
Posts: 19
Poder: 0
REVINFOR Va por buen camino
Gracias por la pronta respuesta...

Sere mas explicito, en realidad son dos procesos que se aplican:

1) registrar la huella a los usuarios para controlar la asistencia, este procedimiento se realiza SOLO UNA VEZ POR USUARIO para guardar el template de comparacion para realizar el registro de asistencia. Al momento de guardar los datos se pasa el array de bytes a una cadena que se guarda en la base. (El primer ejemplo del primer post).

2) Registro de asistencia, para que el usuario registre la asistencia, el lector de huella captura los datos en un array de bytes y se procede a comparar con las huellas que se tienen guardadas en formato de cadena, solo que para que se puedan comparar ambos datos, cada cadena la tengo que convertir en un array de bytes.

Ejemplo:

bAsistencia = array of bytes corresponde al usuario Perez

TUsuarios = Tabla con los 1420 usuarios

Código Delphi [-]
with TUsuarios do
begin
  encontrado := false;
  close;
  open;

  while not eof do
  begin
    if Comparar(bAsistencia, TUsuariosTemplate.asString) then
    begin
      showmessage('Encuentro exitoso');
      encontrado := true;
      break;
    end;      
    next;
  end;

  if not encontrado then
    showmessage('Error: Usuario no encontrado');
end;
Como pueden ver, la funcion Comparar es la que quiero optimizar, esta funcion iria mas o menos asi

Código Delphi [-]
function Comparar(bAsistencia, cadena: string):boolean;
var d,i:integer;
  a:array of byte;
begin
  result := false;
  // sacamos la longitud de la cadena dividido entre dos
  d := length(cadena) div 2;
  // asignamos el tamaño del array de bytes
  setlength(a,d);

  // llenamos el array con los datos de la cadena, haciendo la conversion de hex a decimal
  for i := 1 to d do
    a[i - 1] := strtoint('$' + cadena[2*i - 1] + cadena[2*i]);
  
  // la funcion compare es parte del SDK del lector de huella, que me pide trabajar con dos array de bytes
  result := compare(bAsistencia,a);
end;

Gracias por el apoyo.... revisare el codigo que acaban de publicar para ver como lo podemos optimizar el proceso...
Responder Con Cita
  #4  
Antiguo 15-10-2014
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Y para que lo conviertes en bytes? Porque no lo pasas a string en la BD? o a un Integral?

Parte del truco de hacer algo rapido es elegir la estructura de datos mas optima para el caso, y reducir/eliminar los pasos de conversion.
__________________
El malabarista.
Responder Con Cita
  #5  
Antiguo 15-10-2014
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola REVINFOR.
Cita:
Empezado por REVINFOR Ver Mensaje
2) Registro de asistencia, para que el usuario registre la asistencia, el lector de huella captura los datos en un array de bytes y se procede a comparar con las huellas que se tienen guardadas en formato de cadena, solo que para que se puedan comparar ambos datos, cada cadena la tengo que convertir en un array de bytes.
Código Delphi [-]
with TUsuarios do
begin
  encontrado := false;
  close;
  open;

  while not eof do
  begin
    if Comparar(bAsistencia, TUsuariosTemplate.asString) then
    begin
      showmessage('Encuentro exitoso');
      encontrado := true;
      break;
    end;      
    next;
  end;

  if not encontrado then
    showmessage('Error: Usuario no encontrado');
end;
Como te comenté anteriormente y también te señala mamcx, creo innecesario la reconversión a array of Byte. Una vez obtenida la lectura lo conviertes a cadena y comparas contra la tabla.

Por otro lado la búsqueda secuencial es lenta, voy a reestructurar mi sugerencia anterior para ver si de ese modo me explico mejor.
Código Delphi [-]
function BytesToString(v: array of byte): string;
const
  DIGHEX = '0123456789ABCDEF';
var
  i: Integer;
begin
  SetLength(Result, Length(v) shl 1);
  for i :=  Low(v) to High(v) do
  begin
    Result[1+2*i]:= DIGHEX[(v[i] shr  4)+1];
    Result[2+2*i]:= DIGHEX[(v[i] and 15)+1];
  end;
end;

// Reemplazo de la búsqueda secuencial
function TForm1.IsUserFound(const Signature: string): Boolean;
begin
  with tuQuery do // tuQuery: (TQuery, TADOQuery, TIBQuery, etc)
  begin
    Close;
    SQL.Clear;
    SQL.Add('SELECT ID FROM USUARIOS');
    SQL.Add('WHERE SIGNATURE = :PSIGNAT');
    ParamByName('PSIGNAT').AsString:= Signature;
    Open;
    Result := not IsEmpty; // True si devolvió un resultado
  end;
end;

...
var
  Signature: string;
begin
  Signature:= BytesToString(array_of_bytes_devuelto_x_el_lector);
  if IsUserFound(Signature) then
  ...

Saludos

Edito: Me olvidaba..., Para el caso específico de ADO:
Código Delphi [-]
  Parameters.ParamByName('PSIGNAT').Value:= Signature
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....

Última edición por ecfisa fecha: 15-10-2014 a las 19:20:53.
Responder Con Cita
  #6  
Antiguo 15-10-2014
REVINFOR REVINFOR is offline
Miembro
NULL
 
Registrado: may 2011
Posts: 19
Poder: 0
REVINFOR Va por buen camino
Hola nuevamente....

Revisando sus sugerencias... hay algunos puntos que se tienen que aclarar:

1. Es verdad que seria mas sencillo, cambiar la huella capturada a cadena y comparar directamente con las cadenas que tengo guardadas en la base, pero el SDK que viene con el lector me solicita trabajar con un array de bytes.

2. En un principio, cree un procedimiento almacenado, donde buscaba con un select la cadena capturada dentro de la tabla, pero en todas mis pruebas no acertaba ningun usuario, al revisar la documentacion del lector, resulta que no se trabaja con una imagen identica para verificar la huella, sino una matriz de puntos donde el algoritmo analiza la similitud de los datos capturados, algo asi como un camino de grafos, donde se tiene un porcentaje de exito y fracaso (lo ultimo es algo que deduzco por que el algoritmo es propio del lector y este esta embebido en un componente activeX).

Por los motivos anteriores es que aplico las conversiones que pueden ver, y ahi se encuentra la necesidad de optimizar este proceso...
Responder Con Cita
  #7  
Antiguo 15-10-2014
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola nuevamente.

Entiendo... Una consulta ¿ El array de bytes que devuelve el lector es de longitud fija ? (te hago esta pregunta para ver si se le puede buscar la vuelta por el lado del almacenamiento).

Saludos
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #8  
Antiguo 15-10-2014
REVINFOR REVINFOR is offline
Miembro
NULL
 
Registrado: may 2011
Posts: 19
Poder: 0
REVINFOR Va por buen camino
Hola...

Revisando la tabla, todos tienen una cadena de 3264 caracteres, asi que parece que el lector trabaja con un array de 1632 elementos, y se podria trabajar con un valor de longitud fija
Responder Con Cita
  #9  
Antiguo 15-10-2014
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola.

No sé con que RDBMS estás trabajando, pero siendo así, tal vez puedas definir un formato numérico para el almacenamiento y ahorrarte la conversión a cadena...

Saludos
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #10  
Antiguo 15-10-2014
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Ahora bien, si entiendo esto, es que el metodo de busca obligadamente debe tocar el ActiveX. Y eso obliga a hacer un proceso sequencial por N usuarios.

Seria ideal que supieras que algoritmo se usa para hacer la comparacion, y reimplementarlo en el motor. Si no se puede, entonces hay que hacer algo mas complejo.

Ya que no se como es el asunto con huellas, hago una analogia con como se hace una busqueda de geolocalizacion... en donde si quieres buscar un punto en el globo terraqueo, puedes acortar el rango de busqueda deduciendo que el punto esta en la ciudad tal.

Hay forma de decir:

Esta huella esta entre este rango?

Hay forma de pre-indexar las busquedas? (Osea, tener una tabla de busquedas ya hechas y almacenarlas)

Otra seria tener un proceso de busqueda en paralelo, buscando con N-threads.

Que tan variable son las lecturas entre una tomada de huella y otra? Hay modelos probabilisticos que se podrian evaluar...

Y por ultimo, cuantos usuarios son? Que tan lento es esto? Que tasa de crecimiento tiene esto? No habra otro SDK mas rapido y mejor?

P.D: Me encontre este articulo que habla sobre el tema

http://timvdm.blogspot.com/2012/08/f...g-various.html
__________________
El malabarista.

Última edición por mamcx fecha: 15-10-2014 a las 20:41:54.
Responder Con Cita
  #11  
Antiguo 16-10-2014
engranaje engranaje is offline
Miembro
 
Registrado: may 2011
Posts: 163
Poder: 13
engranaje Va por buen camino
Si he entendido bien los dos procesos en el primero se obtiene la huella completa y se almacena en la bd. Posteriormente en el segundo proceso el lector no lee toda la huella sino una serie de puntos y despues utilizando la sdk se debe comparar si los valores obtenidos todos los puntos leidos coinciden con la cadena que le pasas.

Quiero suponer que el motivo por el que no se utiliza la misma lectura ha de ser al lector le lleva mas tiempo realizar la primer lectura que la segunda. No tengo claro el funcionamiento del proceso puede ser que cuando alguien pone su dedo en el lector es el lector mismo el que te envia una cadena y tu aplicación esté siempre escuchando. También puede ser que sea tu aplicación la que activamente le pida al lector que relize la lectura.

En cualquiera de los dos casos me pregunto si seria posible que el lector realizara siempre lecturas completas para poder compararlas directamente con la bd como ya te han propuesto y sin necesidad de utilizar la sdk para hacer una comparación secuencial. Por supuesto puede ser que la respuesta sea si pero que el lector tarde tanto que no sea factible, de todos modos me gustaría saber como va el tema, ¿cual es la diferencia del proceso de lectura entre la primera lectura que se almacena en la bd y las posteriores lecturas de comprobación?
Responder Con Cita
  #12  
Antiguo 16-10-2014
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.911
Poder: 25
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Exacto. Porque como se ven las cosas, que sentido tiene guardar la huella en la BD, si es un valor inutil para hacer comparaciones?
__________________
El malabarista.
Responder Con Cita
  #13  
Antiguo 19-10-2014
REVINFOR REVINFOR is offline
Miembro
NULL
 
Registrado: may 2011
Posts: 19
Poder: 0
REVINFOR Va por buen camino
Hola nuevamente... les cuento que ya mejore la velocidad de respuesta, tomando en cuenta todas las preguntas que han realizado en este tema.. sobre todo de mancx.

Para empezar el lector al MOMENTO DE REGISTRAR EL TEMPLATE (muestra) para todos los registros posteriores, realiza 4 escaneos de la misma huella, tomando estas cuatro imagenes, verifica cuales son los puntos que se repiten en todo el proceso, y estos puntos son los que se guardan.

Al momento de TOMAR LA HUELLA para comparar con el TEMPLATE, el lector captura todos los puntos de la huella.

Es el algoritmo del sdk que compara los puntos del template guardado con la huella registrada y en base a un porcentaje de exito (dependiendo del algoritmo) es que indica si se tiene exito o fracaso.

Por tal motivo, es necesario guardar los templates en la base de datos, pero no se pueden usar directamente sin el SDK.

Ahora bien, como mejoramos la velocidad del proceso.
  • Cree un servidor TCP con todas las huellas disponibles, ya convertidas en array de bytes.
  • Este proceso se realiza una sola vez al iniciar el servidor
  • Creamos un cliente TCP que manda la huella al servidor, y como respuesta le mando el id del usuario.
  • mejoramos los tiempos de 2 seg. (en promedio) a 0.24 seg. para el caso de exito.
  • en el caso de no existir la huella pasamos de 5 seg. a 0.44 seg.
  • Estoy con cinco lectores de huella que apuntan el proceso al servidor.
Tomando en cuenta todas las preguntas que han realizado, me interiorizare mas en los algoritmos que hay, para ver si se pueden pasar al motor de la base (programarlo como un procedimiento almacenado).


Gracias por todo... y sigan adelante, se cuidan
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Redondear numeros decimales a enteros.... uper Varios 6 26-07-2012 17:52:45
validar que las cajas de texto solo acepten valores enteros y decimales dimer18 OOP 11 12-12-2011 02:58:30
Formatear números enteros y decimales quade C++ Builder 10 13-10-2011 17:09:54
Grabar En SQL Campos Decimales, Solo me graba enteros? Con Codigo freddiaz07 SQL 13 21-09-2006 19:44:34
Grabar En SQL Campos Decimales, Solo me graba enteros? freddiaz07 SQL 2 07-09-2006 17:24:04


La franja horaria es GMT +2. Ahora son las 09:14:59.


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
Copyright 1996-2007 Club Delphi