AntzScript
🎓 The language executed in the Antz system.
本節不涉及OS底層內容,只是關於圖片放大顯示時效果處理的。
Antz系統更新地址
Antz項目地址
| 真機啟動效果 |
|---|
![]() |
圖片來源:phodal/daily
(orz左上角是在處理原圖時自己簽的名)
為了節省鏡像空間,我將圖片從2000乘800左右圖片壓縮為108乘60的24色大小的圖片,計算為RGB值之后也有近6400左右像素點。但是要將它寫入顯存,展現在用戶眼中,效果表明是很差的,我們的分辨率為1080x768,數十倍於這張圖片。
為了解決顯示效果的問題,這里有兩種解決方法。
一. 像素點區域化
這個方法是我自己起的名字,大致意思也如標題所示,就是將一個本來應該顯示在(x1,y1)位置的像素點區域化顯示,將其RGB值覆蓋在(x1,y1)至(x1+x,y1+y)的這片區域。這個方法實現起來非常簡單,但是效果極差,最后顯示出來的效果就好像是我的世界中的超大像素點效果。
圖示大概如這樣:

附上簡單實現。
void to_show(){
int i, x, y ;
int k ;
k = 0 ;
for (y = 0; y < 60; y++) {
for (x = 0; x < 108; x++){
// 在(x*10,y*13)至(x*10+10,y*13+13)這片區域填充RGB值bmp[k]
print_image(x*10,y*13,x*10+10,y*13+13,bmp[k]);
k++;
}
}
}
在虛擬機中效果如下。

二. 雙線性插值
在使用第一種粗略暴力的方式實現啟動動畫之后,第二天的數字圖像處理課程中,聽到老師講matlab中的圖片放大縮小函數的原理,了解了雙線性插值這個算法,於是想到用這個方法來重新實現啟動界面。
雙線性插值的基本原理是,假設源圖像大小為MxN,目標圖像為AxB。那么兩幅圖像的邊長比分別為:M/A和N/B。這兩個比例值一般是浮點數。目標圖像的第(i,j)個像素點(i行j列)可以通過邊長比對應回源圖像。其對應坐標為(im/a,jn/b)。顯然,這個對應坐標一般來說不是整數,而非整數的坐標是無法在圖像這種離散數據上使用的。雙線性插值通過尋找距離這個對應坐標最近的四個像素點,來計算該點的值(灰度值或者RGB值)。
其實可以理解為通過其周圍的四個點,中和出這片區域中的其他點。


我們想得到一張放大的圖片,現在有原圖像和目標圖像。那么,有一個最基本的問題擺在我們面前:是遍歷原圖像呢,還是遍歷目標圖像呢?
在實踐的過程中,通常都是遍歷目標圖像的。因為這樣可以確保目標圖像的每一個像素都是有值的。
就拿上圖的例子來說,右圖目標圖像中的 [0,0] 點很順利的找到了左圖原圖像中與自己對應的 [0,0] 點。然后 [0,1] 點就懵逼了,它應該找[0,0.33]點嗎?沒有這個點啊,所以[0,0.33]的值是需要四個點來進行擬態的。
插值法除了雙線性插值還有最臨近插值,線性插值。
最臨近插值可以理解為取值為最近的一個像素點,線性插值是在周圍兩個像素點中取一個(根據兩邊距離決定)折中值,很明顯它們的作用范圍均是線性一維。
再來說雙線性插值,它可以取空間中的四個點來做擬態取值。
大概理解就是如此,具體實現可以借助公式,下面給出百度百科的公式。

已知的紅色數據點與待插值得到的綠色點
假如我們想得到未知函數f在點P= (x,y) 的值,假設我們已知函數f在Q11 = (x1,y1)、Q12 = (x1,y2),Q21 = (x2,y1) 以及Q22 = (x2,y2) 四個點的值。
首先在x方向進行線性插值,得到R1和R2,然后在y方向進行線性插值,得到P.
這樣就得到所要的結果f(x,y).
其中紅色點Q11,Q12,Q21,Q22為已知的4個像素點.
第一步:X方向的線性插值,在Q12,Q22中插入藍色點R2,Q11,Q21中插入藍色點R1;
第二步 :Y方向的線性插值 ,通過第一步計算出的R1與R2在y方向上插值計算出P點。
線性插值的結果與插值的順序無關。首先進行y方向的插值,然后進行x方向的插值,所得到的結果是一樣的。雙線性插值的結果與先進行哪個方向的插值無關。
如果選擇一個坐標系統使得 的四個已知點坐標分別為 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么插值公式就可以化簡為
f(x,y)=f(0,0)(1-x)(1-y)+f(1,0)x(1-y)+f(0,1)(1-x)y+f(1,1)xy
在x與y方向上,z值成單調性特性的應用中,此種方法可以做外插運算,即可以求解Q1~Q4所構成的正方形以外的點的值。

f(x,y1) ≈ (x2−x / x2−x1) * f(Q11) + (x−x1 / x2−x1) * f(Q21),
f(x,y2) ≈ (x2−x / x2−x1) * f(Q12) + (x−x1 / x2−x1) * f(Q22).
f(x,y) ≈ (y2−y / y2−y1) * f(x,y1) + (y−y1 / y2−y1) * f(x,y2)
int index = 0 ;
for(y=0;y<768;y++){
for(x=0;x<1080;x++){
for(int i=0;i<60;i++){
for(int j=0;j<108;j++){
int getx1 = ((108+13-y)/13)*bmp[index*108+60] + (y/13)*bmp[index*108+60+1] ;
int getx2 = ((108+13-y)/13)*bmp[(index+1)*108+60] + (y/13)*bmp[(index+1)*108+60+1] ;
int getRgb = (i/10)*getx1 + ((60-i)/10)*getx2 ;
print_image(x,y,getRgb);
}
}
}
index ++ ;
}

