OpenCV图像处理之LUT

目录

1、什么是LUT 

2、LUT的作用

1、伪彩色增强

2、灰度增强

3、图像增强

4、数据增强

3、OpenCV中的LUT函数

1、函数原型

2、代码实现

3、原理图

4、OpenCV-LUT优缺点

1、优点

2、缺点

 5、构建自己的颜色表

1、JET算法

2、16bit对数变换算法LUT应用

3、单通道8bit JET算法伪彩色增强

6、总结


1、什么是LUT 

Look Up Table(颜色查找表)、俗称调色板,一行多列的矩阵/数组;可以通过图像像素值或者一组数据值查找表(LUT)中对应的值进行重映射(当像素值x = 180 , 去查找表中第180个位置的值将原x替换)


2、LUT的作用

1、伪彩色增强

设计一种合理的颜色表,将灰度(黑白)图像,通过颜色表进行重映射为彩色图像,使得其具有更丰富明显的视觉效果

2、灰度增强

设计一种合理的颜色表,将灰度(黑白)图像,通过颜色表进行重映射为一种新的灰度图像,使得其具有更丰富明显的视觉效果

3、图像增强

设计一种合理的颜色表,将图像,通过颜色表进行重映射为一种新的图像,使得其具有更丰富明显的视觉效果

4、数据增强

设计一种合理的表,将一组数据,通过表进行重映射为一组新的数据,使得其具有更丰富明显的表达效果


3、OpenCV中的LUT函数

1、函数原型

void LUT(InputArray src, InputArray lut, OutputArray dst);
/**
* @param {InputArray} src 输入图像
* @param {InputArray} lut 查找表的地址,对于多通道图像的查找,它可以有一个通道,也可以与原始图*                         像有相同的通道; 
* @param {InputArray} dst 输出图像
*/       

2、代码实现

实现的大概思路如下,以RGB->RGB为例

