DavRay - 2 months ago 8

C++ Question

Suppose i have a

`vector<Mat>`

`regionFeaMat`

`regionFeaMat.size() == 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);

Answer Source

You seem to have made a few wrong assumptions.

`std::vector`

does store its elements contiguously in memory, but `cv::Mat`

is a header containing a pointer to its internal buffer, so only pointers in `vector<Mat>`

are stored contiguously, not the Mat data itself. Because of that, the memory that lies in between `(float*)regionFeaMat[0].dataend`

and `(float*)regionFeaMat[80].datastart`

is some random garbage - if it does contain other Mat's data partially, it's pure luck.

Because of the above, you can't have a one-liner assigning vector to any other vector and you have to insert each mat separately instead. Try something like this:

```
// 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);
}
}
}
```

Note that I'm checking if a particular Mat object is continuous, because as per OpenCV docs, each row may contain gaps at the end in some cases, and in that case we have to read the matrix row by row.

This code can be simplified, because if matrix is continuous, we may treat it as a 1D vector as per the docs referenced above:

```
// 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);
}
}
```

If you want to prevent vector reallocation in more general cases, you also have to change the method of calculating the number of elements passed to `reserve()`

. The method I use assumes all the Mat objects have only two dimensions that are equal for all the objects since this is how you described your problem.

Also, if you want to assign it to `vector<float>`

, be sure that the element type of `regionFeaMat`

is `CV_32F`

.