# 北軟99 pC 計算BMP圖中線段頭尾座標及斜率
###### tags: `北軟99`
## 題目
光學文字辨識的過程中有傾斜校正的步驟,用來將圖面的傾斜角度(或斜率)計算出來,以便後續的傾斜校正,請依圖規格及圖中的線段頭尾座標來計算斜率。
為簡化程式的撰寫,僅以 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/0NIFHSC.png)
BMP 圖檔的第 0、1 位元組一定是存放 42h、4Dh(h 表十六進位),如上右圖所示。
第 12h∼15h 位元組存放圖面寬的點數,第 16h∼19h 位元組存放圖面高的點數。
第 0036h∼38h 位元組存放點座標(0,0)的藍、綠、紅之值,如上右圖所示為黑點。
第 0039h∼3bh 位元組存放點座標(1,0)的藍、綠、紅之值,如上右圖所示為白點。
第 0093h∼95h 位元組存放點座標(31, 0)的藍、綠、紅之值,如上右圖所示為黑點。
第 0bd6h∼0bd8h 位元組存放點座標(0, 31)的藍、綠、紅之值,如上右圖所示為黑點。
第 0c33h∼0c35h 位元組存放點座標(31, 31)的藍、綠、紅之值,如上右圖所示為黑點。
請寫一支程式能偵測出 32x32 的 BMP 圖檔上線段頭尾兩端點座標(X1,Y1)及(X2,Y2),進而計算線段斜率(Y2-Y1)/(X2-X1),並顯示出來。如下圖所示。
![](https://i.imgur.com/cPkvUuY.png)
請以 A.bmp 及 B.bmp 兩個圖檔來測試。(1. 程式介面 (4 分) 2. 功能正確(21 分))
## 想法
這題是圖像題,不過這題有個規則是左下角為(0,0),但正常而言來說,BMP在讀取pixel的時候,0,0是左上角,所以規則的(0,0)會等於BMP的(0,31)。
那以此類推,規則的(31,0就是BMP右下的點(31,31)。
接下來,我們開兩個迴圈來掃描左邊端點的座標,從(0,31)掃到(0,0),再從(1,31)掃到(1,0),以此類推,直到我們尋找到了一個pixel的R為0的點(黑色)。
針對於右邊端點的座標,從(31,31)掃到(31,0),再從(30,31)掃到(30,0),以此類推,直到我們尋找到了一個pixel的R為0的點(黑色)。
取得了兩點的座標,不過這邊要再做一個處理,假設我們最後掃描的結果,左端點是(X1,Y1),右端點是(X2,Y2),那我們要再將座標做處理,左端點應該是(X1,31-Y1),右端點應該是(X2,31-Y2),因為規則的Y是由下往上,掃描的Y是由下往上,這樣才會符合規則。
接下來,套用公式斜率,即可求出線段斜率。
※線段斜率應該會差個0.01,題目也沒有說要無條件捨去或者進位或者四捨五入之類的。
## 程式碼(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 problemC
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string path = textBox1.Text;
Bitmap bitmap = new Bitmap(path);
pictureBox1.Image = bitmap;
int pointLeftX = -1, pointLeftY = -1, pointRightX = -1, pointRightY = -1;
for (int i = 0; i < 32 && pointLeftY == -1; i++)
{
for (int j = 31; j >= 0 && pointLeftX == -1; j--)
{
if (bitmap.GetPixel(i, j).R == 0)
{
pointLeftX = i;
pointLeftY = 31-j;
}
}
}
for (int i = 31; i >= 0 && pointRightY == -1; i--)
{
for (int j = 31; j >= 0 && pointRightX == -1; j--)
{
if (bitmap.GetPixel(i, j).R == 0)
{
pointRightX = i;
pointRightY = 31-j;
break;
}
}
}
label2.Text = String.Format("線段左邊端({0},{1})點座標", pointLeftX, pointLeftY);
label3.Text = String.Format("線段右邊端({0},{1})點座標", pointRightX, pointRightY);
double m = ((pointRightY - pointLeftY) * 1.0) / ((pointRightX - pointLeftX) * 1.0);
label4.Text = String.Format("線段斜率 {0:0.00}", m) ;
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
```