从零开始 OpenCV (二) —— OpenCV 的基本数据类型和基本函数

从零开始 OpenCV (二) —— OpenCV 的基本数据类型和基本函数

注: 本系列博客主要针对 OpenCV 的 C 语言库部分。

OpenCV 的基本数据类型及其相关函数

...\opencv\build\include\opencv2\core\types_c.h 文件中定义了一些基本的数据类型。

坐标点类型: CvPoint

typedef struct CvPoint
{
    int x;
    int y;
}CvPoint;

针对不同的数值类型, CvPoint 还有几个变体类型: CvPoint2D32f, CvPoint2D64f, CvPoint3D32f 以及 CvPoint3D64f

记录矩形宽高的 CvSize 类型

typedef struct CvSize
{
    int width;
    int height;
}CvSize;

CvSize 类型也有变体类型: CvSize2D32f

矩形类型: CvRect

typedef struct CvRect
{
    int x;
    int y;
    int width;
    int height;
}CvRect;

标量(scalar)类型: CvScalar

typedef struct CvScalar
{
    double val[4];
}CvScalar;

以上类型(CvRect, CvScalar等) 都有一个与之匹配的类似于构造函数的功能的函数(具有与结构类型一样的名字, 只是首字母不大写, 如: cvRect())。

矩阵类型: 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;

    int rows;
    int cols;
}CvMat;

其中, type 指定矩阵中存放的元素类型, 其结构为 CV_<bit_depth>(S|U|F)C<number_of_channels>, 如: CV_8UC3 表示该矩阵存放的是无符号的 8 位三元组的整形数据。 data 指向实际存放矩阵的数据体。step 存储行数据的长度(以字节为单位)。

二. CvMat 的创建,释放和克隆

(1) 创建 type 类型, 行数为 rows, 列数为 cols 的矩阵: cvCreateMat

// Creates a matrix header and allocates the matrix data.
CvMat* cvCreateMat(int rows, int cols, int type);

(2) 矩阵 mat 的释放: cvReleaseMat

// Deallocates a matrix.
// The function decrements the matrix data reference counter and deallocates matrix header. 
// If the data reference counter is 0, it also deallocates the data. :
void cvReleaseMat(CvMat** mat);

(3) 矩阵 mat 的克隆: cvCloneMat

// Creates an exact copy of the input matrix.
CvMat* cvCloneMat(const cvMat* mat);

三. 矩阵的存取

(1) CV_MAT_ELEM()CV_MAT_ELEM_PTR()

#define CV_MAT_ELEM_PTR_FAST( mat, row, col, pix_size ) \
    (assert( (unsigned)(row) < (unsigned)(mat).rows &&   \
             (unsigned)(col) < (unsigned)(mat).cols ),   \
     (mat).data.ptr + (size_t)(mat).step*(row) + (pix_size)*(col))

#define CV_MAT_ELEM_PTR( mat, row, col ) \
    CV_MAT_ELEM_PTR_FAST( mat, row, col, CV_ELEM_SIZE((mat).type) )

#define CV_MAT_ELEM( mat, elemtype, row, col ) \
    (*(elemtype*)CV_MAT_ELEM_PTR_FAST( mat, row, col, sizeof(elemtype)))

注: CvMat 中是将数据存在一个一维数组中,具体存储形式如下图:

StorageOfCvMat.png

关于 CV_MAT_ELEM()CV_MAT_ELEM_PTR 举个例子:

CvMat* may = cvCreateMat(5, 5, CV_32FC1);
// 读取 (3,3) 处的一元组
float elem_3_3 = CV_MAT_ELEM(*mat, float, 3, 3); // 将 (3,3) 处的一元组的值改为 33 float* elemPtr_3_3 = (float*)CV_MAT_ELEM_PTR(*mat, 3, 3); (*elemPtr_3_3) = 33;

(2) cvGet*D 函数簇和 cvPtr*D 函数簇

  • cvGet*D函数簇
// This is the "metatype" used only as a function parameter.
// It denotes that the function accepts arrays of multiple types, such as IplImage*, CvMat* or even CvSeq* sometimes.
// The particular array type is determined at runtime by analyzing the first 4 bytes of the header.
// In C++ interface the role of CvArr is played by InputArray and OutputArray.
typedef void CvArr;

// The functions return a specific array element.
// In the case of a sparse array the functions return 0 
// if the requested node does not exist (no new node is created by the functions).
CvScalar cvGet1D (const CvArr* arr, int idx0);
CvScalar cvGet2D (const CvArr* arr, int idx0, int idx1);
CvScalar cvGet3D (const CvArr* arr, int idx0, int idx1, int idx2);
  • cvPtr*D 函数簇
