問題:
從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()函數,對每一幀圖像鏡像即可。