OpenCV中的三种图像数据结构CvMat, IplImage和Mat(二)IplImage-程序员宅基地

技术标签: 人工智能  数据结构与算法  

本文为原创,若有错误欢迎批评指正!


一. IplImage结构体构成

IplImage比CvMat要复杂一些,结构体组成如下:

 

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


这里比较重要的参数是height、width、depth和nChannels。

 


 

二. 访问图像数据

与CvMat类似,都有三种方法。

首先是函数的方法:

 

/*函数的方法*/
IplImage* img=cvLoadImage(filename);
CvScalar s;       /*sizeof(s) == img->nChannels*/
s=cvGet2D(img,i,j);  /*get the (i,j) pixel value*/
cvSet2D(img,i,j,s);   /*set the (i,j) pixel value*/


采用宏的方法:

 

 

/*宏*/
IplImage* img; //malloc memory by cvLoadImage or cvCreateImage
for(int row = 0; row < img->height; row++)
{
    for (int col = 0; col < img->width; col++)
    {
        b = CV_IMAGE_ELEM(img, UCHAR, row, col * img->nChannels + 0); 
        g = CV_IMAGE_ELEM(img, UCHAR, row, col * img->nChannels + 1); 
        r = CV_IMAGE_ELEM(img, UCHAR, row, col * img->nChannels + 2);
    }
}


接下来是最推崇的使用指针的方法。在这之前要弄清楚IplImage与Cvmat的一些差别,剩下的用法类似。IplImage在计算行地址的时候也要采用行长度widthStep而不是图像的宽度,与CvMat中step类似。IplImage图像的首地址记作imageData,与CvMat中data类似。IplImage访问时指针设置为(uchar*),而CvMat中data为联合类型,必须说明使用的指针类型。

 

 

/*指针访问*/
IplImage* img; //malloc memory by cvLoadImage or cvCreateImage
uchar b, g, r; // 3 channels
for(int row = 0; row < img->height; row++)
{
    for (int col = 0; col < img->width; col++)
    {
        b = ((uchar *)(img->imageData + row * img->widthStep))[col * img->nChannels + 0]; 
        g = ((uchar *)(img->imageData + row * img->widthStep))[col * img->nChannels + 1]; 
        r = ((uchar *)(img->imageData + row * img->widthStep))[col * img->nChannels + 2];
    }
}

 

三. 一个比较综合的应用

这里定义一个稍微复杂一点的应用,包括了对图像的常用操作,基本上足够用来实现其他的图像算法了。

首先读入一幅图像,若为3通道的则转化为一通道,然后将图像右下角1/4置为白色。

 

#include <opencv2\opencv.hpp>  

int main()
{
	IplImage *img = cvLoadImage("D:\\_Gonzalez\\ch02\\Fig0205(a)(cktboard_200dpi).tif");
	//获取图像的参数  
	printf("width=%d\n", img->width);
	printf("height=%d\n", img->height);
	printf("channel=%d\n", img->nChannels);

	if (img->nChannels == 3)
	{
		//新建一个与img一样大的一通道空图像  
		IplImage *dst = cvCreateImage(cvSize(img->width, img->height), img->depth, 1);
		//将彩色图像转化为一通道灰度图  
		cvCvtColor(img, dst, CV_RGB2GRAY);
		img = dst;
	}

	for (int y = img->height / 2; y < img->height; y++)
	{
		uchar* ptr = (uchar*)(img->imageData + y*img->widthStep);
		for (int x = img->width / 2; x < img->width; x++)
		{
			ptr[x + 1] = 255;
			ptr[x + 2] = 255;
			ptr[x + 3] = 255;
		}
	}

	cvNamedWindow("example", CV_WINDOW_AUTOSIZE);
	cvShowImage("example", img);

	cvWaitKey(0);
	cvReleaseImage(&img);
	cvDestroyWindow("example");
}

 

 

如果将要求改为将三通道的img右下角1/4置为白色,相应操作变成:

 

for (int y = img->height / 2; y < img->height; y++)
{
	uchar* ptr = (uchar*)(img->imageData + y*img->widthStep);
	for (int x = img->width / 2; x < img->width; x++)
	{
		ptr[x + 1] = 255;
		ptr[x + 2] = 255;
		ptr[x + 3] = 255;

		/*也可以是
		*(ptr+3*x+1) = 255;
		*(ptr+3*x+2) = 255;
		*(ptr+3*x+2) = 255;
		*/
	}
}


 

转载于:https://www.cnblogs.com/jenny1000000/p/7738334.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30920597/article/details/98499032

智能推荐

使用 arm-linux-androideabi-addr2line 工具定位 libunity.so 崩溃问题-程序员宅基地

文章浏览阅读710次,点赞13次,收藏7次。它的名称有点不同 - aarch64-linux-android-addr2line。尽管该实用程序的名称不包含单词arm,但它成功地解密了arm64-v8下的堆栈跟踪,并通常感知arm64-v8的字符。是 NDK 自带的调试工具,可以用来分析 so 崩溃时输出的的内存地址。之后就是通过 cmd 进入到这个路径。找到了 64 位所需的实用程序。_arm-linux-androideabi

