• Domingo 22 de Diciembre de 2024, 12:48

Autor Tema:  Aplicar Una Máscara A Una Imagen  (Leído 4393 veces)

KAYSS

  • Nuevo Miembro
  • *
  • Mensajes: 19
    • Ver Perfil
Aplicar Una Máscara A Una Imagen
« en: Miércoles 7 de Noviembre de 2007, 10:27 »
0
Alguno sabéis de una forma rápida de aplicar una máscara a una imagen en mapa de bits.

Yo primero creo la máscara (matriz nxn), recorro pixel a pixel la imagen, sitúo la máscara y recorro la máscara posición por posición para dicho pixel, y así con todos los demás pixels de la imagen. Pero esto es muy lento.

Os muestro el código que he desarrollado por si es causa de que no está bien planteado:

Código: Text
  1. Bitmap^ AplicarMascara(Bitmap ^Imagen, Array^ Mascara, int Tamanio){
  2.   Bitmap ^ImagenFiltrada=gcnew Bitmap (Imagen->Width, Imagen->Height);
  3.   int IncX, IncY, X, Y;
  4.   int TamanioNxN=Tamanio*Tamanio;
  5.   double Sumatorio;
  6.   Color color;
  7.  
  8.   // Aplicamos la máscara para cada uno de los pixels de la imagen
  9.   for(int i=0; i<Imagen->Width; i++){
  10.     for (int j=0; j<Imagen->Height; j++){
  11.  
  12.       IncY=Tamanio/2;
  13.       Sumatorio=0;
  14.  
  15.       // Recorremos los valores de la máscara para aplicarlos a la imagen
  16.       for (int k=0; k<Tamanio; k++){
  17.  
  18.         Y=j+IncY;
  19.         IncX=Tamanio/2;
  20.  
  21.         for (int q=0; q<Tamanio; q++){
  22.           X=i+IncX;
  23.           if ((X>=0&&X<Imagen->Width) && (Y>=0&&Y<Imagen->Height))
  24.             Sumatorio=Sumatorio + Mascara->GetValue(Tamanio/2+IncX, Tamanio/2+IncY)) * Imagen->GetPixel(X,Y).R;
  25.  
  26.           IncX--;
  27.         }
  28.  
  29.         IncY--;
  30.       }
  31.  
  32.       // El valor del pixel será el valor del sumatorio obtenido
  33.       color=Color::FromArgb(Sumatorio, Sumatorio, Sumatorio);
  34.       ImagenFiltrada->SetPixel(i, j, color);
  35.     }
  36.   }
  37.  
  38.   return ImagenFiltrada;
  39. }
  40.  



Gracias, un saludo

JuanK

  • Miembro de ORO
  • ******
  • Mensajes: 5393
  • Nacionalidad: co
    • Ver Perfil
    • http://juank.io
Re: Aplicar Una Máscara A Una Imagen
« Respuesta #1 en: Miércoles 7 de Noviembre de 2007, 14:12 »
0
No es muy rápido, lo mejor es que uses trabajo a nivel de bytes. El objeto bitmap te permite acceder directamente a todos los bytes de la imagen usando los metodos de lockbitmap, y una vez allli puedes trabajar todo de una sola vez con operaciones binarias y/o con arreglos. Eso si es muy rápido.


si necesitas ayuda me cuentas... aunque no deberias...
[size=109]Juan Carlos Ruiz Pacheco
[/size]
Microsoft Technical Evangelist
@JuanKRuiz
http://juank.io

KAYSS

  • Nuevo Miembro
  • *
  • Mensajes: 19
    • Ver Perfil
Re: Aplicar Una Máscara A Una Imagen
« Respuesta #2 en: Jueves 8 de Noviembre de 2007, 01:19 »
0
Muchas gracias por la ayuda, Juan Carlos.
He aplicado lo que me propones y he conseguido reducir de 2 minutos y medios a 1 minuto y medio el tiempo empleado en aplicar una máscara 3x3 a una imagen, que aunque sigue siendo mucho tiempo pero mejora el anterior.
Te muestro el código resultante:

