OpenCV图像大小限制

时间:2018-07-24 07:56:35

标签: c++ opencv

我正在尝试使用ITK到openCV Bridge在openCV和itk之间传递巨大的Mat图像(98304x51968)。我有一个错误:

cvIniyImageHeader中的内存不足(图像大小溢出),文件opencv \ modules \ core \ src \ array.cpp第2961行。

这是否意味着opencv对图像大小有限制?

谢谢。

2 个答案:

答案 0 :(得分:2)

IplImage中似乎有一个有符号的int(通常为32位)限制: 在命名的.cpp文件中,这是导致错误的代码段:

const int64 imageSize_tmp = (int64)image->widthStep*(int64)image->height;
image->imageSize = (int)imageSize_tmp;
if( (int64)image->imageSize != imageSize_tmp )
    CV_Error( CV_StsNoMem, "Overflow for imageSize" );

看起来(未经检查)image->imageSize是一个32位带符号的int,这部分代码将检测并处理溢出。根据您在评论中发布的链接,IplImage“错误”可能已得到修复(我没有检查),因此也许您可以在OpenCV代码中删除此溢出检测步骤以获取较新的IplImage版本,但这只是一个猜测,必须确认。您必须检查image->imageSize的类型。如果是64位类型,则可以更改openCV代码以支持大于2147483647字节的Mats。

编辑:备注:我检查了OpenCV 3.4中的代码,但是代码行是正确的,因此在4.0版本中可能还没有更改。

如果您确定IplImage限制已得到修复,则可以尝试以下操作:

const int64 imageSize_tmp = (int64)image->widthStep*(int64)image->height;
image->imageSize = imageSize_tmp; // imageSize isn't 32 bit signed int anymore!
//if( (int64)image->imageSize != imageSize_tmp ) // no overflow detection necessary anymore
//    CV_Error( CV_StsNoMem, "Overflow for imageSize" ); // no overflow detection necessary anymore

但最好确保IplImage的imageSize现在为64位;)

更新:https://github.com/opencv/opencv/pull/7507/commits/a89aa8c90a625c78e40f4288d145996d9cda3599中的链接修复程序添加了溢出检测功能,因此PROBBLY IplImage仍然具有32位int imageSize限制!这里要小心!

答案 1 :(得分:0)

好消息,由于请求请求为handle huge matrices correctly #11505,因此您应该可以执行以下操作(从测试中获取代码):

Mat m(65000, 40000, CV_8U);
ASSERT_FALSE(m.isContinuous());

uint64 i, n = (uint64)m.rows*m.cols;
for( i = 0; i < n; i++ )
    m.data[i] = (uchar)(i & 255);

cv::threshold(m, m, 127, 255, cv::THRESH_BINARY);
int nz = cv::countNonZero(m);  // FIXIT 'int' is not enough here (overflow is possible with other inputs)
ASSERT_EQ((uint64)nz, n / 2);

由于countNonZero()返回int,所以可能发生溢出。这意味着您应该能够创建巨大的矩阵,但并非所有的OpenCV函数都能正确处理巨大的矩阵。


关于您的问题,这是v5.0a02ITKImageToCVMat的代码:

template<typename TInputImageType>
cv::Mat
OpenCVImageBridge::ITKImageToCVMat(const TInputImageType* in, bool force3Channels)
{
  // Extra copy, but necessary to prevent memory leaks
  IplImage* temp = ITKImageToIplImage<TInputImageType>(in, force3Channels);
  cv::Mat out = cv::cvarrToMat( temp, true );
  cvReleaseImage(&temp);
  return out;
}

如您所见,IplImage图片仍在使用,应该是错误的根源。 当前最好的选择是自己进行转换。也许有点像(我不知道ITK,相同的输入和输出类型,一个通道):

typename ImageType::RegionType  region = in->GetLargestPossibleRegion();
typename ImageType::SizeType    size = region.GetSize();
unsigned int w = static_cast< unsigned int >( size[0] );
unsigned int h = static_cast< unsigned int >( size[1] );
Mat m(h, w, CV_8UC1, in->GetBufferPointer());

此处不涉及副本。如果要复制,可以执行以下操作:

Mat m_copy = m.clone();