javaweb-邮件发送_javaweb发送邮件-程序员宅基地

javaweb-邮件发送 摘要: 本文介绍了邮件传输协议(SMTP和POP3)以及电子邮件的发送和接收过程。还讨论了纯文本文件、带图片和附件的邮件发送方法,以及通过servlet方式注册邮箱和使用springboot框架发送邮件的实现。

element-ui table 设置表格滚动条位置_element table 滚动条位置-程序员宅基地

文章浏览阅读4.3k次,点赞6次,收藏11次。在切换不同页面时(被 keep-alive 缓存的组件间切换),页面中的element-ui table的滚动条位置没有停留在原来的位置。目前需要切换不同的页面返回来后,滚动条保持在原来的位置。_element table 滚动条位置

前端开发经验总结_属性值[session.getattribute("strpath")]引用["],在值内使用时必须-程序员宅基地

文章浏览阅读2.6k次。 我设置nowrap和不设置nowrap效果都一样。就是表格随着文字自动伸展,为什么? →回答问题:TD元素noWrap属性的行为与TD元素的width属性有关。 ◆如果未设置TD宽度,则noWrap属性是起作用的。◆如果设置了TD宽度,则noWrap属性是不起作用的。 http://www.blueidea.com/tech/web/2003/943.as_属性值[session.getattribute("strpath")]引用["],在值内使用时必须被转义。

JS如何把Object对象的数据输出到控制台中_前端怎么通过控制台查看字段取值-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏3次。 前端时间在编写程序时遇到这样一个问题,即在前端页面通过一些js框架自带的异步请求返回的数据类型为Object数据类型,笔者根据网上查阅到的资料,找到以下这种简单的方式://把Object类型转为Json数据格式,再通过console命令在控制台中打印出来console.log("xhr的值为:"+JSON.st..._前端怎么通过控制台查看字段取值

8.cc.Button组件使用详解_cc button.start-程序员宅基地

文章浏览阅读556次。1. cc.Button添加按钮的方法 2种方式 (1)直接创建带Button组件的节点; (2) 先创建节点,再添加组件;按钮组件, 按钮是游戏中最常用的组件, 点击然后响应事件;按钮的过渡效果: 过渡: 普通状态, 鼠标滑动到物体上, 按下状态, 禁用状态 (1)没有过渡,只有响应事件; (2)颜色过渡, 过渡效果中使用颜色; (3)精灵..._cc button.start

随便推点

计算机专业游戏本推荐,2018高性价比游戏本推荐_游戏笔记本哪个好-太平洋电脑网...-程序员宅基地

文章浏览阅读245次。【PConline海选导购】晃眼间,秋风又起,让人振奋的开学季又要到来了!虽然说没有学习压力的暑假,在家着实悠哉,但想到回校后可以跟小伙伴们一起各种开黑吃鸡,是不是就感到很兴奋呢?说到“吃鸡”这种吃配置的游戏,就不得不说游戏本了,毕竟普通的笔记本电脑很难给我们带来畅快的游戏体验。而近年来游戏本市场俨然成为了各大厂商的必争之地,而随着开学季的到来,各大厂商更是推出了众多促销活动,下面就让我们一起来看..._计应专业游戏本

codePen按钮样式学习

看到codepen里面有的按钮搞得很炫酷,但其实也不是很难,就学习记录一下。

服务器维护中没法直播游戏,我的世界盒子显示维护中如何进入战堂服务器-程序员宅基地

文章浏览阅读408次。时间:2021-08-11编辑:hxh斗罗大陆魂师对决火雨队怎么搭配?火雨队是近期非常热门的一套阵容,不少玩家想了解该阵容,那么下面就让小编给大家带来斗罗大陆魂师对决火雨队阵容推荐,感兴趣的小伙伴们一起来看看吧。时间:2021-08-11编辑:hxh玩家在巅峰演武副本中不知道怎么打秦明,秦明的盾很厚不知道怎么破?那么下面就让小编给大家带来斗罗大陆魂师对决巅峰演武秦明破盾攻略,感兴趣的小伙伴们一起来...

GNU Radio之Schmidl & Cox OFDM synch.底层C++实现

在 GNU Radio OFDM 系统中,一个非常重要的环节是在接收端准确地同步和检测发送端发出的信号。这就是 Schmidl & Cox 同步算法发挥作用的地方。Schmidl & Cox 算法是一种用于 OFDM 信号的时间同步的技术。本文对其底层 C++ 源码进行学习记录。

项目开发规范

REST,表述性状态转换,他是一种软件架构风格使用URL定位资源,HTTP动词描述操作根据发出请求类型来区分操作此为风格,是约定方式,可以打破描述模块的功能通常使用复数,也就是加s的格式来描述,表示此类资源,而非单个资源。

3.8设计模式——State 状态模式(行为型)

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。