2008-11-18 94 views
13

¿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?Escalado de imagen y rotación en C/C++

A continuación, 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?

Respuesta

10

No existe una forma "simple" de comprender eso. Tanto la escala como la rotación no son "trivial" procesis.

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

8

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

12

Hay muchas formas de escalar y girar las imágenes. La forma más sencilla de escalar es:

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

pero esto produce efectos de bloque 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, bilinear filtering.

para la rotación, la ubicación src pixel se puede calcular utilizando a rotation matrix:

sx,sy = M(dx,dy) 

donde M es una matriz que mapea los 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 profundizar en las matemáticas del procesamiento de imágenes.

3

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 irregularidad. 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 muestreo from 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.

9

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.

Mapping para un cambio de tamaño es fácil:

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

Mapeo para la rotación sólo es 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 frente a la rejilla 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.

2

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.

+0

Si bien esto puede responder a la pregunta en teoría, [sería preferible] (// meta.stackoverflow .com/q/8259) para incluir las partes esenciales de la respuesta aquí y proporcionar el enlace para referencia. –

0
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; 
} 
0

Los métodos de cambio de tamaño 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 redimensionar 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 el color diferente en 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á.

0

Eche 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.

+0

Si bien esto puede responder teóricamente a la pregunta, [sería preferible] (// meta.stackoverflow.com/q/8259) incluir aquí las partes esenciales de la respuesta y proporcionar el enlace de referencia. –

2

No se ha mencionado aún, 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 de escalar y girar generalmente dará como resultado una pérdida significativa de detalles.

El uso de 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); 

Esta escala la imagen hacia abajo por un factor de 0,68 usando Lanczos interpolación.

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 inclinación y la traducción en ella 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()); 

OpenCV Website

They have some very nice documentation too.

+0

Buen punto. He agregado algunos ejemplos, así que ahora es más una respuesta real. – Meta