• 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 }

    运行结果:

  • 相关阅读:
    [windows菜鸟]C#中调用Windows API参考工具
    [windows菜鸟]C#中调用Windows API的技术要点说明
    [windows菜鸟]Windows API函数大全(完整)
    C#卸载加载到进程里的dll
    C# 防火墙操作之开启与关闭
    CMD命令行管道命令
    linux kernel elv_queue_empty野指针访问内核故障定位与解决
    U-Boot Driver Model领域模型设计
    linux I/O stack cache 强制刷新
    基于lcov实现的增量代码UT覆盖率检查
  • 原文地址:https://www.cnblogs.com/codingmengmeng/p/6559724.html
Copyright © 2020-2023  润新知