• OpenCV -- 将16位图像映射到8位


    现在有一张16bit深度的图像,如果不使用PS或者其他工具的话,是很难直接获取到图像里储存的信息的。如下。
    直接在Window里打开一张16位tif格式的图片


    如果能将16位转换成8位的话,就能正常显示了。

    原理
    一张16位的图像,意思是一张图像的每个像素点的像素值都由16位的二进制数表示,每个像素点的颜色有 2^16 = 65536 种可能。
    也就是说,图像的颜色区间被划分成了2^16 = 65536份。
    同理,8位图像,图像的颜色区间被划分成了2^8 = 256份。
    那么,将16位转换成8位,不就是将区间 [0,65535] 映射到 [0,255] 吗?

    软件环境
    VS2017
    OPENCV 3.41

    测试与分析
    16位到8位,是高精度到低精度的转换,必然造成信息的丢失。
    在实际的测试中也是这样。

    下面是笔者直接将16位映射到8位的转换结果

    这实际上是一张失真很严重的图像。
    上面这种方法虽然道理是没错,但是这种转换遗失了图像中太多信息,不是我们想要的。然而当我在百度上搜索关于16位到8位图像的转换思路的时候,提供的却大多是这种方法,这也是我写这篇博客的原因。
    问题的原因是我
    错误地认为了16位的图像像素值就是分布在 [0,65535] 的。

    解决的方法是:

    取图像 像素值 最小值 到 最大值 区间映射到[0,255]。

    最终处理结果如下:

    是不是感觉细节层次丰富了很多呢?

    代码:

    #include <iostream>
    #include <opencv.hpp>
    #include <opencvhighgui.h>
    #include <stdlib.h>
    #include <time.h>
    #include <windows.h>
    
    using namespace cv;
    using namespace std;
    
    int main()
    {
        DWORD Start_time = GetTickCount(); //计时开始
        Mat img = imread("task1.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;
    	}
    }
    DWORD End_time = GetTickCount(); //计时结束
    cout << "Time used:" << End_time - Start_time << " ms"<<'
    ';
    imshow("8bit image", dst);
    imwrite("task1_8bit.jpg", dst);
    waitKey(0);
    system("pause");
    return 0;
    }
    
    
    不光是16位,24位图像的转换也是同样的思路,感兴趣的朋友可以自己试一试。
    不过要另外多说一句,高精度到低精度,信息的丢失是不可避免的,上面提供的方法只是相对效果更好。
    
    补充: 关于数据类型的说明
    ushort 为无符号16位整数,占2个字节,取值范围在0~65,535之间。
    uchar 为无符号8位,占1个字节,取值范围在0~255之间。
    
    要转换数据记得选择合适的数据类型哦。
    
    https://blog.csdn.net/qq_41342525/article/details/105124659
  • 相关阅读:
    Spring Boot 自定义starter
    jvm中的年轻代 老年代 持久代 gc
    nginx反向代理服务器端口问题
    ACE Editor在线代码编辑器简介及使用引导
    Linux下MySQL 5.6.24的编译安装与部署
    C3p0的参数
    Mysql 查看连接数,状态
    linux下mysql定时备份数据库
    Mysql中存储方式的区别
    mysql常用语句
  • 原文地址:https://www.cnblogs.com/zzzsj/p/14281393.html
Copyright © 2020-2023  润新知