Código: Text
  1. Bitmap^ AplicarMascara2(System::Drawing::Bitmap ^Imagen, cli::array<int>^ Mascara, int Tamanio){
  2.    this->ImagenFiltrada=gcnew System::Drawing::Bitmap (Imagen);
  3.    int i, j, k, q, IncX, IncY, X, Y, ValorPixel, PosVectorRGB;
  4.    int TamanioNxN=Tamanio*Tamanio;
  5.    double Sumatorio;
  6.    Color color;
  7.    int Cte1=Tamanio/2;
  8.  
  9.    // formato de pixel
  10.    PixelFormat pxf = PixelFormat::Format24bppRgb;
  11.  
  12.    // Bloqueamos los pixels de la imagen original y la filtrada
  13.    Rectangle rect = System::Drawing::Rectangle(0, 0, Imagen->Width, Imagen->Height);
  14.    BitmapData ^bmpDatosOriginal = Imagen->LockBits(rect, ImageLockMode::ReadWrite, pxf);
  15.    BitmapData ^bmpDatosFiltrada = ImagenFiltrada->LockBits(rect, ImageLockMode::ReadWrite, pxf);
  16.  
  17.    // Obtenemos la direcciones de comienzo
  18.    IntPtr ptrOriginal = bmpDatosOriginal->Scan0;
  19.    IntPtr ptrFiltrada = bmpDatosFiltrada->Scan0;
  20.  
  21.    // Declaramos los arrays para almacenar los bytes de los bitmaps
  22.    int numBytes = Imagen->Width * Imagen->Height * 3;
  23.    array<Byte> ^valoresRGBOriginal = gcnew array<Byte>(numBytes);
  24.    array<Byte> ^valoresRGBFiltrada = gcnew array<Byte>(numBytes);
  25.  
  26.    // Copiamos los valores RGB a los arrays
  27.    Marshal::Copy(ptrOriginal, valoresRGBOriginal, 0, numBytes);
  28.    Marshal::Copy(ptrFiltrada, valoresRGBFiltrada, 0, numBytes);
  29.  
  30.    // Recorremos la imagen
  31.    for(i=0; i<Imagen->Width; i++){
  32.      for (j=0; j<Imagen->Height; j++){
  33.      
  34.        IncY=Cte1;
  35.        Sumatorio=0;
  36.  
  37.        // Recorremos la máscara
  38.        for (k=0; k<Tamanio; k++){
  39.        
  40.          Y=j+IncY;
  41.          IncX=Cte1;
  42.  
  43.          for (q=0; q<Tamanio; q++){
  44.            X=i+IncX;
  45.            if ((X>=0&&X<Imagen->Width)&&(Y>=0&&Y<Imagen->Height)){
  46.              Sumatorio=Sumatorio+
  47.              Convert::ToDouble(Mascara[(Cte1+IncX)*3 + (Cte1+IncY)])*
  48.              Convert::ToDouble(valoresRGBOriginal[(Y*Imagen->Width+X)*3]);
  49.            }
  50.            IncX--;
  51.          }
  52.          IncY--;
  53.        }
  54.      
  55.        // El valor del pixel será el valor del sumatorio obtenido
  56.        if (Sumatorio>0)ValorPixel=Convert::ToInt32(Sumatorio)%255;
  57.        else ValorPixel=0;
  58.        PosVectorRGB=(j*Imagen->Width+i)*3;
  59.        valoresRGBFiltrada[PosVectorRGB]=ValorPixel;
  60.        valoresRGBFiltrada[PosVectorRGB+1]=ValorPixel;
  61.        valoresRGBFiltrada[PosVectorRGB+2]=ValorPixel;
  62.      }
  63.    }
  64.  
  65.    // Copiamos de nuevo los valores del array al bitmap
  66.    Marshal::Copy(valoresRGBFiltrada, 0, ptrFiltrada, numBytes);
  67.  
  68.    // Desbloqueamos los bytes
  69.    ImagenFiltrada->UnlockBits(bmpDatosFiltrada);
  70.    Imagen->UnlockBits(bmpDatosOriginal);
  71.  
  72.    return ImagenFiltrada;
  73. }
  74.  

