opencv之三种不限原位深、通道的灰度变换法详解

一直以来对图像的通道变换,位深变换的本质不理解,今天花时间终于算是搞懂了(纯干货)


1、首先要懂得像素的数据类型

位深度数据类型取值范围
8Uunsigned char0-255
8Schar-128-127
16Uunsigned short int0-65535
16Sshort int-32768-32767
32Slong0-65535
32Ffloat0-1.0
64Fdouble0-1.0

数据类型与通道数没关系,8代表8位,16代表16位。


2、其次要懂得通道变换

3通道->1通道:就是将rgb三个通道的像素数据通过某种方式进行合并,然后写入单通道即可


3、就是映射关系

例:0-1要线性映射到0-100是不是就是将0-1每一个数据线性增大100倍?

那么无符号8位数据要映射到无符号16位数据,是不是就是将0-255线性映射到0-65535?即将0-255中每个数据乘以65535.0/255。


这里介绍一种24位3通道彩色图像转16位灰度图的三种灰度变换法

首先:得明白24位3通道图像每通道的数据类型为unsigned char(24/3=8),16位单通道数据类型为unsigned short int

其次:先创建空白16位单通道图像,再通过灰度算法处理像素数据,但是这时候处理的像素数据的数据类型与原图一致,即uchar。

最后:将处理过的像素数据乘以线性映射系数(计算方式如步骤3)写入空白16位单通道图像中即可以得到16位灰度图。


代码:

    Mat img = imread("./1.jpg",2|4);
    cout<<"原channels=="<<img.channels()<<endl;
    cout<<"原type=="<<data.Type2String(img.type())<<endl;

    double alpha = 65535.0/255;//映射系数:8位->16位
    Mat src16bit = Mat::zeros(Size(img.cols, img.rows), CV_16UC1);
    Mat src16bit1 = Mat::zeros(Size(img.cols, img.rows), CV_16UC1);
    Mat src16bit2 = Mat::zeros(Size(img.cols, img.rows), CV_16UC1);
    for (int i = 0; i < img.rows; i++)
    {
        uchar* data_pix = img.ptr<uchar>(i);
        for (int j = 0; j < img.cols * 3; j = j + 3)
        {
            uchar r, g, b,d,e;
            double val,val1,val2;
            r = data_pix[j];
            g = data_pix[j + 1];
            b = data_pix[j + 2];
            //取rgb三通道像素最大值(此时还是8位数据类型uchar)
            d = r > g ? r : g;
            d = d > b ? d : b;
            //平均值法
            val1 = alpha*((r+g+b)/3.0);
            val = alpha*d;//映射到16位需要把8位数据线性映射到16位数据类型
            //加权平均值法
            val2 = alpha*(0.299*r+0.578*g+0.114*b);
            src16bit.at<unsigned short int>(i, j/3) = (unsigned short int)val;
            src16bit1.at<unsigned short int>(i, j/3) = (unsigned short int)val1;
            src16bit2.at<unsigned short int>(i, j/3) = (unsigned short int)val2;
        }
    }

    cout<<"最值法channels=="<<src16bit.channels()<<endl;
    cout<<"最值法type=="<<data.Type2String(src16bit.type())<<endl;

    cout<<"平均值法channels=="<<src16bit1.channels()<<endl;
    cout<<"平均值法type=="<<data.Type2String(src16bit1.type())<<endl;

    cout<<"加权平均值法channels=="<<src16bit2.channels()<<endl;
    cout<<"加权平均值法type=="<<data.Type2String(src16bit2.type())<<endl;

    imshow("max_dst",src16bit);
    imshow("average_dst",src16bit1);
    imshow("weighted_mean_dst",src16bit2);
    imshow("img",img);
    waitKey(0);

 

 

 

 


个人理解,若有错误欢迎纠正! 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

波了个咪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值