6

jpeg 画像を無損失で回転できるはずだと聞いたことがあります。つまり、IDCT を使用せずに周波数領域で回転を行います。私はそれをグーグルで検索しようとしましたが、何も見つかりませんでした。誰かがこれに光を当てることができますか?

ロスレスとは、ローテーションで追加情報を失わないということです。もちろん、これはおそらく 90 度の倍数を回転させた場合にのみ可能です。

4

1 に答える 1

7

イメージをロスレスで回転させるために IDCT を行う必要はありませ(ラスター イメージのロスレス回転は、90 度の倍数の角度でのみ可能であることに注意してください)。

次の手順では、DCT ドメインで画像の転置を行います。

  1. 各 DCT ブロックの要素を転置する
  2. 各 DCT ブロックの位置を転置する

すでに次のことができると仮定します。

  • JPEG 画像から生の DCT 係数を取得します (そうでない場合は、こちらを参照してください) 。
  • 係数をファイルに書き戻します (回転した画像を保存する場合)

非常に複雑なため、完全なコードを表示することはできませんが、画像を 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
}

これは結果の画像です:

転置

画像が転置されていることがわかります。適切な回転を実現するには、反射と転置を組み合わせる必要があります。

編集

申し訳ありませんが、リフレクションも自明ではないことを忘れていました。また、次の 2 つの手順で構成されます。

  1. 明らかに、必要な軸の各 DCT ブロックの位置を反映します。
  2. あまり明白ではありませんが、DCT ブロックの各奇数行または列を反転 (-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 度回転することに注意してください。

于 2011-02-13T12:07:12.133 に答える