Club Builder - Foros de discusión Club Builder
Foro de C++Builder en español
 
 FAQFAQ   BuscarBuscar   MiembrosMiembros   Grupos de UsuariosGrupos de Usuarios   RegistrarseRegistrarse 
 PerfilPerfil   Entra para ver tus mensajes privadosEntra para ver tus mensajes privados   EntrarEntrar 

Método más rápido de busca un pixel en una imagen

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Consultas
Ver tema anterior :: Ver tema siguiente  
Autor Mensaje
Mensaje    Asunto: Método más rápido de busca un pixel en una imagen Responder citando

Hola a todos!

Tengo un TImage con una imagen cargada.
En esa imagen hay un solo pixel que es de color verde (clGreen).
¿Cual creeis que es la forma más rapida de buscar ese pixel?

Se que puedo buscarlo recorriendo con un "for" cada uno de los pixels de la imagen, pero no va del todo "rápido".

Muchas gracias y un saludo.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Supongo que estas usando la propiedad "Pixel", prueba con "ScanLine" es muchísimo más rápido. Un ejemplo:
Código:
Image1->Picture->Bitmap->PixelFormat = pf32bit;
for (int y = 0; y < Image1->Picture->Bitmap->Height; y++)
{
    TColor* p = static_cast<TColor*>(Image1->Picture->Bitmap->ScanLine[y]);
    for (int x = 0; x < Image1->Picture->Bitmap->Width; x++)
    {
        if (p[x] == clGreen)
        {
            ShowMessage(Format("X=%d, Y=%d", ARRAYOFCONST((x, y)) ));

            y = Image1->Picture->Bitmap->Height;
            break;
        }
    }
}

Otro ejemplo, aunque menos claro, es más rápido que el anterior:
Código:
Graphics::TBitmap* bmp = Image1->Picture->Bitmap;
bmp->PixelFormat = pf32bit;
TColor* p = static_cast<TColor*>(bmp->ScanLine[bmp->Height-1]);
int i = bmp->Height * bmp->Width;
while (i--)
{
    if (*p++ == clGreen)
    {
        int y = i / bmp->Width;
        int x = bmp->Width - (++i - (y * bmp->Width));
        ShowMessage(Format("X=%d, Y=%d", ARRAYOFCONST((x, y)) ));
        break;
    }
}
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

También podríamos hacerlo así:
Código:
bool BuscaColor(Graphics::TBitmap* bmp, TColor TrColor)
{
   if(bmp->Empty) return false;
   bmp->PixelFormat = pf32bit;

   PDWORD pixel = (PDWORD)bmp->ScanLine[bmp->Height-1];
   DWORD tc = (TrColor & 0xFF00FF00) | (GetRValue(TrColor) << 16) | GetBValue(TrColor);
   for (int i = 0;  i < bmp->Height * bmp->Width; i++)
      if(pixel[i] == tc)  return true;
   return false;
}


Saludos.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

En las pruebas que he hecho, el segundo método que he puesto es el más rápido con mucha diferencia, en los otros en el "for" se pierde mucho tiempo.

La prueba que he hecho es ejecutarlo 1000 veces sobre un bitmap de 720x540 (con el pixel verde justo en el centro de la imagen), y me da estos tiempos:
Código:
         Método1  Método2  Escafandra
-------------------------------------
BCB6      2,786    0,204     2,105
CB2010    2,859    0,207     2,103
-------------------------------------
         (Tiempos en segundos)

(Esto desde fuera del IDE y en modo release)
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Bueno, realmente entre el método 2 de _Leo y mi método no hay mucha diferencia salvo el uso de índices para el puntero y el uso de aritmética de punteros en el método de _Leo. Está claro que la aritmética de punteros es mas rápida que los índices.

Quizás es mas fácil de entender los índices para luego optimizarlo con la aritmética de punteros.

Saludos.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

for (int i = 0; i < bmp->Height * bmp->Width; i++)

