111年資訊技師高等程式設計
四、現在有二維矩陣 float[ ][ ] map 存放著一張解析度 M×N 的 24Bits 彩色影像資料,以 Y, I, Q 顏色編碼,其資料存放方式是依像素(Pixel)循序存放,如下圖所示。 請以 Java 或 C++ 撰寫一函式 int[ ][ ] YIQ2RGB(float[ ][ ] map) { .. },對其傳入 map 矩陣後,可傳回一轉成 RGB (R, G, B 各範圍皆是0~255 整數) 的二維整數矩陣,排列方式如同 YIQ 矩陣。像素的 YIQ 轉 RGB 公式如下圖所示,轉換時小數部分四捨五入,但不可低於0或超過255。 接著請再撰寫一函式 void Floodfill(int[ ][ ] m , int x, int y, int r1, int r2) { .. },此函式以水流填充演算法 (flood fill),由上題所得的二維 RGB 矩陣 m,以指定的 (X, Y) 座標為起點沿上下左右四個方向,持續的水流填充 (搜尋) 鄰近點中 (R, G, B) 值範圍符合 r1 ≤ R 且 R ≤ r2 條件的點。最後,將這些符合點的 (R, G, B) 值皆改為 (127, 127, 127)。如下圖所示,假設 (X, Y) 點本身符合條件,則向四個方向水流填充,假設 (X-1, Y) 點也符合條件,則繼續針對 (X-1, Y) 點的週邊水流填充。此題需用遞迴 (Recursion) 方式處理。(25分) |
答:
題目出錯,說明如下:
1.YIQ 轉 RGB 公式改成:
2.題目部分需求內容改成:
將「將這些符合點的 (R, G, B) 值皆改為 (127, 127, 127)」,改成「將指定的 (X, Y) 座標的值改為127」。這樣才能順利做出水流填充演算法。
3.這個題目出題教授應該只是單純使用文字來出實作題,本身也沒有去實作出程式來驗證出題題目所描述的內容是否可行,這種出題方式很容易造成題目邏輯嚴重問題。希望未來這些出題教授出實作題時,請先自己寫程式來驗證,免得誤導考生。
程式碼:
package a20221007; public class test20221205 { public final static int M = 7; public final static int N = 14; public static int[ ][ ]YIQ2RGB(float[ ][ ]map) { int[ ][ ]RGB = new int[M][N]; float Y = 0, I = 0, Q = 0; int R, G, B; int pos = 0; // RGB 陣列儲存的位置 int cnt = 0; // 決定採用那一個 RGB 公式 int x = 0; int y = 0; for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { pos = (i-0)*N+(j-0); if (pos%3 == 0) { Y = map[i][j]; } else if (pos%3 == 1) { I = map[i][j]; } else if (pos%3 == 2) { Q = map[i][j]; x = cnt/N; // 計算 RGB 陣列儲存的行位置 y = cnt%N; // 計算 RGB 陣列儲存的列位置 if (cnt%3 == 0) { R = (int) (1*Y+0.956*I+0.619*Q); RGB[x][y] = R; } else if (cnt%3 == 1) { G = (int) (1*Y-0.272*I-0.647*Q); RGB[x][y] = G; } else if (cnt%3 == 2) { B = (int) (1*Y-1.106*I+1.703*Q); RGB[x][y] = B; } cnt++; } } } return RGB; } static void Floodfill(int[ ][ ] m , int x, int y, int r1, int r2) { int pos = (y-0)*N+(x-0); // RGB 陣列儲存的位置 /* 找出 R 的正確位置 */ if (pos%3 == 0) { } else if ((pos-1)%3 == 0) { pos = pos-1; } else if ((pos+1)%3 == 0) { pos = pos+1; } int R = m[pos/N][pos%N]; // 取出 RGB 陣列的 R 值 // System.out.printf("R = %d\n", R); if (R >= r1 && R <= r2) { m[y][x] = 127; if (y > 0 && m[y-1][x] != 127) { // 往上方遞迴 Floodfill(m, x, y-1, r1, r2); } if (y < M-1 && m[y+1][x] != 127) { // 往下方遞迴 Floodfill(m, x, y+1, r1, r2); } if (x > 0 && m[y][x-1] != 127) { // 往左方遞迴 Floodfill(m, x-1, y, r1, r2); } if (x < N-1 && m[y][x+1] != 127) { // 往右方遞迴 Floodfill(m, x+1, y, r1, r2); } } } public static void main(String[ ] args) { float[ ][ ]map = { {1, 10, 200, 15, 30, 10, 50, 60, 40, 100, 10, 5, 1, 2}, {80, 70, 10, 3, 8, 99, 77, 12, 20, 47, 52, 55, 87, 22}, {20, 72, 20, 23, 28, 29, 72, 22, 22, 47, 22, 25, 27, 222}, {5, 15, 250, 55, 50, 15, 55, 65, 45, 150, 15, 55, 51, 52}, {6, 63, 60, 62, 60, 156, 66, 61, 46, 156, 156, 65, 56, 6}, {7, 73, 70, 72, 70, 157, 76, 71, 47, 157, 157, 75, 57, 7}, {8, 83, 80, 82, 80, 158, 88, 81, 48, 158, 158, 85, 58, 8} }; System.out.print("map矩陣資料\n"); for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { System.out.print(map[i][j]+" "); } System.out.println(""); } System.out.println(""); int[ ][ ]tmp = new int[M][N]; tmp = YIQ2RGB(map); System.out.print("RGB資料\n"); for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { System.out.print(tmp[i][j]+" "); } System.out.println(""); } System.out.println(""); Floodfill(tmp, 1, 1, 0, 255); System.out.print("Floodfill資料\n"); for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { System.out.print(tmp[i][j]+" "); } System.out.println(""); } } } |
執行結果:
map矩陣資料
1.0 10.0 200.0 15.0 30.0 10.0 50.0 60.0 40.0 100.0 10.0 5.0 1.0 2.0
80.0 70.0 10.0 3.0 8.0 99.0 77.0 12.0 20.0 47.0 52.0 55.0 87.0 22.0
20.0 72.0 20.0 23.0 28.0 29.0 72.0 22.0 22.0 47.0 22.0 25.0 27.0 222.0
5.0 15.0 250.0 55.0 50.0 15.0 55.0 65.0 45.0 150.0 15.0 55.0 51.0 52.0
6.0 63.0 60.0 62.0 60.0 156.0 66.0 61.0 46.0 156.0 156.0 65.0 56.0 6.0
7.0 73.0 70.0 72.0 70.0 157.0 76.0 71.0 47.0 157.0 157.0 75.0 57.0 7.0
8.0 83.0 80.0 82.0 80.0 158.0 88.0 81.0 48.0 158.0 158.0 85.0 58.0 8.0
RGB資料
134 0 51 112 -51 64 150 -23 139 85 -4 -13 80 -125
414 112 8 227 104 6 0 201 102 122 182 90 140 133
-66 262 195 60 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
Floodfill資料
127 127 127 127 127 127 127 127 127 127 127 127 127 127
127 127 127 127 127 127 127 127 127 127 127 127 127 127
127 127 127 127 127 127 127 127 127 127 127 127 127 127
127 127 127 127 127 127 127 127 127 127 127 127 127 127
127 127 127 127 127 127 127 127 127 127 127 127 127 127
127 127 127 127 127 127 127 127 127 127 127 127 127 127
127 127 127 127 127 127 127 127 127 127 127 127 127 127
說明:
1.YIQ轉RGB公式:
R = 1×Y+0.956×I+0.619×Q
G = 1×Y-0.272×I-0.647×Q
B = 1×Y-1.106×I+1.703×Q
2.方向:
|
(X,Y+1) |
|
(X-1,Y) |
(X,Y) |
(X+1,Y) |
|
(X,Y-1) |
|
3.map[2][14]:
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
0 |
1 R 0 |
10 G 1 |
200 B 2 |
15 R 3 |
30 G 4 |
10 B 5 |
50 R 6 |
60 G 7 |
40 B 8 |
100 R 9 |
10 G 10 |
5 B 11 |
1 R 12 |
2 G 13 |
1 |
80 B 14 |
70 R 15 |
10 G 16 |
3 B 17 |
8 R 18 |
99 G 19 |
77 B 20 |
12 R 21 |
20 G 22 |
47 B 23 |
52 R 24 |
55 G 25 |
87 B 26 |
22 R 27 |
2 |
20 G 28 |
72 B 29 |
20 R 30 |
23 G 31 |
28 B 32 |
29 R 33 |
72 G 34 |
22 B 35 |
22 R 36 |
47 G 37 |
22 B 38 |
25 R 39 |
27 G 40 |
222 B 41 |
3 |
5 R 42 |
15 G 43 |
250 B 44 |
55 R 45 |
50 G 46 |
15 B 47 |
55 R 48 |
65 G 49 |
45 B 50 |
150 R 51 |
15 G 52 |
55 B 53 |
51 R 54 |
52 G 55 |
4 |
6 B 56 |
63 R 57 |
60 G 58 |
62 B 59 |
60 R 60 |
156 G 61 |
66 B 62 |
61 R 63 |
46 G 64 |
156 B 65 |
156 R 66 |
65 G 67 |
56 B 68 |
6 R 69 |
5 |
7 G 70 |
73 B 71 |
70 R 72 |
72 G 73 |
70 B 74 |
157 R 75 |
76 G 76 |
71 B 77 |
47 R 78 |
157 G 79 |
157 B 82 |
75 R 81 |
57 G 82 |
7 B 83 |
6 |
8 R 84 |
83 G 85 |
80 B 86 |
82 R 87 |
80 G 88 |
158 B 89 |
88 R 90 |
81 G 91 |
48 B 92 |
158 R 93 |
158 G 94 |
85 B 95 |
58 R 96 |
8 G 97 |
藍色字是 pos。
※參考資料:
1.https://baike.baidu.hk/item/%E7%9F%A9%E9%99%A3%E4%B9%98%E6%B3%95/5446029
2.https://zh.wikipedia.org/zh-hk/YIQ
3.https://en.wikipedia.org/wiki/YIQ
4.http://dystopiancode.blogspot.com/2012/06/yiq-rgb-conversion-algorithms.html
5.https://zh.wikipedia.org/wiki/Flood_fill
留言列表