OpenCV:图像像素访问方法

图像像素访问方法比较常见的有三种

指针访问:速度最快

迭代器iterator:较慢,非常安全,指针访问可能出现越界问题

动态地址计算:更慢,通过at()实现。适用于访问具体某个第i行,j列的像素,而不适用遍历像素

要想访问图像像素就需知道图像在内存中的存储方式

Mat在内存中存储方式如下:

 

                                        

                                                                      灰度图的存储方式

 

   

                                                                      RGB的存储形式

一般情况下,Mat是连续存储的,按行连接。可以通过isContinuous()函数,判断矩阵是否连续存储,若连续返回true。

由于,内存地址排列方式是行列从左到右从上到下,因此访问像素时顺序是先访问对应行后访问对应列。

1. 指针访问. ptr(行)[列]

    cv::Mat image = cv::Mat(400, 600, CV_8UC1); //宽400,长600
    uchar * data00 = image.ptr<uchar>(0);
    uchar * data10 = image.ptr<uchar>(1);
    uchar * data01 = image.ptr<uchar>(0)[1];

解释:

  • 定义了一个Mat变量image。
  • data00是指向image第一行第一个元素的指针。
  • data10是指向image第二行第一个元素的指针。
  • data01是指向image第一行第二个元素的指针。

复制代码

 1 void VisitImgByPointer(Mat &inputImg, Mat &dstImg)
 2 {
 3     dstImg = inputImg.clone();
 4     int rows = dstImg.rows;
 5     int cols = dstImg.cols * dstImg.channels();
 6 
 7     for(int i = 0; i < rows; i++)
 8     {
 9         uchar* data = dstImg.ptr<uchar>(i);
10         for(int j = 0; j < cols; j++)
11         {
12             data[j] = 0;  //处理每一个像素
13             //add code
14         }
15     } 
16 }

复制代码

当Mat按行连续存储时,可以用指针直接访问所有数据。

复制代码

 1 void VisitContinueImgByPointer(Mat &inputImg, Mat &dstImg)
 2 {
 3     dstImg = inputImg.clone();
 4     int rows = dstImg.rows;
 5     int cols = dstImg.cols;
 6     int channels = dstImg.channels();
 7 
 8     if(dstImg.isContinuous())
 9     {
10         cols *= rows;
11         rows = 1;
12         //cout << "is continuous " << endl;
13     }
14 
15     for(int i = 0; i < rows; i++)
16     {
17         uchar* data = dstImg.ptr<uchar>(i);
18         for(int j = 0; j < cols * channels; j++)
19         {
20             data[j] = 155;  //处理每一个像素
21             //add code
22         }
23     } 
24     //若存储连续,等效于以下代码
25     //uchar* data = dstImg.data;
26     //for(int i = 0; i < cols * rows * channels; i++)
27     //    data[i] = 155;    //处理每一个像素
28 
29 }

复制代码

 

 

2.迭代器访问 iterator

复制代码

 1 void VisitImgByIterator(Mat &inputImg, Mat &dstImg)
 2 {
 3     dstImg = inputImg.clone();
 4     const int channels = dstImg.channels();
 5   
 6     switch(channels)
 7     {
 8     case 1:
 9         {
10             Mat_<uchar>::iterator it= dstImg.begin<uchar>();
11             Mat_<uchar>::iterator itend= dstImg.end<uchar>();
12             for ( ; it!= itend; it++) //处理每一个像素
13             {
14                 *it = 150;
15             }
16             break;
17         }
18     case 3:
19         {
20             Mat_<Vec3b>::iterator it3= dstImg.begin<Vec3b>();
21             Mat_<Vec3b>::iterator itend3= dstImg.end<Vec3b>();
22             for ( ; it3!= itend3; it3++) //处理每一个像素
23             { 
24                 (*it3)[0]= 255;
25                 (*it3)[1]= 0;
26                 (*it3)[2]= 0;
27             }
28             break;
29         }
30     }
31 }

复制代码

 

3.动态地址访问 at<uchar/Vec3b>(行,列)

复制代码

 1 void VisitImgByAt(Mat &inputImg, Mat &dstImg)
 2 {
 3     dstImg = inputImg.clone();
 4     int rows = dstImg.rows;
 5     int cols = dstImg.cols;
 6     int channels = dstImg.channels();
 7 
 8     switch(channels)
 9     {
10     case 1:
11         {
12             for(int i = 0; i < rows; i++)
13                 for(int j = 0; j < cols; j++)
14                     dstImg.at<uchar>(i,j) = 150;
15             break;
16         }
17     case 3:
18         {
19             for(int i = 0; i < rows; i++)
20                 for(int j = 0; j < cols; j++)
21                 {
22                     dstImg.at<Vec3b>(i,j)[0] =  0;
23                     dstImg.at<Vec3b>(i,j)[1] =  0;
24                     dstImg.at<Vec3b>(i,j)[2] = 255;
25                 }
26             break;
27         }
28     }
29 }

复制代码

 

测试代码-总

