假设我有vector<Mat>
名为regionFeaMat
和regionFeaMat.size() == 81
。换句话说,regionFeaMat有81个相等大小的矩阵,regionFeaMat[0].rows==256
和regionFeaMat[0].cols==1
。我想将reginFeaMat
转换为vector<float> reginFeaVec
。我尝试使用以下代码,但结果出错:
vector<float> regionFeaVec;
regionFeaVec.assign((float*)regionFeaMat[0].datastart, (float*)regionFeaMat[80].dataend);
答案 0 :(得分:1)
你似乎做了一些错误的假设。
std::vector
会将其元素连续存储在内存中,但cv::Mat
是一个包含指向其内部缓冲区的指针的标头,因此只有vector<Mat>
中的指针是连续存储的,而不是Mat数据本身。因此,位于(float*)regionFeaMat[0].dataend
和(float*)regionFeaMat[80].datastart
之间的内存是一些随机垃圾 - 如果它确实包含其他Mat的数据,那就是纯粹的运气。
由于上述原因,您不能将矢量分配给任何其他矢量,您必须分别插入每个垫子。尝试这样的事情:
// prevent vector reallocation after each Mat insertion:
regionFeaVec.reserve(regionFeaMat.size()*regionFeaMat[0].cols*regionFeaMat[0].rows);
for (int i = 0; i < regionFeaMat.size(); ++i)
{
if (regionFeaMat[i].isContinuous())
regionFeaVec.insert(
regionFeaVec.end(),
(float*)regionFeaMat[i].datastart,
(float*)regionFeaMat[i].dataend
);
else
{
for (int j = 0; j < regionFeaMat[i].rows; ++j)
{
const float* row = regionFeaMat[i].ptr<float>(j);
regionFeaVec.insert(regionFeaVec.end(), row, row + regionFeaMat[i].cols);
}
}
}
请注意,我正在检查特定的Mat对象是否是连续的,因为根据OpenCV docs,在某些情况下,每行可能在末尾包含间隙,在这种情况下,我们必须通过以下方式读取矩阵行:行。
这段代码可以简化,因为如果矩阵是连续的,我们可以按照上面引用的文档将其视为一维向量:
// prevent vector reallocation after each Mat insertion:
regionFeaVec.reserve(regionFeaMat.size()*regionFeaMat[0].cols*regionFeaMat[0].rows);
for (int i = 0; i < regionFeaMat.size(); ++i)
{
cv::Size size = regionFeaMat[i].size();
if (regionFeaMat[i].isContinuous())
{
size.width *= size.height;
size.height = 1;
}
for (int j = 0; j < size.height; ++j)
{
const float* row = regionFeaMat[i].ptr<float>(j);
regionFeaVec.insert(regionFeaVec.end(), row, row + size.width);
}
}
如果要在更一般的情况下阻止向量重新分配,还必须更改计算传递给reserve()
的元素数量的方法。我使用的方法假设所有Mat对象只有两个对所有对象都相同的维度,因为这就是你描述问题的方式。
另外,如果您要将其分配给vector<float>
,请确保regionFeaMat
的元素类型为CV_32F
。