玄関コンピュータの部屋各種解説コーナーデータ圧縮法概説

【第2章 連長符号化(Run Length Encoding、RLE)】

2.1 符号化手順

一番単純な圧縮法で、前章で説明しましたように同じ記号がたくさん続く場合にしか圧縮効果がありませんので、主として画像データの圧縮に利用されています。 この手法の実用例としては、MacintoshのPICTファイルでモノクロのビットマップデータを圧縮するのに用いられているPackBitsが有名です。

PackBitsでは次のような規則に基づいて元データを符号化します。

  1. 元データは8ビットの固定長符号であると仮定し、8ビット単位で符号化する。
  2. 「abcd」のように繰り返しのない一連の記号は、1バイト目に(記号数−1)という1バイト整数を、2バイト以後に一連の記号を並べた(記号数+1)バイトで符号化する。 1バイト目の整数は0から127の範囲、つまり記号数にすると1個から128個とし、一連の記号が129個以上続く場合は2つ以上に分割して符号化する。
    例えば元データが「abcd」の場合、「3abcd」と符号化される。
  3. 「aaaa」のように同じ記号が複数個連続して続く場合は、1バイト目に(−記号の繰り返し数+1)という負の1バイト整数を、2バイト目に記号そのものを並べた2バイトで符号化する。 1バイト目の整数は-1から-127の範囲、つまり繰り返し数にすると2個から128個とし、同じ記号が129個以上続く場合は2つ以上に分割して符号化する。
    例えば元データが「aaaa」の場合、「-3a」と符号化される。
  4. 2.のようなデータを「リテラル(文字列)グループ」、3.のようなデータを「反復グループ」といい、これらは1バイト目が正の整数か負の整数かによって区別される。 「a」のように記号が1つだけの場合、どちらの方法で符号化しても「0a」となる。

以上の規則に基づく実際の符号化手順は、例えば次のようになります。

  1. 一連の記号をリテラルとして保存するための一時記憶場所を確保し、リテラル数mを0にする。 同時に反復グループ用に前記号を保存するための一時記憶場所を確保し、繰り返し数nを0にする。
  2. 元データから最初の1記号(8ビット固定長符号)を入力し、入力記号を前記号として記憶し、nを1にする。
  3. 元データから次の1記号を入力する。
  4. 入力記号が前記号と異なる場合は、

    もし前記号の繰り返し数nが2以上ならば、
     反復グループとして「-(n-1)<前記号>」を出力。
    あるいは前記号の繰り返し数nが2未満ならば、
     もしリテラル数mが128未満ならば、
      mを1増加して、前記号をリテラルのm文字目として保存。
     あるいはリテラル数mが128以上ならば、
      リテラルグループとして「(m-1)<リテラル>」を出力。
      リテラルをクリアし、リテラル数mを0にする。

    入力記号を前記号として記憶し、nを1にする。
    3.に戻る。
  5. 入力記号が前記号と同じ場合は、

    もしリテラル数mが1以上ならば、
     リテラルグループとして「(m-1)<リテラル>」を出力。
     リテラルをクリアし、リテラル数mを0にする。 もし前記号の繰り返し数nが128未満ならば、
     繰り返し数nを1増加する。
    あるいは前記号の繰り返し数nが128以上ならば、
     反復グループとして「-(n-1)<前記号>」を出力。
     前記号はそのままで、nを1にする。

    3.に戻る。
  6. 元データが終了した場合、

    もし前記号の繰り返し数nが1未満(1記号も入力せず)ならば、
     何もしない。
    あるいは前記号の繰り返し数nが1ならば、
     mを1増加して、前記号をリテラルのm文字目として保存。
     リテラルグループとして「(m-1)<リテラル>」を出力。
    あるいは前記号の繰り返し数nが2以上ならば、
     もしリテラル数mが1以上ならば、
      リテラルグループとして「(m-1)<リテラル>」を出力。
     反復グループとして「-(n-1)<前記号>」を出力。

2.2 実例

例として、「abbbccccde」というデータを前節の手順に従って符号化してみましょう。

  1. リテラル記憶場所確保、m=0。 前記号記憶場所確保、n=0。
  2. 1記号目の「a」を入力。
    前記号=a、n=1
  3. 「b」入力。
    入力記号b≠前記号a
     前コードの繰り返し数n=1<2
      リテラルの繰り返し数m=0<128
       m=1、リテラル=a
    前記号=b、n=1
  4. 「b」入力。
    入力記号b=前記号b
     リテラル数m=1≧1
      「0a」を出力
      リテラルをクリア、m=0
     前記号の繰り返し数n=1<128
      n=2
  5. 「b」入力。
    入力記号b=前記号b
     リテラル数m=0
     前記号の繰り返し数n=2<128
      n=3
  6. 「c」入力。
    入力記号c≠前記号b
     前記号の繰り返し数n=3≧2
      「(-2)b」を出力。
     前記号=c、n=1
  7. 「c」入力。
    入力記号c=前記号c
     前記号の繰り返し数n=1<128
      n=2
  8. 「c」入力。
    入力記号c=前記号c
     前記号の繰り返し数n=2<128
      n=3
  9. 「c」入力。
    入力記号c=前記号c
     前記号の繰り返し数n=3<128
      n=4
  10. 「d」入力。
    入力記号d≠前記号c
     前記号の繰り返し数n=4≧2
      「(-3)c」を出力。
     前記号=d、n=1
  11. 「e」入力。
    入力記号e≠前記号d
     前記号の繰り返し数n=1<2
      リテラルの繰り返し数m=0<128
       m=1、リテラル=d
    前記号=e、n=1
  12. 元データ終了。
    前記号の繰り返し数n=1
     m=2、リテラル=de
     「1de」を出力

以上の結果、出力データは「0a(-2)b(-3)c1de」となり、この時の圧縮率と平均符号長は次のようになります。

圧縮率=9×8
───
10×8
=0.9(90%)
平均符号長=72
──
10
=7.2ビット

2.3 復号手順

符号化されたデータ「0a(-2)b(-3)c1de」から元のデータを復元する手順は以下のとおりです。

  1. 「0」入力
  2. リテラルグループのため、次の記号「a」を入力しそのまま出力
    復元データ:「a」
  3. 「(-2)」入力
  4. 反復グループのため、次の記号「b」を入力しそれを3個出力
    復元データ:「abbb」
  5. 「(-3)」入力
  6. 反復グループのため、次の記号「c」を入力しそれを4個出力
    復元データ:「abbbcccc」
  7. 「1」入力
  8. リテラルグループのため、次の2記号「de」を入力しそのまま出力
    復元データ:「abbbccccde」
  9. 復元終了

2.4 PackBits以外の連長符号化実用例

連長符号は、PackBits以外ではWindowsのBMPファイルでビットマップデータを圧縮する場合にも用いられています。 BMPのRLEの場合、リテラルグループの記号数と反復グループの繰り返し数はどちらも1から255までの1バイト整数が用いられ、記号数および繰り返し数は最大255までとなります。 その代わり、リテラルグループと反復グループを区別するために、リテラルグループの場合は記号数の前に値0の1バイト整数が付け加えられます。 したがって、例えば「abcd」は「04abcd」と符号化され、「aaaa」は「4a」と符号化されます。

実際にプログラムを組んだりデータを圧縮してみたりするとわかりますが、このWindows方式はPackBits方式よりも効率が悪く、あまり合理的な方法とは言えません。

2.5 連長符号化の特徴