OpenCV-------Iplimage结构详解

文章来源:点击打开链接

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
depth变量:像素的深度。深度值有:

#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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

通俗一点讲就是像素的取值大小,例如:IPL_DEPTH_8U 即代表有8位数据,最大值256,即一个像素的颜色等级分为256种。从0到256不断加深。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

nChannels变量:图像通道(通道的概念之前有介绍)。
彩色图像的排列方式:
彩色图像一般是由3通道表示。3通道表示一个像素点有三个值,分别对应R,G,B.RGB决定该像素点的颜色。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
一下其他的重要参数:
imageData 包含一个指向第一行图像数据的指针。
widthStep是指一个排列图像行的大小,以字节为单位。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

访问图像数据

实例:分别打印一个彩色图像和R,G,B三个单通道的图像

int main()
{
    IplImage* img;
    img = cvLoadImage("F:\\Opencv\\素材\\楪析.jpg");
    IplImage* b_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
    IplImage* g_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
    IplImage* r_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
    int x, y;
    for (y = 0; y < img->height; y++)
    {
        unsigned char* prow = (unsigned char*)(img->imageData + y*img->widthStep);
        unsigned char* brow = (unsigned char*)(b_img->imageData + y*b_img->widthStep);
        unsigned char* grow = (unsigned char*)(g_img->imageData + y*g_img->widthStep);
        unsigned char* rrow = (unsigned char*)(r_img->imageData + y*r_img->widthStep);

        for (x = 0; x < img->width; x++)
        {
            brow[x] = prow[3 * x + 0];
            grow[x] = prow[3 * x + 1];
            rrow[x] = prow[3 * x + 2];
        }
    }

    cvNamedWindow("1");
    cvShowImage("1", img);

    cvNamedWindow("b");
    cvShowImage("b", b_img);

    cvNamedWindow("r");
    cvShowImage("r", r_img);

    cvNamedWindow("g");
    cvShowImage("g", g_img);

    cvWaitKey(0);
    return 0;


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

对ROI和widthStep的补充

ROI全称:region of interest,即:感兴趣的区域。使用ROI可以对图像的部分区域进行操作而不是对图像额整个区域进行运算,可以提高计算机视觉代码的执行速度。
例:用imageROI来增加某范围的像素。

int main()
{
    IplImage* img;
    img = cvLoadImage("F:\\Opencv\\素材\\楪析.jpg");
    CvRect rect;
    rect.x = 350;
    rect.y = 102;
    rect.width = 166;
    rect.height = 141;
    cvSetImageROI(img, rect);

    cvAddS(img, cvScalar(150), img);

    cvResetImageROI(img);
    cvNamedWindow("1");
    cvShowImage("1", img);

    cvWaitKey(0);

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

介绍几个主要函数:
cvSetImageROI()和cvResetImageROI()这两个函数用来设置和取消ROI,
void cvSetImageROI(IplImage* image,CvRect rect);
需要传递一个图像指针和矩阵,这个矩阵

typedef struct CvRect
{
    int x;
    int y;
    int width;
    int height;
}
CvRect;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

x,y是ROI图像起始点的坐标,width和height是ROI图像的宽度和高度。
图像指针是指我们选取ROI区域的母图像。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

我们可以使用widthStep达到同样的效果,
首先我们要创建一个CvRect结构体,设置图像起点和大小。
然后创建一个图像头,让它的width和height和之前创建CvRect结构体的width和height相同,并且让它的通道和像素深度与母图像的相同。
在使图像头的origin(起点)和widthStep(步长)和母图像相同,
可以理解为创建一个大小与母图像相等CvRect结构体指定的图像区域有颜色,其他地方是透明的图像覆盖在母图像上面。例程如下:

int main()
{
    IplImage* interest_img = cvLoadImage("F:\\Opencv\\素材\\楪析.jpg");
    CvRect interest_rect = cvRect(350, 102, 166, 141);
    IplImage* sub_img = cvCreateImageHeader
        (
        cvSize(interest_rect.width, interest_rect.height),
        interest_img->depth,
        interest_img->nChannels
        );
    sub_img->origin = interest_img->origin;
    sub_img->widthStep = interest_img->widthStep;
    sub_img->imageData = interest_img->imageData + 
        interest_img->widthStep*interest_rect.y +
        interest_img->nChannels*interest_rect.x;
    cvAddS(sub_img, cvScalar(150), sub_img);

    cvNamedWindow("interest_img");
    cvNamedWindow("sub_img");
    cvShowImage("interest_img", interest_img);
    cvShowImage("sub_img", sub_img);
    cvResetImageROI(sub_img);
    cvWaitKey(0);
    cvDestroyWindow("interest_img");
    cvDestroyWindow("sub_img");
    interest_img = NULL;
    sub_img = NULL;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

看起来设置和重置ROI更方便一些,为什么还要使用widthStep?原因在于有些时候在处理的过程中,想在操作过程中设置和保持一幅图像的多个子区域处于活动状态,但是ROI只能串行处理并且必须不断地设置和重置。

widthStep与width*nChannels是否相等:

其中IPL_DEPTH_SIGN是0x800000000,align大小为CV_DEFAULT_IMAGE_ROW_ALIGN,定义为4,由此可见当图像为3*5,通道为3通道时,widthStep为12;同时经过分析可以知道事实上是widht*nChannels按4整数倍内存对齐的结果。
如宽度为3、通道数为3的图像,每一行需要的实际内存长度为3*3,为了内存对齐,OpenCV会在每行末尾自动补上3个字节的内存,内存初始化都为0,所以widthStep变为了12。
widthStep大小对IplImage极为重要,在array.cpp中,我们可以找到如下代码行:
image->imageSize = image->widthStep * image->height;
img->imageData = img->imageDataOrigin =
(char*)cvAlloc( (size_t)img->imageSize );
可见widthStep直接影响到imageData的数据长度。

阅读更多

没有更多推荐了,返回首页