日々のコンピュータ情報の集積と整理

Dr.ウーパのコンピュータ備忘録

2015年3月25日水曜日

画像処理:文字情報をモザイク処理した場合の、パターン数とその分布(Windows UI)

イントロダクション

画像処理:モザイクによって文字情報を処理した場合の、パターン数について考える」では、文字情報をモザイク処理した場合に、元の画像の推測が容易かどうかを考えてみました。

そのときは、前提条件として次のような条件を設定しました。
  • 文字 1 文字の全体を、モザイク処理によって均質な色にする
  • 画像の色情報は、白から黒の濃淡で表されるグレースケール
  • 色の階調情報のデータ量は、一般的な 256 段階(8bit)
  • 文字のビットマップ情報については考えず、あくまで文字の数でのみ考える
    • モザイク処理後の色かぶりが無いと仮定
    • モザイク処理によって均質化した色情報が、均等にばらけていると仮定


特に、机上で計算しやすいように、実際の文字の形(ビットマップ情報)は考慮せずに、計算しました。


そこで、今回は実際にプログラムを作成し、文字 1 文字をモザイク処理した場合のパターン数と、どのようなモザイク処理後の色のパターンの分布が生じるのかを調べてみました。

モザイクによって文字情報を処理した場合の、パターン数とその分布を生成


前提条件

条件を分かりやすくするために、文字 1 文字の全体を、モザイク処理によって均質な色にした場合を考えてみます。

文字 1 文字の全体を、 モザイク処理によって均質な色にした場合
文字 1 文字の全体を、
モザイク処理によって均質な色にした場合


モザイク処理の方式はいくつかありますが、ここではモザイクの 1 つのブロック内のピクセルの色を平均する方法によるモザイク処理方式を用います。

画像の色情報は、白から黒の濃淡で表されるグレースケールとします。
色の階調情報のデータ量は、一般的な 256 段階(8bit)とします。


元の文字情報は、以下の条件とします。

  • Windows のUIで標準的に使用されるフォントとサイズ(Windows Vista 以前(Windows 7 以降は、Meiryo UIが使われることが多くなっています))
    • MS UI Gothic
    • 9pt


モザイクを施す領域のサイズは、描画する文字のサイズの最大の幅・高さを用います。


使用するプログラム

モザイクによって文字情報を処理した場合の、パターン数とその分布を生成するプログラムを C# で作成しました。

コンソールアプリケーションとして動作します。
入力として、モザイクを施した時のグレースケールのパターンを知りたい文字の集合を与えます。

すると、モザイクを施した時のグレースケールの頻度情報を計算して出力します。

出力は、コマンドプロンプト上にテキストデータとして出力されます。
そして、モザイク処理の計算に使用した文字を画像化したデータに対して、右下にモザイクとして計算されたグレースケールの色を描画したものを、画像ファイルとして全て保存します。(番号.png という形式でカレントディレクトリに対して保存されます。なお、同じファイル名のファイルがあった場合には、強制的に上書きされます。)


グレースケールの頻度情報は、モザイクを施した場合に適用されるグレースケールの色の情報を、0 から 255 のグレースケールの段階として記録したものです。

コマンドプロンプト上には、0 から 255 のグレースケールの段階ごとに、そのグレースケールの色がモザイクとして適用された回数を表示します。

また、コマンドプロンプト上に表示された HTML を、HTML ファイルとして保存すると、どの文字が、モザイク処理によってグレースケールのどの段階として処理されたのか、一覧で見ることができます。


