2010-12-06 13 views
5

He escrito un programa que toma una "foto" y por cada píxel que elige para insertar una imagen de una serie de otras fotos. La imagen elegida es la foto cuyo color promedio es el más cercano al píxel original de la fotografía.Adjuntar a un archivo de imagen

He hecho esto promediando los valores de rgb de cada píxel en la imagen 'stock' y luego convirtiéndolo en CIE LAB para poder calcular cuán 'cerca' está del píxel en cuestión en términos de percepción humana del color

He compilado una imagen en la que cada píxel de la imagen original 'foto' ha sido reemplazado por la imagen de stock 'más cercana'.

Funciona bien y el efecto es bueno, sin embargo, el tamaño de la imagen es de 300 por 300 píxeles e incluso con los indicadores de la máquina virtual de "-Xms2048m -Xmx2048m", que sí sé es ridículo, en 555px por 540px imagen I solo puede reemplazar las imágenes de stock reducidas a 50 px antes de que obtenga un error de falta de memoria.

Así que, básicamente, estoy tratando de pensar en soluciones. En primer lugar, creo que el efecto de imagen puede mejorarse promediando cada 4 píxeles (2x2 cuadrados) de la imagen original en un solo píxel y luego reemplazando este píxel con la imagen, de esta manera las fotos pequeñas serán más visibles en la impresión individual . Esto también debería permitirme dibujar las imágenes en un tamaño mayor. ¿Alguien tiene alguna experiencia en este tipo de manipulación de imágenes? Si es así, ¿qué trucos ha descubierto para producir una imagen agradable?

En última instancia, creo que la forma de reducir los errores de memoria sería guardar la imagen en el disco varias veces y anexar la siguiente línea de imágenes mientras se elimina continuamente el antiguo conjunto de imágenes renderizadas de la memoria. ¿Cómo puede hacerse esto? Es similar a agregar un archivo normal.

Cualquier ayuda en este último asunto sería muy apreciada.

Gracias,

Alex

Respuesta

3

Sugiero consultar la API de Java Advanced Imaging (JAI). Probablemente esté utilizando BufferedImage ahora mismo, lo que mantiene todo en la memoria: las imágenes de origen y las de salida. Esto se conoce como procesamiento de "modo inmediato". Cuando llamas a un método para cambiar el tamaño de la imagen, sucede de inmediato. Como resultado, todavía conserva las imágenes en la memoria.

Con JAI, hay dos ventajas que puede aprovechar.

  1. Procesamiento en modo diferido.
  2. cálculo de azulejos.

El modo diferido significa que las imágenes de salida no se calculan correctamente cuando llama a los métodos en las imágenes. En cambio, una llamada para cambiar el tamaño de una imagen crea un pequeño objeto de "operador" que puede hacer el cambio de tamaño más tarde. Esto le permite construir cadenas, árboles o tuberías de operaciones. Por lo tanto, su trabajo crearía un árbol de operaciones como "recorte, cambio de tamaño, compuesto" para cada imagen de stock.Lo bueno es que las operaciones son solo objetos de comando, así que no estás consumiendo toda la memoria mientras construyes tus comandos.

Esta API está basada en el tirón. Se difiere el cálculo hasta que alguna acción de salida extraiga píxeles de los operadores. Esto ayuda a ahorrar tiempo y memoria al evitar operaciones de píxeles innecesarias.

Por ejemplo, suponga que necesita una imagen de salida de 2048 x 2048 píxeles, ampliada a partir de un recorte de 512x512 de una imagen de origen que tiene 1600x512 píxeles. Obviamente, no tiene sentido escalar toda la imagen fuente de 1600x512, solo para tirar 2/3 de los píxeles. En cambio, el operador de escala tendrá una "región de interés" (ROI) en función de sus dimensiones de salida. El operador de escalado proyecta el retorno de la inversión en la imagen de origen y solo calcula esos píxeles.

