2011-02-13 155 views
5

我听说应该可以在jpeg图像上进行无损旋转。这意味着你在没有IDCT的情况下进行频域旋转。我试图谷歌它,但没有发现任何东西。有人能为此带来一些启示吗?如何在频域中旋转图像?

我的意思是无损是我在旋转中不会丢失任何其他信息。当然,这可能只有在旋转90度的倍数时才有可能。

回答

6

你做不是需要IDCT图像无损地旋转它(注意光栅图像的无损旋转仅适用于90度倍数的角度)。

以下步骤实现所述图像的换位,在DCT域中:

  1. 转置每个DCT的元件阻挡
  2. 转置每个DCT的位置方框

I” m会假设你已经可以做到以下几点:

  • 获取原始DCT系数米JPEG图像(如果不是,见here
  • 写系数回文件(如果您想保存旋转后的图像)

我不能告诉你完整的代码,因为它是相当参与其中,但在这里就是我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); 
} 

这是显示的图像:

Lenna

这里没有什么奇特的事情发生 - 这只是原始图像。

现在,这里实现我上面提到的换位步骤的代码:

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 
} 

这是得到的图像:

transposed

你可以看到图像是现在换位了。为了实现正确的旋转,你需要结合反射与换位。

编辑

对不起,我忘了,反射也并不是微不足道的。它还包括两个步骤:

  1. 显然,反映每个DCT块的位置在所需要的轴
  2. 较少明显,转化(乘以-1)每个每个奇数行OR柱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); 
} 

这里就是你得到的图像:

final

你会注意到这个逆时针90度构成的旋转。

0

免责声明: :-)

诚然,我所知道的JPEG压缩算法只在非常肤浅的水平。我所知道的来自Rick Booth的有点过时但很好的书Inner Loops,第17章:JPEG。

我对您的问题没有一个完整的答案,而是我对解决方案可能会有一个模糊的想法。也许这对你已经有所帮助了。说实话,我确实有些惊讶,看到我说得对。


JPEG图像的

无损旋转,如果你不会有第一次使用IDCT再次进行解码,然后重新编码,一旦你旋转的图像,因为这似乎只是可能两个可能发生信息丢失的计算步骤。

这似乎是可行的,因为编码为JPEG的图像已经在频域中,因为已经对其执行了DCT(离散余弦变换)。让我引用上述书中的一小段话(第325页):

通常被称为DCT [&hellip;]。从概念上来说,会发生什么情况是8张图片乘以另外两张8矩阵以产生一个导数8矩阵。 [&hellip;]

通常,两个8 × 8矩阵乘法将需要1204(64 2)乘法步骤。 DCT的神奇之处在于为这一步选择的非常特殊的矩阵有很多内部对称性,所以有一种方法只用80个乘法步骤来执行数学运算。正是这种对称性为JPEG节省了一天,并保持算法相当快。 —(由我添加的重点。)

我可以想像,在DCT变换矩阵的对称性使人们有可能以后转动在一些非常具体的角度变换8点× 8矩阵没有知觉改变图像(除从它旋转的事实当然)。从概念上讲,我的意思是这样的:比方说,你已经改变使用基质如下面原来8个× 8像素块:因为我

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

(我用符号代替实际数值只想显示这个矩阵的对称性。)

这样的转换矩阵可能允许您在任何方向上将转换后的矩阵旋转90度的倍数,因为如果在相同角度下转换,转换矩阵本身总是看起来相同。

如果确实这是你读到的内容,这将意味着无损旋转不适用于任意旋转角度。保证无损失的角度取决于JPEG编码过程中使用的矩阵。

+0

嗯,也许我不够清楚。我的意思是无损的是我不会在轮换中丢失任何其他信息。当然,这可能只有在旋转90度的倍数时才有可能。 – onemasse 2011-02-13 12:01:28

+0

你说的无损旋转只适用于90度倍数的角度是正确的,但是对于IDCT步骤是强制性的你错了。 – misha 2011-02-13 12:09:27