如之前所说,我们需要将16位图像转换为8位图像;16位图像的像素值一共有:
2^16=65536种颜色;
而8位位图像只有:
2^8=256种颜色,传统的位数转换都是:像素值*256/65536,比如photoshop,以及matlab的im2uint8函数都是如此,在一般场景下是没有问题的,我们姑且称之为“真转换”,而如果是labelme得到的label.png标注图像在进行转换时,由于每个类别的像素值从0开始赋值,如0,1,2,3,4.......如果进行“真转换”的话,由于这些值都太小,基本转换后的像素值都是(0,1)之间,所以都变成了0,所以我们需要将16位转换位8位的时候还保留住原来的像素值,这种只改变位数,而不改变具体数值的转换方法,姑且称之为“伪转换”;
而解决的思路也很简单,图像说白了也就是一个矩阵,像素值也就是一个数值而已,我们只需要把表示类别的像素值找出来,并且把他们的值投射到8位即可:
使用的软件环境如下:
- Python 3.6.3
- VS2013
- OPENCV 2.4.11
- PIL
- Labelme 2.8.0
首先,C++使用opencv转化,核心代码如下:(完整代码(批量转换,速度最快,需要配置opencv):点击打开链接)
for (int k = 0; k<src.rows; k++) { for (int kk = 0; kk<src.cols; kk++) { int n = src.at<ushort>(k, kk); ff.at<uchar>(k, kk) = n; } }
python使用PIL进行转换,更加简单,核心语句就一行(完整代码(推荐,批量转化,速度也很快,但是少了配置opencv的麻烦):点击下载完整python转换代码):
img = Image.fromarray(np.uint8(img))
转换完成后,可以使用软件查看时候变为8位,但是打开图片依然是一片黑:
如果需要提高类别之间的差异性,可以直接乘以一个较大的值:如下:
img = Image.fromarray(np.uint8(img)*20)
图片就会有明显的区分,如下: