書上講到比特平面分層的時候講的很模糊,我不太能夠理解如何分離出每個bit平面的圖像,以及具體的計算方法,查閱資料后發現有兩類說法,其中一類是典型的錯誤說法。
說法一(經典錯誤):
private int bitLevel(int color, int level) {
int color_lev1 = color & 1; //00000001
int color_lev2 = color & 0x2; //00000010
int color_lev3 = color & 0x4; //00000100
int color_lev4 = color & 0x8; //00001000
int color_lev5 = color & 0x10;//00010000
int color_lev6 = color & 0x20;//00100000
int color_lev7 = color & 0x40;//01000000
int color_lev8 = color & 0x80;//10000000
int color_lev;// = color & 0x80;
color_lev = color & (1 << level)//level取值為0到7
return (255 << 24) + (color_lev << 16) + (color_lev << 8) + color_lev;
}
這個算法的作用就是簡單的提取每一層的比特,但我忽略了“突出該層比特”的要義。實際結果也證明是錯誤的,例如第一層,值不是0就是1,這樣的色值顯示出來就是純黑,根本顯現不了第一層比特的貢獻。突出分層的最好做法就是二值化,因為每個像素點每層比特的值只有1(有貢獻)和0(無貢獻),我們要做的就是突出1值。
真正的分層算法如下:
第一層:
第一層位置上的值只能是0和1,所以值為0時,可令其轉換值為255
private int bitLevelOne(int color){
int gray = color >> 8 & 0xFF;
int color_lev;
if(gray == 1)color_lev = 255;
else color_lev = 0;
return (255 << 24) + (color_lev << 16) + (color_lev << 8) + color_lev;
}
(實驗是以《數字圖像處理》書中提供的樣圖作處理的,該圖本身就是8比特的灰度圖,傳給函數的參數值是argb像素點值,該值a=r=g=b,所以取出右邊的8位即得到它的灰度圖,同樣為了“突出”考慮,alpha通道取255)
書中原話:“顯示一幅8比特圖像的第8個比特平面並不困難,它可以用閾值灰度變換函數處理輸入圖像得到二值函數,該函數將0-127之間的所有灰度映射為0,128-255之間的所有灰度值映射為1.”
原圖:(500x1192像素的灰度圖)
第一層平面圖:
其它層級的分層算法如上依次類推,如果該層級的比特值為1,則二值化為255,如果為0,則二值化為0。比如第六層分層算法如下
private int bitLevelSixth(int color) {
int gray = color >> 8 & 0xFF;
int color_lev6 = gray & 0x20;// 00100000
int color_lev;
if (color_lev6 == 0x20)
color_lev = 255;
else
color_lev = 0;
return (255 << 24) + (color_lev << 16) + (color_lev << 8) + color_lev;
}
注意:上述算法涉及到各種移位等操作,實際結果效率比較低,這里暫不考慮這一點,只說明實際的比特平面分層算法的原理。
第6,7,8層結果如下:
比特平面分層的另一個應用是在圖像壓縮中,從上面的分層圖結果來看,我們只需要使用高階的幾層便能重建原圖,這也就意味着可以使用比原來更少的比特層來構建原圖(比如4層,這樣就減少了50%的存儲量)。
使用6,7,8三個平面重建的算法和結果如下:
private int combine678(int color){
int gray = color >> 8 & 0xFF;
int colors = gray & 0xE0;//11100000
return (255 << 24) + (colors << 16) + (colors << 8) + colors;
}