c++ - tamaños - ¿Cómo hago una escala de alta calidad de una imagen?
tamaño de imagen (11)
Un artículo genérico de nuestro amado anfitrión: Mejor cambio de tamaño de la imagen , discutiendo las cualidades relativas de varios algoritmos (y se vincula a otro artículo de CodeProject).
Estoy escribiendo un código para escalar una imagen RGBA de 32 bits en C / C ++. He escrito algunos intentos que han sido un tanto exitosos, pero son lentos y lo más importante es que la calidad de la imagen de tamaño no es aceptable.
Comparé la misma imagen escalada por OpenGL (es decir, mi tarjeta de video) y mi rutina, y está a millas de distancia en calidad. Tengo Google Code Searched, árboles de fuentes de todo lo que pensé que arrojaría algo de luz (SDL, Allegro, wxWidgets, CxImage, GD, ImageMagick, etc.) pero generalmente su código está enrevesado o esparcido por todo el lugar o plagado de ensamblador y poco o nada de comentarios. También he leído varios artículos en Wikipedia y en otros lugares, y simplemente no encuentro una explicación clara de lo que necesito. Entiendo los conceptos básicos de interpolación y muestreo, pero estoy luchando para obtener el algoritmo correcto. NO quiero confiar en una biblioteca externa para una rutina y tener que convertir a su formato de imagen y viceversa. Además, me gustaría saber cómo hacerlo yo mismo de todos modos. :)
He visto una pregunta similar sobre el desbordamiento de pila antes, pero en realidad no fue respondida de esta manera, pero espero que haya alguien que pueda ayudarme a empujarme en la dirección correcta. Tal vez apuntarme a algunos artículos o pseudocódigos ... cualquier cosa para ayudarme a aprender y hacer.
Esto es lo que estoy buscando:
- No ensamblador (estoy escribiendo código muy portátil para múltiples tipos de procesadores).
- Sin dependencias en bibliotecas externas.
- Me preocupa principalmente escalar hacia ABAJO, pero también necesitaré escribir una rutina de escala más adelante.
- La calidad del resultado y la claridad del algoritmo es lo más importante (puedo optimizarlo más adelante).
Mi rutina esencialmente toma la siguiente forma:
DrawScaled(uint32 *src, uint32 *dst,
src_x, src_y, src_w, src_h,
dst_x, dst_y, dst_w, dst_h );
¡Gracias!
ACTUALIZACIÓN: para aclarar, necesito algo más avanzado que una nueva muestra de cuadro para la reducción de escala que desenfoca demasiado la imagen. Sospecho que lo que quiero es algún tipo de filtro bicúbico (u otro) que sea algo inverso a un algoritmo de escalamiento bicúbico (es decir, cada píxel de destino se calcula a partir de todos los píxeles fuente combinados con un algoritmo de ponderación que mantiene las cosas nítidas.
Ejemplo
Aquí hay un ejemplo de lo que obtengo del algoritmo wxWidgets BoxResample contra lo que quiero en un mapa de bits de 256x256 a escala de 55x55.
- www.free_image_hosting.net/uploads/1a25434e0b.png
Y finalmente:
- www.free_image_hosting.net/uploads/eec3065e2f.png
la imagen original de 256x256
¿Es posible que OpenGL esté escalando en el dominio vectorial? Si es así, no hay forma de que una escala basada en píxeles vaya a estar cerca de la calidad. Esta es la gran ventaja de las imágenes basadas en vectores.
El algoritmo bicúbico se puede sintonizar para la nitidez frente a los artefactos. Estoy tratando de encontrar un enlace, lo editaré cuando lo haga.
Editar: Fue en el trabajo de Mitchell-Netravali en el que estaba pensando, al que se hace referencia al final de este enlace:
http://www.cg.tuwien.ac.at/~theussl/DA/node11.html
También podría considerar el remuestreo de Lanczos como alternativa al bicúbico.
Artículos de CodeProject discutiendo y compartiendo el código fuente para escalar imágenes:
Como seguimiento, Jeremy Rudd publicó este artículo arriba. Implementa el cambio de tamaño de dos pases filtrados. Las fuentes son C #, pero se ve lo suficientemente claro como para poder portarlo para intentarlo. Ayer encontré un código C muy similar que era mucho más difícil de entender (nombres de variable muy malos). Lo hice por tipo de trabajo, pero fue muy lento y no produjo buenos resultados, lo que me llevó a creer que había un error en mi adaptación. Puede que tenga mejor suerte escribiéndolo desde cero con esto como referencia, lo intentaré.
Pero teniendo en cuenta cómo funciona el algoritmo de dos pasos, me pregunto si no hay una manera más rápida de hacerlo, tal vez incluso en una sola pasada.
Eche un vistazo a ImageMagick , que hace todo tipo de filtros de cambio de escala.
He encontrado la implementación de wxWidgets bastante fácil de modificar según sea necesario. Es todo C ++ así que no hay problemas con la portabilidad allí. La única diferencia es que su implementación funciona con arreglos de caracteres sin signo (que, en mi opinión, es la forma más fácil de tratar las imágenes) con un orden de bytes de RGB y el componente alfa en una matriz separada.
Si se refiere al archivo "src / common / image.cpp" en el árbol de código fuente de wxWidgets, hay una función down-sampler que utiliza un método de muestreo de cuadro "wxImage :: ResampleBox" y una función de aumento de escala llamada "wxImage :: ResampleBicubic ".
Intel tiene bibliotecas IPP que proporcionan algoritmos de interpolación de alta velocidad optimizados para procesadores de la familia Intel. Es muy bueno, pero no es gratuito. Eche un vistazo al siguiente enlace:
Intente utilizar la biblioteca de imágenes genérica de Adobe ( http://opensource.adobe.com/wiki/display/gil/Downloads ) si quiere algo listo y no solo un algoritmo.
Extracto de: http://www.catenary.com/howto/enlarge.html#c
Aumentar o reducir: el código fuente de C requiere la Biblioteca de procesamiento de imágenes Victor para Windows v 5.3 o superior de 32 bits.
int enlarge_or_reduce(imgdes *image1)
{
imgdes timage;
int dx, dy, rcode, pct = 83; // 83% percent of original size
// Allocate space for the new image
dx = (int)(((long)(image1->endx - image1->stx + 1)) * pct / 100);
dy = (int)(((long)(image1->endy - image1->sty + 1)) * pct / 100);
if((rcode = allocimage(&timage, dx, dy,
image1->bmh->biBitCount)) == NO_ERROR) {
// Resize Image into timage
if((rcode = resizeex(image1, &timage, 1)) == NO_ERROR) {
// Success, free source image
freeimage(image1);
// Assign timage to image1
copyimgdes(&timage, image1);
}
else // Error in resizing image, release timage memory
freeimage(&timage);
}
return(rcode);
}
Este ejemplo cambia el tamaño de un área de imagen y reemplaza la imagen original con la nueva imagen.
Un algoritmo bastante simple y decente para volver a muestrear imágenes es la interpolación Bicúbica , solo wikipedia tiene toda la información que necesita para implementarlo.
Ahora que veo su imagen original, creo que OpenGL está usando un algoritmo vecino más cercano. No solo es la forma más sencilla de cambiar el tamaño, sino que también es la más rápida. El único inconveniente es que se ve muy duro si hay algún detalle en la imagen original.
La idea es tomar muestras espaciadas uniformemente de su imagen original; en su caso, 55 de 256, o uno de cada 4.6545. Simplemente redondee el número para obtener el píxel a elegir.
Parece que lo que realmente está teniendo dificultades para entender es el flujo discreto -> continuo -> que implica el remuestreo de una imagen. Un buen informe técnico que podría ayudar a darle una idea de esto que necesita es Un píxel de Alvy Ray Smith no es una pequeña plaza .