コード

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace MosaicPatternCalculator
{
    class Program
    {
        // allCharText の文字を 1 文字ずつ描画するときに必要となる、
        // 最大サイズを返す
        static SizeF getMaxSize(string allCharText, Font font)
        {
            Bitmap bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            Graphics g = Graphics.FromImage(bmp);

            SizeF maxSize = new SizeF(0, 0);

            // 描画に必要な最大サイズを計算
            for (int i = 0; i < allCharText.Length; i++)
            {
                SizeF s = g.MeasureString(allCharText[i].ToString(), font);

                // 最大となるサイズを保存
                if (s.Width > maxSize.Width) maxSize.Width = s.Width;
                if (s.Height > maxSize.Height) maxSize.Height = s.Height;
            }

            g.Dispose();
            bmp.Dispose();

            return maxSize;
        }

        static void Main(string[] args)
        {
            // テストに使用する文字列
            Console.WriteLine("チェックに使用する文字の集合を入力してください:");
            string allCharText = Console.ReadLine();
            Console.WriteLine("チェックに使用する文字の集合:" + allCharText);

            // 描画に使用するフォント
            Font font = new Font("MS UI Gothic", 9);
            Console.WriteLine("使用するフォント情報:");
            Console.WriteLine(" FontFamily : " + font.FontFamily);
            Console.WriteLine(" Size : " + font.Size);

            // 描画サイズ計算
            SizeF size = getMaxSize(allCharText, font);
            Console.WriteLine("描画に必要な最大サイズ:");
            Console.WriteLine(" Width : " + size.Width);
            Console.WriteLine(" Height : " + size.Height);

            // モザイク後の色の頻度・ファイル名を保存
            List<String>[] grayScaleColorCount = new List<String>[256];
            for (int i = 0; i < grayScaleColorCount.Length; i++)
            {
                grayScaleColorCount[i] = new List<string>();
            }

            // 描画先確保
            Bitmap bmp = new Bitmap((int) Math.Ceiling(size.Width), (int) Math.Ceiling(size.Height), 
                System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            Console.WriteLine("確保したビットマップサイズ:");
            Console.WriteLine(" Width : " + bmp.Width);
            Console.WriteLine(" Height : " + bmp.Height);
            
            
            Graphics g = Graphics.FromImage(bmp);

            // モザイク処理
            for (int i = 0; i < allCharText.Length; i++)
            {
                // 背景色描画
                g.FillRectangle(Brushes.White, g.VisibleClipBounds);

                // 文字描画
                g.DrawString(allCharText[i].ToString(), font, Brushes.Black, 0, 0);


                // ---
                // 描画した画像を 8 bit のグレースケール画像に見立てて、
                // r に対して、モザイク処理を実施
                
                // 画像の平均的な色を計算
                // 画像サイズが小さいことを前提とした処理
                // sum のオーバーフロー注意
                long sum = 0;
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        Color c = bmp.GetPixel(x, y);
                        sum += c.R;
                    }
                }

                double average = sum / (double)(bmp.Width * bmp.Height);
                byte grayScaleColor = (byte)average;                          // グレースケール色の計算
                

                // 右下に対して、モザイク色を設定
                for (int y = bmp.Height - 2; y < bmp.Height; y++)
                {
                    for (int x = bmp.Width - 2; x < bmp.Width; x++)
                    {
                        // 描画先が背景色だったら、モザイク色を描画
                        Color c = bmp.GetPixel(x, y);
                        if (c.R == Color.White.R)
                        {
                            bmp.SetPixel(x, y, Color.FromArgb(grayScaleColor, grayScaleColor, grayScaleColor));
                        }
                    }
                }


                // 処理後のデータを出力
                String fileName = i + ".png";
                bmp.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);

                // モザイク後のグレースケール色の頻度を更新
                grayScaleColorCount[grayScaleColor].Add(fileName);
            }

            g.Dispose();
            bmp.Dispose();


            // モザイク後のグレースケール色の頻度を出力
            Console.WriteLine("モザイク後のグレースケール色の頻度:");
            for (int i = 0; i < grayScaleColorCount.Length; i++)
            {
                // 一度も登場していない色は除外
                if (grayScaleColorCount[i].Count != 0)
                {
                    Console.WriteLine(i + ":" + grayScaleColorCount[i].Count);
                }
            }

            // 頻度を HTML として出力
            Console.WriteLine("モザイク後のグレースケール色の頻度[HTML]:");
            Console.WriteLine("<html><head><title></title></head><body>");
            for (int i = 0; i < grayScaleColorCount.Length; i++)
            {
                // 一度も登場していない色は除外
                if (grayScaleColorCount[i].Count != 0)
                {
                    Console.WriteLine(i + ":");
                    for (int j = 0; j < grayScaleColorCount[i].Count; j++)
                    {
                        Console.WriteLine("<img src=\"" + grayScaleColorCount[i][j] + "\">");
                    }
                    Console.WriteLine("<br>");
                }
            }
            Console.WriteLine("</body></html>");
        }
    }
}



