緒:
在OpenCV中,widthStep是相對于IplImage*進行圖像像素拜候操作的;
而step是相對于Mat進行圖像像素拜候操作的;
widthStep:存儲一行像素需要的字節數;
step:每一行中所有元素的字節總量,單元字節;
本文本家兒要介紹:
widthStep界說;widthStep在IplImage中的感化;widthStep在圖像像素拜候中的應用;
widthStep總結;
step在Mat類中的感化;step在圖像像素拜候中的應用;
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。
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;
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];
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類型,并不會將字節對齊,只是加了個文件頭罷了;
是以需要如下操作:
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。
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_(位數)+(數據類型)+(通道數),如下:
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];
0 篇文章
如果覺得我的文章對您有用,請隨意打賞。你的支持將鼓勵我繼續創作!