// Return pointer to a particular array element.
// The functions return a pointer to a specific array element.
// Number of array dimension should match to the number of indices passed to the function
// except for cvPtr1D function that can be used for sequential access to 1D, 2D or nD dense arrays.
uchar* cvPtr1D(const CvArr* arr, int idx0, int* type = NULL);
uchar* cvPtr2D(const CvArr* arr, int idx0, int idx1, int* type = NULL);
uchar* cvPtr3D(const CvArr* arr, int idx0, int idx1, int idx2, int* type = NULL);

(3) 直接对 data 指针进行操作。

IplImage 数据结构

一. IplImage 数据结构的定义

/* * The following definitions (until #endif) * is an extract from IPL headers. * Copyright (c) 1995 Intel Corporation. */

#define IPL_DEPTH_SIGN 0x80000000

#define IPL_DEPTH_1U     1
#define IPL_DEPTH_8U     8
#define IPL_DEPTH_16U   16
#define IPL_DEPTH_32F   32

#define IPL_DEPTH_8S  (IPL_DEPTH_SIGN| 8)
#define IPL_DEPTH_16S (IPL_DEPTH_SIGN|16)
#define IPL_DEPTH_32S (IPL_DEPTH_SIGN|32)

#define IPL_DATA_ORDER_PIXEL  0
#define IPL_DATA_ORDER_PLANE  1

#define IPL_ORIGIN_TL 0
#define IPL_ORIGIN_BL 1

#define IPL_ALIGN_4BYTES   4
#define IPL_ALIGN_8BYTES   8
#define IPL_ALIGN_16BYTES 16
#define IPL_ALIGN_32BYTES 32

#define IPL_ALIGN_DWORD   IPL_ALIGN_4BYTES
#define IPL_ALIGN_QWORD   IPL_ALIGN_8BYTES

#define IPL_BORDER_CONSTANT   0
#define IPL_BORDER_REPLICATE  1
#define IPL_BORDER_REFLECT    2
#define IPL_BORDER_WRAP       3

/** The IplImage is taken from the Intel Image Processing Library, in which the format is native. OpenCV only supports a subset of possible IplImage formats, as outlined in the parameter list above. In addition to the above restrictions, OpenCV handles ROIs differently. OpenCV functions require that the image size or ROI size of all source and destination images match exactly. On the other hand, the Intel Image Processing Library processes the area of intersection between the source and destination images (or ROIs), allowing them to vary independently. */
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(Region of Interest). 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;

(1) origin 取值 IPL_ORIGIN_TLIPL_ORIGIN_BL, 分别设置坐标原点的位置为图像的左上角或者左下角
(2) dataOrder 取值 IPL_DATA_ORDER_PIXELIPL_DATA_ORDER_PLANE, 前者指明数据是将像素点的不同通道的值交错在一起, 后者是把所有像素同通道值排在一起m 形成通道平面, 再把平面排列起来。
(3) ROI(Region of Interest): 一旦设置了 ROI, 通常作用于整幅图像的函数便会只对 ROI 所表示的子图像进行操作。 如果 ROICOI(Channel of Interest) 设置为非 0 值, 则只对该对子图像的指定通道上进行操作。

二. 加载图像: cvLoadImage

IplImage* cvLoadImage(const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR);

三. 展示图像: cvShowImage

/* display image within window (highgui windows remember their content) */
void cvShowImage(const char* name, const CvArr* image);

四. 设置和释放 ROI:cvSetImageROIcvResetImageROI

// Sets an image Region Of Interest (ROI) for a given rectangle.
// If the original image ROI was NULL and the rect is not the whole image,
//  the ROI structure is allocated.
// image: A pointer to the image header
// rect: The ROI rectangle
void cvSetImageROI(IplImage* image, CvRect rect);

// Resets the image ROI to include the entire image and releases the ROI structure.
void cvResetImageROI(IplImage* image);

五. 举个例子: 将 src 的指定 ROI 的像素点减去指定的 cvScalar

#include "opencv/highgui.h"
#include "opencv/cv.h"

int main()
{
    // load image from file
    IplImage* src = cvLoadImage("C:\\Users\\yanglion\\Pictures\\Img\\Ali.jpg");

    // 
    // set image's ROI
    cvSetImageROI(src, cvRect(216, 123, 100, 70));
    // dst(mask) = src(mask) - value = src(mask) + (-value)
    cvSubS(src, cvScalar(50,50,100), src);
    // Resets the image ROI to include the entire image and releases the ROI structure.
    cvResetImageROI(src);

    // create window
    cvNamedWindow("Ali");
    // display image within window (highgui windows remember their content)
    cvShowImage("Ali", src);
    // wait for key event infinitely (delay<=0) or for "delay" milliseconds
    cvWaitKey();

    return 0;
}

运行效果:

全部评论

相关推荐

有工作后先养猫:太好了,是超时空战警,我们有救了😋
点赞 评论 收藏
分享
Yushuu:你的确很厉害,但是有一个小问题:谁问你了?我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了😆
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务