【OpenCV】OpenCV实战从入门到精通之 -- 访问图像中的像素
目录
1、图像在内存之中的存储方式
2、颜色空间缩减
3、LUT函数:Look up table操作
4、计时函数
5、访问图像中像素的三类方法
5.1、指针访问像素
5.2、迭代器操作像素
5.3、动态地址计算
1、图像在内存之中的存储方式
图像矩阵的大小取决于所用的颜色模型,确切说,取决于所用通道数。如果是灰度图像,矩阵就会如图5.1所示。
对于多通道图像来说,矩阵中的列会包含多个子列,其子列个数与通道数相同,如图5.2所示RGB颜色模型的矩阵。
可以看到,OpenCV中子列的通道顺序是反过来的——BGR而不是RGB。 有时候,由于内存足够大,可实现连续存储,图像中的各行是一行一行连接起来的,形成一个长行。可以使用isContinuous()来判断矩阵是否是连续存储的。
2、颜色空间缩减
颜色空间缩减的做法是:将现有颜色空间值除以某个输入值,以获得较少的颜色数。即做减法,比如颜色值0到9可取为新值0,10到19可取为10,以此类推。
有一个简单的公式来实现颜色空间缩减:
在处理像素时,每个像素需要进行一遍上述公式计算,也需要一定的时间花销。我们可以把256中计算好的结果提前存在列表table中,这样每种情况不需计算,直接从table中取取结果即可。
int divideWith = 10;
unchar table[256];
for( int i =0; i<256; ++i)table[i] = divideWith*(i/divideWith);
于是table[i]存放的是值为 i 的像素减小颜色空间的结果,这样就可以理解上述方法中的操作:p [j] = table[ p [j] ]
简单的颜色空间缩减算法就由以下两步组成:
- 遍历图像矩阵的每一个像素
- 对像素应用上述公式
3、LUT函数:Look up table操作
Look up table操作使用operationsOnArrays:LUT()<lut>函数,用于批量进行图像元素查找、扫描与操作图像。使用方法如下:
//首先建立一个mat型用于查表
Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.data;
for(int i = 0; i < 256; ++i)p[i] = table[i];//调用函数(I是输入,J是输出)
for (int i = 0; i < times; ++i)LUT(I, lookUpTable, J);
4、计时函数
简便的计时函数:getTickCount()和get TickFrequency()
getTickCount()函数:返回CPU自某个事件以来走过的时钟周期数
getTickFrequency()函数:返回CPU一秒钟所走的时钟周期数。这样,就能以秒为单位对某运算计时。
两个函数组合起来使用的实例如下:
double time0 = static_cast<double>(getTickCount()); //记录起始事件
//进行图像处理操作……
time0 = ((double) getTickCount()-time0)/getTickFrequency();
cout << "此方法运行时间为: " << time0 << "秒" << endl; //输出运行时间
5、访问图像中像素的三类方法
OpenCV中,有三种方式访问图像像素:
- 指针访问:C操作符[];
- 迭代器iterator
- 动态地址计算
上述方法在访问速度上略有差异。debug模式下,差异非常明显,在release模式下,差异就不太明显。
下边通过一组例子来说明这三种方法的使用,程序的作用是减少颜色的数量,比如原来的图像是256种颜色,我们希望将它变成64中颜色,只需要将原来的颜色除以4(整除)以后再乘以4即可。
主程序代码如下:
//---------------------------------【头文件、命名空间包含部分】--------------------------
// 描述:包含程序所使用的头文件和命名空间
//---------------------------------------------------------------------------------------
#include <opencv2/opencv.hpp>
#include <iostream> using namespace std;
using namespace cv;//-----------------------------------【全局函数声明部分】-----------------------------------
// 描述:全局函数声明
//------------------------------------------------------------------------------------------
//减少颜色
void colorReduce(Mat& inputImage, Mat& outputImage, int div);//--------------------------------------【main( )函数】---------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main()
{//【1】创建原始图并显示Mat srcImage = imread("1.jpg");imshow("原始图像", srcImage);//【2】按原始图的参数规格来创建创建效果图Mat dstImage;dstImage.create(srcImage.rows, srcImage.cols, srcImage.type());//效果图的大小、类型与原图片相同 //【3】记录起始时间double time0 = static_cast<double>(getTickCount());//【4】调用颜色空间缩减函数colorReduce(srcImage, dstImage, 32);//【5】计算运行时间并输出time0 = ((double)getTickCount() - time0) / getTickFrequency();cout << "\t此方法运行时间为: " << time0 << "秒" << endl; //输出运行时间//【6】显示效果图imshow("效果图", dstImage);waitKey(0);
}
5.1、指针访问像素
指针访问像素利用的是C语言中的操作符[]。这种方法最快,但是略有点抽象。实验条件下单词运行时间为0.00370487秒,代码如下:
//---------------------------------【colorReduce( )函数】---------------------------------
// 描述:使用【指针访问:C操作符[ ]】方法版的颜色空间缩减函数
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{//参数准备outputImage = inputImage.clone(); //拷贝实参到临时变量int rowNumber = outputImage.rows; //行数int colNumber = outputImage.cols*outputImage.channels(); //列数 x 通道数=每一行元素的个数//双重循环,遍历所有的像素值for (int i = 0; i < rowNumber; i++) //行循环{uchar* data = outputImage.ptr<uchar>(i); //获取第i行的首地址for (int j = 0; j < colNumber; j++) //列循环{// ---------【开始处理每个像素】------------- data[j] = data[j] / div*div;// ----------【处理结束】---------------------} //行处理结束}
}
分析讲解上述代码:
Mat类属性:
- 公有变量cols和rows给出图像的宽和高
- channels():返回图像的通道数。灰度图通道数为1,彩色通道数为3
- ptr()函数:得到任意行的首地址。ptr是一个模板函数,它返回第i行的首地址:uchar* data = outputImage.ptr<uchar>(i); //获取第i行的首地址
每行的像素值个数以下语句得到:
int colNumber = outputImage.cols*outputImage.channels(); //列数 x 通道数=每一行元素的个数
运行结果:
原始图 |
效果图 |
5.2、迭代器操作像素
迭代器需要做的仅仅是获得图像矩阵的begin和end,然后增加迭代直至从begin到end。将 * 操作符添加在迭代指针前,即可访问当前指向的内容。
相比使用指针可能越界问题,迭代器绝对是非常安全的方法。
//-------------------------------------【colorReduce( )函数】-----------------------------
// 描述:使用【迭代器】方法版的颜色空间缩减函数
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{//参数准备outputImage = inputImage.clone(); //拷贝实参到临时变量//获取迭代器Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>(); //初始位置的迭代器Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>(); //终止位置的迭代器//存取彩色图像像素for (; it != itend; ++it){// ------------------------【开始处理每个像素】--------------------(*it)[0] = (*it)[0] / div*div; //蓝色通道(*it)[1] = (*it)[1] / div*div; //绿色通道(*it)[2] = (*it)[2] / div*div; //红色通道// ------------------------【处理结束】----------------------------}
}
运行结果:
原始图 |
效果图 |
5.3、动态地址计算
动态地址运算配合at方法。这种方法简单明了,符合我们对像素的认识。
//----------------------------------【colorReduce( )函数】-------------------------------
// 描述:使用【动态地址运算配合at】方法版本的颜色空间缩减函数
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{//参数准备outputImage = inputImage.clone(); //拷贝实参到临时变量int rowNumber = outputImage.rows; //行数int colNumber = outputImage.cols; //列数//存取彩色图像像素for (int i = 0; i < rowNumber; i++){for (int j = 0; j < colNumber; j++){// ------------------------【开始处理每个像素】--------------------outputImage.at<Vec3b>(i, j)[0] = outputImage.at<Vec3b>(i, j)[0] / div*div; //蓝色通道outputImage.at<Vec3b>(i, j)[1] = outputImage.at<Vec3b>(i, j)[1] / div*div; //绿色通道outputImage.at<Vec3b>(i, j)[2] = outputImage.at<Vec3b>(i, j)[2] / div*div; //红是通道// -------------------------【处理结束】----------------------------} // 行处理结束 }
}
分析讲解代码:
Mat:
- 成员函数at(int y, int x):用来存储图像元素,但是必须在编译期知道图像的数据类型。需要注意的是,一定要确保指定的数据类型和矩阵中的数据类型符合,因为at方法本身不会对任何数据类型进行转换。
Vec3b:
- 一个图像的Mat会返回一个由三个8位数组成的向量,,将其定义为Vec3b,即由三个unsigned char组成的向量,所以存取彩色图像像素的代码可以写出如下形式:
image.at<Vec3b>(i, j)[chanel] = value; //索引值channel标明了颜色通道号
运行结果:
原始图 |
效果图 |
【OpenCV】OpenCV实战从入门到精通之 -- 访问图像中的像素相关推荐
- 《OpenCV3编程入门》学习笔记5 Core组件进阶(一)访问图像中的像素
第5章 Core组件进阶 5.1 访问图像中的像素 5.1.1 图像在内存中的存储方式 1.图像矩阵大小取决于通道数,矩阵中的子列个数与通道数相等. 2.如果内存足够大,可以实现连续存储,有助于提升图 ...
- OpenCV学习笔记(七):访问图像中像素的三类方法
该文章参考毛星云著<OpenCV3编程入门>,电子工业出版社. 图像是以像素为单位储存的,访问图像中的每个像素是处理图像的基础,一般有三种访问图像像素的方法: 方法一:指针访问:C操作符[ ...
- 访问图像中每个像素的值
转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7557063 !!此篇是基于IplImage* (C接口或者说2.1之前版本的接口, ...
- opencv计算图像亮度调节_【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整...
今天我们来看一下如何访问图像的像素,以及如何改变图像的亮度与对比度. 在之前我们先来看一下图像矩阵数据的排列方式.我们以一个简单的矩阵来说明: 对单通道图像排列如下: 对于双通道图像排列如下: 那么对 ...
- 【OpenCV】OpenCV函数精讲之 -- 访问图像中的像素
图像在内存之中的存储方式: 图像矩阵的大小取决于所用的颜色模型,确切说,取决于所用通道数.如果是灰度图像,矩阵就会如图5.1所示. 对于多通道图像来说,矩阵中的列会包含多个子列,其子列个数与通道数相同 ...
- 【OpenCV】OpenCV实战从入门到精通之 -- 基本图像绘制
目录 1.DrawEllipse()函数的写法 2.DrawFilledCircle()函数的写法 3.DrawPolygon()函数的写法 4.DrawLine()函数的写法 基本绘制图形代码: m ...
- 【OpenCV】OpenCV函数精讲之 -- 访问图像中的像素--计时函数
计时函数: 简便的计时函数:getTickCount()和get TickFrequency() getTickCount()函数:返回CPU自某个事件以来走过的时钟周期数 getTickFreque ...
- OpenCV访问Mat图像中每个像素的值
原文:http://blog.csdn.net/xiaowei_cqu/article/details/7771760 matlab中, a=[1,2,3;4,5,6;7,8,9] a(1,2) 第一 ...
- 【Python】Python实战从入门到精通之二 -- 教你使用Python中列表操作
本文是Python实战–从入门到精通系列的第二篇文章: [Python]Python实战从入门到精通之一 – 教你深入理解Python中的变量和数据类型 Python实战从入门到精通之二 – 教你使用 ...
最新文章
- java夯实基础:final脑图
- 设计模式复习-备忘录模式
- ARCHLinux SETUP WITH FDISK
- 如何能出令自己满意的代码
- extern 在c/c++ 中的作用
- Spring MVC DispatcherServlet介绍
- (转)页面滚动条(scrollbar)颜色设置详解
- 速修复!CISA警告称 Zoho 服务器0day已遭在野利用
- configure make make install in linux
- .net文档生成工具2.0 支持自定义文档生成器【转:http://www.cnblogs.com/lucc/archive/2008/09/05/1284762.html】...
- 生鲜配送小程序源码_ThinkPHP社区水果生鲜蔬菜同城配送服务平台 社区团购商城小程序源码...
- opencv.js调用摄像头(Electron环境)
- java编译过程_java 程序编译和运行过程详解
- shader篇-漫反射
- 本地策略和组策略,更改安全设置和用户权限分配兼容性问题
- 如何在IDEA中创建一个项目
- memcpy 函数详解
- 知识分享:配音员与声优的区别
- linux 电源管理 Generic PM之Suspend功能
- kruskal java_Kruskal算法(三)之 Java详解
热门文章
- 1708硬盘转接口_ICY DOCK全球首款U.2转USB转接器震撼上市
- android 摇一摇动画效果,android 微信摇一摇动画效果
- input搜索mysql_实现input输入时智能搜索
- html5 can,基于html5 can-vas实现漫天飞雪效果实例
- jumpserver 重启mysql_jumpserver 常见错误解决
- android本地socket正常,【报Bug】Android 本地打包 websocket 出错
- php5.5 getter setter,实现了一个PHP5的getter/setter基类的代码
- 多个字符合并成一个数组_一个excel多个sheet,需要合并为一个sheet
- HTML嵌入php已经过时,**PHP, 这段嵌入html的php代码为何第15、16、17行报错?**
- springboot指定属性返回_SpringBoot中必须掌握的45个注解