如何在频域中旋转图像?

发布于 2024-10-17 02:34:22 字数 145 浏览 6 评论 0原文

我听说应该可以对 jpeg 图像进行无损旋转。这意味着您可以在频域中进行旋转,而无需 IDCT。我尝试用谷歌搜索但没有找到任何东西。有人可以对此带来一些启发吗?

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

I've heard that it should be possible to do a lossless rotation on a jpeg image. That means you do the rotation in the frequency domain without an IDCT. I've tried to google it but haven't found anything. Could someone bring some light to this?

What I mean by lossless is that I don't lose any additional information in the rotation. And of course that's probably only possible when rotating multiples of 90 degrees.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冷月断魂刀 2024-10-24 02:34:22

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

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

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

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

  • 从 JPEG 中获取原始 DCT 系数图像(如果没有,请参阅此处
  • 写回系数到文件(如果你想保存旋转的图像)

我无法向你展示完整的代码,因为它非常复杂,但这里是我对图像进行IDCT的部分(注意IDCT仅用于显示目的< /strong>):

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
}

这是生成的图像:

 transpose

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

编辑

抱歉,我忘记了反射也不是微不足道的。它也包含两个步骤:

  1. 显然,反映每个 DCT 块在所需轴上的位置
  2. 不太明显,反转(乘以 -1)eachOR 列> 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 度。

You do not need to IDCT an image to rotate it losslessly (note that lossless rotation for raster images is only possible for angles that are multiples of 90 degrees).

The following steps achieve a transposition of the image, in the DCT domain:

  1. transpose the elements of each DCT block
  2. transpose the positions of each DCT block

I'm going to assume you can already do the following:

  • Grab the raw DCT coefficients from the JPEG image (if not, see here)
  • Write the coefficients back to the file (if you want to save the rotated image)

I can't show you the full code, because it's quite involved, but here's the bit where I IDCT the image (note the IDCT is for display purposes only):

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);
}

This is the image that is shown:

Lenna

Nothing fancy is happening here -- this is just the original image.

Now, here's the code that implements both the transposition steps I mentioned above:

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
}

This is the resulting image:

transposed

You can see that the image is now transposed. To achieve proper rotation, you need to combine reflection with transposition.

EDIT

Sorry, I forgot that reflection is also not trivial. It also consists of two steps:

  1. Obviously, reflect the positions of each DCT block in the required axis
  2. Less obviously, invert (multiply by -1) each odd row OR column in each DCT block. If you're flipping vertically, invert odd rows. If you're flipping horizontally, invert odd columns.

Here's code that performs a vertical reflection after the transposition.

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);
}

Here's the image you get:

final

You will note that this constitutes a rotation by 90 degrees counter-clockwise.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文