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:
- transponer los elementos de cada DCT bloquear
- 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:
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:
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:
- Obviamente, reflejar las posiciones de cada bloque DCT en el eje requerido
- 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:
Usted notará que esto constituye una rotación de 90 grados hacia la izquierda.
Un programa llamado jpegtran http://jpegclub.org/jpegtran/ implementando todo esto está incluido en libjpeg http://jpegclub.org – datenwolf
Gracias por una muy buena explicación. – onemasse
@datenwolf: gracias. Definitivamente es mejor usar eso que tirar el tuyo. No es tan divertido, sin embargo :) – misha