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]这么计算了

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

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

(0)
上一篇 2022年6月9日 下午1:00
下一篇 2022年6月9日 下午1:00


相关推荐

  • 车载逆变器设计[通俗易懂]

    车载逆变器设计[通俗易懂]逆变器,别称为变流器、反流器,是一种可将直流电转换为交流电的器件,由逆变桥、逻辑控制、滤波电路三大部分组成,主要包括输入接口、电压启动回路、MOS开关管、PWM控制器、直流变换回路、反馈回路、LC振荡及输出回路、负载等部分,可分为半桥逆变器、全桥逆变器等。目前已广泛适用于空调、家庭影院、电脑、电视、抽油烟机、风扇、照明、录像机等设备中  逆变变压器原理  它的工作原理流

    2022年6月8日
    39
  • 深度相机种类_深度相机原理

    深度相机种类_深度相机原理本文首发于微信公众号:计算机视觉life。本文的深度相机制造商涉及:Microsoft、Intel、LeapMotion、Orbbec、图漾、OccipitalStructure、Stereolabs、DUO。文末附深度相机详细对比清单。MicrosoftKinect微软推出了两款Kinect,Kinect一代(Kinectv1)是基于结构光原理的深度相机,Kinect二代(Kine

    2025年6月23日
    6
  • strip 命令的使用方法

    strip 命令的使用方法

    2021年12月9日
    46
  • LLDP 链路发现协议「建议收藏」

    LLDP 链路发现协议「建议收藏」LLDP链路发现协议公有标准协议作用:在网络设备之间运行后,可以直接查看到设备之间的互联端口以及对方设备的简要信息配置:在每个设备的系统试图下开启LLDP就可以了。配置命令:[SW1]lldpenable//开启LLDP功能[SW2]lldpenable//开启LLDP功能displaylldpneighborbrief//查看设备上的LLDP邻居表LocalIntfNeighborDevNeighborIn

    2022年5月22日
    64
  • 删除链表倒数第n个节点_求链表的倒数第m个元素

    删除链表倒数第n个节点_求链表的倒数第m个元素原题链接给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。进阶:你能尝试使用一趟扫描实现吗?示例 1:输入:head = [1,2,3,4,5], n = 2输出:[1,2,3,5]示例 2:输入:head = [1], n = 1输出:[]示例 3:输入:head = [1,2], n = 1输出:[1]提示:链表中结点的数目为 sz1 <= sz <= 300 <= Node.val <= 1001 <= n <= s

    2022年8月8日
    10
  • C++RTSP服务端(附源码)

    C++RTSP服务端(附源码)源代码 demo 已上传到百度网盘 永久生效 代码实现了 rtsp 服务端功能 而且对模块进行了封装 只需要简单的调用 4 个函数就可以 实现服务器的功能 主要是针对 h264 流的封包 本代码完全提取 live555rtsp 代码 并加以修改与封装 我已经封装成 DLL 了 当然一切都提供源吗 先看下接口封装 要是有了这几个接口 你还是不知道怎么用 那我真的没有办法了 取到流 设像头或者文件 你开启服务 等待连接啊 有连接上后 发送你的流啊 你不用怀疑代码有没问

    2026年3月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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