复制代码

  1 #include <iostream>
  2 #include <opencv2/opencv.hpp>  
  3 using namespace cv;
  4 using namespace std;
  5 
  6 void VisitImgByPointer(Mat &inputImg, Mat &dstImg);
  7 void VisitContinueImgByPointer(Mat &inputImg, Mat &dstImg);
  8 void VisitImgByIterator(Mat &inputImg, Mat &dstImg);
  9 void VisitImgByAt(Mat &inputImg, Mat &dstImg);
 10 
 11 int main()
 12 {
 13     Mat srcImg = imread("pig.png"), dstImg;
 14     Mat grayImg;
 15     cvtColor(srcImg, grayImg, CV_BGR2GRAY);
 16     //VisitImgByPointer(srcImg,dstImg);
 17     //VisitContinueImgByPointer(grayImg,dstImg);
 18     
 19     //VisitImgByIterator(srcImg,dstImg);
 20     //VisitImgByIterator(grayImg,dstImg);
 21     
 22     //VisitImgByAt(srcImg,dstImg);
 23     VisitImgByAt(grayImg,dstImg);
 24 
 25     //imshow("原始图", srcImg);
 26     //imshow("灰度图", grayImg);
 27     imshow("生成图", dstImg);
 28 
 29     waitKey(0);
 30     return 0;
 31 }
 32 
 33 void VisitImgByPointer(Mat &inputImg, Mat &dstImg)
 34 {
 35     dstImg = inputImg.clone();
 36     int rows = dstImg.rows;
 37     int cols = dstImg.cols * dstImg.channels();
 38 
 39     for(int i = 0; i < rows; i++)
 40     {
 41         uchar* data = dstImg.ptr<uchar>(i);
 42         for(int j = 0; j < cols; j++)
 43         {
 44             data[j] = 0;  //处理每一个像素
 45             //add code
 46         }
 47     } 
 48 }
 49 
 50 void VisitContinueImgByPointer(Mat &inputImg, Mat &dstImg)
 51 {
 52     dstImg = inputImg.clone();
 53     int rows = dstImg.rows;
 54     int cols = dstImg.cols;
 55     int channels = dstImg.channels();
 56 
 57     if(dstImg.isContinuous())
 58     {
 59         cols *= rows;
 60         rows = 1;
 61         //cout << "is continuous " << endl;
 62     }
 63 
 64     for(int i = 0; i < rows; i++)
 65     {
 66         uchar* data = dstImg.ptr<uchar>(i);
 67         for(int j = 0; j < cols * channels; j++)
 68         {
 69             data[j] = 155;  //处理每一个像素
 70             //add code
 71         }
 72     } 
 73     //若存储连续,等效于一下代码
 74     //uchar* data = dstImg.data;
 75     //for(int i = 0; i < cols * rows * channels; i++)
 76     //    data[i] = 155;    //处理每一个像素
 77 
 78 }
 79 
 80 
 81 void VisitImgByIterator(Mat &inputImg, Mat &dstImg)
 82 {
 83     dstImg = inputImg.clone();
 84     const int channels = dstImg.channels();
 85   
 86     switch(channels)
 87     {
 88     case 1:
 89         {
 90             Mat_<uchar>::iterator it= dstImg.begin<uchar>();
 91             Mat_<uchar>::iterator itend= dstImg.end<uchar>();
 92             for ( ; it!= itend; it++) //处理每一个像素
 93             {
 94                 *it = 150;
 95             }
 96             break;
 97         }
 98     case 3:
 99         {
100             Mat_<Vec3b>::iterator it3= dstImg.begin<Vec3b>();
101             Mat_<Vec3b>::iterator itend3= dstImg.end<Vec3b>();
102             for ( ; it3!= itend3; it3++) //处理每一个像素
103             { 
104                 (*it3)[0]= 255;
105                 (*it3)[1]= 0;
106                 (*it3)[2]= 0;
107             }
108             break;
109         }
110     }
111 }
112 
113 void VisitImgByAt(Mat &inputImg, Mat &dstImg)
114 {
115     dstImg = inputImg.clone();
116     int rows = dstImg.rows;
117     int cols = dstImg.cols;
118     int channels = dstImg.channels();
119 
120     switch(channels)
121     {
122     case 1:
123         {
124             for(int i = 0; i < rows; i++)
125                 for(int j = 0; j < cols; j++)
126                     dstImg.at<uchar>(i,j) = 150;
127             break;
128         }
129     case 3:
130         {
131             for(int i = 0; i < rows; i++)
132                 for(int j = 0; j < cols; j++)
133                 {
134                     dstImg.at<Vec3b>(i,j)[0] =  0;
135                     dstImg.at<Vec3b>(i,j)[1] =  0;
136                     dstImg.at<Vec3b>(i,j)[2] = 255;
137                 }
138             break;
139         }
140     }
141 }

复制代码

参考文章:

1. https://www.cnblogs.com/kuotian/p/6389260.html

2. https://blog.csdn.net/github_35160620/article/details/51708659

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值