応用情報技術者 2020年 秋期 午後 問03
誤差拡散法による減色処理に関する次の記述を読んで、設問1~4に答えよ。
画像の情報量を落として画像ファイルのサイズを小さくしたり、モノクロの液晶画面に画像を表示させたりする際に、減色アルゴリズムを用いた画像変換を行うことがある。誤差拡散法は減色アルゴリズムの一つである。誤差拡散法を用いて、階調ありのモノクロ画像を、黒と白だけを使ったモノクロ2値の画像に画像変換した例を図1に示す。
階調ありのモノクロ画像の場合は、各ピクセルが色の濃淡をもつことができる。濃淡は輝度で表す。輝度0のとき色は黒に、輝度が最大になると色は白になる。モノクロ2値の画像は、輝度が0か最大かの2値だけを使った画像である。


〔誤差拡散法のアルゴリズム〕
画像を構成するピクセルの輝度は、1ピクセルの輝度を8ビットで表す場合、0~255の値を取ることができる。0が黒で、255が白を表す。誤差拡散法では、次の二つの処理をピクセルごとに行うことで減色を行う。
① 変換前のピクセルについて、白に近い場合は輝度を255、黒に近い場合は輝度を0としてモノクロ2値化し、その際の輝度の差分を評価し、輝度の誤差Dとする。例えば、変換前のピクセルの輝度が223の場合、変換後の輝度を255とし、輝度の誤差Dは、223-255から、-32である。
② 事前に定義した誤差拡散のパターンに従って、評価した誤差Dを周囲のピクセル(以下、拡散先という)に拡散させる。
拡散先の数が4の場合の、誤差拡散のパターンの例を図2に、減色処理の手順を図3に示す。なお、拡散する誤差の値は整数とし、小数点以下は切り捨てる。


図2のパターンを使い、図3の手順に従って、1行目の左上から2ピクセル分の処理をした後、その右隣のピクセル(左上から3ピクセル目)について処理した例を図4に示す。変換前画像の輝度の値が128で、変換後輝度配列の同じ要素の値が-14なので、Fは128+(-14)=114となる。Fが128未満なので、輝度は0、誤差Dは114となる。誤差114に7/16を乗じて、小数点以下を切り捨てた値は49なので、変換後輝度配列の一つ右の要素に49を加算する。同様に、左下には21、下には35、右下には7を加算する。

〔誤差拡散法を用いて減色するプログラム〕
誤差拡散法を用いて減色するプログラムを作成した。プログラム中で使用する主な変数、定数及び配列を表1に、作成したプログラムを図5に示す。


〔画質向上のための改修〕
ビクセルを処理する順番を、Y座標ごとに逆向きにすることで、誤差拡散の方向の偏りを減らし、画質を改善することができる。
Y座標が奇数の場合:ピクセルを左から順に処理する。
Y座標が偶数の場合:ピクセルを右から順に処理する。
なお、Y座標が偶数の場合は、誤差拡散のパターンを左右逆にして評価する。画質を向上させるために、図5の①と②の行の処理を書き換えた。書き換えた後の①の行の処理を図6に、書き換えた後の②の行の処理を図7に示す。なお、A mod Bは、AをBで割った余りである。


