2012-01-24 34 views
5

tengo una herramienta con controles deslizantes barra de seguimiento utilizados para ajustar de una imagen de brillo, contraste, gamma, etc.algoritmo de contraste más rápido para un mapa de bits

Estoy tratando de obtener actualizaciones en tiempo real a mi imagen mientras el usuario arrastra el control deslizante. Los algoritmos de brillo y gamma son una velocidad aceptable (alrededor de 170 ms). Pero el algoritmo de contraste es de aproximadamente 380 ms.

Básicamente mi formulario es una ventana de herramientas con controles deslizantes. Cada vez que se actualiza la imagen, envía un evento al padre que vuelve a dibujar la nueva imagen. La ventana de herramientas mantiene la imagen original no modificada bloqueada en la memoria para que siempre tenga acceso a los bytes de la misma. Básicamente, hago esto cada vez que se cambia el evento ValueChanged para un control deslizante (como el control deslizante Contraste).

  • LockBits del mapa de bits de trabajo (destino) como Format24bppRgb (mapa de bits original se encuentra en Format32bppPArgb)
  • Marshal.Copy los bits en un byte [] array
  • Comprobar qué operación que estoy haciendo (que deslizador fue elegido)
  • utilizar el siguiente código para el contraste:

código:

double newValue = 0; 
double c = (100.0 + contrast)/100.0; 

c *= c; 

for (int i = 0; i < sourcePixels.Length; i++) 
{ 
    newValue = sourcePixels[i]; 

    newValue /= 255.0; 
    newValue -= 0.5; 
    newValue *= c; 
    newValue += 0.5; 
    newValue *= 255; 

    if (newValue < 0) 
     newValue = 0; 
    if (newValue > 255) 
     newValue = 255; 

    destPixels[i] = (byte)newValue; 
} 

Leí una vez sobre el uso de enteros en lugar de valores de coma flotante para aumentar la velocidad de contraste, pero no pude encontrar ese artículo de nuevo.

Intenté usar un código inseguro (punteros) pero en realidad noté una disminución de velocidad. Supongo que fue porque el código estaba usando ciclos anidados para iterar xey en lugar de un solo bucle.

+0

posible duplicado de [Ajuste el contraste de una imagen en C# de forma eficiente] (http://stackoverflow.com/questions/3115076/adjust-the-contrast-of-an-image-inc-c-sharp-efficiently) – Magnus

+0

El código inseguro en la pregunta a la que se vinculó, cuando lo pruebo con la misma imagen que estaba usando con mi código, toma más de 900ms por rutina. Por supuesto que lo modifiqué para que no clone ni cree mapas de bits nuevos, es solo el ciclo anidado con punteros y matemática de coma flotante. Es muy lento. –

+1

Quizás pueda modificar su código para usar punteros en lugar de código inseguro. – Magnus

Respuesta

10

Dependiendo de la máquina en la que esté ejecutando esto, su técnica podría ser bastante lenta. Si está utilizando un sistema ARM sin una FPU, cada una de esas operaciones llevaría bastante tiempo. Como está aplicando la misma operación a cada byte, una técnica más rápida sería crear una tabla de búsqueda de 256 entradas para el nivel de contraste y luego traducir cada byte de imagen a la tabla. El bucle sería parecido a:

byte contrast_lookup[256]; 
double newValue = 0; 
double c = (100.0 + contrast)/100.0; 

c *= c; 

for (int i = 0; i < 256; i++) 
{ 
    newValue = (double)i; 
    newValue /= 255.0; 
    newValue -= 0.5; 
    newValue *= c; 
    newValue += 0.5; 
    newValue *= 255; 

    if (newValue < 0) 
     newValue = 0; 
    if (newValue > 255) 
     newValue = 255; 
    contrast_lookup[i] = (byte)newValue; 
} 

for (int i = 0; i < sourcePixels.Length; i++) 
{ 
    destPixels[i] = contrast_lookup[sourcePixels[i]]; 
} 
+1

Mucho más rápido. Eso redujo la velocidad de aproximadamente 380ms a aproximadamente 155ms. ¡Gracias! –

+1

Vale la pena señalar que también puede aplicar este mismo enfoque a sus algoritmos de brillo y gamma para hacerlos aún más rápidos. – Seph

+0

Eso pensé y lo iba a intentar. Este método escala muy bien con mapas de bits de alta resolución como los archivos 2976x1536 con los que estoy tratando. –

3

@BitBank responde a su pregunta, tal como solicitó, que quería añadir que si lo que busca es el rendimiento que debe tener en cuenta el código que está recibiendo los datos de píxeles y se establece después.

código de trabajo completo el uso de punteros (apoyos a @BitBank en el código for circular):

private unsafe void ApplyContrast(double contrast, Bitmap bmp) 
{ 
    byte[] contrast_lookup = new byte[256]; 
    double newValue = 0; 
    double c = (100.0 + contrast)/100.0; 

    c *= c; 

    for (int i = 0; i < 256; i++) 
    { 
     newValue = (double)i; 
     newValue /= 255.0; 
     newValue -= 0.5; 
     newValue *= c; 
     newValue += 0.5; 
     newValue *= 255; 

     if (newValue < 0) 
      newValue = 0; 
     if (newValue > 255) 
      newValue = 255; 
     contrast_lookup[i] = (byte)newValue; 
    } 

    var bitmapdata = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), 
     System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 

    int PixelSize = 4; 

    for (int y = 0; y < bitmapdata.Height; y++) 
    { 
     byte* destPixels = (byte*)bitmapdata.Scan0 + (y * bitmapdata.Stride); 
     for (int x = 0; x < bitmapdata.Width; x++) 
     { 
      destPixels[x * PixelSize] = contrast_lookup[destPixels[x * PixelSize]]; // B 
      destPixels[x * PixelSize + 1] = contrast_lookup[destPixels[x * PixelSize + 1]]; // G 
      destPixels[x * PixelSize + 2] = contrast_lookup[destPixels[x * PixelSize + 2]]; // R 
      //destPixels[x * PixelSize + 3] = contrast_lookup[destPixels[x * PixelSize + 3]]; //A 
     } 
    } 
    bmp.UnlockBits(bitmapdata); 
} 

Si va a configurar sus datos de píxeles de la imagen usando Marshal.Copy se encuentra este tiene un mejor rendimiento.

Esto debería funcionar más rápido que su código actual, y también reduce la huella de memoria que es buena cuando se trata de imágenes muy grandes.

+0

También podría ser un poco más rápido si escalas desde y hacia 255. I.E. newValue = (double) i; newValue - = 128; newValue * = c; newValue + = 128; – DkAngelito

+0

Otra gran mejora sería calcular x * PixelSize una vez en lugar de 6 veces en el interior para – DkAngelito

Cuestiones relacionadas