2011-11-23 12 views
9

Actualmente estoy manejando imágenes muy grandes, que básicamente se generan uniendo muchas imágenes más pequeñas (por ejemplo, software de mosaico panorámico o fotográfico). Para evitar excepciones a la memoria insuficiente (en la memoria solo hay "mapas" de cómo organizar las imágenes más pequeñas), escribí un código guardando estas imágenes línea por línea como mapas de bits usando BinaryWriter y LockBits. Hasta aquí todo bien.C# guardando mapas de bits muy grandes como jpegs (o cualquier otro formato comprimido)

El problema ahora es que me gustaría guardar estas imágenes como Jpegs (o PNG) también. Como soy bastante nuevo en C#, ahora solo puedo pensar en dos maneras:

1) Similar al procedimiento de guardado del mapa de bits. Generando un encabezado jpeg y guardando las imágenes grandes línea por línea, comprimiéndolas de alguna manera antes. Aunque no tengo idea de cómo realizar la compresión.

2) Transmitiendo el mapa de bits ya guardado a la memoria y guardándolo como jpeg codificado.

Desde el segundo enfoque parecía más fácil, he intentado algo como esto:

FileStream fsr = 
    new FileStream("input.bmp", FileMode.Open, FileAccess.Read); 
FileStream fsw = 
    new FileStream("output.jpg", FileMode.CreateNew, FileAccess.Write); 

EncoderParameters encoderParameters = new EncoderParameters(1); 
encoderParameters.Param[0] = 
    new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80L); 

Bitmap bmp = new Bitmap(fsr); 
bmp.Save(fsw, GetEncoder(ImageFormat.Jpeg), encoderParameters); 
bmp.Dispose(); 

El problema ahora es que el método de guardar intenta cargar por completo el mapa de bits en la memoria primero, causando un out-of-memory excepción.

Estaría más que feliz por cualquier sugerencia sobre cómo resolver o eludir este problema.

+1

OutOfMemoryException en esta época? ¿Qué tan grande es tu mapa de bits? – zmbq

+2

sí, puede encontrarse con problemas de memoria fácilmente, estaba redimensionando alrededor de 10K imágenes y ejecutándose en 'OutOfMemoryException' a menudo, aunque estaba desechando correctamente. – DarthVader

+1

OOM de un mapa de bits es muy sospechoso. Esta clase arrojará la excepción de memoria para casi todo lo que sale mal, incluidos los parámetros incorrectos, etc. –

Respuesta

0

Sospecho que no puede hacer esto en .NET, pero siempre puede llamar a una biblioteca de C para hacer el trabajo pesado. No lo he usado yo mismo, pero sugiero que mires la biblioteca GraphicsMagick. Es una biblioteca C con licencia que permite el uso de código abierto y comercial, y parece que podría hacer lo que necesita.

+0

Gracias, lo echaré un vistazo. Pero preferiría evitar bibliotecas adicionales. – mgulde

+0

Revisé la lib de GraphicsMagick pero no pude encontrar nada sobre cómo escribir jpegs (o pngs) en fragmentos. – mgulde

1

Tenga en cuenta que la compresión JPEG tiene algunos inconvenientes importantes no triviales:

1) JPEG tiene pérdida, lo que no tendrá regenerar la misma imagen. Esto podría ser perfectamente aceptable, pero si necesita regenerar exactamente la imagen de origen, entonces PNG es el camino a seguir.

2) JPEG está alineado en los límites de 8 píxeles. Si Stich juntos imágenes que los tamaños no son múltiplo de 8, ya sea en altura o anchura, obtendrá algunos artefactos fuertes en los límites imagen

Teniendo en cuenta su caso de uso, prefiero recomendar a no imágenes puntada juntos, y utilice un algoritmo de compresión estándar, como PNG o Zlib, en cada imagen más pequeña. Aún puede almacenar las secuencias comprimidas resultantes en un solo archivo. La ventaja es que puede "saltar" directamente a la posición de la imagen pequeña que desea extraer, lo que ahorrará * mucha * memoria.

La desventaja es que no se puede "previsualizar visualmente" todas las imágenes más pequeñas en una sola grande (deberá crear un programa para este uso).

+0

Antes que nada, muchas gracias. Cambiar el código para guardar la imagen grande no en línea, sino en fragmentos de 8x8px no debería ser un problema. También la pérdida leve de información debido a guardarlo como jpeg no importa. Mi problema ahora es que no tengo absolutamente ninguna pista sobre cómo escribir un archivo jpeg (o png, para el caso) en bloque. – mgulde

+0

Si quiere seguir con el método de la "imagen grande", prefiero recomendar guardarlo en bandas de 8 líneas. A continuación, obtendrá en la memoria un mapa de bits de Ancho x 8 píxeles, lo que reducirá los requisitos de memoria en comparación con la imagen completa. – Cyan

+0

Acabo de modificar el código y ahora estoy guardando la imagen en bandas de 8 líneas. Pero aún existe el problema de que no sé cómo guardarlo como un jpeg: para bmps escribí un encabezado y luego simplemente transmití los valores de bytes ARGB uno por uno. Necesitaría alguna función, que pueda escribir un encabezado jpeg y luego, esto es lo que considero la parte difícil, codificar las bandas en formato jpeg y anexarlas al fragmento de archivo existente por partes. – mgulde

0

(ya que el título dice "o cualquier otro formato comprimido")

formato TIFF tiene una noción de azulejos y rayas. Ambos pueden usarse para evitar tener toda la imagen grande en la memoria en cualquier momento. Tal vez las fichas te serán útiles ya que estás cosiendo pequeñas imágenes.

Puede probar LibTiff.Net (gratuito, comercialmente compatible, de código abierto, escrito en C# solamente) para la tarea.

Hay un artículo Basic introduction to the capabilities of the library con información sobre la imagen orientada a la tira y a la teja IO (en la segunda parte del artículo).

Descargo de responsabilidad: Trabajo para la empresa.

+0

Gracias, lo intentaré. ¿Sabes si hay algo similar para jpegs, pngs, aso, también? Por lo general, siempre voy por jpegs. – mgulde

+0

Hasta donde yo sé, no hay nada como esto para los archivos JPEG. Desafortunadamente, no sé si hay algo como esto para PNG. – Bobrovsky

Cuestiones relacionadas