# 北軟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) { } } } ```