Opencv step by step - 基本数据类型


CvArr,CvMat,IplImage这三者是继承的关系。

打开opencv 3.0的源码:


cvArr


/* CvArr* is used to pass arbitrary
 * array-like data structures
 * into functions where the particular
 * array type is recognized at runtime:
 */
typedef void CvArr;

oh god,它是可变类型的数据


cvMat

再看一下cvMat。



typedef struct CvMat
{
    int type;
    int step;

    /* for internal use only */
    int* refcount;
    int hdr_refcount;

    union
    {
        uchar* ptr;
        short* s;
        int* i;
        float* fl;
        double* db;
    } data;

#ifdef __cplusplus
    union
    {
        int rows;
        int height;
    };

    union
    {
        int cols;
        int width;
    };
#else
    int rows;
    int cols;
#endif


#ifdef __cplusplus
    CvMat() {}
    CvMat(const CvMat& m) { memcpy(this, &m, sizeof(CvMat));}
    CvMat(const cv::Mat& m);
#endif

}
CvMat;


这里先不管C++了,纯c的做法是:


typedef struct CvMat
{
    int type;
    int step;

    /* for internal use only */
    int* refcount;
    int hdr_refcount;

    union
    {
        uchar* ptr;
        short* s;
        int* i;
        float* fl;
        double* db;
    } data;


    int rows;
    int cols;

}
CvMat;

这里,cvMat有几个属性,到底是干什么的呢?

可以看看它的初始化函数:


CV_INLINE CvMat cvMat( int rows, int cols, int type, void* data CV_DEFAULT(NULL))
{
    CvMat m;

    assert( (unsigned)CV_MAT_DEPTH(type) <= CV_64F );
    type = CV_MAT_TYPE(type);
    m.type = CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG | type;
    m.cols = cols;
    m.rows = rows;
    m.step = m.cols*CV_ELEM_SIZE(type);
    m.data.ptr = (uchar*)data;
    m.refcount = NULL;
    m.hdr_refcount = 0;

    return m;
}

微笑看了之后恍然大悟:


type是矩阵中每一个数据点的类型。

cols是矩阵的列数。

rows当然是行数。

step是每一行的数据大小(应该是byte数吧)。

data是一个union的类型,里面是不同类型的指针,这样做的目的应该是可以接收 不同的数据类型吧。

比如你传了一个float*的指针进去,他就是float*了,反正这个联合体的大小就是sizeof(pointer) = 4了


internal use的先不管了。


在其他版本中把rows和height写在union里面的做法应该是做变量的兼容性吧。


IplImage

下面来重点看一下这个结构体:


typedef struct
#ifdef __cplusplus
  CV_EXPORTS
#endif
_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 */

#ifdef __cplusplus
    _IplImage() {}
    _IplImage(const cv::Mat& m);
#endif
}
IplImage;

可以看出来,这个结构体和cvMat很像。

下面通过实际操作来understand一下这个结构体:

#include <cv.h>
#include <highgui.h>

#define u8 unsigned char


void image_operation(IplImage *image)
{
	printf("nchannels:%d\n",image->nChannels);
	printf("depth:%d\n",image->depth);
	/* ./modules/core/include/opencv2/core/types_c.h:
	 *		#define IPL_DATA_ORDER_PIXEL  0 
	 */
	printf("dataOrder:%d\n",image->dataOrder);
	printf("width:%d\n",image->width);
	printf("height:%d\n",image->height);
	printf("origin:%d\n",image->origin);
	printf("widthStep:%d\n",image->widthStep);


	for (int y = 0; y<image->height ; y++) {
		u8* row = (u8*)(image->imageData + y*image->widthStep);
		for(int x = 0; x<image->width; x++) {
			row[3*x + 1] = 0;
			row[3*x + 2] = 0;
		}
	}
}

int main(int argc,char **argv)
{


	printf("this is image transforming plus\n");
        IplImage *image;  
        image = cvLoadImage(argv[1]);  
        if(argc != 2)  
        {  
            std::cout << "No image data\n";  
            return -1;  
        }

	cvNamedWindow("image input");
	cvNamedWindow("image output");
	cvShowImage("image input", image);	
	image_operation(image);
	cvShowImage("image output", image);	
	cvReleaseImage(&image);
	cvWaitKey(0);
	cvDestroyWindow("image input");
	cvDestroyWindow("image output");





	return 0;
}


这里读取一个图像,并且将两个通道变成0,结果如下:

tan@ubuntu:~/cv$ ./TransformImage image/1.jpg 
this is image transforming plus
nchannels:3
depth:8
dataOrder:0
width:400
height:300
origin:0
widthStep:1200




从结果来看,这里把蓝色通道提取了,再次验证一下就可以发现opencv的存储是 BGR 顺序存储的。

重要的一个变量是image->widthStep,因为opencv会把图像数据4字节对齐,每过一行需要加上这个值而不是自己进行处理。



posted @ 2014-10-30 20:39  crazy_thb  阅读(197)  评论(0编辑  收藏  举报