OpenCV 图像遍历与颜色缩减
2017-01-21 16:32
260 查看
1. 概述
图像处理的基础是对图像每一个像素点的遍历,即图像扫描。在本节中,将介绍几种不同的图像遍历方式,为了对比不同方法的效率,我们不是单纯的遍历,而是对图像做更多的处理。在此,我们测试的是一种简单的颜色缩减方法。为了比较不同遍历算法的运行时间,你还将看到 OpenCV 中计时函数的用法。2. 图像存储方式
在进行下面的论述之前,先对图像矩阵在内存中的存储方式简单介绍。对于单通道灰度图像:而对于多通道图像来说,矩阵中的列会包含多个子列,子列数与通道数相等,如 BGR 颜色模型的矩阵为:
3. 颜色缩减
何谓颜色缩减?对于元素类型为 uchar 的单通道图像矩阵,每个像素点有 256 个灰度值,但是对于三通道图像,每个像素点的颜色种类达 16777216 种(256 的三次方)。如此多的颜色可能会对算法性能造成严重影响,我们往往只需要颜色的一部分,也能满足要求,因此引入了颜色缩减。如上图所示,左侧为颜色缩减前,右侧为颜色缩减后,数字表示灰度值。可以看出,灰度值 92 到 114 映射为 92;115 到 137 映射为 115,以此类推,左侧 164 种颜色缩减为右侧的 7 种颜色。实现方法也很简单:
//color1输入,color2输出 color2 = (color1 / 23) * 23;
但是,如果直接对图像的每个像素进行上述除法和乘法,这样效率是很低的。一个较好的办法是事先生成一张颜色缩减的查找表,表中缩减前后的值都明确给定,这样遍历图像时,利用查找表直接对相应像素点进行赋值即可。其优势在于只需读取、无需计算。以下代码生成颜色查找表 color_table:
// 生成颜色查找表 vector<int> color_table; int width = 20; for (int i = 0; i < 256; i++) { color_table.push_back(i / width * width); }
4. 图像遍历
有了颜色查找表后,我们便可以对图像进行遍历并对像素点进行颜色缩减了。我们采用了几种不同的图像遍历方法,为了对比它们的效率,采用 OpenCV 提供的两个简单的计时器函数 getTickCount() 和 getTickFrequency(), 它们分别返回 CPU 走过的时钟周期数和 CPU 一秒的时钟周期数。因此,可以这样来计时(单位:秒):double time_begin = (double)getTickCount(); // do something double time_end = (double)getTickCount(); double time = (time_end - time_begin) / getTickFrequency();
4.1 利用指针遍历
Mat& ScanImageAndReduceC(Mat& I, vector<int> color_table) { //只接收字符型矩阵 CV_Assert(I.d c321 epth() != sizeof(uchar)); int channels = I.channels(); //获取图像通道数 int row = I.rows * channels; int col = I.cols; uchar* p; if (I.isContinuous()) //判断像素是否连续存储 { col *= row; row = 1; } for (int i = 0; i < row; i++) { p = I.ptr<uchar>(i); for (int j = 0; j < col; j++) { p[j] = color_table[p[j]]; } } return I; }
颜色缩减结果(根据查找表的width设置缩减的程度,在此 width = 20)
算法执行时间为 0.0134007 秒。
4.2 利用迭代器遍历
Mat& ScanImageAndReduceIterator(Mat& I, vector<int> color_table) { //只接收字符型矩阵 CV_Assert(I.depth() != sizeof(uchar)); int channels = I.channels(); switch (channels) { case 1: { MatIterator_<uchar> it, end; for (it = I.begin<uchar>(), end = I.end<uchar>(); it != end; it++) *it = color_table[*it]; break; } case 3: { MatIterator_<Vec3b> it, end; for (it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; it++) { (*it)[0] = color_table[(*it)[0]]; (*it)[1] = color_table[(*it)[1]]; (*it)[2] = color_table[(*it)[2]]; } break; } } return I; }
算法执行时间 0.0693951 秒。用迭代器遍历速度稍慢,但是更加安全。上述代码中,我们首先对图像的通道数进行判断,通道数为 1 时,直接对灰度值赋值;对于三通道彩色图像,每个像素可以看做一个包含三个 uchar 元素的 vector, 在 OpenCV 中用 Vec3b 命名。对于彩色图像,如果我们仅仅使用 uchar 而不是 Vec3b 迭代的话就只能获得蓝色通道的值(BGR模型中的第一个通道)。
4.3 通过相关返回值的 On-the-fly 地址遍历
Mat& ScanImageAndReduceRadomAccess(Mat& I, vector<int> color_table) { //只接收字符型矩阵 CV_Assert(I.depth() != sizeof(uchar)); int channels = I.channels(); switch (channels) { case 1: { for (int i = 0; i < I.rows; i++) { for (int j = 0; j < I.cols; j++) { I.at<uchar>(i, j) = color_table[I.at<uchar>(i, j)]; } } break; } case 3: { for (int i = 0; i < I.rows; i++) { for (int j = 0; j < I.cols; j++) { I.at<Vec3b>(i, j)[0] = color_table[I.at<Vec3b>(i, j)[0]]; I.at<Vec3b>(i, j)[1] = color_table[I.at<Vec3b>(i, j)[1]]; I.at<Vec3b>(i, j)[2] = color_table[I.at<Vec3b>(i, j)[2]]; } } break; } } return I; }
通过 at() 函数获取并更改图像中的元素。事实上,这种方法并不推荐呗用来进行图像扫描。
4.4 核心函数 LUT (The Core Function)
核心函数 LUT 是最被推荐用于实现批量图像元素查找和更改的方法,它并不需要你自己去扫描图像。我们先建立一个查找表:Mat table(1, 256, CV_8U); uchar* p = table.data; for(int i = 0; i < 256; i++) p[i] = color_table[i];
然后调用函数:
//image是输入,image_reduce是输出 LUT(image, table, image_reduce);
4.5 结论
尽量使用 OpenCV 内置函数,调用 LUT 函数可以获得最快的速度,这是因为 OpenCV 库可以通过英特尔线程架构启用多线程,当然,迭代器也是一个不错的选择,优点是安全,缺点是速度较慢,on-the-fly方法不推荐使用。More
相关文章推荐
- opencv学习(三)之图像像素遍历(颜色空间缩减、查找表)
- 遍历图像中每一个像素(已颜色缩减法为例)
- opencv249图片指定颜色抠图(指针遍历图像法)
- opencv学习笔记(2)----颜色缩减(使用指针遍历图像)
- opencv学习(十)颜色缩减 // 查表 // 计时 // 访问像素的三个方法(指针/STL迭代器(待详细了解)/动态地址)//历遍图像的14种方法
- opencv图像存储之颜色缩减
- OpenCv学习笔记(六)----图像空间缩减,OpenCv中的计时函数和OpenCv中操作图像单个像素点的方法
- OpenCV中文网站例程——图像颜色分布直方图
- OpenCV学习C++接口:图像遍历+像素压缩
- opencv像素基本操作及图像遍历at
- python中opencv读取RGB图像存储的矩阵,颜色通道顺序是B,G,R。
- OpenCV优化:图像的遍历4种方式
- opencv遍历图像
- OpenCV3_C++_BitwiseNot()图像颜色的反转 实例
- vc 下 用 opencv 实现的--- 遍历图像,返回值为 a 的 像素点 的坐标
- (学习笔记)基于opencv颜色过滤只保留红色区域(适用于图像分割方面)
- Opencv-遍历图像的几种方法
- OpenCV学习篇之五 使用指针遍历图像
- 【OpenCV笔记 08】OpenCV中分离颜色通道split()和图像通道混合merge()
- 将文件夹中的图像路径自动生成txt文件(便于opencv遍历处理图像)