2012-04-18 10 views
9

Necesito escalar imágenes en forma de matriz en un Trabajador web. Si estuviera fuera de un trabajador web, podría usar un lienzo y un dibujo para copiar ciertas partes de una imagen o escalarla.Trabajador web y escalado de imágenes

Parece que en un trabajador web no puedo usar un lienzo, entonces, ¿qué puedo hacer? ¿Hay alguna biblioteca de JavaScript pura que pueda ayudarme?

Gracias mucho por adelantado.

+0

Hey hombre que necesito para hacer lo mismo, ¿alguna findf cualquier ImageData/ByteArray RGBA se superpone y amplía/reduce bibliotecas o funciones? – Noitidart

Respuesta

15

La escala se puede realizar de varias formas, pero todas se reducen a la eliminación o creación de píxeles de la imagen. Dado que las imágenes son esencialmente matrices (redimensionadas como matrices) de valores de píxel, puede considerar la ampliación de las imágenes como la ampliación de la matriz y el llenado de los espacios en blanco y la reducción de imágenes como una reducción de la matriz dejando valores.

Habiendo dicho eso, generalmente no es tan difícil escribir su propia función de escala en JavaScript que funciona en matrices. Como entiendo que ya tiene las imágenes en forma de matriz de JavaScript, puede pasar esa matriz en un mensaje al Trabajador web, escalar su función de escala y enviar la matriz escalada al hilo principal.

En términos de representación, le aconsejo que use el Uint8ClampedArray que fue diseñado para imágenes codificadas RGBA (color, con canal alfa) y es más eficiente que las matrices JavaScript normales. También puede enviar fácilmente objetos Uint8ClampedArray en mensajes a su Trabajador web, por lo que no será un problema. Otra ventaja es que se usa un Uint8ClampedArray en el tipo de datos ImageData (después de reemplazar CanvasPixelArray) de Canvas API. Esto significa que es bastante fácil volver a dibujar su imagen escalada en un lienzo (si eso era lo que quería), simplemente obteniendo el ImageData actual del contexto 2D del lienzo usando ctx.getImageData() y cambiando su atributo de datos a su escala Objeto Uint8ClampedArray.

Por cierto, si aún no tiene sus imágenes como matrices, puede usar el mismo método. Primero dibuje la imagen en el lienzo y luego use el atributo de datos del objeto ImageData actual para recuperar la imagen en un Uint8ClampedArray.

En cuanto a los métodos de escala para mejorar una imagen, básicamente hay dos componentes que debe implementar. El primero es dividir los píxeles conocidos (es decir, los píxeles de la imagen que está escalando) sobre la nueva matriz más grande que ha creado. Una forma obvia es dividir uniformemente todos los píxeles sobre el espacio. Por ejemplo, si está haciendo que el ancho de una imagen sea el doble de ancho, simplemente debe omitir una posición después de que cada píxel deje espacios en blanco intermedios.

El segundo componente es rellenar esos espacios en blanco, lo que puede ser un poco menos sencillo. Sin embargo, hay varios que son bastante fáciles. (Por otro lado, si tiene algún conocimiento de Visión artificial o Procesamiento de imágenes, le recomendamos que consulte algunos métodos más avanzados.) Un método fácil y algo obvio es interpolar cada posición de píxel desconocida utilizando el vecino más cercano (es decir, el más cercano valor de píxel que se conoce) duplicando el color del píxel conocido. Normalmente, esto produce el efecto de píxeles más grandes (bloques más grandes del mismo color) al escalar demasiado las imágenes. En lugar de duplicar el color del píxel más cercano, también puede tomar el promedio de varios píxeles conocidos que están cerca. Posiblemente, incluso en combinación con los pesos, logras que los píxeles más cercanos cuenten más en el promedio que los píxeles que están más lejos. Otros métodos incluyen difuminar la imagen usando gaussianos. Si desea averiguar qué método es el mejor para su aplicación, consulte algunas páginas sobre interpolación de imágenes. Por supuesto, recuerda que escalar siempre significa rellenar cosas que realmente no existen. Lo cual siempre se verá mal si lo haces demasiado.

