OpenCV图像像素操作及效率分析
来源:互联网 发布:网络的各种好处 编辑:程序博客网 时间:2024/05/19 06:51
学习OpenCV也几个月了,虽然对OpenCV有些了解,但是感觉基础还是没打实,在这在介绍一下OpenCV的像素操作,以及OpenCV读取图像的格式和读取图像的效率分析。当然文章也有很多没有介绍到的地方,希望大家多多指教,相互交流。
在计算机视觉应用中,对于图像内容的读取分析是第一步,所以学习高效的处理图像是很有用的。一个图像有可能包含数以万计的像素,从根本上说图像就是一系列像素值,所以OpenCV使用数据结构cv::Mat来表示图像。矩阵中每一个元素都代表一个像素,对于灰度图像,像素用8位无符号数,0表示黑色,255表示白色。对于彩色像素而言,每个像素需要三位这样的8位无符号数来表示,即三个通道(R,G,B),矩阵则依次存储一个像素的三个通道的值,然后再存储下一个像素点。
cv::Mat中,成员变量cols代表图像的宽度(图像的列数),成员变量rows代表图像的高度(图像的行数),step代表以字节为单位的图像的有效宽度,elemSize返回像素的大小,像素的大小 = 颜色大小(字节)*通道数,比如三通道short型矩阵(CV_16SC3)的大小为2*3 = 6,像素的channels方法返回图像的通道数,total函数返回图像的像素数。
闲话少说直接介绍几种读取方式:
RGB图像的颜色数目是256*256*256,本文对图像进行量化,缩减颜色数目到256的1/8(即32*32*32)为目标,分别利用一下几种方法实现,比较几种方法的安全和效率。
1.ptr遍历图像
cv::Mat中提供ptr函数访问任意一行像素的首地址,特别方便图像的一行一行的横向访问,如果需要一列一列的纵向访问图像,就稍微麻烦一点。但是ptr访问效率比较高,程序也比较安全,有越界判断。
int nl= image.rows; //行数 int nc= image.cols * image.channels(); // 每行的元素个数,每行的像素数*颜色通道数(RGB = 3) for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- data[i]= data[i]/div*div + div/2; // end of pixel processing ---------------- } // end of line }也可以使用:
for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- *data++= *data/div*div + div/2; // end of pixel processing ---------------- } // end of line }
2.使用迭代器遍历图像
cv::Mat 同样有标准模板库(STL),可以使用迭代器访问数据。
用迭代器来遍历图像像素,可简化过程降低出错的机会,比较安全,不过效率较低;如果想避免修改输入图像实例cv::Mat,可采用const_iterator。iterator有两种调用方法,cv::MatIterator_<cv::Vec3b> it;cv::Mat_<cv::Vec3b>::iterator it;中间cv::Vec3b是因为图像是彩色图像,3通道,cv::Vec3b可以代表一个像素。
// get iterators cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>(); cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>(); for ( ; it!= itend; ++it) { // process each pixel --------------------- (*it)[0]= (*it)[0]/div*div + div/2; (*it)[1]= (*it)[1]/div*div + div/2; (*it)[2]= (*it)[2]/div*div + div/2; // end of pixel processing ---------------- }
3.at方法遍历
cv::Mat也是向量,可以使at方法取值,使用调用方法image.at<cv::Vec3b>(j,i),at方法方便,直接给i,j赋值就可以随意访问图像中任何一个像素,其中j表示第j行,i表示该行第i个像素。但是at方法效率是这3中访问方法中最慢的一个,所以如果遍历图像或者访问像素比较多时,建议不要使用这个方法,毕竟程序的效率还是比程序的可读性要重要的。下面是完整的调用方法,其运行时间在下面会介绍。
int nl= image.rows; // number of lines int nc= image.cols; // number of columns for (int j=0; j<nl; j++) { for (int i=0; i<nc; i++) { // process each pixel --------------------- image.at<cv::Vec3b>(j,i)[0]= image.at<cv::Vec3b>(j,i)[0]/div*div + div/2; image.at<cv::Vec3b>(j,i)[1]= image.at<cv::Vec3b>(j,i)[1]/div*div + div/2; image.at<cv::Vec3b>(j,i)[2]= image.at<cv::Vec3b>(j,i)[2]/div*div + div/2; // end of pixel processing ---------------- } // end of line }
4.row(i),col(i)
cv::Mat提供image.row(i),和image.col(j)对图像整行和整列进行处理,处理比较方便,因为很少遇到,所以就没有进行效率比较
程序代码如下(三通道):
result.row(0).setTo(cv::Scalar(0,0,0));//将第一行数据设为零result.row(result.rows-1).setTo(cv::Scalar(0,0,0));//将最后一行数据设置为零result.col(0).setTo(cv::Scalar(0,0,0));//将第一列数据设为零result.col(result.cols-1).setTo(cv::Scalar(0,0,0));//将最后一列数据设为零
5.高效率图像遍历循环
对于迭代的for循环,外面一层的循环次数越少速度越快,同样是cols*rows*channels()次循环,使用nc = cols,nl = rows*channels(),与使用nc = cols*rows*channels,nl = 1,以及nc = cols,nl = rows,for函数最里层运行三次颜色的处理。这三种方法最快的是第二种,第三种其次,最慢的是第一种.int nl= image.rows; // number of lines int nc= image.cols * image.channels(); // total number of elements per line if (image.isContinuous()) { // then no padded pixels nc= nc*nl; nl= 1; // it is now a 1D array } int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); // mask used to round the pixel value uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- *data++= *data&mask + div/2; // end of pixel processing ---------------- } // end of line }
6.位运算代替乘法和除法
int nl= image.rows; // number of lines int nc= image.cols * image.channels(); // total number of elements per line int n= static_cast<int>(log(static_cast<double>(div))/log(2.0)); // mask used to round the pixel value uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0 for (int j=0; j<nl; j++) { uchar* data= image.ptr<uchar>(j); for (int i=0; i<nc; i++) { // process each pixel --------------------- *data++= *data&mask + div/2; // end of pixel processing ---------------- } // end of line }
运行时间比较,以测试图片为例,(Debug模式下的时间)
ptr函数的两种方法的时间:using .ptr and [] =3.50202ms
using .ptr and * ++ =3.26124ms
迭代器方法:
using Mat_ iterator =143.06ms
at方法的运行时间:
using at =252.779ms
高效率迭代方法:
using .ptr and * ++ and bitwise (continuous) =2.68335ms
位运算方法:
using .ptr and * ++ and bitwise =2.59823ms
using .ptr and * ++ and modulo =3.78029ms
using .ptr and * ++ and bitwise =2.59823ms
using direct pointer arithmetic =2.57317ms
using .ptr and * ++ and bitwise with image.cols * image.channels() =22.864ms
using Mat_ iterator and bitwise =139.92ms
using MatIterator_ =185.996ms
using .ptr and * ++ and bitwise (continuous+channels) =2.11271ms
using input/output images =2.97717ms
using overloaded operators =2.7237ms
源图像:
量化处理结果 image1:
量化处理后的结果 image2:
- OpenCV图像像素操作及效率分析
- OpenCV图像像素操作及效率分析
- OpenCV图像像素读取及效率分析
- opencv像素基本操作及图像遍历at
- opencv像素基本操作及图像遍历at
- opencv像素基本操作及图像遍历at
- opencv-不同方式操作像素效率对比
- opencv对图像像素进行操作
- OpenCV中图像遍历与像素操作
- Python-OpenCV图像像素点操作
- opencv 图像读取显示和像素操作
- Opencv像素点操作--图像加减
- opencv访问图像像素及简单应用
- Python-OpenCV 处理图像(三):图像像素点操作
- Python-OpenCV 处理图像(三):图像像素点操作
- Python-OpenCV 处理图像(三):图像像素点操作
- opencv访问图像像素
- opencv图像像素操作方法
- 从程序员到项目经理(2)
- mysql中插入单引号的问题
- Delphi 控件显示金额(¥0.00)
- RIO包的领悟
- 《Small Memory Software:Patterns For System With Limited Memory》读书笔记
- OpenCV图像像素操作及效率分析
- Lesson 2 Thirteen equals one
- memcached服务器搭建(RedHat5)
- 从一个文件中读取明密对照表,翻译密文(注释部分为c++primer标准答案,非注释部分自己写的)
- 梦
- 如何在浏览器中打开PDF文件并实现预览的思路与代码
- C++实现快速排序(源代码)
- 详解Eclipse Dynamic Web Project
- jtable排序后的索引问题