Los comandos deben eventualmente ser evaluados. Esto sucede en algunas situaciones, principalmente relacionadas con la salida de la imagen final. Por lo tanto, pedir que una Imagen Buffered muestre la salida en la pantalla obligará a todos los comandos a evaluar. Del mismo modo, escribir la imagen de salida en el disco forzará la evaluación.

En algunos casos, puede mantener el segundo beneficio de JAI, que es la representación basada en mosaico. Mientras que BufferedImage hace todo su trabajo de inmediato, en todos los píxeles, la representación de mosaico solo funciona en secciones rectangulares de la imagen a la vez.

Utilizando el ejemplo de antes, la imagen de salida de 2048x2048 se dividirá en mosaicos. Supongamos que son 256x256, y luego la imagen completa se divide en 64 mosaicos. Los objetos del operador JAI saben cómo trabajar una ficha en una ficha. Por lo tanto, escalar la sección de 512x512 de la imagen de origen realmente sucede 64 veces en píxeles de origen de 64x64 a la vez.

Calcular un mosaico a la vez significa pasar por encima de los mosaicos, lo que parecería llevar más tiempo. Sin embargo, dos cosas funcionan a su favor cuando se realiza el cálculo de los mosaicos. En primer lugar, las teselas se pueden evaluar en varios subprocesos al mismo tiempo. Segundo, el uso de la memoria transitoria es mucho, mucho más bajo que el cálculo del modo inmediato.

Todo lo cual es una explicación larga de por qué desea utilizar JAI para este tipo de procesamiento de imágenes.


Un par de notas y advertencias:

  1. Usted puede derrotar representación basada baldosas sin darse cuenta. En cualquier lugar en el que tenga una Imagen Buffered en el flujo de trabajo, no puede actuar como fuente o receptor de mosaicos.
  2. Si renderiza en el disco utilizando los operadores JAI o JAI Image I/O para JPEG, entonces está en buena forma. Si intenta utilizar las clases de imágenes integradas del JDK, necesitará toda la memoria. (Básicamente, evite mezclar los dos tipos de manipulación de imágenes. El modo inmediato y el modo diferido no se combinan bien).
  3. Todas las cosas elegantes con ROI, mosaicos y modo diferido son transparentes para el programa. Solo haces una llamada API en la clase JAI. Solo maneja la maquinaria si necesita más control sobre cosas como el tamaño de los mosaicos, el almacenamiento en caché y la simultaneidad.
0

Cada vez que áppend '¿Estás quizás implícitamente creando un nuevo objeto con una más píxeles para reemplazar el anterior (es decir, un paralelo al clásico problema de añadir varias veces a una cadena en lugar de usar un StringBuilder)?

Si publica la parte de su código que almacena y agrega, probablemente alguien lo ayude a encontrar una forma eficiente de recodificarlo.

2

Aquí hay una sugerencia que podría ser útil;

Intente segregar las dos tareas principales en programas individuales.Su primera tarea es decidir qué imágenes van a donde, y que puede ser un simple mapeo de coordenadas a los nombres de archivo, que puede representarse como líneas de texto:

0,0,image123.jpg 
0,1,image542.jpg 
..... 

Después se lleva a cabo esa tarea (y parece que usted tenerlo bien manejado), entonces puede tener un programa separado para manejar la compilación.

Esta compilación se puede hacer agregando a una imagen, pero es probable que no quiera perder el tiempo con los formatos de archivo. Es mejor dejar que su entorno de programación lo haga mediante el uso de un objeto de imagen Java de algún tipo. El tamaño más grande que puede caber en la memoria en píxeles será de 2 GB, lo que da como resultado una altura y ancho máximos de sqrt (2x10^9). A partir de este número y dividiendo por el número de imágenes que tiene para la altura y el ancho, obtendrá los píxeles generales por subimagen permitidos, y puede pintarlos en los lugares apropiados.

Cuestiones relacionadas