首页 > 技术文章 > opencv 视频输出图像颠倒

yishuxue 2013-08-21 13:33 原文

问题:

从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()函数,对每一帧图像镜像即可。

 

推荐阅读