1、查找表

之前我在OpenCV中图像遍历与像素操作中有提到过查找表遍历图像的API函数cv::LUT,鉴于其大巧于内的美感,特意写一篇博客探讨一下。从数学上来看查找表是一个简单的一对一或多对一的函数,定义了如何将像素转换为新的值。从数据的组织关系上来看,查找表是一维或多维的数组,存储了不同输入值所对应的输出值。数据表在图像处理中主要用于像素的点运算,尤其是像素之间无位置相关性的操作中。比如我们在上面提到的博客中,求图像镜像变换的示例就很难运用查找表的方法来实现。而在颜色缩减、图片取反以及直方图均衡化等不涉及像素位置相关性的算法中我们都可以应用。当然,查找表的优势也很明显[大巧于内],只需读取、无需计算。

先上几个例子,直观感受一下。


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}。

代码如下:

#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"using namespace std;
using namespace cv;void Invert(Mat &img, const uchar* const lookup)
{int rows=img.rows;int cols=img.cols*img.channels();for(int i=0; i<rows; i++){uchar *p=img.ptr<uchar>(i);for(int j=0; j<cols;j++)p[j]=lookup[p[j]];}
}int main()
{Mat src=imread("test.jpg");  //将任意一张名为test.jpg的图片放置于工程文件夹test中if(!src.data){cout<<"error! The image is not built!"<<endl;return -1;}// 为了演示效果,将图片转换成灰度图片Mat img1=src;//cvtColor( src, img1, CV_RGB2GRAY );imshow("First",img1);//建立查找表uchar lookup[256];for(int i=0; i<256; i++)lookup[i]=255-i;//调用自定义图像取反函数Invert(img1, lookup);imshow("Second",img1);waitKey();return 0;
}

运行结果:

本来觉得上彩图难看,结果发现灰度图也难看的过分,那就这样吧。

2、LUT函数

上面我们程序中我们建立查找表之后,对图像的遍历是手动实现的,其实OpenCV中为我们提供了一个非常高效的API函数cv::LUT,可以应用查找表生成新图像。LUT是OpenCV的core mudle中的函数,其函数原型如下:

void LUT(InputArray src, InputArray lut, OutputArray dst)
Parameters:
第一个参数:原始图像的地址;
第二个参数:查找表的地址,对于多通道图像的查找,它可以有一个通道,也可以与原始图像有相同的通道;
第三个参数:输出图像的地址。

典型用法(借助图像取反示例说明)是:

Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.data;
for( int i = 0; i < 256; ++i)p[i] = 255-i;

调用就很简单啦,LUT(src, lookUpTable,dst )。 
还是贴一下全部代码:

#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>using namespace std;
using namespace cv;int main()
{Mat src=imread("test.jpg");  //将任意一张名为test.jpg的图片放置于工程文件夹test中if(!src.data){cout<<"error! The image is not built!"<<endl;return -1;}// 为了演示效果,将图片转换成灰度图片Mat img1=src;//cvtColor( src, img1, CV_RGB2GRAY );imshow("First",img1);//建立查找表Mat lookUpTable(1, 256, CV_8U);uchar *p = lookUpTable.data;for(int i=0; i<256; i++)p[i]=255-i;//通过LUT函数实现图像取反LUT(img1,lookUpTable,img1);imshow("Second",img1);waitKey();return 0;
}

最后唠叨两句,虽然手动遍历可以达到同样效果,但尽量使用 OpenCV 内置函数。调用LUT 函数可以获得最快的速度,这是因为OpenCV库可以通过英特尔线程架构启用多线程。
--------------------- 
作者:鼹鼠的胡须 
原文:https://blog.csdn.net/qq_23968185/article/details/51282049

亲测可用,只是这两种方式,测试的结果是“数组赋值”运行速度比“LUT”方式要快,也可能是程序较小吧,后续会继续测试。

