opencv学习笔记(八)IplImage* 访问图像像素的值

  opencv2.1版本之前使用IplImage*数据结构来表示图像,2.1之后的版本使用图像容器Mat来存储。IplImage结构体如下所示。

 1 typedef struct _IplImage  
 2     {  
 3         int  nSize;         /* IplImage大小 */  
 4         int  ID;            /* 版本 (=0)*/  
 5         int  nChannels;     /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */  
 6         int  alphaChannel;  /* 被OpenCV忽略 */  
 7         int  depth;         /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U, 
 8                                IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */  
 9         char colorModel[4]; /* 被OpenCV忽略 */  
10         char channelSeq[4]; /* 同上 */  
11         int  dataOrder;     /* 0 - 交叉存取颜色通道, 1 - 分开的颜色通道. 
12                                cvCreateImage只能创建交叉存取图像 */  
13         int  origin;        /* 0 - 顶—左结构, 
14                                1 - 底—左结构 (Windows bitmaps 风格) */  
15         int  align;         /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */  
16         int  width;         /* 图像宽像素数 */  
17         int  height;        /* 图像高像素数*/  
18         struct _IplROI *roi;/* 图像感兴趣区域. 当该值非空只对该区域进行处理 */  
19         struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */  
20         void  *imageId;     /* 同上*/  
21         struct _IplTileInfo *tileInfo; /*同上*/  
22         int  imageSize;     /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/  
23         char *imageData;  /* 指向排列的图像数据 */  
24         int  widthStep;   /* 排列的图像行大小,以字节为单位 */  
25         int  BorderMode[4]; /* 边际结束模式, 被OpenCV忽略 */  
26         int  BorderConst[4]; /* 同上 */  
27         char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */  
28     }  
29     IplImage;  

1、使用指针遍历图像像素

(1)单通道字节型图像像素访问

 1 /*
 2 @author:CodingMengmeng
 3 @theme:Read the image pixel values
 4 @time:2017-3-16 11:27:31
 5 @blog:http://www.cnblogs.com/codingmengmeng/
 6 */
 7 #include <cv.h>  
 8 #include <highgui.h>  
 9 using namespace std;
10 using namespace cv;
11 int main(void)
12 {
13     IplImage* imgSrc = cvLoadImage("./inputData\\shuke1.jpg",0);
14     uchar* pixel = new uchar;
15     for (int i = 0; i < imgSrc->height; i++)
16     {
17         for (int j = 0; j < imgSrc->width; j++)
18         {
19             pixel = (uchar*)(imgSrc->imageData + i*imgSrc->widthStep+j);
20             cout << "pixel=" <<(*pixel)+0<< endl;//+0隐式转换为整型,否则会打印出字符
21         }
22     }
23     delete pixel;
24 return 0; 25 }

输出结果是0-255灰度级的灰度值。

其中(uchar*)(imgSrc->imageData + i*imgSrc->widthStep+j)的具体含义:

a)imgSrc->imageData指向图像第一行的首地址,i是指当前像素点所在的行,widthStep是指图像每行所占的字节数;所以imgSrc->imageData + i*imgSrc->widthStep表示该像素点所在行的首地址;j表示当前像素点所在列,所以imgSrc->imageData + i*imgSrc->widthStep+j即表示该像素点的地址。而因为IplImage->ImageData 的默认类型是 char 类型,所以再对图像像素值进行操作时,要使用强制类型转换为unsigned char,再对其进行处理。否则,图像像素值中,会有负值出现。

(b)widthStep表示存储一行像素需要的字节数

一个m*n的单通道字节型图像,其imageData排列如下:

因为opencv分配的内存是按4字节对齐的,所以widthStep必须是4的倍数,如果8U图像宽度为3,那么widthStep是4,加一个字节补齐。这个图像的一行需要4个字节,只使用前3个,最后一个空在那儿不用。也就是一个宽3高3的图像的imageData数据大小为4*3=12字节。

 

(2)三通道字节型图像像素访问

多通道字节型图像的imageData排列如下:

其中(Bi,Bj)(Gi,Gj)(Ri,Rj)表示图像(i,j)处BGR分量的值。

 1 /*
 2 //@author:CodingMengmeng
 3 //@theme:Read the image pixel values
 4 //@time:2017-3-16 11:59:17
 5 //@blog:http://www.cnblogs.com/codingmengmeng/
 6 */
 7 #include <cv.h>  
 8 #include <highgui.h>  
 9 using namespace std;
