Tesseract OCRを使って3つの画像の文字を正しく認識できるか実験してみました。



(赤地に白)プレゼント員(惜しい!)
(黒地に白)レル2かさ(ぜんぜんダメ)
(白地に黒)プレゼント中(正しく認識できる)
白地の場合は正しく認識されましたが、黒地と赤地はうまくいきませんでした。黒地にいたっては全然ダメです。
そこで背景を白地に変換するにはどうすればいいかを考えます。
まず白黒にすることを考えましょう。
このサイトを参考にしました。
2値化して、1bppの白黒画像を作成する – .NET Tips (VB.NET,C#…)
白黒のビットマップはBitmapクラスのコンストラクタにPixelFormat.Format1bppIndexedを指定することで作成できます。しかし、
Bitmap srcBitmapを白黒化するとして
| 1 2 3 4 | Bitmap newBitmap = new Bitmap(                         srcBitmap.Width,                         srcBitmap.Height,                         System.Drawing.Imaging.PixelFormat.Format1bppIndexed); | 
これはいいのですが、
| 1 2 | Graphics g = Graphics.FromImage(newBitmap); // これができない g.DrawImage(srcBitmap, new Point(0, 0)); | 
コンパイルはできるのですが、実行すると例外が発生します。
| 1 2 3 4 5 6 7 8 | for(int row = 0; row < srcBitmap.Height; row++) {     for(int colum = 0; colum < srcBitmap.Width; colum++)     {         Color color = srcBitmap.GetPixel(colum, row);         newBitmap.SetPixel(colum, row, color); // これもできない     } } | 
これもコンパイルはできるのですが、実行すると例外が発生します。
1bppのBitmapに色を付けるには、Bitmap.LockBitsメソッドを使うしかありません。
白黒化するにはピクセルの色の明るさが設定した閾値を越えれば白くし、越えなければ黒くするという方法をとります。色の明るさはColor.GetBrightnessメソッドで取得できます。
リンク先の記事の丸写しではおもしろくないので、白黒反転もできるようにしました。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | using System.Drawing.Imaging; using System.Runtime.InteropServices; public static Bitmap Create1bppImage(Bitmap srcBitmap, float threshold, bool reverse) {     //1bppイメージを作成する     Bitmap newImg = new Bitmap(srcBitmap.Width, srcBitmap.Height, PixelFormat.Format1bppIndexed);     //Bitmapをロックする     BitmapData bmpData = newImg.LockBits(         new Rectangle(0, 0, newImg.Width, newImg.Height),         ImageLockMode.WriteOnly, newImg.PixelFormat);     //新しい画像のピクセルデータを作成     byte[] pixels = new byte[bmpData.Stride * bmpData.Height];     for(int y = 0; y < bmpData.Height; y++)     {         for(int x = 0; x < bmpData.Width; x++)         {             //ピクセルデータの位置             int pos = (x >> 3) + bmpData.Stride * y;             if(!reverse)             {                 //明るさが閾値以上の時は白くする                 if(threshold <= srcBitmap.GetPixel(x, y).GetBrightness())                 {                     //白くする                     byte b = (byte)(0x80 >> (x & 0x7));                     pixels[pos] |= b;                 }             }             else             {                 //明るさが閾値以下の時は白くする                 if(threshold >= srcBitmap.GetPixel(x, y).GetBrightness())                 {                     byte b = (byte)(0x80 >> (x & 0x7));                     pixels[pos] |= b;                 }             }         }     }     //作成したピクセルデータをコピー     IntPtr ptr = bmpData.Scan0;     Marshal.Copy(pixels, 0, ptr, pixels.Length);     // ロックを解除     newImg.UnlockBits(bmpData);     return newImg; } | 
実験してみると赤のGetBrightnessを調べてみると0.5を超えているため、第二引数に0.5を指定すると、生成される画像は真っ白になります。適切な値に調整する必要があります(赤なら0.52以上にするとよい)。

これも実験してみました。
処理なし

なにも表示されない。
閾値50%で処理

当然、なにも表示されない。
閾値80%で処理

本日は5のつく日
EDZEI:生|
またはヤフーカード
ご利用額の+ %
閾値80%で処理して白黒反転

本日は5のつく日
PayPay残高
または ヤフーカード
ご利用額の+ %
白黒をはっきりさせたほうが精度はよくなります。また背景が黒の場合はあまりうまくいかないようです。
