OpenCV:widthStep vs step

绪:

在OpenCV中,widthStep是相对于IplImage*进行图像像素拜候操作的;

而step是相对于Mat进行图像像素拜候操作的;

widthStep:存储一行像素需要的字节数;

step:每一行中所有元素的字节总量,单元字节;

本文本家儿要介绍:

widthStep界说;widthStep在IplImage中的感化;widthStep在图像像素拜候中的应用;

widthStep总结;

step在Mat类中的感化;step在图像像素拜候中的应用;

东西/原料

  • OpenCV 2410

方式/步调

  1. 1

    widthStep界说:

    ①OpenCV中,默认图像原点为图像左上角,img->origin=IPL_ORIGIN_TL;若是想更改图像原点坐标也可以,如img->origin=IPL_ORIGIN_BL,将图像原点更改为左下角;

    一般采用默认的图像原点;

    ②OpenCV用imread或者cvLoadImage获得的图像数据都是unsigned char类型的;

    ③IplImage布局体中的widthStep元素巨细纷歧心猿意马等于width*nChannels,

    ④在cxcore/cxarray.cpp文件中,cvInitImageHeader对widthStep巨细赋值:

    image->widthStep =

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

    此中,

    cxtypes.h界说IPL_DEPTH_SIGN为:#define IPL_DEPTH_SIGN 0x80000000;

    cxmisc.h中界说align为:#define  CV_DEFAULT_IMAGE_ROW_ALIGN 4;

    depth取8位深度;

    则可计较图像的widthStep;

    一些图像的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。

  2. 2

    widthStep在IplImage*中的感化:

    如下:

    typedef struct _IplImage{

        int  nSize;             /* sizeof(IplImage) */

        int  ID;                /* version (=0)*/

        int  nChannels;         /* Most of OpenCV functions support 1,2,3 or 4 channels */

        int  alphaChannel;      /* Ignored by OpenCV */

        int  depth; /* Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported.  */

        char colorModel[4];     /* Ignored by OpenCV */

        char channelSeq[4];     /* ditto */

        int  dataOrder;         /* 0 - interleaved color channels, 1 - separate color channels.

                                   cvCreateImage can only create interleaved images */

        int  origin; /* 0 - top-left origin, 1 - bottom-left origin (Windows bitmaps style).  */

        int  align; /* Alignment of image rows (4 or 8). OpenCV ignores it and uses widthStep instead. */

        int  width;             /* Image width in pixels.                           */

        int  height;            /* Image height in pixels.                          */

        struct _IplROI *roi;    /* Image ROI. If NULL, the whole image is selected. */

        struct _IplImage *maskROI;      /* Must be NULL. */

        void  *imageId;                 /* "           " */

        struct _IplTileInfo *tileInfo;  /* "           " */

        int  imageSize;  /* Image data size in bytes (==image->height*image->widthStep in case of interleaved data)*/

        char *imageData;        /* Pointer to aligned image data.         */

        int  widthStep;         /* Size of aligned image row in bytes.    */

        int  BorderMode[4];     /* Ignored by OpenCV.                     */

        int  BorderConst[4];    /* Ditto.                                 */

        char *imageDataOrigin;  /* Pointer to very origin of image data (not necessarily aligned) -

                                   needed for correct deallocation */

    }IplImage;

  3. 3

    IplImage*拜候图像像素:widthStep

    对8bit,单通道,unsigned char类型的图像I---IplImage* img:

    I(x, y)~((unsigned char*)(img->imageData+img->widthStep*y))[x];

    对8bit,3通道,unsigned char类型的图像I---IplImage* img:

    I(x, y)blue~((unsigned char*)(img->imageData+img->widthStep*y))[x*3];

    I(x, y)green~((unsigned char*)(img->imageData+img->widthStep*y))[x*3+1];

    I(x, y)red~((unsigned char*)(img->imageData+img->widthStep*y))[x*3+2];

    或者

    unsigned char* ptr=&((unsigned char*)(img->imageData+img->widthStep*y))[x*3];

    I(x, y)blue ~ ptr[0];

    I(x, y)green~ ptr[1];

    I(x, y)red ~ ptr[2];

     

    对32bit,1通道,float*类型的图像I---IplImage* img:

    I(x, y)~((float*)(img->imageData+img->widthStep*y))[x];

    对32bit,3通道,float*类型的图像I---IplImage*img;

    I(x, y) blue ~((float*)(img->imageData+img->widthStep*y))[3*x];

    I(x, y) green ~(( float *)(img->imageData+img->widthStep*y))[x*3+1];

    I(x, y) red ~(( float *)(img->imageData+img->widthStep*y))[x*3+2];

     

    对64bit,3通道,double*类型的图像数据I--- IplImage*img;

    image=cvCreateImage(cvSize(111,113),IPL_DEPTH_64F,3);

    这里widthstep=(111*3*sizeof(double)+3)/4*4=2664;因为111*3*sizeof(double)=2664已经正好是4的倍数了,是以无需弥补字节。

    若是用指针拜候第31行、51列的图像数据,

    则这个数据为double类型的,image->imageData为unsigned char类型,

    是以可以转换当作double,经由过程double指针来拜候:

    double *data=(double*)image->imageData; 

    double val=*(data+31*width+51); 

    ②或者经由过程unsigned char指针找到(31,51)处的地址,

    然后转换当作double指针进行拜候:

    unsigned  char* data=image->imageData; 

    double val=*(double*)(data+31*image->widthStep+51*sizeof(double));  

    对于IplImage,指针拜候可以参考以上两种体例,其实这素质就是数据类型的转换罢了。

     

    一般,拜候图像像素方式,格局:

    对于N通道,T类型的图像,

    I(x,y)c~((T*)(img->imageData+img->widthStep*y))[x*N+c];

  4. 4

    widthStep常识总结:

    width暗示图像的每行像素数,

    widthStep暗示存储一行像素需要的字节数,widthStep必需是4的倍数,从而实现字节对齐,有利于提高运算速度。

    若是8U单通道图像宽度为3,那么widthStep是4,加一个字节补齐。

    这个图像的一行需要4个字节,只利用前3个,最后一个空着。

    也就是一个宽3高3的图像的imageData数据巨细为4*3=12字节。

    【注】:分歧数据类型长度的图像,widthStep也不不异;

    widthStep的值的计较有两种环境:

    ①当(width*3)%4=0,这时width*3=widthStep;

    ②当(width*3)%4 !=0,此时widthStep=(width/4+1)*3。

    Mat的数据并不是字节对齐的;

    直接将cv::Mat转换为IplImage类型,并不会将字节对齐,只是加了个文件头罢了;

    是以需要如下操作:

  5. 5

    BYTE*与IplImage*之间的转换:

    IplImage* iplImage:opencv中图像数据头;

    BYTE* data:内存中的图像数据,一般为工业相机采集的图像数据;

    ①由IplImage*转BYTE*图像数据:

    data = iplImage->imageDataOrigin; //未对齐的原始图像数据

    或者

    data = iplImage->imageData; //已对齐的图像数据

    ②BYTE*转IplImage*图像数据

    iplImage = cvCreateImageHeader(cvSize(width,height),depth,channels);

    cvSetData(iplImage,data,step);

    起首,由cvCreateImageHeader()建立IplImage图像头,设置图像尺寸、深度和通道数;

    然后,由cvSetData()按照BYTE*图像数据指针设置IplImage图像头的数据,

    此中,step指心猿意马该IplImage图像,每行占的字节数,对于1通道的 IPL_DEPTH_8U图像,step可以等于width。

  6. 6

    Mat拜候图像像素---step:

    data:unsigned char类型的指针,指标的目的Mat数据矩阵的首地址;

    dims:Mat矩阵的维度;

    rows:Mat矩阵的行数;

    cols:Mat矩阵的列数;

    size():是一个布局体,有image.size().width==image.cols; image.size().height==image.rows

    channels():Mat矩阵元素拥有的通道数;

    depth:怀抱每一个像素中每一个通道的精度,但它自己与图像的通道数无关!depth数值越年夜,精度越高。在Opencv中,Mat.depth()获得的是一个0~6的数字,别离代表分歧的位数,如下:{CV_8U=0,CV_8S=1,CV_16U=2,CV_16S=3,CV_32S=4,CV_32F=5,CV_64F=6}

    elemSize:暗示矩阵中每一个元素的数据巨细,单元字节,若是Mat中的数据类型是CV_8UC1,那么elemSize==1;若是是CV_8UC3或CV_8SC3,那么elemSize==3;若是是CV_16UC3或者CV_16SC3,那么elemSize==6;即elemSize是以8位(一个字节)为一个单元,乘以通道数和8位的整数倍;

    elemSize1:

    暗示Mat矩阵中每一个元素单个通道的数据巨细,单元字节,elemSize1=elemSize/channels;

    step:为Mat矩阵中每一行的“步长”,以字节为根基单元,每一行中所有元素的字节总量;

    step1():以字节为根基单元,Mat矩阵中每一个像素的巨细step1==step/elemSize1;

    type:Mat矩阵的类型,包含有矩阵中元素的类型、通道数信息,type的定名格局为CV_(位数)+(数据类型)+(通道数),如下:

  7. 7

    Mat拜候图像像素---step

    step:为Mat矩阵中每一行的“步长”,以字节为根基单元,每一行中所有元素的字节总量;

    经常应用在拜候图像像素操作中;如下:

     

    对8bit,单通道,unsigned char类型的图像I---Mat img:

    unsigned char* pData=(unsigned char*)img.data;

    I(x, y)~pData[img.step*y+x];//

     

    对8bit,3通道,unsigned char类型的图像I---IplImage* img:

    I(x, y)blue~((unsigned char*)(img.data+img.step*y))[x*3];

    I(x, y)green~((unsigned char*)(img.data+img.step*y))[x*3+1];

    I(x, y)red~((unsigned char*)(img.data+img.step*y))[x*3+2];

     

    对32bit,1通道,float*类型的图像I---Mat img:

    I(x, y)~((float*)(img.data+img.step*y)[x];

     

    对32bit,3通道,float*类型的图像I--- Mat img;

    I(x, y) blue ~((float*)(img.data+img.step*y))[3*x];

    I(x, y) green ~((float*)(img.data+img.step*y))[x*3+1];

    I(x, y) red ~((float*)(img.data+img.step*y) )[x*3+2];

     

    对64bit,1通道,double*类型的图像I---Mat img:

    I(x, y)~((double*)(img.data+img.step*y)[x];

     

    对64bit,3通道,double*类型的图像数据I--- Mat img;

    I(x, y) blue ~(( double *)(img.data+img.step*y))[3*x];

    I(x, y) green ~(( double *)(img.data+img.step*y))[x*3+1];

    I(x, y) red ~(( double *)(img.data+img.step*y))[x*3+2];

     

    一般,拜候图像像素方式,格局:

    对于N通道,T类型的图像,

    I(x,y)c~((T*)(img.Data+img.step *y))[x*N+c];

注重事项

  • step拜候图像像素的形式;
  • widthStep拜候图像像素的形式;
  • 发表于 2018-05-05 00:00
  • 阅读 ( 1337 )
  • 分类:其他类型

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
admin
admin

0 篇文章

作家榜 »

  1. xiaonan123 189 文章
  2. 汤依妹儿 97 文章
  3. luogf229 46 文章
  4. jy02406749 45 文章
  5. 小凡 34 文章
  6. Daisy萌 32 文章
  7. 我的QQ3117863681 24 文章
  8. 华志健 23 文章

联系我们:uytrv@hotmail.com 问答工具