再谈OpenCV中查询表lookup table的LUT函数

来源:互联网 发布:linux如何拷贝文件夹 编辑:程序博客网 时间:2024/05/17 02:00

       今天在复习之前的OpenCV的学习内容时,发现自己对OpenCV的LUT这个函数理解得不是很透彻,研究了一上午终于是搞明白了,但自己在学习的时候发现对于这个函数的解释很少,现在把自己的理解分享出来,给大家一个参考。

       首先看下我测试用的程序:

#include <cv.h>#include <highgui.h>using namespace std;using namespace cv;#define QUAN_VAL          (100)void CreateLookupTable(Mat& table, uchar quan_val){table.create(1, 256, CV_8UC1);uchar *p = table.data;for (int i = 0; i < 256; ++i){p[i] = quan_val*(i / quan_val);}}int main(int argc, char *argv[]){Mat img;Mat out;img = imread("F:/Photo/OpenCV_Photo/tsukuba_l.png", 1);Mat table;//定义查找表//创建灰度级别是100的查找表CreateLookupTable(table, QUAN_VAL);//使用查找表直接计算出量化灰度级后的图像并将其保存到out1中LUT(img, table, out);namedWindow("源图像", CV_WINDOW_NORMAL);imshow("源图像", img);namedWindow("利用查询表灰度等级变换后", CV_WINDOW_NORMAL);imshow("利用查询表灰度等级变换后", out);waitKey(0);return 0;}
在学习OpenCV二的博客中已经详细讲了查询表的作用以及它到底是什么东西,这里就不多说了。其实查询表的实质就是:把图像中的数据从之前的比较高的灰度级降下来,例如灰度级是256的char类型的灰度级,我们通过一个参数(例如上述程序中就是100),将原来的256个灰度级降到了3个灰度级,原来图像中灰度值在0-100的数据现在灰度值变成了0,原来灰度值为101-200的图像数据现在灰度值变为了1,而201-256的灰度值就变为了2。所以通过参数100,图像的灰度级就到了2,只有0,1,2三个灰度值,那么原来的图像矩阵中的每一位数据我们是char型的,需要8位来表示一个数据,而灰度级降下来之后,我们只需要2位就足以表示所有灰度值。

上面只是解释了查询表是如何产生的,那么查询表有什么作用呢?其作用就是:提高我们扫描图像时效率。我们要处理一张图片,其实就是对整个图像数据进行处理,那么这就要求我们在处理的时候要对图像的全部数据进行扫描读取,然后进行相应的处理,而处理中耗时最短的操作便是赋值,但是这种方法对于数据比较大的图像来说处理起来效率会很低。那么我们应该怎么办呢?前面我们讲过尽量不去进行所谓加减乘除这些操作,能不能直接在图像处理中只进行赋值操作呢?那么这时候查询表就排上用场了,前面我们已经介绍了查询表的产生方法了,那么查询表是怎么用的呢?其实用查询表来进行图像处理的实质就是:根据源图像(img)中的像素值例如灰度值是78,然后去查询表中去找它对应的是哪个灰度值(对于上面的程序78在查询表中对应的灰度值是0),然后把查询表中78对应的灰度值0赋值给新的图像矩阵(out)中

下面通过图像介绍一下这个过程:
首先我们调试程序,先看一下程序产生的table在内存中是什么样子:


从查询表在内存中的情况来看,它已经通过150这个值把256这个灰度级分成了3个灰度级空间,这个灰度空间只包含三种灰度值即0(对应于图像中灰度值在0-100之间的)、100(对应101-200)、200(对应201-256).这说明我们的查询表已经有了,那么接下来就看查询表是怎么用来替换原始图像(img)中的数据的:

先看一下原始图像在内存中的数据:


从图中看出原始图像灰度值都比较低,原始图像应该在边缘是比较暗的,下面我们再看一下原始图像经过查询表替换成什么样的输出图像了:


从图中可以看出,确实灰度值在0-100之间的值都被替换成新的灰度空间中的灰度值0了,这里屏幕有限,其它灰度值在100以上的都在后面,可以自己看下。最终的效果图是:


从右边的输出图像中可以看出,其只有三种灰度变化。

那么可能会有人疑问了,这种替换是怎么实现的呢?请看下面的代码:

//制作查询表,做颜色空间减少操作uchar table[256];for (int i = 0; i < 256; ++i)table[i] = (uchar)(divideWith * (i / divideWith));

uchar* p;for (i = 0; i < nRows; ++i){p = I.ptr<uchar>(i);for (j = 0; j < nCols; ++j){p[j] = table[p[j]];//假设图像第一个像素的第一个灰度值23,则p[0]=table[p[0]]=table[23]=2;//这样就实现了利用查找表table的方法来替换源图像中的数据,并且灰度等级//降下来了,例如源图像的灰度级23变成了灰度等级2了。}
这里p是图像矩阵的第i行指针,p[j]即是图像的第i行第j列的像素值,例如我们上面的原始图像第一行第一列的像素值是1,即p[0]=table[p[0]]=table[1]=0。这对图像就不是加减乘除这种计算了,而全部是直接去查询表中找对应的值然后再替换。

到这里应该解释得很明白了,总之,遇到问题多调试,多想。

3 0
原创粉丝点击