Gracias, un saludo

JuanK

  • Miembro de ORO
  • ******
  • Mensajes: 5393
  • Nacionalidad: co
    • Ver Perfil
    • http://juank.io
Re: Aplicar Una Máscara A Una Imagen
« Respuesta #3 en: Jueves 8 de Noviembre de 2007, 02:52 »
0
Bueno no ando con mucho tiempo para revisar la logica completa del programa y hacer una optimizacion agresiva, pero si por encima estos son los tips:


1- Trata de deshacerte de todo lo que implique conversion de tipos de dato, ejemplo
Código: Text
  1. Convert::ToDouble
  2.  

Seguramente deberas replantear la mayoria de las operaciones aritmeticas que tienes para trabajar sin convertir tipos de datos por lo menos mientras estes dentro de los bucles.

2- Optimiza de acuerdo a la plataforma, si vas a trabajar para plataforma de 32 bot utiliza tipos de dato de 32 bit o si es plataforma de 64 utiliza tipos de dato de 64 bit, el punto es que si usas plataforma de 32 bit maneja tipos de dato Int32 en contadores ciclos etc, y utiliza todas las operaciones sobre unidades de 32 bit, inclusive las operaciones de corrimiento.

Seguramente la logica de tu programa sera un poco mas elaborada pero creeme que justificara.

3- Minimiza la mayor cantidad de operaciones posibles a operaciones a nivel binario.

En todo caso de todo lo que te mencione lo mas importante es lo de las conversiones de tipo de dato.

Ahh si, trata de reducirlos bucles, entre menos vueltas mejor.


saludos,
[size=109]Juan Carlos Ruiz Pacheco
[/size]
Microsoft Technical Evangelist
@JuanKRuiz
http://juank.io

KAYSS

  • Nuevo Miembro
  • *
  • Mensajes: 19
    • Ver Perfil
Re: Aplicar Una Máscara A Una Imagen
« Respuesta #4 en: Jueves 8 de Noviembre de 2007, 11:23 »
0
Muchas gracias de nuevo, todos tus consejos me han sido de gran ayuda.

Aplicaré todo lo que me dices


Un saludo

JuanK

  • Miembro de ORO
  • ******
  • Mensajes: 5393
  • Nacionalidad: co
    • Ver Perfil
    • http://juank.io
Re: Aplicar Una Máscara A Una Imagen
« Respuesta #5 en: Jueves 8 de Noviembre de 2007, 14:27 »
0
bueno ok.

Se me olvidaba otro muy buen tip:

1- no hagas las pruebas de velocidad compilando el programa en modo debug siempre hazlas compilando en modo Release

2- no hagas las pruebas de velocidad ejecutando el programa desde visual studio o el ide que uses, hazlo siempre de manera independiente.

3- En la compilación en modo release selecciona optimizar codigo y no selecciones definir DEBUG ni definir TRACE.

4- En destino plataforma selecciona la plataforma a donde quieres que se ejeccute el programa salvo que quieras que corra tanto en x86 como en x64

bye.
[size=109]Juan Carlos Ruiz Pacheco
[/size]
Microsoft Technical Evangelist
@JuanKRuiz
http://juank.io

KAYSS

  • Nuevo Miembro
  • *
  • Mensajes: 19
    • Ver Perfil
Re: Aplicar Una Máscara A Una Imagen
« Respuesta #6 en: Viernes 9 de Noviembre de 2007, 20:18 »
0
Muchas gracias por todo!!!   :)

Un saludo