CLR: .Net / Mono / Boo / Otros CLR > Otros CLR

 Aplicar Una Máscara A Una Imagen

(1/2) > >>

KAYSS:
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 ---Bitmap^ AplicarMascara(Bitmap ^Imagen, Array^ Mascara, int Tamanio){  Bitmap ^ImagenFiltrada=gcnew Bitmap (Imagen->Width, Imagen->Height);  int IncX, IncY, X, Y;  int TamanioNxN=Tamanio*Tamanio;  double Sumatorio;  Color color;   // Aplicamos la máscara para cada uno de los pixels de la imagen  for(int i=0; i<Imagen->Width; i++){    for (int j=0; j<Imagen->Height; j++){       IncY=Tamanio/2;      Sumatorio=0;       // Recorremos los valores de la máscara para aplicarlos a la imagen      for (int k=0; k<Tamanio; k++){         Y=j+IncY;        IncX=Tamanio/2;         for (int q=0; q<Tamanio; q++){          X=i+IncX;          if ((X>=0&&X<Imagen->Width) && (Y>=0&&Y<Imagen->Height))            Sumatorio=Sumatorio + Mascara->GetValue(Tamanio/2+IncX, Tamanio/2+IncY)) * Imagen->GetPixel(X,Y).R;           IncX--;        }         IncY--;      }       // El valor del pixel será el valor del sumatorio obtenido      color=Color::FromArgb(Sumatorio, Sumatorio, Sumatorio);      ImagenFiltrada->SetPixel(i, j, color);    }  }   return ImagenFiltrada;} 


Gracias, un saludo

JuanK:
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...

KAYSS:
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 ---Bitmap^ AplicarMascara2(System::Drawing::Bitmap ^Imagen, cli::array<int>^ Mascara, int Tamanio){   this->ImagenFiltrada=gcnew System::Drawing::Bitmap (Imagen);   int i, j, k, q, IncX, IncY, X, Y, ValorPixel, PosVectorRGB;   int TamanioNxN=Tamanio*Tamanio;   double Sumatorio;   Color color;   int Cte1=Tamanio/2;    // formato de pixel   PixelFormat pxf = PixelFormat::Format24bppRgb;    // Bloqueamos los pixels de la imagen original y la filtrada   Rectangle rect = System::Drawing::Rectangle(0, 0, Imagen->Width, Imagen->Height);   BitmapData ^bmpDatosOriginal = Imagen->LockBits(rect, ImageLockMode::ReadWrite, pxf);   BitmapData ^bmpDatosFiltrada = ImagenFiltrada->LockBits(rect, ImageLockMode::ReadWrite, pxf);    // Obtenemos la direcciones de comienzo   IntPtr ptrOriginal = bmpDatosOriginal->Scan0;   IntPtr ptrFiltrada = bmpDatosFiltrada->Scan0;    // Declaramos los arrays para almacenar los bytes de los bitmaps   int numBytes = Imagen->Width * Imagen->Height * 3;   array<Byte> ^valoresRGBOriginal = gcnew array<Byte>(numBytes);   array<Byte> ^valoresRGBFiltrada = gcnew array<Byte>(numBytes);    // Copiamos los valores RGB a los arrays   Marshal::Copy(ptrOriginal, valoresRGBOriginal, 0, numBytes);   Marshal::Copy(ptrFiltrada, valoresRGBFiltrada, 0, numBytes);    // Recorremos la imagen   for(i=0; i<Imagen->Width; i++){     for (j=0; j<Imagen->Height; j++){             IncY=Cte1;       Sumatorio=0;        // Recorremos la máscara       for (k=0; k<Tamanio; k++){                 Y=j+IncY;         IncX=Cte1;          for (q=0; q<Tamanio; q++){           X=i+IncX;           if ((X>=0&&X<Imagen->Width)&&(Y>=0&&Y<Imagen->Height)){             Sumatorio=Sumatorio+             Convert::ToDouble(Mascara[(Cte1+IncX)*3 + (Cte1+IncY)])*             Convert::ToDouble(valoresRGBOriginal[(Y*Imagen->Width+X)*3]);           }           IncX--;         }         IncY--;       }             // El valor del pixel será el valor del sumatorio obtenido       if (Sumatorio>0)ValorPixel=Convert::ToInt32(Sumatorio)%255;       else ValorPixel=0;       PosVectorRGB=(j*Imagen->Width+i)*3;       valoresRGBFiltrada[PosVectorRGB]=ValorPixel;       valoresRGBFiltrada[PosVectorRGB+1]=ValorPixel;       valoresRGBFiltrada[PosVectorRGB+2]=ValorPixel;     }   }    // Copiamos de nuevo los valores del array al bitmap   Marshal::Copy(valoresRGBFiltrada, 0, ptrFiltrada, numBytes);    // Desbloqueamos los bytes   ImagenFiltrada->UnlockBits(bmpDatosFiltrada);   Imagen->UnlockBits(bmpDatosOriginal);    return ImagenFiltrada;} 
Gracias, un saludo

JuanK:
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 ---Convert::ToDouble 
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,

KAYSS:
Muchas gracias de nuevo, todos tus consejos me han sido de gran ayuda.

Aplicaré todo lo que me dices


Un saludo

Navegación

[0] Índice de Mensajes

[#] Página Siguiente

Ir a la versión completa