モノクロ画像のデータ圧縮
高校生の健太さんは、モノクロ画像のデータ圧縮方法について調べている。題材として、0(白)と 1(黒)のピクセル値が並んだ1次元の配列 Data を考える。
健太:「例えば、Data = [0, 0, 0, 1, 1, 1, 1, 0, 0] (要素数 N=9) のようなデータがあるとする。このまま保存すると 9 個のデータが必要だけど、0 が 3 個、1 が 4 個、0 が 2 個というように、同じ値が連続する『長さ』を記録すれば、データ量を削減できそうだ。」
この「ランレングス符号化(RLE)」と呼ばれる方法を実装するため、健太さんは以下の仕様でプログラムを作成することにした。
仕様:
Data を走査し、連続する値の「長さ」を新しい配列 RLE に順に格納する。Data は必ず 0 か 1 で始まる。RLE の 0 番目の要素 (RLE[0]) は、最初の「0(白)」の連続する長さとする。RLE の 1 番目の要素 (RLE[1]) は、次の「1(黒)」の連続する長さとする。RLE の偶数番目 (RLE[2k]) は 0 の長さ、奇数番目 (RLE[2k+1]) は 1 の長さ、と交互に格納する。Data が 1(黒)から始まる場合、Data[0] より前に「長さ 0 の 0(白)のラン」があったとみなし、RLE[0] に 0 を格納する。仕様の例:
Data = [0, 0, 0, 1, 1, 1, 1, 0, 0] (N=9) の場合:
0 のラン (長さ 3), 1 のラン (長さ 4), 0 のラン (長さ 2)RLE = [3, 4, 2] となる。Data = [1, 1, 0, 0, 0, 1, 1, 1, 1] (N=9) の場合:
0 のラン (長さ 0) (仕様6), 1 のラン (長さ 2), 0 のラン (長さ 3), 1 のラン (長さ 4)RLE = [0, 2, 3, 4] となる。健太さんは、この仕様に基づき、配列 Data とその要素数 N を受け取り、配列 RLE を出力する CreateRLE という手続き(プログラム1)を作成した。
プログラム1
// 配列 Data (要素数 N) から配列 RLE を作成する
手続 CreateRLE(Data, N)
RLE = [] // 空の配列
もし (N == 0) ならば
戻る // データがなければ終了
// 仕様6: 最初のピクセルが 1 の場合の処理
もし (Data[0] == 1) ならば
RLE.追加(0)
現在の値 = Data[0]
現在の長さ = 0
i = 0
反復 i < N
もし (Data[i] == 現在の値) ならば
// 同じ値が続いている
現在の長さ = 現在の長さ + 1
そうでなければ
// 値が変わった
RLE.追加(現在の長さ)
現在の値 = 1 - 現在の値 // 0 なら 1 に、1 なら 0 にする
現在の長さ = 1 // 新しいランのカウント開始
i = i + 1
// 最後のランの長さを配列に追加
RLE.追加(現在の長さ)
表示(RLE)
戻る
プログラム1について、Data = [0, 0, 1, 1, 1, 0, 0, 0, 0] (N=9) を入力として CreateRLE を実行したとき、表示(RLE) によって出力される配列として、最も適切なものを次のA〜Dのうちから一つ選べ。
プログラム1について、Data = [1, 1, 1, 0, 1, 1, 1, 1] (N=8) を入力として CreateRLE を実行したとき、表示(RLE) によって出力される配列として、最も適切なものを次のA〜Dのうちから一つ選べ。
ある 20x20 ピクセル (N=400) のモノクロ画像があり、元のデータは 1 ピクセル 1 ビットで保存される。
このデータをプログラム1で圧縮したところ、RLE = [100, 50, 100, 50, 100] という配列が得られた。
圧縮後の RLE 配列では、各要素(100 や 50 など)が、それぞれ 8 ビット(1バイト)の符号なし整数として保存されるものとする。
このときのデータサイズに関する記述として、最も適切なものを次のA〜Dのうちから一つ選べ。
健太さんは、問3の前提(RLE の各要素を 8 ビットで保存する)について、問題があることに気づいた。8 ビットの符号なし整数で表現できる最大の長さは 255 () である。
もし Data 配列に 300 個の 0 が連続する [...0, 0, ... (合計300個) ..., 1, 1, ...] というデータがあった場合、現在のプログラム1では、RLE 配列に 300 という値がそのまま追加されようとするため、8 ビットに収まらず正しく保存できない(オーバーフロー)。
この問題を解決するため、プログラム1を修正し、「一つのランの長さが 255 を超える場合は、255 以下の複数のランに分割して RLE 配列に格納する」という方法を考えた。
この新方式では、RLE の仕様(偶数番目が 0 のラン、奇数番目が 1 のラン)を維持する必要がある。0 のランを (0, 255) と (0, 45) のように2つの 0 のランに分割したい場合、間に「長さ 0 の 1 のラン」 (1, 0) を挿入する必要がある。
Data = [0, 0, ... (300個) ..., 1, 1, 1] というデータ(0が300個、1が3個)を、この新方式(8ビット上限)で RLE 配列に正しく格納したものはどれか。次の A〜H から一つ選べ。