从数学上来看查找表是一个简单的一对一或多对一的函数,定义了如何将像素转换为新的值。从数据的组织关系上来看,查找表是一维或多维的数组,存储了不同输入值所对应的输出值。数据表在图像处理中主要用于像素的点运算,尤其是像素之间无位置相关性的操作中。比如求图像镜像变换的示例就很难运用查找表的方法来实现。而在颜色缩减、图片取反以及直方图均衡化等不涉及像素位置相关性的算法中我们都可以应用。当然,查找表的优势也很明显[大巧于内],只需读取、无需计算
查表实例说明:
1.颜色空间缩减:将现有颜色空间值除以某个输入值,以获得较少的颜色数。例如,颜色值0到9可取为新值0,10到19可取为10,以此类推。(示例来源于OpenCV官网)。
显然这是一个多对一的映射,I[new] = I[old]/10*10。很容易想到,只要遍历图像矩阵的每一个像素,对像素应用上述公式就可以完成任务。只是这里用到了除法和乘法运算,而这两种运算又特别费时。鉴于一幅图像只涉及256个像素,我们大可开一个长度为256的数组,让其下标代表旧像素值,数组值代表新的像素值,如lookup[256]={0,…,0,10,…,10,20,…,20,…,250,…,250}。这样我们遍历修改时不就可以通过像素值从表中查出要改变的像素值了么,而且这一过程只有赋值运算。
2.图像取反:反转图像的像素强度,使图像中的前景变为背景,背景变为前景。
显然这是一个一对一的映射,即像素值0变为255,1变为254…254变为1,255变为0。对应的查找表为lookup[256]={255,254,…,1,0}
不使用LUT查表函数的程序
#include<opencv2/opencv.hpp> #include<iostream> #include <vector> void Invert(cv::Mat& img, uchar* lookup) { //取反函数 int rows = img.rows; int cols = img.cols; int k = 0; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { int k = img.at<uchar>(i, j); img.at<uchar>(i, j) = *(lookup+k); } } } int main(int argc, char** argv) { cv::Mat src = cv::imread("D:/bb/tu/ma1.png",0); cv::imshow("修改前", src); //建立查找表 uchar lookup[256]; for (int i = 0; i < 256; i++) { lookup[i] = 255 - i; } Invert(src, lookup); cv::imshow("修改后", src); cv::waitKey(0); return 0; }
使用LUT查表函数的程序
方式一
#include<opencv2/opencv.hpp> #include<iostream> #include <vector> int main(int argc, char** argv) { cv::Mat src = cv::imread("D:/bb/tu/ma1.png",0); cv::Mat lookUpTable(1, 256, CV_8U); //创建表矩阵 uchar* p = lookUpTable.data; //让指针p指向表矩阵的数据地址 for (int i = 0; i < 256; ++i) p[i] = 255 - i;//给表矩阵赋值 cv::Mat dst; cv::LUT(src, lookUpTable, dst);//查表 //第一个参数:原始图像的地址 //第二个参数:查找表的地址;查找表也可以是单通道,也可以是3通道,如果输入图像为单通道, //那查找表必须为单通道,若输入图像为3通道,查找表可以为单通道,也可以为3通道, //若为单通道则表示对图像3个通道都应用这个表,若为3通道则分别应用 //第三个参数:输出图像的地址 cv::imshow("修改前", src); cv::imshow("修改后", dst); cv::waitKey(0); return 0; }
方式二
#include<opencv2/opencv.hpp> #include<iostream> #include <vector> int main(int argc, char** argv) { cv::Mat src = cv::imread("D:/bb/tu/ma1.png",0); uchar lookup[256]; for (int i = 0; i < 256; i++) { lookup[i] = 255 - i; } cv::Mat lut(1, 256, CV_8UC1, lookup);//创建表矩阵 cv::Mat dst; cv::LUT(src, lut, dst); cv::imshow("修改前", src); cv::imshow("修改后", dst); cv::waitKey(0); return 0; }