Вам не нужно IDCT изображение, чтобы повернуть его без потерь (обратите внимание, что вращение без потерь для растровых изображений возможно только для углов, кратных 90 градусам).
Следующие шаги позволяют выполнить транспонирование изображения в области DCT:
- транспонировать элементы каждого блока DCT
- транспонировать позиции каждого блока DCT
Я предполагаю, что вы уже можете делать следующее:
- Получение необработанных коэффициентов DCT из изображения JPEG (если нет, см. здесь )
- Запишите коэффициенты обратно в файл (если вы хотите сохранить повернутое изображение)
Я не могу показать вам полный код, потому что он довольно сложный, но вот фрагмент, где я IDCT изображение (обратите внимание, IDCT предназначен только для отображения ):
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);
}
Это изображение, которое показано:
Здесь ничего необычного не происходит - это просто исходное изображение.
Теперь вот код, который реализует оба шагов транспонирования, которые я упомянул выше:
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
}
Это полученное изображение:
Вы можете видеть, что изображение теперь транспонировано. Чтобы добиться правильного вращения, вам нужно объединить отражение с транспозицией.
EDIT
Извините, я забыл, что отражение тоже не тривиально. Он также состоит из двух этапов:
- Очевидно, отразите положения каждого блока DCT на требуемой оси
- Менее очевидно, инвертировать (умножить на -1) каждую нечетную строку ИЛИ столбец в каждый блок DCT. Если вы переворачиваете вертикально, инвертируйте нечетные строки . Если вы переворачиваете по горизонтали, инвертируйте нечетные столбцы .
Вот код, который выполняет вертикальное отражение после транспонирования.
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);
}
Вот изображение, которое вы получаете:
Вы заметите, что это составляет поворот на 90 градусов против часовой стрелки.