La parte marcada en negrita es lo que más ralentiza el código (lo vuelve a calcular cada vez), haciendo este cálculo solo una vez antes de comenzar el bucle baja muchísimo el tiempo.. el índice ralentiza también un poco, pero no tanto como ese cálculo.. bueno, no realmente haciendo el calculo, sino leyendo las propiedades para hacer el calculo..

Con el siguiente pequeño cambio sobre el segundo método se consigue mejorar un poco más el tiempo (en las mismas condiciones 0,150 seg.):
Código:
Graphics::TBitmap* bmp = Image1->Picture->Bitmap;
bmp->PixelFormat = pf32bit;
TColor* p = static_cast<TColor*>(bmp->ScanLine[bmp->Height-1]);
for (int i = bmp->Height * bmp->Width-1; i >= 0; i--)
{
    if (*p++ == clGreen)
    {
        int y = i / bmp->Width;
        int x = bmp->Width - (++i - (y * bmp->Width));
        ShowMessage(Format("X=%d, Y=%d", ARRAYOFCONST((x, y)) ));
        break;
    }
}
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Si _leo, tienes razón, ese producto repetido es innecesario...

Siempre pensé que el bucle for o while eran indiferentes a la hora de la velocidad. Yo prefiero casi siempre el for por la sintaxis mas compacta y su mayor plasticidad, pero no creí que hubiesen diferencias de velocidad también.

Una pregunta, _Leo. He observado que cuando accedes a la memoria del bitmap32 como DWORD, tenemos permutados el rojo y el azul, por eso hago la conversión del color con esto:
Código:
DWORD tc = (TrColor & 0xFF00FF00) | (GetRValue(TrColor) << 16) | GetBValue(TrColor);


Sin embargo tu haces directamente el casting entre el color y el valor en memoria, que no deje de ser un DWORD con esos componentes cambiados, o es que ¿el static_cast<TColor*> modifica esto?, yo creo que no.

Saludos.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

escafandra escribió:
Sin embargo tu haces directamente el casting entre el color y el valor en memoria, que no deje de ser un DWORD con esos componentes cambiados, o es que ¿el static_cast<TColor*> modifica esto?, yo creo que no.

Cierto, estaba mas concentrado en la velocidad que en este detalle que casualmente el verde es igual en RGB y BGR.

Quedaría así (usando como base la que menos tarda):
Código:
bool BuscaColor(Graphics::TBitmap* bmp, TColor color, TPoint& pt)
{
    bool ret = false;
    bmp->PixelFormat = pf32bit;
    DWORD bgr = GetRValue(color) << 16 | GetGValue(color) << 8 | GetBValue(color);
    DWORD* p = static_cast<DWORD*>(bmp->ScanLine[bmp->Height-1]);
    for (int i = bmp->Height * bmp->Width-1; i >= 0; i--)
    {
        if (*p++ == bgr)
        {
            pt.y = i / bmp->Width;
            pt.x = bmp->Width - (++i - (pt.y * bmp->Width));
            ret = true;
            break;
        }
    }
    return ret;
}

Y un ejemplo de uso:
Código:
void __fastcall TForm1::Button5Click(TObject *Sender)
{
    TPoint pt;
    if ( BuscaColor(Image1->Picture->Bitmap, clSkyBlue, pt) )
        ShowMessage(Format("X=%d, Y=%d", ARRAYOFCONST((pt.x, pt.y)) ));
    else
        ShowMessage("No encontrado..");

(Yo estoy presuponiendo que necesitas saber la posición del pixel en concreto)
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

perfecto!
Muchas gracias

PD: gracias por la posición del pixel, en realidad me hacia falta...
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mostrar mensajes de anteriores:   
Cambiar a:  
No puedes publicar temas nuevos en este foro
No puedes responder a temas en este foro
No puedes editar tus mensajes en este foro
No puedes borrar tus mensajes en este foro
No puedes votar en las encuestas de este foro


Hosting WordPress Indedmedia desde 3,99 €
© 2002–2026 Club Builder · Funciona con phpBB.