Opencv访问图像像素

1.图像存储方式

图像在内存中的存储方式是连续的,每列连续存储RGB三个通道,可以用isContinuous()函数判断是否连续存储。下图为灰度图和彩色图的存储结构。
Gray
RGB

2.访问图像像素方式
2.1 Mat 的at方法

at< Vec3b >(i,j)[k]的方式访问,其中i,j表示图像的行列,k表示通道数,RGB图像有三个通道,分别是0,1,2。如不需要访问图像每个通道,可以直接访问图像像素,则可用: at< uchar >(i,j) 方式直接去除图像特定行列的像素值。
注:图像的像素点的灰度值类型必须为 uchar (unsigned char),因为char: -128~127; uchar: 0~255。如果定义为char类型,在不需要对图像像素进行运算的时候是没问题的,但是一旦进行像素运算就有可能出错,为了避免出错,要习惯使用 uchar类型。
特别的:OpenCV定义了一个Mat的模板子类为Mat_,它重载了operator()让我们可以更方便的取图像上的点。

Mat_<uchar> im=outputImage;
im(i,j)=im(i,j)/div*div+div/2;
2.2指针法

Mat 的 uchar*p = ptr(i)的方式可以取出图像的行指针,这样访问图像数据的时候就可以遍历每行使用p[j]取出图像特定行列的像素值。
该方法速度最快,效率最高,但是有可能出现越界问题。

2.3迭代法

采用 Mat_< Vec3b >::iterator it; 的方式声明一个迭代器,该方法比较安全,不会越界,但是效率低。

上述方法的代码例子如下:

/*
主函数,声明了一个void colorReduce()函数,该函数分别用三种方式访问图像像素,运行例子的时候将不用的函数注释掉即可。
颜色空间缩减
对于三通道图像,一个像素对应的颜色有一千六百多万种,用如此多的颜色可能会影响算法性能。颜色空间缩减即用颜色中具有代表性的一部分表示相近颜色,做法是:将现有颜色空间值除以某个输入值,以获得较少的颜色数。对每个像素进行乘除操作也需要浪费一定的时间(加,减,赋值等代价较低),对于较大的图像,可以预先计算所有可能的值,建立 look up table
该例子没有采用查找表,而是直接对每个像素进行乘除操作,方便理解图像访问方式。
*/
#include <opencv2/opencv.hpp>    
#include<iostream>  
using namespace std;  
using namespace cv;  
void colorReduce(Mat& inputImage, Mat& outputImage, int div);  

int main()  
{  

    Mat srcImage = imread("D:\\vvoo\\lena.jpg");  
    imshow("原始图像", srcImage); 
    Mat dstImage;  
    dstImage.create(srcImage.rows, srcImage.cols, srcImage.type());//效果图的大小、类型与原图片相同   

    //记录起始时间  
    double time0 = static_cast<double>(getTickCount());  
    //调用颜色空间缩减函数  
    colorReduce(srcImage, dstImage, 128);  
    //计算运行时间并输出  
    time0 = ((double)getTickCount() - time0) / getTickFrequency();  
    cout << "此方法运行时间为: " << time0 << "秒" << endl;  //输出运行时间  
    //显示效果图  
    imshow("效果图", dstImage);  
    waitKey(0);  
    return 0;  
}  
//使用指针的方式访问
//void colorReduce(Mat& inputImage, Mat& outputImage, int div){
//  outputImage = inputImage.clone();
//  int rows = outputImage.rows;
//  int cols = outputImage.cols;
//  for (int i = 0; i < rows; ++i){
//      uchar* dataout = outputImage.ptr<uchar>(i);
//      for (int j = 0; j < cols; ++j){
//          dataout[j] = dataout[j] / div*div + div / 2;
//      }
//  }
//}
//使用at方法访问
//void colorReduce(Mat& inputImage, Mat& outputImage, int div){
//  outputImage = inputImage.clone();
//  int rows = outputImage.rows;
//  int cols = outputImage.cols;
//  for (int i = 0; i < rows; ++i){
//      for (int j = 0; j < cols; ++j){
//          outputImage.at<Vec3b>(i, j)[0] = outputImage.at<Vec3b>(i, j)[0] / div*div + div / 2;
//          outputImage.at<Vec3b>(i, j)[1] = outputImage.at<Vec3b>(i, j)[1] / div*div + div / 2;
//          outputImage.at<Vec3b>(i, j)[2] = outputImage.at<Vec3b>(i, j)[2] / div*div + div / 2;
//      }
//  }
//}
//使用迭代器的方式访问
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>();
//  //也可以通过指明cimage类型的方法不写begin和end的类型    
//  /*Mat_<Vec3b> cimage = outputImage;
//  Mat_<Vec3b>::iterator itout =outputImage.begin<Vec3b>();
//  Mat_<Vec3b>::iterator itoutend = cimage.end();*/
//  for (; it != itend; it++/*, it++*/)
//  {
//      (*it)[0] = (*it)[0] / div*div + div / 2;
//      (*it)[1] = (*it)[1] / div*div + div / 2;
//      (*it)[2] = (*it)[2] / div*div + div / 2;
//  }
//}

参考博客:
http://www.cnblogs.com/Xiaoyan-Li/p/5792796.html
http://blog.csdn.net/qq_29540745/article/details/52443697

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首次接触图像处理,通过次来记录自己的学习记录,以方便回忆。 //指针访问像素 void colorReduce(Mat& temImage, int div) { //行数 int rowNumber = temImage.rows; cout << "图像通道数:" << temImage.channels() << endl; //列数*通道数=每一行的元素个数 int colNumber = temImage.cols * temImage.channels(); for (int row = 0; row < rowNumber;row++) { uchar* data = temImage.ptr<uchar>(row); for (int col = 0; col < colNumber;col++) { data[col] = data[col] / div*div + div / 2; } } } //迭代器iterator操作像素 void iterColorReduce(Mat& temImage,int div) { Mat_<Vec3b>::iterator it = temImage.begin<Vec3b>(); Mat_<Vec3b>::iterator itend = temImage.end<Vec3b>(); //存取彩色图像像素 while (it != itend) { //开始处理每个像素 (*it)[0] = (*it)[0] / div*div + div / 2; (*it)[1] = (*it)[1] / div*div + div / 2; (*it)[2] = (*it)[2] / div*div + div / 2; ++it; } } //动态地址计算像素 void atColorReduce(Mat& temImage, int div) { int rowNumber = temImage.rows; int colNumber = temImage.cols; //存取彩色图像 for (int row = 0; row < rowNumber; row++) { for (int col = 0; col < colNumber; col++) { //开始处理每个图像 //蓝色通道 temImage.at<Vec3b>(row, col)[0] = temImage.at<Vec3b>(row, col)[0] / div*div + div / 2; //绿色通道 temImage.at<Vec3b>(row, col)[1] = temImage.at<Vec3b>(row, col)[1] / div*div + div / 2; //红色通道 temImage.at<Vec3b>(row, col)[2] = temImage.at<Vec3b>(row, col)[2] / div*div + div / 2; } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值