void LUT(Mat src, InputArray lut, Mat & dst)
{
    Vec3b * p = lut.ptr<Vec3b>(0);
    //指针遍历
    for(int i = 0 ; i < src.rows ; i++)
    {
        Vec3b *cur = src.ptr< Vec3b >(i); // 取当前行的首地址
        Vec3b *out = dst.ptr< Vec3b >(i); // 取当前行的首地址
        for(int j = 0 ; j < in.cols ; j++)
        {
            out[j][0] = p[cur[j][0]][0];
            out[j][1] = p[cur[j][1]][1];
            out[j][2] = p[cur[j][2]][2];
        }
    }

3、原理图

SRC代表原图中的某一行,OUT代表LUT映射后的输出图

LUT映射原理图

从上图可以看出,输入图x位置处的BGR值为:SRC[x][0]、 SRC[x][1]、SRC[x][2];对应输出图x位置处的BGR值为:OUT[x][0]、 OUT[x][1]、OUT[x][2];以原图BGR值为下标去查找LUT对应位置的像素值进行替换,如公式所示

OUT[x][0] = LUT[SRC[x][0]][0];

OUT[x][1] = LUT[SRC[x][1]][1]; 

OUT[x][2] = LUT[SRC[x][1]][2]; 


4、OpenCV-LUT优缺点

1、优点

避免对每一个像素都进行一次计算。预先计算每个像素值的对应的匹配值,然后直接对原图中的像素值在LUT中进行查找,即可快速得到匹配值,减少大量不必要的计算。

2、缺点

1、颜色表长度为256,仅适用于8bit的图像

2、对与灰度图的伪彩色增强不可直接使用LUT函数,可以将其转换为RGB图像,此时视觉效果依然是灰度图,只是3个通道的颜色值与原单通道颜色值一致。例:234->[234,234,234],再使用LUT函数


5、构建自己的颜色表

首先,为了方便对比我们构建一个常规的16bit灰度映射表Gray分别从0->65535。

  • C++代码实现
void OpenCVStudy::Build_COLOR_table(Mat & MyLUT)
{   
     Mat GRAY_LUT(5000 , 65536 , CV_16UC1); // 为了方便观察输出,使用5000行数据,映射时需要改成1
    MyLUT = GRAY_LUT;
    for(int j = 0 ; j < MyLUT.rows ; j ++)
    {
        ushort * GRAY = MyLUT.ptr<ushort>(j);
        for(int i = 0 ; i < MyLUT.cols ; i ++)
        {
            GRAY[i] = i;
        }
    }
    imwrite("../images/16bit_LUT.tif" , MyLUT);
}
  • 输出​​​​​​​

1、JET算法

该算法为OpenCV中 cv::applyColorMap()包含的一种颜色映射算法,映射方式如下表所示

JET映射算法
像素值BGR
0-31128+4*value00
3225500
33-952554+4*value0
962542552
97-158250-4*value2556+4*value
1591255254
160-2230252-4*value255
224-25500252-4*value

需要注意的是,其中value从0开始,当像素值为33-95之间时,value从0-62。

  • C++代码实现:
void OpenCVStudy::Build_COLOR_table(Mat & MyLUT)
{
    MyLUT = Mat(20 , 256 , CV_8UC3); // 映射时需要将20行改为1行

    for(int i = 0 ; i < MyLUT.rows ; i++)
    {
        //获取行首地址
        uchar * p = MyLUT.ptr<uchar>(i);
        // *p++ // B
        // *p++ // G
        // *p++ // R
        for(int value = 0 ; value <= 31 ; value++) 
        {
            *p++ = 128 + (4 * value);
            *p++ = 0;
            *p++ = 0; // B G R
        }

        // 32
        {
            *p++ = 255;
            *p++ = 0;
            *p++ = 0;

        }

        //32 + 63 = 95
        for(int value = 0 ; value < 63 ; value++) 
        {
            *p++ = 255;
            *p++ = 4 + (4 * value);
            *p++ = 0;
        }

        //96
        {
            *p++ = 254;
            *p++ = 255;
            *p++ = 2;
        }

        //96 + 62 = 158
        for(int value = 0 ; value < 62 ; value++) 
        {
            *p++ = 250 - (4 * value);
            *p++ = 255;
            *p++ = 6 + (4 * value);
        }
        
        //159
        {
            *p++ = 1;
            *p++ = 255;
            *p++ = 254;
        }

        //159 + 64 = 223
        for(int value = 0 ; value < 64 ; value++) 
        {
            *p++ = 0;
            *p++ = 252 - (4 * value);
            *p++ = 255;
        }

        //223 + 32 = 255
        for(int value = 0 ; value < 32 ; value++) 
        {
            *p++ = 0;
            *p++ = 0;
            *p++ = 252 - (4 * value);
        }
    }
}
  • 输出结果

  • 使用OpenCV自带的LUT函数
Mat out;
cv::LUT(SRC , MyLUT , out); // 映射
  •  对比图

然而,OpenCV自带的LUT函数只支持8bit的图像,下面以LUT映射思想,构建并实现16bit图像的LUT映射 

2、16bit对数变换算法LUT应用

  • 对数变换算法:

dst = C * log(1+src)

C = Max/log(1 + Max) 

dst 代表输出图像素,src代表输入图像素,LUT表的输入像素从0-65535,为了保证数据在0-65535之间,乘以系数C

  • C++代码实现
    Mat LOG_LUT(5000 , 65536 , CV_16UC1);  // 映射时需要将行数改为1
    
    for(int j = 0 ; j < LOG_LUT.rows ; j ++)
    {
        ushort * LOG = LOG_LUT.ptr<ushort>(j);
        double c = (65535 / log(65535 + 1));
        for(int i = 0 ; i < LOG_LUT.cols ; i ++)
        {
            
            LOG[i] = saturate_cast<ushort>(c * log(1.0 + i));
            SRC[i] = i;
        }
    }
    imwrite("../images/LOG_LUT.tif" , LOG_LUT);
  • 输出:

我们可以从构建的LUT表直观的看到灰度变换算法的特点---图像整体亮度提高,我们在本章开始实现了常规的0-65535表, 如果以常规的表作为输入,将得到与LUT表相同的效果。

  • 接下来,将通过LUT映射思想,实现16bit图像的映射
void 16bitLUT(Mat & in)
{    
    cvtColor(in , in ,COLOR_BGR2GRAY);
    in.convertTo(in , CV_16UC1);
    normalize(in, in, 0, 65535, NORM_MINMAX);
    Mat LOG_OUT(in.rows , in.cols , CV_16UC1);
    ushort * lut = LOG_LUT.ptr<ushort>(0);
    //指针遍历
    for(int i = 0 ; i < in.rows ; i++)
    {
        ushort *cur = in.ptr<ushort>(i); // 取当前行的首地址
        ushort * OUT = LOG_OUT.ptr<ushort>(i);
        for(int j = 0 ; j < in.cols ; j++)
        {
            *OUT++ = lut[*cur];     
            cur++; // 偏移到下一个像素值
        }
    }
    imwrite("../images/LOG-OUT.tif" , LOG_OUT);
}
  • 输出结果:

抛开算法效果,重点在于思想!!! 

3、单通道8bit JET算法伪彩色增强

该方法输入图像为单通道8bit图像,有两种方法:

1、映射时可以将其转换为BGR图像通过5.1方法即可实现

2、LUT表查询时,可以将输出图BGR数据分别使用一个通道的数据,本质上与1一致

  • C++代码实现
    Mat in = imread("../images/test.heic" , 0);
    
    in.convertTo(in , CV_8UC1);
    normalize(in, in, 0, 255, NORM_MINMAX);
    Mat MyLUT ;
    image.Build_COLOR_table(MyLUT);
    cout << "ch" << in.channels() << endl;
    Mat out(in.rows , in.cols , MyLUT.type());
    Vec3b * p = MyLUT.ptr<Vec3b>(0);
    //指针遍历
    for(int i = 0 ; i < out.rows ; i++)
    {
        uchar *cur = in.ptr<uchar>(i); // 取当前行的首地址
        Vec3b *o = out.ptr<Vec3b>(i); // 取当前行的首地址
        for(int j = 0 ; j < out.cols ; j++)
        {
            o[j][0] = p[cur[j]][0];
            o[j][1] = p[cur[j]][1];
            o[j][2] = p[cur[j]][2];
            
        }
    }
    imwrite("../images/OUT-8.jpg" , in);
    imwrite("../images/JET-8.jpg" , out);
  • 输出对比图

强调:重在思想!!!!!


6、总结

1、LUT函数提供了一种颜色以及颜色空间与另一种颜色及颜色空间的映射方法,虽然OpenCV本身提供的函数对非8bit图像不友好,但是我们可以利用其思想自己动手实现

2、通过构建LUT,我们可以直观的看到我们算法的特点(例:色谱颜色过渡自然程度、灰度增强灰度值偏亮、暗等等)

  • 请各位大佬批评指正!!

  • 13
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
### 回答1: 光照不均匀是指图像中的光源分布不均匀,导致图像的亮度在不同区域存在差异。光照不均匀常出现在拍照、摄影等场景中,会影响图像的质量和视觉效果。 在opencv中,我们可以采用以下方法来处理光照不均匀的问题: 1. 直方图均衡化:直方图均衡化是一种常见的图像增强技术,通过将图像的像素值映射到更平均的直方图上来均衡化图像的亮度。在opencv中,可以使用`cv2.equalizeHist()`函数来实现直方图均衡化。 2. 伽马校正:伽马校正是一种通过改变图像的亮度曲线来调整图像亮度的方法。在opencv中,可以使用`cv2.LUT()`函数来实现伽马校正。 3. 颜色校正:光照不均匀问题往往伴随着色彩偏差,可以通过颜色校正来调整图像的颜色分布。我们可以使用`cv2.xphoto.createSimpleWB()`函数来实现简单的白平衡操作,进一步提升图像的色彩质量。 4. 图像分割和局部增强:可以采用图像分割的方法将图像分成多个区域,然后对每个区域进行局部增强处理,使得每个区域的光照均匀。在opencv中,可以使用基于图像梯度的分割算法,例如`cv2.grabCut()`和`cv2.watershed()`。 通过组合以上方法,我们可以在opencv中实现光照不均匀的图像处理。根据具体情况选择合适的方法,并根据需求调整参数,可以得到更好的处理效果。 ### 回答2: 光照不均匀是指图像中不同区域的光照强度不一致。处理光照不均匀的方法有很多种,下面介绍一个基于OpenCV的方法。 首先,我们可以使用OpenCV的cv2.imread函数将图像读入,并将其转换为灰度图像,以便于后续处理。接下来,可以使用OpenCV的cv2.medianBlur函数对图像进行中值滤波,以去除一些图像噪声。 然后,我们可以使用OpenCV的cv2.threshold函数将图像中的亮度区分为背景和前景。可以尝试不同的阈值来获取最佳的效果。阈值化后,可以使用OpenCV的cv2.distanceTransform函数计算图像中每个像素到最近背景像素的距离。 接着,我们可以对距离图像进行归一化,使所有像素值都在0到255之间。然后,我们可以对归一化的距离图像进行高斯滤波,以减少噪声。 最后,我们可以使用OpenCV的cv2.multiply函数将原始图像与归一化的距离图像相乘,以增强图像的低灰度区域,并使光照更加均匀。 最后,我们可以使用OpenCV的cv2.imshow函数显示处理后的图像,并使用cv2.waitKey函数等待用户按键以关闭窗口。 通过上述步骤,我们可以使用OpenCV对图像的光照不均匀进行处理,使图像的光照更加均匀,细节更加清晰。当然,具体的处理方法可能因图像的不同而有所差异,可以根据具体情况进行调整和优化。 ### 回答3: 在图像处理中,光照不均匀是指图像中不同区域的光照强度不同,导致图像中部分区域的明暗度明显不同。光照不均匀的问题常常会导致图像细节的丢失或者重要信息的隐藏,因此需要进行光照均匀化处理。 OpenCV是一种经常被使用的图像处理库,提供了丰富的函数和工具来处理光照不均匀问题。其中常用的方法是基于图像的直方图来进行调整。 一种简单的方法是使用直方图均衡化。该方法可以将图像的直方图调整为均匀分布,从而提高图像整体的对比度,使得光照不均匀的问题得到一定程度的改善。OpenCV中提供了equalizeHist函数来实现直方图均衡化操作。 另外,OpenCV还提供了一些更加高级的光照均匀化方法,如adaptiveEqualizeHist函数。该方法在直方图均衡化的基础上,根据图像的局部特征进行自适应调整,从而更好地保留图像的细节信息。 除了直方图均衡化,还可以使用其他的方法来解决光照不均匀问题,比如基于图像分割的方法、利用光照模型进行估计和调整等。具体的方法选择可以根据实际情况和需求来决定。 总之,OpenCV提供的丰富功能和方法可以帮助我们有效地处理光照不均匀的问题。通过选择合适的方法和参数,我们可以实现对图像光照均匀化的需求,从而改善图像的质量和视觉效果。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

波了个咪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值