2019年11月13日水曜日

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

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

1.座標変換処理
座標変換処理
1
2
3
4
5
6
7
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.白黒判定処理
白黒判定処理
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
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 件のコメント:

コメントを投稿