2019年11月13日水曜日

棋譜OCRプログラムの軌跡(4-1)手順番号検出(石の座標および色検出)

前回の処理で、石の座標をピクセル単位で求めることができました。棋譜を作るには、ピクセル単位の石の座標を、縦横1~19に変換し、各石に記述されてい手順番号を読み取ることが必要です。手順番号の取得は、以下の手順で行いました。
  1. 石の座標を縦横1~19に変換する
  2. 石の白黒を判定する
  3. 手順番号を検出する
    3-1. 黒石処理
    3-2. 白石処理

1.座標変換処理
            foreach (CircleSegment circle in circles)
            {
                int x = (int)Math.Truncate((circle.Center.X - xmin) / dx + 0.5);
                int y = (int)Math.Truncate((circle.Center.Y - ymin) / dy + 0.5);

                vs[x, y] = "*";
            }
   circles:前回検出した円の配列
   xmin  :前々回検出した輪郭の左辺の位置
   dx      :前々回検出した輪郭の(右辺の位置 - 左辺の位置)÷18 つまりマス目の幅
   ymin  :前々回検出した輪郭の上辺の位置
   dx      :前々回検出した輪郭の(下辺の位置 - 上辺の位置)÷18 つまりマス目の高さ
上記処理で、変換後の石の座標(x,y)を求め、石がある個所を配列 vsに”*”をセットしています。
注1) x , y :0~18

x, y を求めた後、x=0または18 y=0または18 の 円の中心座標と、前々回求めた輪郭の座標を比較し、原点(左上端)の座標および輪郭の幅高さを補正しています。

2.白黒判定処理
            Mat bin_img = new Mat(); //2値画像を入れておくためのMat         
            Cv2.Threshold(gray, bin_img, 160, 255, OpenCvSharp.ThresholdTypes.Binary); //閾値160で2値画像に変換
            for (int i = 0; i < 19; i++)
            {
                for (int j = 0; j < 19; j++)
                {
                    if (vs[i, j] == "*")
                    {
                        Mat clipMat = new Mat();
                        clipMat= bin_img.Clone(new OpenCvSharp.Rect((int)(xs + i * this.dx), (int)(ys + j * this.dy), (int)this.dx, (int)this.dy));
                        
                        // ここから 白黒判定処理 -----------------------------------------------
                        int wCnt = 0;
                        int bCnt = 0;

                        for (int y = 0; y < clipMat.Height; y++)
                        {
                            for (int x = 0; x < clipMat.Width; x++)
                            {
                                Vec3b color = clipMat.Get<Vec3b>(y, x);
                                int cnt = 0;
                                if (color.Item0 == 0) cnt++;
                                if (color.Item1 == 0) cnt++;
                                if (color.Item2 == 0) cnt++;

                                if (cnt < 2)
                                    wCnt++;
                                else
                                    bCnt++;
                            }
                        }
                        string ishiColor = (wCnt > bCnt) ? "W" : "B";
                        // ここまで 白黒判定処理  -----------------------------------------------

                        if (ishiColor == "B){
                            === 黒石手順番号検出処理 ===
                        }
                        else{
                            === 白石手順番号検出処理 ===
                        }
                    }
                }
            }

  1. 先行処理で、取得したモノクロ画像から Threshold関数を使って
    黒白の2値画像(bin_img)を取得します。
  2. 1.で求めた 石が存在しているマス目(i ,j)について、2値画像(bin_img)から Clone関数を使って、マス目の画像を切り取りclipMatに格納します。
  3. clipMat内のピクセルを判定し、白が多ければ白石、黒が多ければ黒石とします。

    2値画像のため 黒(0,0,0) または 白(255,255,255) のみと思いましたが、実際には(255,255,0)といったピクセルも存在したため、0が1以下の場合 該当ピクセルは白、以外黒と判定しました。




開発環境
 OS:Windows10
 言語:C#(WPF使用)
 IDE:VisualStudio2019
 仕様Tool:OpenCvSharp v4.0.0.20181129
      Tesseract v3.3.0.0
 使用電子本:電子書店パピレスのNHK 囲碁講座 テキスト

0 件のコメント:

コメントを投稿