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

java+widthstep,i*step+j*channels+k 以及widthStep大小计算及原理一直以为IplImage结构体中的widthStep元素大小等于width*nChannels,大错特错!查看OpenCV2.1的源码,在src/cxcore/cxarray.cpp文件中,找到cvInitImageHeader函数,函数中对widthStep大小赋值如下:image->widthStep=(((image->width*image->nChannels…

大家好,又见面了,我是你们的朋友全栈君。

一直以为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]这么计算了

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/133291.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • git 查看当前所在分支「建议收藏」

    git 查看当前所在分支「建议收藏」gitbranch

  • 第三章:hadoop安装配置,jps命令不能使用。apt-get命令不能下载jdk,缺少依赖包,设置静态ip后不能上网,ubuntu防火墙,ssh无密码登录

    第三章:hadoop安装配置,jps命令不能使用。apt-get命令不能下载jdk,缺少依赖包,设置静态ip后不能上网,ubuntu防火墙,ssh无密码登录第三章:hadoop安装配置,jps命令不能使用。apt-get命令不能下载jdk,缺少依赖包,设置静态ip后不能上网,ubuntu防火墙,ssh无密码登录

  • linux 命令行 查找文件_grep命令查找文件

    linux 命令行 查找文件_grep命令查找文件一grep:查看文件内容,在文件中查询一个关键字,即搜索字符串的命令(在指定的文件中搜索符合条件的字符串)grep是包含匹配,不是完全的精确匹配,特别适合查找内容语法:grep[-option]需要搜索的关键字文件名参数:-n—-连行号一起显示-c—-统计有几行-i—-忽略大小写(一般用的少)-v—-排除指定的字符串(了解),取反,查找出来的内容是搜索条件以外的所有的内容例如:[root@localhostTEST~]#grep-n

  • 51单片机按键控制步进电机加减速及正反转

    51单片机按键控制步进电机加减速及正反转之前尝试用单片机控制42步进电机正反转,电机连接导轨实现滑台前进后退,在这里分享一下测试程序及接线图,程序部分参考网上找到的,已经实际测试过,可以实现控制功能。所用硬件:步进电机及驱动器、STC89C52单片机、直流电源1、硬件连接图注意:上图为共阳极接法,实际连接参考总体线路连接。 驱动器信号端定义:PUL+:脉冲信号输入正。(C…

  • 微信小程序的面试题_小程序面试题汇总

    微信小程序的面试题_小程序面试题汇总小程序面试题简单描述下微信小程序的相关文件类型?一、WXML(WeiXinMarkupLanguage)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。内部主要是微信自己定义的一套组件。与html差不多。二、WXSS(WeiXinStyleSheets)是一套样式语言,用于描述WXML的组件样式,与css差不多二、js逻辑处理,…

  • stringbuffer和stringbuilder是什么_Java编程

    stringbuffer和stringbuilder是什么_Java编程字符串常量池什么是字符串常量池?JVM为了减少字符串对象的重复创建,其维护了一块特殊的内存,这段内存被称为字符串常量池(存储在方法区中)。具体实现当代码中出现字符串时,JVM首先会对其进行检查。如果字符串常量池中存在相同内容的字符串对象,则将这个对象的地址返回。如果字符串常量池中不存在相同内容的字符串对象,则创建一个新的字符串对象并放入常量池。newString(“str…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号