10 using namespace cv;
11 int main(void)
12 {
13     IplImage* imgSrc = cvLoadImage("./inputData\\shuke1.jpg");
14     uchar* b_pixel = new uchar;
15     uchar* g_pixel = new uchar;
16     uchar* r_pixel = new uchar;
17     for (int i = 0; i < imgSrc->height; i++)
18     {
19         for (int j = 0; j < imgSrc->width; j++)
20         {
21             b_pixel = (uchar*)(imgSrc->imageData + i*imgSrc->widthStep + (j*imgSrc->nChannels + 0));
22             g_pixel = (uchar*)(imgSrc->imageData + i*imgSrc->widthStep + (j*imgSrc->nChannels + 1));
23             r_pixel=(uchar*)(imgSrc->imageData + i*imgSrc->widthStep + (j*imgSrc->nChannels + 2));
24             cout << "b_pixel=" << *b_pixel+0 << endl;
25             cout << "g_pixel=" << *g_pixel+0 << endl;
26             cout << "r_pixel=" << *r_pixel+0 << endl;
27             cout << "/********************************************/" << endl;
28         }
29     }
30     delete b_pixel;
31     delete g_pixel;
32     delete r_pixel;
33     return 0;
34 }

 

运行结果:

 

2、使用cvGet2D()函数访问

cvGet*D系列函数可以用来返回特定位置的数组元素(一般使用cvGet2D),原型如下:

1 CvScalar cvGet1D( const CvArr* arr, int idx0 );  
2 CvScalar cvGet2D( const CvArr* arr, int idx0, int idx1 );  
3 CvScalar cvGet3D( const CvArr* arr, int idx0, int idx1, int idx2 );  
4 CvScalar cvGetND( const CvArr* arr, int* idx );  

(1)单通道图像像素访问

 1 /*
 2 @author:CodingMengmeng
 3 @theme:Read the image pixel values
 4 @time:2017-3-16 15:12:57
 5 @blog:http://www.cnblogs.com/codingmengmeng/
 6 */
 7 #include <cv.h>  
 8 #include <highgui.h>  
 9 using namespace std;
10 using namespace cv;
11 int main(void)
12 {
13     IplImage* imgSrc = cvLoadImage("./inputData\\shuke1.jpg",0);
14     CvScalar pixel_v;
15     /*
16     CvScalar是一个可以用来存放4个double数值的数组
17     一般用来存放像素值(不一定是灰度值哦)的,最多可以存放4个通道的
18     如何赋值:
19     a) 存放单通道图像中像素:cvScalar(255);
20     b) 存放三通道图像中像素:cvScalar(255,255,255);
21     c)只使用第一个通道,val[0]=val0;等同于cvScalar(val0,0,0,0);
22     */
23     for (int i = 0; i < imgSrc->height; i++)
24     {
25         for (int j = 0; j < imgSrc->width; j++)
26         {
27             pixel_v = cvGet2D(imgSrc, i, j);
28             cout << "pixel=" << pixel_v.val[0] << endl;
29         }
30     }
31     return 0;
32 }

注意:

对于图像中的某一像素点 P(x, y), 在我们正常的坐标系中,x代表其横坐标,y代表其纵坐标;而在opencv的函数cvGet2D()的函数原型是 : CvScalar cvGet2D (const CvArr * arr, int idx0, int idx1); 函数返回的是一个CvScalar 容器,其参数中也有两个方向的坐标,但跟我们平常习惯的坐标不一样的是,idx0代表是的行,即高度,对应于我们平常坐标系的y, idx1代表的是列,即宽度,对应于我们平常坐标系的x使用时请千万别弄反,否则容易出现溢出引发异常。

(2)多通道字节型/浮点型图像像素访问

 1 /*
 2 @author:CodingMengmeng
 3 @theme:Read the image pixel values
 4 @time:2017-3-16 15:18:29
 5 @blog:http://www.cnblogs.com/codingmengmeng/
 6 */
 7 #include <cv.h>  
 8 #include <highgui.h>  
 9 using namespace std;
10 using namespace cv;
11 int main(void)
12 {
13     IplImage* imgSrc = cvLoadImage("./inputData\\shuke1.jpg");
14     CvScalar pixel_v;
15     /*
16     CvScalar是一个可以用来存放4个double数值的数组
17     一般用来存放像素值(不一定是灰度值哦)的,最多可以存放4个通道的
18     如何赋值:
19     a) 存放单通道图像中像素:cvScalar(255);
20     b) 存放三通道图像中像素:cvScalar(255,255,255);
21     c)只使用第一个通道,val[0]=val0;等同于cvScalar(val0,0,0,0);
22     */
23     for (int i = 0; i < imgSrc->height; i++)
24     {
25         for (int j = 0; j < imgSrc->width; j++)
26         {
27             pixel_v = cvGet2D(imgSrc, i, j);
28             cout << "b_pixel=" << pixel_v.val[0] << endl;//B分量
29             cout << "g_pixel=" << pixel_v.val[1] << endl;//G分量
30             cout << "r_pixel=" << pixel_v.val[2] << endl;//R分量
31             cout << "/********************************************/" << endl;
32         }
33     }
34     return 0;
35 }

运行结果:

转载于:https://www.cnblogs.com/codingmengmeng/p/6559724.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值