# 北軟100 pD 辨識圖中的阿拉伯數字
###### tags: `北軟100`
## 題目
方法:請觀察下面數字 :請觀察下面數字 0~9 圖形的最左邊一欄 0~9 圖形的最左邊一欄或是最底邊之特徵,每一個數字最左邊一欄 ,每一個數字最左邊一欄或是最底邊黑點的位置及數量均不同。請用其中一種特徵來辨識是哪一個數字。
![](https://i.imgur.com/uKzLMTY.png)
實作:為簡化程式的撰 :為簡化程式的撰寫,僅以 32x32 的 BMP 圖檔為實作對象,BMP 圖上任一點在 BMP 圖檔 上是用 3Bytes(藍、綠、紅)存放,若是白點則存放著 255、255、255,若是黑點則存放著 0、0、0。本題目所附的 BMP 圖檔是由黑色的點組成。
本題目特別規定 BMP 圖左下角座標為(0, 0)、右下角座標為(31, 0)、左上角座標為(0, 31)、
右上角座標為(31, 31),如下左圖所示。
![](https://i.imgur.com/VEcXZ16.png)
BMP 圖檔的第 0、1 位元組一定是存放 42h、4Dh(h 表十六進位),如上右圖所示。
第 12h∼15h 位元組存放圖面寬的點數(32 點),第 16h∼19h 位元組存放圖面高的點數(32 點)。
第 0036h∼38h 位元組存放點座標(0,0)的藍、綠、紅之值為 0、0、0 表示一個黑點。
第 0039h∼3bh 位元組存放點座標(1,0)的藍、綠、紅之值為 255、255、255 表示一個白點。
第 0093h∼95h 位元組存放點座標(31, 0)的藍、綠、紅之值為 0、0、0 表示一個黑點。
第 0bd6h∼0bd8h 位元組存放點座標(0, 31)的藍、綠、紅之值為 0、0、0 表示一個黑點。
第 0c33h∼0c35h 位元組存放點座標(31, 31)的藍、綠、紅之值為 0、0、0 表示一個黑點。
請寫一支程式能辨識出 32x32 的 BMP 圖中的阿拉伯數字,
並將辨識結果顯示出來,如下圖所示。(20 分含操作介面 3 分)
![](https://i.imgur.com/PgkeAKt.png)
阿拉伯數字不在 32x32 的 BMP 圖的正中間也要能辨識出來,如下圖所示。(3 分)
![](https://i.imgur.com/eNUBVTs.png)
圖中阿拉伯數字最左邊一欄的特徵不符前面所定的方法,請顯示 “無法辨識” ,如下圖所示。(2 分)
![](https://i.imgur.com/8WBxXCO.png)
## 想法
由於最左邊一欄的特徵不符合也要偵測,選擇偵測的最好方法當然是偵測字形最左邊的邊緣。
我們先從圖像的最左邊開始進行掃描,依次每一pixel的直行由上往下掃描。
直到某個直行出現了黑點,即為字形的最左邊邊緣。
觀察題目給的圖示,為高度21的圖示。
接下來,我們針對於該直行的每21個pixel做掃描,
由於圖像只有黑色和白色,我們可以將它陳述為0與1。
我們可以觀察題目給的圖示,每個字元最左邊的邊緣一定是獨一無二的(這很難看出來,請仔細觀看)
將每個圖示的邊緣用0與1陳述。
0 為 000000111111111000000
1 為 001000000000000000001
2 為 000001000000000000001
3 為 000100000000000000010
4 為 000000000000001100000
5 為 000000010000000000100
6 為 000000000111111100000
7 為 000011000000000000000
8 為 000111100000001111000
9 為 000011111100000000001
接下來,我們在掃描的過程中,一旦發現了**完全**符合上面21個bit的結果,即可確定圖示為哪個字元。
## 程式碼(C#)
```csharp=
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace problemD
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string path = textBox1.Text;
Bitmap bmp = new Bitmap(path);
pictureBox1.Image = bmp;
int readLine = -1;
for(int i = 0; i < bmp.Width && readLine == -1; i++)
{
for(int j = 0; j < bmp.Height && readLine == -1; j++)
{
if(bmp.GetPixel(i,j).R == 0)
{
readLine = i;
}
}
}
string[] array = {
"000000111111111000000",
"001000000000000000001",
"000001000000000000001",
"000100000000000000010",
"000000000000001100000",
"000000010000000000100",
"000000000111111100000",
"000011000000000000000",
"000111100000001111000",
"000011111100000000001"
};
int number = -1;
for (int i = 0; i < bmp.Height - 21; i++)
{
string str = "";
for (int j = i; j < i + 21; j++)
{
str += bmp.GetPixel(readLine, j).R == 0 ? "1" : "0";
}
for(int j = 0; j < array.Length; j++)
{
if(str == array[j])
{
number = j;
}
}
Console.WriteLine(str);
}
if(number == -1)
{
textBox2.Text = "無法辨識";
return;
}
textBox2.Text = number + "";
}
}
}
```