您的位置:首页 > 运维架构

Opencv【7】---IplImage中四字节对其问题

2016-07-29 19:58 387 查看

问题概述

typedef struct _IplImage
{
int  nSize;                 /* IplImage大小,=sizeof(IplImage)*/
int  ID;                    /* 版本 (=0)*/
int  nChannels;             /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */
int  alphaChannel;          /* 被OpenCV忽略 */
int  depth;                 /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,
IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */
char colorModel[4];         /* 被OpenCV忽略 */
char channelSeq[4];         /* 被OpenCV忽略 */
int  dataOrder;             /* 0 - 交叉存取颜色通道,对三通道RGB图像,像素存储顺序为BGR BGR BGR ... BGR;
1 - 分开的颜色通道,对三通道RGB图像,像素存储顺序为RRR...R GGG...G BBB...B。
cvCreateImage只能创建交叉存取图像 */
int  origin;                /* 0 - 顶—左结构,
1 - 底—左结构 (Windows bitmaps 风格) */
int  align;                 /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */
int  width;                 /* 图像宽像素数 */
int  height;                /* 图像高像素数*/
struct _IplROI *roi;        /* 图像感兴趣区域. 当该值非空只对该区域进行处理 */
struct _IplImage *maskROI;  /* 在 OpenCV中必须置NULL */
void  *imageId;             /* 同上*/
struct _IplTileInfo *tileInfo; /*同上*/
int  imageSize;             /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/
char *imageData;            /* 指向排列的图像数据 */
int  widthStep;             /* 排列的图像行大小,以字节为单位 */
int  BorderMode[4];         /* 边际结束模式, 被OpenCV忽略 */
int  BorderConst[4];        /* 同上 */
char *imageDataOrigin;      /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */
}IplImage;


  可以知道IplImage数据结构体中有两个width,一是width属性;二是widthStep属性。前者是表示图像的每行像素数,后者指表示存储一行像素需要的字节数。在OpenCV里边,widthStep必须是4的倍数,从而实现字节对齐,有利于提高运算速度。

  比如有一幅550x733像素的RGB图像(3通道),经过OpenCV中C接口的
cvLoadImage
函数读取进来后,得到的
imageData
不是550*733个像素,这时候产生了四字节对其问题,因为550*3=1650字节,对4取余是不为零的,则会补上两个字节到每行的后面。如果这个时候去用图像的
width
height
以及
imageData
这三个信息去处理图像的话可能会出现意向不到的错误,比如你传入某个函数去处理这张图像数据,每次读取
width
个字节,那么这个时候读完这个图像数据就会产生一个错位了,处理数据也就会出现问题了。

  当然是用C++接口就没有这个问题了,通过Mat类来读取图像,没有四字节对其问题。

class CV_EXPORTS Mat
{
public:
// ... a lot of methods ...
...

/*! includes several bit-fields:
- the magic signature
- continuity flag
- depth
- number of channels
*/
int flags;
//! the array dimensionality, >= 2
int dims;
//! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions
int rows, cols;
//! pointer to the data
uchar* data;

//! pointer to the reference counter;
// when array points to user-allocated data, the pointer is NULL
int* refcount;

// other members
...
};


四字节问题处理

  方式一:将IplImage数据结构转为Mat来操作

Mat newImage(iplImage, true); // 设置为true基于原始图像拷贝一份数据


  方式二:直接将原始数据提取出来

IplImage *image_color = cvLoadImage(argv[1], 1);
if (!image_color) {
fprintf(stderr, "cvLoadImage is failed\n");
return -1;
}

unsigned char * rowData = (unsigned char*)image_color->imageData;

unsigned char *data = (unsigned char *)malloc(image_color->width * image_color->height * 3);

for (int i = 0; i < image_color->height; i++){
memcpy(data + image_color->width * i *3, rowData + image_color->widthStep * i, image_color->width*3);
}

cvReleaseImage(&image_color);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息