2011-02-13 11 views
5

He oído que debería ser posible hacer una rotación sin pérdida en una imagen JPEG. Eso significa que haces la rotación en el dominio de la frecuencia sin un IDCT. Intenté buscar en Google pero no encontré nada. ¿Podría alguien traer algo de luz a esto?¿Cómo giro una imagen en el dominio de la frecuencia?

Lo que quiero decir con lossless es que no pierdo ninguna información adicional en la rotación. Y, por supuesto, eso probablemente solo sea posible al girar múltiplos de 90 grados.

Respuesta

6

no es necesario IDCT una imagen para girar sin pérdidas (tenga en cuenta que la rotación sin pérdida de imágenes de trama solo es posible para ángulos que son múltiplos de 90 grados).

Los pasos siguientes lograr una transposición de la imagen, en el dominio de la DCT:

  1. transponer los elementos de cada DCT bloquear
  2. transponer las posiciones de cada DCT bloquear

I' Voy a suponer que ya puede hacer lo siguiente:

  • Obtenga los coeficientes crudos de DCT para soy la imagen JPEG (si no, ver here)
  • Escribe los coeficientes de nuevo al archivo (si desea guardar la imagen girada)

no se puede mostrar el código completo, porque es bastante involucrado, pero aquí está la parte en la que la imagen IDCT (tenga en cuenta el IDCT es para propósitos de visualización única):

Size s = coeff.size(); 
Mat result = cv::Mat::zeros(s.height, s.width, CV_8UC1); 

for (int i = 0; i < s.height - DCTSIZE + 1; i += DCTSIZE) 
for (int j = 0; j < s.width - DCTSIZE + 1; j += DCTSIZE) 
{ 
    Rect rect = Rect(j, i, DCTSIZE, DCTSIZE); 
    Mat dct_block = cv::Mat::Mat(coeff, rect); 
    idct_step(dct_block, i/DCTSIZE, j/DCTSIZE, result); 
} 

Ésta es la imagen que se muestra:

Lenna

Aquí no sucede nada sofisticado: esta es solo la imagen original.

Ahora, aquí está el código que implementa tanto las medidas de transposición que he mencionado anteriormente:

Size s = coeff.size(); 
Mat result = cv::Mat::zeros(s.height, s.width, CV_8UC1); 

for (int i = 0; i < s.height - DCTSIZE + 1; i += DCTSIZE) 
for (int j = 0; j < s.width - DCTSIZE + 1; j += DCTSIZE) 
{ 
    Rect rect = Rect(j, i, DCTSIZE, DCTSIZE); 
    Mat dct_block = cv::Mat::Mat(coeff, rect); 
    Mat dct_bt(cv::Size(DCTSIZE, DCTSIZE), coeff.type()); 
    cv::transpose(dct_block, dct_bt);    // First transposition 
    idct_step(dct_bt, j/DCTSIZE, i/DCTSIZE, result); // Second transposition, swap i and j 
} 

Ésta es la imagen resultante:

transposed

se puede ver que la imagen es ahora transpuesto Para lograr una rotación adecuada, debe combinar la reflexión con la transposición.

EDITAR

Lo siento, se olvidó también que la reflexión no es trivial.También consta de dos pasos:

  1. Obviamente, reflejar las posiciones de cada bloque DCT en el eje requerido
  2. menos evidente, invertido (multiplicar por -1) cada fila impar O columna en cada Bloque DCT. Si está volteando verticalmente, invierta las filas . Si está volteando horizontalmente, invierta las columnas .

Aquí hay un código que realiza una reflexión vertical después de la transposición.

for (int i = 0; i < s.height - DCTSIZE + 1; i += DCTSIZE) 
for (int j = 0; j < s.width - DCTSIZE + 1; j += DCTSIZE) 
{ 
    Rect rect = Rect(j, i, DCTSIZE, DCTSIZE); 
    Mat dct_block = cv::Mat::Mat(coeff, rect); 

    Mat dct_bt(cv::Size(DCTSIZE, DCTSIZE), coeff.type()); 
    cv::transpose(dct_block, dct_bt); 

    // This is the less obvious part of the reflection. 
    Mat dct_flip = dct_bt.clone(); 
    for (int k = 1; k < DCTSIZE; k += 2) 
    for (int l = 0; l < DCTSIZE; ++l) 
     dct_flip.at<double>(k, l) *= -1; 

    // This is the more obvious part of the reflection. 
    idct_step(dct_flip, (s.width - j - DCTSIZE)/DCTSIZE, i/DCTSIZE, result); 
} 

