文章来源:点击打开链接
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的数据长度。