En lo que respecta a la reducción de escala, uno normalmente solo elimina los píxeles transfiriendo solo una selección de píxeles de la matriz actual a la matriz más pequeña.Por ejemplo, si desea duplicar el tamaño de una imagen, recorre aproximadamente la matriz actual con pasos de 2 (Esto depende un poco de las dimensiones de la imagen, par o impar, y de la representación que está utilizando). Hay métodos que lo hacen incluso mejor eliminando aquellos píxeles que podrían perderse más. Pero no sé lo suficiente sobre ellos.

Por cierto, todo esto prácticamente no está relacionado con los trabajadores de la web. Lo haría exactamente de la misma manera si quisiera escalar imágenes en JavaScript en el hilo principal. O en cualquier otro idioma para ese asunto. Sin embargo, Web Workers es una forma muy agradable de hacer estos cálculos en un hilo separado en lugar de en el hilo de UI, lo que significa que el sitio web en sí no parece no responder. Sin embargo, como dijiste, todo lo que implica el elemento canvas debe hacerse en el hilo principal, pero las matrices de escala pueden realizarse en cualquier lugar.

Además, estoy seguro de que existen bibliotecas de JavaScript que pueden hacer esto por usted y, dependiendo de sus métodos, también puede cargarlas en su Trabajador web utilizando importScripts. Pero diría que en este caso podría ser más fácil y mucho más divertido tratar de escribirlo usted mismo y hacerlo a medida para su propósito.

Y dependiendo de qué tan avanzadas sean sus habilidades de programación y la velocidad a la que necesita escalar, siempre puede intentar hacer esto en la GPU en lugar de en la CPU utilizando WebGL. Pero eso parece una ligera exageración en este caso. Además, puede intentar cortar la imagen en varias piezas y tratar de escalar las partes separadas en varios Trabajadores web, lo que hace que sea multihilo. Aunque ciertamente no es trivial combinar las partes más tarde. Tal vez con múltiples subprocesos tiene más sentido cuando tiene muchas imágenes que necesitan escalarse en el lado del cliente.

Todo depende de su aplicación, las imágenes y sus propias habilidades y deseos.

De todos modos, espero que responda aproximadamente a su pregunta.

+0

Muchas gracias por todos los detalles. Y una simple implementación de javascript por sí sola será suficiente en mi caso. –

+1

hombre ... esa es una respuesta – Jeremythuff

5

Creo que se necesitan algunos detalles sobre la respuesta de mslatour, ya que solo pasé 6 horas tratando de descubrir cómo "... simplemente ... cambiar su atributo de datos a su objeto Uint8ClampedArray a escala". Para hacer esto:

① Envíe su matriz desde el trabajador web. Utilice el formulario:

self.postMessage(bufferToReturn, [bufferToReturn]); 

para pasar su memoria intermedia desde y hacia el trabajador web sin necesidad de hacer una copia de la misma, si no quiere. (Es más rápido de esta manera.) (Hay some MDN documentation, pero no puedo vincular a él ya que estoy fuera de representante. Lo siento,) De todos modos, también puedes poner el primer bufferToReturn dentro de listas o mapas, como este:

self.postMessage({buffer:bufferToReturn, width:500, height:500}, [bufferToReturn]); 

Usted usar algo como

webWorker.addEventListener('message', function(event) {your code here}) 

para escuchar un mensaje publicado. (En este caso, los eventos que se publican son del trabajador web y el evento que escucha está en el código JS normal. Funciona de la misma manera, simplemente cambie las variables 'self' y 'webWorker'.)

② En su Javascript del lado del navegador (a diferencia del lado del trabajador), puede usar imageData .data.set() para "simplemente" cambiar el atributo de datos y volver a colocarlo en el lienzo.

var imageData = context2d.createImageData(width, height); 
imageData.data.set(new Uint8ClampedArray(bufferToReturn)); 
context2d.putImageData(imageData, x_offset, y_offset); 

Me gustaría dar las gracias hacks.mozilla.org para mí alertar a la existencia del método data.set().

p.s. No sé de ninguna biblioteca para ayudar con esto ... todavía. Lo siento.

Cuestiones relacionadas