【问题标题】:How do I rotate an image in the frequency domain?如何在频域中旋转图像?
【发布时间】:2023-03-04 09:27:01
【问题描述】:

我听说应该可以对 jpeg 图像进行无损旋转。这意味着您在没有 IDCT 的情况下在频域中进行旋转。我试图用谷歌搜索它,但没有找到任何东西。有人可以对此有所启发吗?

我所说的无损是指我不会在轮换中丢失任何附加信息。当然,这可能只有在旋转 90 度的倍数时才有可能。

【问题讨论】:

    标签: image-processing image-manipulation jpeg image-rotation


    【解决方案1】:

    您确实不需要需要对图像进行 IDCT 以无损旋转它(请注意,光栅图像的无损旋转仅适用于 90 度的倍数)。

    以下步骤在 DCT 域中实现图像的转置:

    1. 转置每个 DCT 块的元素
    2. 转置每个 DCT 块的位置

    我假设您已经可以执行以下操作:

    • 从 JPEG 图像中获取原始 DCT 系数(如果没有,请参阅 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);
    }
    

    这是显示的图像:

    这里没有什么花哨的东西——这只是原始图像。

    现在,这是实现我上面提到的两个转置步骤的代码:

    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
    }
    

    这是生成的图像:

    您可以看到图像现在已转置。要实现正确的旋转,您需要将反射与转置结合起来。

    编辑

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

    1. 很明显,反映每个DCT块在所需轴上的位置
    2. 不太明显,将 每个 DCT 块中的每个奇数行 OR 列反转(乘以 -1)。如果您要垂直翻转,请反转奇数。如果您要水平翻转,请反转奇数

    这是在转置后执行垂直反射的代码。

    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 度。

    【讨论】:

    • 一个名为 jpegtran jpegclub.org/jpegtran 的程序实现了所有这些,包含在 libjpeg jpegclub.org
    • @datenwolf:谢谢。绝对比自己动手更好。不过没那么有趣:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-03
    • 2017-04-14
    • 2016-02-04
    • 2015-04-04
    • 2011-06-25
    • 2016-07-20
    相关资源
    最近更新 更多