[05]16位图像转8位图像
1.原理
1)16位图像
16位图像的每个像素点的像素值都由16位的二进制数表示,每个像素点的颜色有 2^16 = 65536 种可能。也就是说,图像的颜色区间被划分成了2^16 = 65536份。
2)8位图像
8位图像的每个像素点的像素值都由8位的二进制数表示,每个像素点的颜色有 2^8 = 256 种可能图像的颜色区间被划分成了2^8 = 256份。
3)数据类型
ushort 为无符号16位整数,占2个字节,取值范围在0~65,535之间。
uchar 为无符号8位,占1个字节,取值范围在0~255之间。
2.转化
16位到8位,是高精度到低精度的转换,必然造成信息的丢失,信息丢失是不可避免的
1)错误思维:
将16位转换成8位是将区间 [0,65535] 映射到 [0,255] ,错误的认为16位的图像像素值分布在 [0,65535] 。
2)正确思维----相对好方式
取图像像素值最小值到最大值区间映射到[0,255]。
int main()
{
Mat img = imread("test.tif", CV_LOAD_IMAGE_UNCHANGED);//加载图像
int width = img.cols;//图片宽度
int height = img.rows;//图片高度
Mat dst = Mat::zeros(height, width, CV_8UC1);//生成空目标图
double minv = 0.0, maxv = 0.0;
double* minp = &minv;
double* maxp = &maxv;
minMaxIdx(img, minp, maxp); //取得像素值最大值和最小值
//用指针访问像素,速度更快
ushort *p_img;
uchar *p_dst;
for (int i = 0; i < height; i++)
{
p_img = img.ptr<ushort>(i);//获取每行首地址
p_dst = dst.ptr<uchar>(i);
for (int j = 0; j < width; ++j)
{
p_dst[j] = (p_img[j] - minv) / (maxv - minv) * 255;
//下面是失真较大的转换方法
//int temp = img.at<ushort>(i, j);
//dst.at<uchar>(i, j) = temp;
}
}
imshow("8bit image", dst);
imwrite("task1_8bit.jpg", dst);
waitKey(0);
system("pause");
return 0;
}