c++ c image image-scaling
de VirtualDub

Escalado de imagen y rotación en C/C++



image-scaling (10)

point scaling(point p,float sx,float sy) { point s; int c[1][3]; int a[1][3]={p.x,p.y,1}; int b[3][3]={sx,0,0,0,sy,0,0,0,1}; multmat(a,b,c); s.x=c[0][0]; s.y=c[0][1]; return s; }

¿Cuál es la mejor manera de escalar una matriz de imágenes 2D? Por ejemplo, supongamos que tengo una imagen de 1024 x 2048 bytes, con cada byte como un píxel. Cada píxel es un nivel de escala de grises de 0 a 255. Me gustaría poder escalar esta imagen por un factor arbitrario y obtener una nueva imagen. Entonces, si escalo la imagen por un factor de 0.68, debería obtener una nueva imagen de tamaño 0.68 * 1024 x 0.68 * 2048. algunos píxeles se colapsarán entre sí. Y, si escalara por un factor de, por ejemplo, 3.15, obtendría una imagen más grande con píxeles duplicados. Entonces, ¿cuál es la mejor manera de lograr esto?

Luego, me gustaría poder rotar una imagen en un ángulo arbitrario, en el rango de 0 a 360 grados (0 - 2Pi). El recorte de la imagen después de rotar no es un problema. Cuál sería la mejor forma de hacer esto?


¿Desea hacer el trabajo sucio usted mismo o ImageMagick puede hacerlo por usted?


Duplicar o descartar píxeles no es el mejor método ni cambiar el tamaño de la imagen, ya que los resultados mostrarán pixelación y flojedad. Para obtener los mejores resultados, debe volver a muestrear la imagen, lo que le dará a la imagen resultante un aspecto mucho más suave. Hay muchos métodos para remuestrear, como bilineal, bicúbico, lanczos, etc.

Eche un vistazo a la función BicubicResample de wxWidgets. Funciona con todo tipo de imágenes, no solo en escala de grises, pero debería ser capaz de adaptarlo a sus necesidades. Luego también hay un código de remuestreo de VirtualDub . Google Codesearch puede revelar más código relacionado.

EDITAR: los enlaces se ven bien en la vista previa, pero se rompen cuando se publican. Esto es extraño. Vaya a google codesearch y busque "wxwidgets resamplebicubic" y "virtualdub remuestreo" respectivamente para obtener los mismos resultados.


Lo que estás haciendo es mapear un conjunto de puntos de entrada a un conjunto de puntos de salida. La primera parte del problema es determinar la asignación para su redimensionamiento o rotación; la segunda parte es para manejar puntos que no se encuentran exactamente en un límite de píxel.

El mapeo para cambiar el tamaño es fácil:

x'' = x * (width'' / width) y'' = y * (height'' / height)

El mapeo para la rotación es solo un poco más difícil.

x'' = x * cos(a) + y * sin(a) y'' = y * cos(a) - x * sin(a)

La técnica para determinar el valor de los píxeles que se encuentran fuera de la cuadrícula se llama interpolación. Existen muchos algoritmos de este tipo, que varían ampliamente en velocidad y calidad de imagen final. Algunos de ellos en orden ascendente de calidad / tiempo son el vecino más cercano, bilineal, bicúbico y filtro Sinc.


No hay una manera "simple" de comprender eso. Tanto la escala como la rotación no son procesos "triviales".

Google para una biblioteca de imágenes 2D. Magick ++ puede ser una idea como divideandconquer.se puntos, pero hay otros.


CxImage es una biblioteca gratuita para manejar imágenes, que puede hacer lo que desee. No lo he usado personalmente excepto por cosas triviales, pero lo he visto recomendado repetidamente.


Los métodos de cambio de tamaño de CxImage producen resultados extraños. Utilicé las funciones Resample y Resample2 con todas las variaciones disponibles de los métodos de interpolación con el mismo resultado. Por ejemplo, intente cambiar el tamaño de la imagen de 1024 x 768 llena de color blanco al tamaño 802 x 582. ¡Encontrará que hay píxeles en la imagen que tienen un color diferente al blanco! Puede verificar esto: abra la imagen de nuevo tamaño en Windows Paint e intente llenarla de color negro. El resultado seguramente te divertirá.


Echa un vistazo a Intel Performance Primitives . Lo he usado antes y produce un rendimiento casi óptimo en x86. También hay un programa de prueba que permite jugar con varios algoritmos.


Hay muchas formas de escalar y rotar imágenes. La forma más simple de escalar es:

dest[dx,dy] = src[dx*src_width/dest_width,dy*src_height/dest_height]

pero esto produce efectos de bloques al aumentar el tamaño y la pérdida de detalles al reducir el tamaño. Hay formas de producir resultados de mejor aspecto, por ejemplo, el filtrado bilineal .

Para rotar, la ubicación del píxel src puede calcularse usando una matriz de rotación :

sx,sy = M(dx,dy)

donde M es una matriz que asigna píxeles de destino a la imagen de origen. Nuevamente, deberá hacer interpolación para producir resultados no compactos.

Pero hay muchas bibliotecas disponibles si no desea adentrarse en las matemáticas del procesamiento de imágenes.


Todavía no se ha mencionado, así que señalaré que OpenCV tiene funciones para escalar y rotar imágenes, así como una enorme cantidad de otras utilidades. Puede contener muchas características que no son relevantes para la pregunta, pero es muy fácil de configurar y usar para una biblioteca de este tipo.

Puede intentar implementar transformaciones como esta manualmente, pero el enfoque simple para escalar y girar generalmente dará como resultado una pérdida significativa de detalles.

Usando OpenCV, la escala se puede hacer así:

float scaleFactor = 0.68f; cv::Mat original = cv::imread(path); cv::Mat scaled; cv::resize(original, scaled, cv::Size(0, 0), scaleFactor, scaleFactor, cv::INTER_LANCZOS4); cv::imwrite("new_image.jpg", scaled);

Esto escala la imagen por un factor de 0.68 usando la interpolación de Lanczos.

No estoy tan familiarizado con las rotaciones, pero esto es parte de un ejemplo de uno de los tutoriales en el sitio web de OpenCV que he editado en las partes correspondientes. (El original tenía sesgo y traducción en él también ...)

/// Compute a rotation matrix with respect to the center of the image Point center = Point(original.size().width / 2, original.size().height / 2); double angle = -50.0; double scale = 0.6; /// Get the rotation matrix with the specifications above Mat rot_mat( 2, 3, CV_32FC1 ); rot_mat = getRotationMatrix2D(center, angle, scale); /// Rotate the image Mat rotated_image; warpAffine(src, rotated_image, rot_mat, src.size());

Sitio web de OpenCV

También tienen una documentación muy buena.