自制作業系統Antz(15)——實現啟動介面
AntzScript
:mortar_board: The language executed in the Antz system.
本節不涉及OS底層內容,只是關於圖片放大顯示時效果處理的。
真機啟動效果 |
---|
![]() |
圖片來源: 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列)可以通過邊長比對應回源影象。其對應座標為(i m/a,j n/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 ++ ; }