OpenCV LUT用法相关推荐

  1. OpenCV calcOpticalFlowPyrLK用法的实例(附完整代码)

    OpenCV calcOpticalFlowPyrLK用法的实例 OpenCV calcOpticalFlowPyrLK用法的实例 OpenCV calcOpticalFlowPyrLK用法的实例 # ...

  2. openCV—converTo()用法

    convertTo的用法 src.convertTo(dst, type, scale, shift) img参数为图像数据来源,其类型为Mat. 注意也不是所有格式的Mat型数据都能被使用保存为图片 ...

  3. 【opencv学习】opencv基础用法

    一.opencv Mat初始化 初始化为三通道彩色图像 Mat src = Mat(r, c, CV_8UC3, Scalar(0)); 初始化为单通道灰度值图像 Mat src = Mat(src. ...

  4. OpenCV函数用法详解21~30,含代码示例,可直接运行

    opencv3 文章目录 opencv3 1.图像加权和 2.图像加密与解密 3.数字水印 4.色彩空间类型转换 5.dst = cv2.inRange(src, lowerb, upperb) 6. ...

  5. opencv摄像头用法

    python: 设置视频起始帧: cap.set(cv2.CAP_PROP_POS_FRAMES, keys_frame) # keys_frame为关键帧的序号 import cv2 import ...

  6. python利用opencv自带的颜色查找表(LUT)进行色彩风格变换

    1 LUT颜色查找表介绍 Look Up Table(LUT)查找表 1.颜色查找表就是一种像素值映射的表,如下是一个对比度改变图像的查找表,从图中可以知道: 原图中像素值为40的像素,经过查找表映射 ...

  7. OpenCV常见的优化方法和技巧总结

    OpenCV常见的优化方法和技巧总结 [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/78540206 目录 OpenCV常 ...

  8. opencv之伪彩变换

    opencv之伪彩变换 我们在处理红外图像时,由于红外图像都是16位的数据,灰度范围较大,对比度不明显,经常通过直方图均衡的方式将图像增强进行8位的显示. 红外图像在一定程度上反映了环境中物体的温度变 ...

  9. OpenCV之core 模块. 核心功能(2)基本绘图 随机数发生器绘制文字 离散傅立叶变换 输入输出XML和YAML文件 与 OpenCV 1 同时使用

    基本绘图 目的 本节你将学到: 如何用 Point 在图像中定义 2D 点 如何以及为何使用 Scalar 用OpenCV的函数 line 绘 直线 用OpenCV的函数 ellipse 绘 椭圆 用 ...

最新文章

  1. Unicode转义(\uXXXX)的编码和解码
  2. windows系统下批量修改文件后缀
  3. 在Flex3中使用Runtime Shared Library (RSL)
  4. arping 帮助——翻译
  5. 短url服务java_Serverless-实现一个短网址服务(二)
  6. 内蒙古计算机专修学院单招,内蒙古电子信息职业技术学院单招多少分能上?
  7. Android自动伸展动画,android – 如何实现平滑的展开/折叠动画
  8. 聊一聊Load Average
  9. .NET core3.0 使用Jwt保护api
  10. ASP.NET Core MVC+EF Core从开发到部署
  11. Android 四大组件 —— 服务
  12. 仿iphone触屏手机界面
  13. 如何优化Jupyter Notebook
  14. Java 算法 礼物分配
  15. 基本功 | Java即时编译器原理解析及实践
  16. Java虚拟机(一)——内存管理
  17. 【JavaScript应用篇】--实现文字的特效
  18. R绘图笔记 | 生存曲线的绘制
  19. 使用ESP8266驱动TFT显示屏
  20. 马来西亚留学回国人员证明

热门文章

  1. Android手机WiFi下强制使用4G数据流量上网
  2. 图像I、B、P帧介绍
  3. 如何让你做软件测试不再迷茫?
  4. GM如何修改服务器密码,魔力gm帐号密码修改及gm命令大全使用方法
  5. Action Bar
  6. wms分析系列文章 老罗
  7. 没想到 Hash 冲突还能这么玩,你的服务中招了吗?
  8. FDX-B|EMID格式低频RFID 读卡模块LD6900技术选型与说明
  9. 常用缩略词 ACRONYMS
  10. MerkleTree 构建QT实现UI