一直以为IplImage结构体中的widthStep元素大小等于width*nChannels,大错特错!

查看OpenCV2.1的源码,在src/cxcore/cxarray.cpp文件中,找到cvInitImageHeader函数,函数中对widthStep大小赋值如下:

image->widthStep = (((image->width * image->nChannels *

(image->depth & ~IPL_DEPTH_SIGN) + 7)/8)+ align - 1) & (~(align - 1));                                             (1)

其中IPL_DEPTH_SIGN的定义可以在cxtypes.h中找到,定义为:#define IPL_DEPTH_SIGN 0x80000000, align的大小为CV_DEFAULT_IMAGE_ROW_ALIGN,其大小在cxmisc.h中定义为:#define  CV_DEFAULT_IMAGE_ROW_ALIGN 4,depth取8位深度。

根据(1)式,已知IPL_DEPTH_SIGN、align、depth 的大小,分别手动计算如下图像的widthStep:

图像宽度     图像通道数              计算得到的widthStep

3                    3                             12

3                    1                             4

5                    3                            16

5                    1                             8

7                    3                             24

7                    1                             8

4                    3                             12

4                    1                             4

为了进一步验证手算的正确性,我们编程实现输出widthStep的大小,程序如下:

IplImage *image_33 = cvCreateImage(cvSize(3, 3), 8, 3);

IplImage *image_31 = cvCreateImage(cvSize(3, 3), 8, 1);

IplImage *image_53 = cvCreateImage(cvSize(5, 3), 8, 3);

IplImage *image_51= cvCreateImage(cvSize(5, 3), 8, 1);

IplImage *image_73 = cvCreateImage(cvSize(7, 3), 8, 3);

IplImage *image_71 = cvCreateImage(cvSize(7, 3), 8, 1);

printf("%d, %d, %d, %d, %d, %d", image_33->widthStep,image_31->widthStep,

image_53->widthStep,image_51->widthStep,image_73->widthStep,image_71->widthStep);

运行结果为:12, 4, 16, 8, 24, 8, 与手动计算结果相同。

从网上查阅资料,OpenCV分配的内存按4字节对齐,这样我们对上述计算的结果可以有个合理的解释,如宽度为3、通道数为3的图像,每一行需要的 实际内存长度为3*3,为了内存对齐,OpenCV会在每行末尾自动补上3个字节的内存,内存初始化都为0,所以widthStep变为了12。

widthStep大小对IplImage极为重要,在cxarray.cpp中,我们可以找到如下代码行:

image->imageSize = image->widthStep * image->height;

img->imageData = img->imageDataOrigin =

(char*)cvAlloc( (size_t)img->imageSize );

可见widthStep直接影响到imageData的数据长度。在操作imageData时,我们要避开对OpenCV自动补齐的内存进行操作,如直方图计算等。

写到这里,可能有人会问,我们平常都用widthStep = width * nChannels,怎么就没出错?我之前也一直在疑惑,合理的解释是,一般在实际应用中,图像的宽度一般为128, 256, 240, 320, 356,704等,刚好这些数字都能被4整除,widthStep刚好等于width * nChannels, 所以OpenCV并没有为这些图像分配多的内存,因此我们在对imageData做顺序操作也没出错。但是,请问谁能保证图像的宽度一定会是4的倍数?

纯属个人理解,如有错误,还请大虾多多指出。

经过上面的分析,我已经完全理解了widthStep的计算以及为何data[i * step + j * channels + k]这么计算了

