问题:
从opengl的渲染环境中获取影像data数据,然后create一个mat,mat转化为iplimage,然后保存至视频文件,打开后发现视频文件颠倒。
网上搜集原因:
使用opencv显示图像时会出现图像倒立的情况,IplImage的origin属性有关系。
origin为0表示顶左结构,即图像的原点是左上角,
如果为1为左下角。
一般从硬盘读入的图片或者通过cvCreateImage方法创建的IplImage图片默认的origin为0,即显示的时候都是正的。
而由摄像头或者视频文件获取的帧图像origin为1,此时显示的时候扫描顺序是从下到上,显示也是正的
(opencv显示的时候是根据origin的值显示的,如果origin=1,则从下到上显示,否则反之)。
但是如果你自己创建了一个IplImage格式的图像img,且从帧图像中copy或者截取一部分区域进行显示的时候就会出现倒立情况。
这是因为cvCreateImage方法得到的img的origin是0,而帧图像的origin为1,
它会将帧图像的第i行赋值给img的第height-i行,因此就出现了倒立.解决办法是:在创建之后将origin调整为与帧图像的origin一致即可。
解决办法:
应该在ilpimage的属性中修改origin为1。mat到iplimage的转化时候:只是创建图像头,而没有复制数据。
例: // 假设Mat类型的imgMat图像数据存在
IplImage pImg= IplImage(imgMat);
此时修改文件头,那什么时候复制数据呢?
查看opencv源码
Mat::operator IplImage() const { CV_Assert( dims <= 2 ); IplImage img; cvInitImageHeader(&img, size(), cvIplDepth(flags), channels()); cvSetData(&img, data, (int)step[0]); return img; }
在初始化信息头函数中:

cvInitImageHeader( IplImage * image, CvSize size, int depth, int channels, int origin, int align ) { const char *colorModel, *channelSeq; if( !image ) CV_Error( CV_HeaderIsNull, "null pointer to header" ); memset( image, 0, sizeof( *image )); image->nSize = sizeof( *image ); icvGetColorModel( channels, &colorModel, &channelSeq ); strncpy( image->colorModel, colorModel, 4 ); strncpy( image->channelSeq, channelSeq, 4 ); if( size.width < 0 || size.height < 0 ) CV_Error( CV_BadROISize, "Bad input roi" ); if( (depth != (int)IPL_DEPTH_1U && depth != (int)IPL_DEPTH_8U && depth != (int)IPL_DEPTH_8S && depth != (int)IPL_DEPTH_16U && depth != (int)IPL_DEPTH_16S && depth != (int)IPL_DEPTH_32S && depth != (int)IPL_DEPTH_32F && depth != (int)IPL_DEPTH_64F) || channels < 0 ) CV_Error( CV_BadDepth, "Unsupported format" ); if( origin != CV_ORIGIN_BL && origin != CV_ORIGIN_TL ) CV_Error( CV_BadOrigin, "Bad input origin" ); if( align != 4 && align != 8 ) CV_Error( CV_BadAlign, "Bad input align" ); image->width = size.width; image->height = size.height; if( image->roi ) { image->roi->coi = 0; image->roi->xOffset = image->roi->yOffset = 0; image->roi->width = size.width; image->roi->height = size.height; } image->nChannels = MAX( channels, 1 ); image->depth = depth; image->align = align; image->widthStep = (((image->width * image->nChannels * (image->depth & ~IPL_DEPTH_SIGN) + 7)/8)+ align - 1) & (~(align - 1)); image->origin = origin; image->imageSize = image->widthStep * image->height; return image; }
可以看到origin的如何传递的。到这里找到根本原因了。在mat转化iplimage时,因为默认的操作函数默认的origin值为零,也就是以左上角为起点,但是glreadpixel是从左下角读取的。因此出现的翻转。
解决办法就是将默认的操作函数,自己重新一遍,添加origin属性即可。
修改origin属性后,输出的视频仍然存在镜像错误。
利用cvFlip()函数,对每一帧图像镜像即可。