问题:
从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;
}
View Code
可以看到origin的如何传递的。到这里找到根本原因了。在mat转化iplimage时,因为默认的操作函数默认的origin值为零,也就是以左上角为起点,但是glreadpixel是从左下角读取的。因此出现的翻转。
解决办法就是将默认的操作函数,自己重新一遍,添加origin属性即可。
修改origin属性后,输出的视频仍然存在镜像错误。
利用cvFlip()函数,对每一帧图像镜像即可。