java+widthstep,i*step+j*channels+k 以及widthStep大小计算及原理相关推荐

  1. 2021-12-08:扑克牌中的红桃J和梅花Q找不到了,为了利用剩下的牌做游戏,小明设计了新的游戏规则: 1) A,2,3,4....10,J,Q,K分别对应1到13这些数字,大小王对应0; 2) 游

    2021-12-08:扑克牌中的红桃J和梅花Q找不到了,为了利用剩下的牌做游戏,小明设计了新的游戏规则: A,2,3,4-10,J,Q,K分别对应1到13这些数字,大小王对应0; 游戏人数为2人,轮流 ...

  2. 使用指针交换i,j,k的值

    <程序设计基础-c语言>杨莉 刘鸿翔 ISBN-978-7-03-032903-5 p137 习题5 2.从键盘输入三个数分别赋给变量i.j.k.同时设置三个指针变量p1.p2.p3分别指 ...

  3. java加载c库阻塞_【死磕Java並發】-----J.U.C之阻塞隊列:DelayQueue

    DelayQueue是一個支持延時獲取元素的無界阻塞隊列.里面的元素全部都是"可延期"的元素,列頭的元素是最先"到期"的元素,如果隊列里面沒有元素到期,是不能從 ...

  4. java.util.UnknownFormatConversionException: Conversion = ‘j‘ || Conversion = ‘D‘ || Conversion = ‘Y‘

    执行内容: String a = "select * from j_question j where j.status = %s and j.title like '%java%'" ...

  5. lintcode 734. 形式为a^i b^j c^k的子序列数量 题解

    描述 给一字符串, 对形式为 a^i b^j c^k 的子序列进行计数, 即它由 i 个字符 a, 接着是 j 个字符 b, 然后是 k 个字符 c组成, i >= 1, j >= 1, ...

  6. USB 2.0 协议中J、K、SE0状态的定义

    一.通俗解释 1.J态.K态.SE0 低速设备: J态: D+ ="0",D- ="1" K态: D+ ="1",D- ="0&q ...

  7. 求赌王的密码 【问题描述】 赌王喜欢“A”,密码由6行6列扑克牌中每行“A”的位置数字组合而成。扑克牌点数由1~9,J,Q,K,A组成,每行的扑克牌中最多只能出现一次“A”;也可能没有“A”,

    题头的话:长按点赞可私我赠送50+本C与C++书籍电子书资源 求赌王的密码 [问题描述] 赌王喜欢"A",密码由6行6列扑克牌中每行"A"的位置数字组合而成.扑 ...

  8. for(j=0,i=0;j6,i10;j++,i++) { k=i+j; } k 值结果是多少?

    <script type="text/javascript">function Test(){var k=0;for(j=0,i=0;j<6,i<10;j+ ...

  9. 道路测量xy坐标表示什么_三坐标(CMM)测量的矢量方向(i,j,k)

    三坐标(CMM)测量的矢量方向(i,j,k) 什么是矢量方向? 矢量方向(以下简称矢量)是垂直于零件表面的路径方向.任何特征都需要有矢量,它指导测量探针垂直于测量表面操作.这个复杂的计算工作通常交给测 ...

  10. Android Studio ---- Cannot resolve symbol 'XXX',java文件 显示蓝色J的图标

    问题: 现象1. 我在MsgReceiver.java中 使用Msg2.java , 但是报红,引用失败,无法找到.(之前是好的,不知什么原因导致) Cannot resolve symbol 'XX ...

最新文章

  1. java验证码(采用struts2实现)转
  2. Ubuntu 安装 Linux Deepin 截图工具(.deb)
  3. ospf lesson 3
  4. Java 程序员中位数薪资达 1.45 万,但面试屡屡被拒?
  5. 试题10 最大子阵(枚举)
  6. quartus仿真17:T触发器的时序逻辑电路
  7. edge浏览器的html文件,手把手解决win10系统利用edge浏览器共享网页的具体方法
  8. java 围棋_围棋冠军都输了?用Java编写的智能围棋战力惊人?
  9. HPE comms CTO:我们的单位在增长,即使我们的客户不是
  10. ant中修改a-switch的大小、修改a-checkbox的大小
  11. local_listener参数(2)---elaine
  12. 网络维护工程师的要求是什么?
  13. 基于JAVA的企业部门报销管理信息系统的设计与实现
  14. 【CTSC2016】时空旅行
  15. 新月音标_又一个新月?
  16. nginx 反向代理及负载均衡策略
  17. K近邻(KNN)算法总结
  18. SUMO仿真教程(1) ——安装环境的设置(Windows 10系统)
  19. 关于IAR安装的注意问题和教训
  20. centos7 登录到经典桌面_centos7操作系统安装与配置

热门文章

  1. 人工智能的常用十种算法
  2. 基于PHP+MySQL的个人网页设计与实现
  3. 黑马程序员html基本笔记
  4. java通过银行账号获取银行名称
  5. WORDNET与HOWNET之比较
  6. 【OpenCV】绘图与注释——绘制色差图
  7. 交换机在局域网内的日常工作
  8. 【NodeJs-5天学习】第一天篇② —— 安装NodeJs环境以及VsCode开发工具
  9. 【软考软件评测师】历年真题大汇总
  10. 保存特定模式的snp文件