Ésta es la imagen que se obtiene:

final

Usted notará que esto constituye una rotación de 90 grados hacia la izquierda.

+1

Un programa llamado jpegtran http://jpegclub.org/jpegtran/ implementando todo esto está incluido en libjpeg http://jpegclub.org – datenwolf

+0

Gracias por una muy buena explicación. – onemasse

+0

@datenwolf: gracias. Definitivamente es mejor usar eso que tirar el tuyo. No es tan divertido, sin embargo :) – misha

0

responsabilidad: :-)

La verdad es que conocen el algoritmo de compresión JPEG sólo a un nivel muy superficial. Lo que sé proviene del libro de Rick Booth, ligeramente anticuado pero excelente, Inner Loops, capítulo 17: JPEG.

No tengo una respuesta completa a su pregunta, más bien tengo una vaga idea de cuál podría ser la solución. Quizás eso ya sea útil para ti. Para ser honesto, en realidad estaría algo sorprendido de ver que lo tengo correcto.


rotación sin pérdida de una imagen JPEG parece sólo es posible si usted no tiene que decodificar primero usando un IDCT, y luego volver a codificar de nuevo una vez que haya girado la imagen, ya que es dos pasos computacionales donde puede ocurrir la pérdida de información.

Esto parece factible en absoluto porque una imagen codificada como JPEG ya está en el dominio de la frecuencia, ya que una DCT (Discrete Cosine Transform) ya se ha realizado en ella. Permítanme citar un breve pasaje del libro anterior (página 325):

Normalmente se lo conoce como DCT [& hellip;]. Conceptualmente, lo que sucede es que la 8 × 8 piezas de la imagen se multiplica por otras 8 matrices 8 × 8 para producir una matriz derivada 8 × 8. [& Hellip;]

Ordinariamente, dos 8 × 8 multiplicaciones de matrices requerirían 1.204 (64 2) pasos de multiplicación. Parte de la magia del DCT es que las matrices muy especiales elegidas para este paso tienen muchas simetrías internas, por lo que hay una manera de ejecutar las matemáticas con solo 80 pasos de multiplicación. Es esta simetría la que salva el día para JPEG y mantiene el algoritmo bastante rápido. — (el subrayado es de mí.)

pude imaginar que las simetrías en las matrices de transformación DCT hacen que sea posible girar más tarde, los transformados 8 × 8 matrices en algunos ángulos muy específicas sin alterar perceptualmente la imagen (aparte por el hecho de que se rotó, por supuesto). A nivel conceptual, lo que quiero decir es esto: Digamos que usted había transformado las 8 × 8 bloques de píxeles originales utilizando matrices tales como las siguientes:

   * . . . . . . * 
       . * . . . . * . 
       . . * . . * . . 
       . . . * * . . . 
       . . . * * . . . 
       . . * . . * . . 
       . * . . . . * . 
       * . . . . . . * 

(estoy usando símbolos en lugar de valores numéricos reales desde la Primera solo quiero mostrar la simetría de esta matriz.)

Tal matriz de transformación fuerza le permiten girar las matrices transformadas en un múltiplo de 90 grados en cualquier dirección, desde la matriz de transformación en sí siempre se vería idénticos si transformado en los mismos ángulos.

Si de hecho esto es lo que lee, significa que la rotación sin pérdida no funcionará para ángulos de rotación arbitrarios. Los ángulos que garantizan ninguna pérdida dependerán de las matrices utilizadas durante la codificación JPEG.

+0

Bueno, tal vez no fui lo suficientemente claro. Lo que quiero decir con lossless es que no pierdo información adicional en la rotación. Y, por supuesto, eso probablemente solo sea posible al girar múltiplos de 90 grados. – onemasse

+0

tiene razón acerca de que la rotación sin pérdidas solo es posible para ángulos que son múltiplos de 90 grados, pero está equivocado sobre que el paso de IDCT es obligatorio. – misha

+0

* @ misha *: Eso es bueno saberlo. ¿Conoces, por casualidad, un buen documento sobre el funcionamiento de JPEG? Siempre estoy feliz de aprender – stakx

Cuestiones relacionadas