书上讲到比特平面分层的时候讲的很模糊,我不太能够理解如何分离出每个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;
}