元の情報:数値情報

文字一覧

0123456789


実行結果

チェックに使用する文字の集合:0123456789
使用するフォント情報:
 FontFamily : [FontFamily: Name=MS UI Gothic]
 Size : 9
描画に必要な最大サイズ:
 Width : 10.1875
 Height : 13.5
確保したビットマップサイズ:
 Width : 11
 Height : 14
モザイク後のグレースケール色の頻度:
220:2
221:3
225:2
228:1
233:1
236:1


モザイク後のグレースケール色の頻度[HTML]

モザイク後のグレースケール色の頻度[HTML] 元の情報:数値情報 MS UI Gothic, 9pt
モザイク後のグレースケール色の頻度[HTML]
元の情報:数値情報
MS UI Gothic, 9pt


解説

前提条件をもとに、数字をモザイク処理した場合には、220~236の間にモザイク処理後のグレースケールの色データが現れます。

モザイク処理後のグレースケールの色に被りも見られますが、まったく被らない数値も 3 つあります。

数値データでこれほどまでにデータが被った理由としては、

  • 文字サイズが小さい
  • 文字がアンチエイリアスされていない
  • 文字に対して、モザイクを施す領域が広い

という点が考えられます。


元の情報:アルファベット情報(大文字と小文字)と数値と記号

文字一覧

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~


実行結果
チェックに使用する文字の集合:!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
使用するフォント情報:
 FontFamily : [FontFamily: Name=MS UI Gothic]
 Size : 9
描画に必要な最大サイズ:
 Width : 13.1875
 Height : 13.5
確保したビットマップサイズ:
 Width : 14
 Height : 14
モザイク後のグレースケール色の頻度:
215:2
217:1
219:1
221:1
222:3
223:1
225:2
226:3
227:5
228:8
230:4
231:8
232:2
234:4
235:4
236:6
238:5
239:5
240:5
241:5
243:5
244:1
245:2
247:2
248:2
249:1
251:2
252:3
253:1


モザイク後のグレースケール色の頻度[HTML]

モザイク後のグレースケール色の頻度[HTML] 元の情報:アルファベット情報(大文字と小文字)と数値と記号 MS UI Gothic, 9pt
モザイク後のグレースケール色の頻度[HTML]
元の情報:アルファベット情報(大文字と小文字)と数値と記号
MS UI Gothic, 9pt


解説

前提条件をもとに、数字をモザイク処理した場合には、215~253の間にモザイク処理後のグレースケールの色データが現れます。

モザイク処理後のグレースケールの色に被りも見られますが、まったく被らない数値も 7 つあります。

アルファベット情報(大文字と小文字)と数値と記号で、これほどまでにデータが被った理由としては、
  • 文字サイズが小さい
  • 文字がアンチエイリアスされていない
  • 文字に対して、モザイクを施す領域が広い

という点が考えられます。


まとめ

画像処理:モザイクによって文字情報を処理した場合の、パターン数について考える」でパターン数を計算した時には、元の情報がアルファベット情報(大文字と小文字)と数値と記号のときですら、モザイク後の色の被りがなく、元の情報と 1:1 で対応可能という試算でした。

しかし、実際に文字のビットマップ情報を使って計算してみると、元の情報が数値情報の場合でも、モザイク後の色に被りが生じています。

そのため、モザイク後の画像から元の文字情報を推測する困難さが上がっています。

その理由としては、
  • 文字サイズが小さい
  • 文字がアンチエイリアスされていない
  • 文字に対して、モザイクを施す領域が広い
という点が考えられます。

なお、前提条件であるモザイクを施す領域や、フォント名、フォントサイズなどが変わると、文字情報をモザイク処理した場合の、パターン数とその分布は変わるので注意が必要です。


このような点に注意して、安全に画像を処理していきましょう。


次回

もう少し大きな文字に対して、アンチエイリアスの施されるフォントを使用して文字情報をモザイク処理した場合の、パターン数とその分布を計算してみました。

画像処理:文字情報をモザイク処理した場合の、パターン数とその分布(メイリオ)
http://upa-pc.blogspot.com/2015/03/public-image-process-mosaic-pattern-check-meiryo.html







関連記事

関連記事を読み込み中...

同じラベルの記事を読み込み中...