〔処理の高速化に関する検討〕
図5中の③の箇所では、誤差を拡散させる先のピクセルが画像の範囲の外側にならないように制御している。このような処理をクリッピングという。
③のif文は、プログラムの終了までにキ回呼び出され、その度に、条件判定における比較演算と論理演算の評価が、あわせて最大でク回行われる。
ここでの計算量が少なくなるようにプログラムを改修することで、処理速度を向上させることができる可能性がある。
設問1:図4の左上から3ピクセル目について処理した後の状態から処理を進め、太枠で示されたピクセルの一つ右隣のピクセルを処理した後の変換後輝度配列について、(1)、(2)に答えよ。
(1)減色処理の結果のピクセル(上から1行目、左から4列目の要素)の色を、白か黒で答えよ。
模範解答
黒
解説
解答の論理構成
-
前提となる数値を確認
- 変換前画像の輝度(上から1行目・左から4列目)は図4の左端行列より「35」
- 変換後輝度配列の同じ要素は、3ピクセル目まで処理した後の図4右端行列より「49」
-
F の算出
【問題文】図3 手順3
「変換前画像の輝度と、変換後輝度配列の同じ要素の値を加算し、これをFとする。」
よって
-
2値判定
【問題文】図3 手順4
「Fの値が128未満なら変換後輝度配列の輝度を0とし…」
84 は「128未満」であるため、該当ピクセルは輝度「0」。 -
黒・白への対応
【問題文】冒頭説明
「0が黒で、255が白を表す。」
輝度0は黒なので、求める色は黒です。
誤りやすいポイント
- 変換後輝度配列の最新値を参照せず、初期値0で計算してしまう
- 「F≧128」と「F>128」を取り違え、境界値の扱いを誤る
- 2値判定だけで完結したと勘違いし、誤差拡散の加算結果を次のピクセルに反映させない
FAQ
Q: 128 ちょうどのときは白ですか黒ですか?
A: 手順4に従い「128以上なら…255」とあるので白(255)です。
A: 手順4に従い「128以上なら…255」とあるので白(255)です。
Q: 誤差拡散係数を掛けた結果は四捨五入しますか?
A: 指示は「小数点以下は切り捨てる」です。
A: 指示は「小数点以下は切り捨てる」です。
Q: 画像端のピクセルで拡散先が範囲外の場合はどうなりますか?
A: 手順5に記載のとおり「その値を無視する」ため、加算しません。
A: 手順5に記載のとおり「その値を無視する」ため、加算しません。
関連キーワード: 誤差拡散法、2値化、ハーフトーン、量子化誤差、クリッピング
設問1:図4の左上から3ピクセル目について処理した後の状態から処理を進め、太枠で示されたピクセルの一つ右隣のピクセルを処理した後の変換後輝度配列について、(1)、(2)に答えよ。
(2)(1)のピクセルの処理後に、そのピクセルの下のピクセル(上から2行目、左から4列目の要素)に入る輝度の値を整数で答えよ。
模範解答
33
解説
解答の論理構成
-
対象ピクセルの同定
図4の右端マトリクスは「左上から3ピクセル目の処理後」の状態です。太枠で示されたピクセルは1行目3列目(輝度0)なので、問題が指す「一つ右隣」は1行目4列目です。 -
変換前輝度と現在値の合算
変換前画像(図4左端)で1行目4列目は「35」、変換後輝度配列(図4中央)で同じ位置には「49」が既に蓄積されています。
【問題文】図3‐手順3
「変換前画像の輝度と、変換後輝度配列の同じ要素の値を加算し、これをFとする。」
よって
F = 35 + 49 = 84 -
2値化と誤差算出
F が 128 未満なので白黒判定は黒(0)となり、誤差 D は次式で求まります。
【問題文】図3‐手順4
「Fの値が128未満なら…誤差の値DをFとする。」
D = 84 -
誤差の拡散
【問題文】図2
「真下(南隣)のセル … D×5/16」
画像範囲内のためそのまま加算します。小数点以下は切り捨てです。
84 × 5 / 16 = 26.25 → 26 -
既存値への加算
拡散先は1行下2列右の同じ列、すなわち「上から2行目、左から4列目」。図4右端マトリクスの同要素は「7」です。
7 + 26 = 33 -
結論
求める輝度値は 33 となります。
誤りやすいポイント
- 「F」に現在の累積値(図4での「49」)を足し忘れ、誤差 D を過小評価する。
- 拡散係数「5/16」の適用方向を取り違え、左下や右下に配分してしまう。
- 「小数点以下は切り捨てる」という指示を無視し四捨五入してしまう。
FAQ
Q: 分母が「16」でないパターンでも処理手順は同じですか?
A: はい。同様に D に係数を掛けて切り捨て、指定位置に加算します。分母は denominator、係数は ratio[ ] で与えられます。
A: はい。同様に D に係数を掛けて切り捨て、指定位置に加算します。分母は denominator、係数は ratio[ ] で与えられます。
Q: 既に負の値が入っている要素に誤差を加える場合、特別な処理は必要ですか?
A: ありません。図4左上の例と同じく、そのまま整数加算してください。負の値が残っても次の F 計算で相殺されます。
A: ありません。図4左上の例と同じく、そのまま整数加算してください。負の値が残っても次の F 計算で相殺されます。
Q: Y 座標偶数行で左右を反転させる改修は今回の計算に影響しますか?
A: 今回処理した1行目は奇数行なので反転は関係ありません。偶数行の場合のみ tdxc が図7の式で反転します。
A: 今回処理した1行目は奇数行なので反転は関係ありません。偶数行の場合のみ tdxc が図7の式で反転します。
関連キーワード: 誤差拡散、2値化、ハーフトーニング、ビットマップ、クリッピング
設問2:
図5中のア〜ウに入れる適切な字句を答えよ。
模範解答
ア:abmpFrom[x, y] + bmpTo[x, y]
イ:fが128以上
ウ:bmpTo[px, py] + (d * ratioc/denominator)
解説
解答の論理構成
-
F の求め方
- 【問題文】図3‐手順3
「変換前画像の輝度と、変換後輝度配列の同じ要素の値を加算し、これをFとする。」 - よって f ← bmpFrom[x, y] + bmpTo[x, y] でなければなりません。
- 結論:
ア bmpFrom[x, y] + bmpTo[x, y]
- 【問題文】図3‐手順3
-
2値化判定条件
- 【問題文】図3‐手順4
「Fの値が128以上なら…」「Fの値が128未満なら…」 - if 文は “F が128以上かどうか” を判定する必要があります。
- 結論:
イ fが128以上
- 【問題文】図3‐手順4
-
誤差拡散値の加算
- 【問題文】図3‐手順5
「誤差拡散のパターンに定義された割合に従って配分し、拡散先の要素に加算する。」 - 加算先は bmpTo[px, py]。加算量は整数化された 。
- 結論:
ウ bmpTo[px, py] + (d * ratioc/denominator)
- 【問題文】図3‐手順5
誤りやすいポイント
- F を「bmpFrom のみ」や「bmpTo のみ」で計算してしまい、誤差が累積しない実装にしてしまう。
- if 条件を “> 128” と書き、F=128 のとき白にできない。
- ウ で既存値を上書きしてしまい、以前に拡散された誤差を失う。必ず「加算」する。
- ratio と denominator を誤って逆にし、誤差の比率が 1/ratioc になるケース。
FAQ
Q: bmpTo[x, y] は最初に 0 で初期化されていますが、途中で負値になることがありますか?
A: あります。誤差を加算する段階では負値・正値どちらも取り得ます。最終的に 0 または 255 に丸められるので問題ありません。
A: あります。誤差を加算する段階では負値・正値どちらも取り得ます。最終的に 0 または 255 に丸められるので問題ありません。
Q: ratio 配列を変更するとき、denominator も必ず 16 にする必要がありますか?
A: いいえ。ratio 配列の総和に合わせて denominator を設定すれば構いません。ただし整数演算に合わせて切り捨てルールを明確にしておくことが重要です。
A: いいえ。ratio 配列の総和に合わせて denominator を設定すれば構いません。ただし整数演算に合わせて切り捨てルールを明確にしておくことが重要です。
Q: クリッピング判定を省くと処理は速くなりますか?
A: 条件判定自体は減りますが、配列外アクセスの危険が生じます。処理速度向上は「判定回数削減」よりも「判定を安全にまとめる」方向で最適化するのが一般的です。
A: 条件判定自体は減りますが、配列外アクセスの危険が生じます。処理速度向上は「判定回数削減」よりも「判定を安全にまとめる」方向で最適化するのが一般的です。
関連キーワード: 誤差拡散法、減色処理、ディザリング、クリッピング、二値化
設問3:
図6、図7中のエ〜カに入れる適切な字句を答えよ。
模範解答
エ:y
オ:2
カ:width − tx + 1
解説
解答の論理構成
-
処理方向を決定する基準
【問題文】には
「Y座標が奇数の場合:ピクセルを左から順に処理する。
Y座標が偶数の場合:ピクセルを右から順に処理する。」
とあります。従って偶奇判定に使うのは現在処理中の行番号“y”です。
よって エ = y となります。 -
偶奇判定の方法
奇数/偶数の判定は 2 で割った余りで行うのが最も自然です。さらに図6・図7で
( エ mod オ )
と同じ式が二度使われているため、割る数は 2 で統一されます。
よって オ = 2 です。 -
右→左走査時の X 座標変換
偶数行ならば左端 (tx = 1) を右端 (width) に、右端 (tx = width) を左端 (1) に 対応させる必要があります。一般化すると
反転後の x = width − tx + 1
となるので カ = width − tx + 1 です。 -
まとめ
以上より
エ:y
オ:2
カ:width − tx + 1
誤りやすいポイント
- 行番号ではなく列番号 tx を偶奇判定に使ってしまう
→ 反転処理が 1 行おきではなく 1 列おきに起き、画像が崩れます。 - 偶数判定を mod 2 = 1 と誤って書く
→ 奇数行と偶数行が逆転し、誤差拡散パターンが不均一になります。 - 反転式を width − x としてしまう
→ 両端の列が 0 や空振りとなり、画像端の処理が欠落します。
FAQ
Q: なぜ mod 2 で偶奇を判定するのですか?
A: 2 で割った余りが 0 なら偶数、1 なら奇数という整数の基本性質を利用するためです。演算コストも最小です。
A: 2 で割った余りが 0 なら偶数、1 なら奇数という整数の基本性質を利用するためです。演算コストも最小です。
Q: width − tx + 1 という式にプラス 1 が必要なのは?
A: 配列添字が 1 から始まるためです。0 起点なら width − tx になりますが、本プログラムは左上が [1,1] と定義されています。
A: 配列添字が 1 から始まるためです。0 起点なら width − tx になりますが、本プログラムは左上が [1,1] と定義されています。
Q: 反転後に誤差拡散パターンも左右反転する理由は?
A: 偶数行では走査方向が逆になるため、誤差を本来「右隣」に渡すピクセルが論理的には「左隣」になるからです。パターンも合わせて反転しないと誤差の配布方向が片寄ります。
A: 偶数行では走査方向が逆になるため、誤差を本来「右隣」に渡すピクセルが論理的には「左隣」になるからです。パターンも合わせて反転しないと誤差の配布方向が片寄ります。
関連キーワード: 誤差拡散法、画像二値化、ハーフトーニング、クリッピング、モジュロ演算
設問4:
本文中のキ、クに入れる適切な字句を答えよ。
模範解答
キ:height × width × ratioCount
ク:7
解説
解答の論理構成
-
③の if 文が呼び出される回数
図5の外側ループは
• for ( y を 1 から height まで繰り返す )
• for ( x を 1 から width まで繰り返す )
• for ( c を 1 から ratioCount まで繰り返す )
の三重構造です。したがって、各ピクセルにつき ratioCount 回、画像全体では
height × width × ratioCount 回 ③の if 文が実行されます。よって
キ=height × width × ratioCount です。 -
1 回の if 文で評価される演算数
条件部は
( px が 1 以上 ) かつ ( px が width 以下 ) かつ ( py が 1 以上 ) かつ ( py が height 以下 )
で構成されています。
• 比較演算 4 回
‐ px ≥ 1
‐ px ≤ width
‐ py ≥ 1
‐ py ≤ height
• 論理 AND の評価 3 回
‐ 1 つ目と 2 つ目の比較結果を AND
‐ その結果と 3 つ目の比較結果を AND
‐ さらに 4 つ目の比較結果を AND
最大で 4 + 3 = 7 回の演算評価が行われます。よって
ク=7 です。
• 比較演算 4 回
‐ px ≥ 1
‐ px ≤ width
‐ py ≥ 1
‐ py ≤ height
• 論理 AND の評価 3 回
‐ 1 つ目と 2 つ目の比較結果を AND
‐ その結果と 3 つ目の比較結果を AND
‐ さらに 4 つ目の比較結果を AND
最大で 4 + 3 = 7 回の演算評価が行われます。よって
ク=7 です。
誤りやすいポイント
- 「比較演算」と「論理演算」を区別せず、比較 4 回だけを数えてしまう。
- ループ回数を height × width と誤認し、ratioCount を掛け忘れる。
- 短絡評価(ショートサーキット)を想定して演算数を 4~6 回と誤計算する。設問は「あわせて最大で」と明記しているため、すべて真になるケースで数える必要がある。
FAQ
Q: ratioCount が変わった場合、キ の式を修正する必要はありますか?
A: いいえ、式は height × width × ratioCount のままで、値だけが更新されます。
A: いいえ、式は height × width × ratioCount のままで、値だけが更新されます。
Q: ショートサーキット評価が有効なら演算数は減りますか?
A: 可能性はありますが、設問は「最大で」と指定しています。最悪ケースを答えるのが正解です。
A: 可能性はありますが、設問は「最大で」と指定しています。最悪ケースを答えるのが正解です。
Q: クリッピング処理を完全に無くせば高速化できますか?
A: 画像外への書き込みを防ぐ必須処理なので削除は不可です。高速化は回数削減や条件式最適化で行います。
A: 画像外への書き込みを防ぐ必須処理なので削除は不可です。高速化は回数削減や条件式最適化で行います。
関連キーワード: 誤差拡散法、クリッピング、計算量、比較演算、論理演算


