Create 2D vector from 2 1D vectors - c++

I am fairly new to vectors and I'm trying to populate a 2D vector from 2 1D vectors for coordinate points. I have 2 vectors like this where source_x and source_y contains values from a file:
std::vector<float,T<float>> pos_x(5);
std::vector<float,T<float>> pos_y(5);
for (int i = 0; i < 5 ; i++){
pos_x[i] = i+1; //{1,2,3,4,5}
}
for (int i = 0; i < num ; i++){
pos_y[i] = i+1 ; //{1,2,3,4,5}
}
I created my 2D vector like this:
std::vector<std::vector<float, T<float>>> position;
for (int i = 0; i < num ; i++){
for (int j = 0; j < num ; i++){
//Output expected: {{1,2,3,4,5},{1,2,3,4,5}}
position[i][j] = //I'm confuse here
}
}
I am not certain how to populate pos_x to position[i] and pos_y to position[j].
Thank you

So my guess is this
std::vector<std::vector<float>> position(num, std::vector<float>(2));
for (int i = 0; i < num ; i++){
position[i][0] = pos_x[i];
position[i][1] = pos_y[i];
}
But I could easily be wrong.
UPDATE based on the example in the question I now think this is the correct code
std::vector<std::vector<float>> position(2, std::vector<float>(num));
for (int i = 0; i < num ; i++){
position[0][i] = pos_x[i];
position[1][i] = pos_y[i];
}

There's no such thing as a 2D vector. The truth is that you can create a vector that contains vectors. The first vector is used as an index in the collected vectors.
Note that this concept is similar to a 2D array: arr[3][4] means 3 indices, each one points to 4 data.
To create such 2D vector:
std::vector< std::vector <float>> positions.
Notice I didn't use the second parameter (as in std::vector<float, SomeAllocator> because we don't need this custom memory allocator.
Also notice that, contrary to arrays, I did't tell anything about the sizes of each vector, because the std::vector will take care of it.
Let's populate it.
The "main" vector contains vectors. So these secondary vectors may be created before stored in the "main" one.
std::vector<float> v1; //secondary
positions.push_back(v1); //add it to main vector
Put some values in the secondary:
v1.push_back(7.5);
v1.push_back(-3.1);
Another way is to access through the main vector. If we new this main vector contains v1 in its first index:
positions[0].push_back(8.); // same as v1.push_back(8.) if positions[0] refers to v1
or better using "at": positions.at(0).push_back(8.);
Change some value:
v1.at(1) = 66.88;
or
positions[0].at(1) = 66.88;
You can also do v1[1] = 66.88 but prefer the at() methof because it will check that index "1" is allowed by the size of the vector v1.
You can create and add another secondary vector:
std::vector<float> v2; //secondary
positions.push_back(v2); //add it to main vector
and work with it the same as with previous v1. Now, positions[1] refers to v2
I leave the rest of pulling from other vectors to you.

Related

C++ : Create 3D array out of stacking 2D arrays

In Python I normally use functions like vstack, stack, etc to easily create a 3D array by stacking 2D arrays one onto another.
Is there any way to do this in C++?
In particular, I have loaded a image into a Mat variable with OpenCV like:
cv::Mat im = cv::imread("image.png", 0);
I would like to make a 3D array/Mat of N layers by stacking copies of that Mat variable.
EDIT: This new 3D matrix has to be "travellable" by adding an integer to any of its components, such that if I am in the position (x1,y1,1) and I add +1 to the last component, I arrive to (x1,y1,2). Similarly for any of the coordinates/components of the 3D matrix.
SOLVED: Both answers from #Aram and #Nejc do exactly what expected. I set #Nejc 's answer as the correct one for his shorter code.
The Numpy function vstack returns a contiguous array. Any C++ solution that produces vectors or arrays of cv::Mat objects does not reflect the behaviour of vstack in this regard, becase separate "layers" belonging to individual cv::Mat objects will not be stored in contiguous buffer (unless a careful allocation of underlying buffers is done in advance of course).
I present the solution that copies all arrays into a three-dimensional cv::Mat object with a contiguous buffer. As far as the idea goes, this answer is similar to Aram's answer. But instead of assigning pixel values one by one, I take advantage of OpenCV functions. At the beginning I allocate the matrix which has a size N X ROWS X COLS, where N is the number of 2D images I want to "stack" and ROWS x COLS are dimensions of each of these images.
Then I make N steps. On every step, I obtain the pointer to the location of the first element along the "outer" dimension. I pass that pointer to the constructor of temporary Mat object that acts as a kind of wrapper around the memory chunk of size ROWS x COLS (but no copies are made) that begins at the address that is pointed-at by pointer. I then use copyTo method to copy i-th image into that memory chunk. Code for N = 2:
cv::Mat img0 = cv::imread("image0.png", CV_IMREAD_GRAYSCALE);
cv::Mat img1 = cv::imread("image1.png", CV_IMREAD_GRAYSCALE);
cv::Mat images[2] = {img0, img1}; // you can also use vector or some other container
int dims[3] = { 2, img0.rows, img0.cols }; // dimensions of new image
cv::Mat joined(3, dims, CV_8U); // same element type (CV_8U) as input images
for(int i = 0; i < 2; ++i)
{
uint8_t* ptr = &joined.at<uint8_t>(i, 0, 0); // pointer to first element of slice i
cv::Mat destination(img0.rows, img0.cols, CV_8U, (void*)ptr); // no data copy, see documentation
images[i].copyTo(destination);
}
This answer is in response to the question above of:
In Python I normally use functions like vstack, stack, etc to easily create a 3D array by stacking 2D arrays one onto another.
This is certainly possible, you can add matrices into a vector which would be your "stack"
For instance you could use a
std::vector<cv::Mat>>
This would give you a vector of mats, which would be one slice, and then you could "layer" those by adding more slices vector
If you then want to have multiple stacks you can add that vector into another vector:
std::vector<std::vector<cv::Mat>>
To add matrix to an array you do:
myVector.push_back(matrix);
Edit for question below
In such case, could I travel from one position (x1, y1, z1) to an immediately upper position doing (x1,y1,z1+1), such that my new position in the matrix would be (x1,y1,z2)?
You'll end up with something that looks a lot like this. If you have a matrix at element 1 in your vector, it doesn't really have any relationship to the element[2] except for the fact that you have added it into that point. If you want to build relationships then you will need to code that in yourself.
You can actually create a 3D or ND mat with opencv, you need to use the constructor that takes the dimensions as input. Then copy each matrix into (this case) the 3D array
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main() {
// Dimensions for the constructor... set dims[0..2] to what you want
int dims[] = {5, 5, 5}; // 5x5x5 3d mat
Mat m = Mat::zeros(5, 5, CV_8UC1);
for (size_t i = 0; i < 5; i++) {
for (size_t k = 0; k < 5; k++) {
m.at<uchar>(i, k) = i + k;
}
}
// Mat with constructor specifying 3 dimensions with dimensions sizes in dims.
Mat 3DMat = Mat(3, dims, CV_8UC1);
// We fill our 3d mat.
for (size_t i = 0; i < m2.size[0]; i++) {
for (size_t k = 0; k < m2.size[1]; k++) {
for (size_t j = 0; j < m2.size[2]; j++) {
3DMat.at<uchar>(i, k, j) = m.at<uchar>(k, j);
}
}
}
// We print it to show the 5x5x5 array.
for (size_t i = 0; i < m2.size[0]; i++) {
for (size_t k = 0; k < m2.size[1]; k++) {
for (size_t j = 0; j < m2.size[2]; j++) {
std::cout << (int) 3DMat.at<uchar>(i, k, j) << " ";
}
std::cout << endl;
}
std::cout << endl;
}
return 0;
}
Based on the question and comments, I think you are looking for something like this:
std::vector<cv::Mat> vec_im;
//In side for loop:
vec_im.push_back(im);
Then, you can access it by:
Scalar intensity_1 = vec_im[z1].at<uchar>(y, x);
Scalar intensity_2 = vec_im[z2].at<uchar>(y, x);
This assumes that the image is single channel.

How to convert vector<Mat> to vector<float>?

Suppose i have a vector<Mat> called regionFeaMatand regionFeaMat.size() == 81 .In other words, regionFeaMat have 81 equal size matrix, and regionFeaMat[0].rows==256 and regionFeaMat[0].cols==1. I want to convert reginFeaMat to vector<float> reginFeaVec. I tried with following code but i got wrong result:
vector<float> regionFeaVec;
regionFeaVec.assign((float*)regionFeaMat[0].datastart, (float*)regionFeaMat[80].dataend);
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.

Copy y-components of a vector

I want to copy the y-components of a vector of the type: std::vector <glm::vec3> example because I can't access only the y-components of this vector by doing something like example.size().y.... So, I assume I have to copy the content of the y-components to another another vector/array, but is there a way to do that? I was thinking of something like:
std::vector <int> something;
for (int i = 0; i < example.size(); i++)
{
something[i] = example[i].y;
}
but it doesn't work apparently.
Thanks!
You need to make sure the size of the vector grows along with the elements you push into them. The [] operator is only an accessor.
std::vector <int> something;
something.resize(example.size());
for (int i = 0; i < example.size(); i++)
{
something[i] = example[i].y;
}
std::vector <int> something;
for (int i = 0; i < example.size(); i++)
{
something[i] = example[i].y;
}
Two issues:
glm::vec3 is a floating-point type, and example[i].y is going to return a floating point value. And if these are normalized model vertices, they're very likely all in the range [-1,1], which means that something[i] would always be assigned -1, 0, or 1.
something never has its memory initialized in the code snippet you're providing. That will cause runtime crashes. You should be writing something like
std::vector<float> something(example.size());

How to initialize an empty global vector in C++

I have a general question. Hopefully, one of you has a good approach to solve my problem. How can I initialize an empty vector?
As far as I read, one has to know the size of an array at compiling time, though for vectors it is different. Vectors are stored in the heap (e.g. here: std::vector versus std::array in C++)
In my program I want to let the client decide how accurate interpolation is going to be done. That's why I want to use vectors.
The problem is: For reasons of clear arrangement I want to write two methods:
one method for calculating the coefficients of an vector and
one method which is providing the coefficients to other functions.
Thus, I want to declare my vector as global and empty like
vector<vector<double>> vector1;
vector<vector<double>> vector2;
However, in the method where I determine the coefficients I cannot use
//vector containing coefficients for interpolation
/*vector<vector<double>>*/ vector1 (4, vector<double>(nn - 1));
for (int ii = 0; ii < nn - 1; ii++) {vector1[ii][0] = ...;
}
"nn" will be given by the client when running the program. So my question is how can I initialize an empty vector? Any ideas are appreciated!
Note please, if I call another function which by its definition gives back a vector as a return value I can write
vector2= OneClass.OneMethod(SomeInputVector);
where OneClass is an object of a class and OneMethod is a method in the class OneClass.
Note also, when I remove the comment /**/ in front of the vector, it is not global any more and throws me an error when trying to get access to the coefficients.
Use resize:
vector1.resize(4, vector<double>(nn - 1));
Use resize() function as follows:
vector<vector<double>> v;
int f(int nn){
v.resize(4);
for(int i = 0; i < 4; i++){
v[i].resize(nn - 1);
}
}
It look to me that you're actually asking how to add items to your global vector. If so this might help:
//vector containing coefficients for interpolation
for (int i = 0; i < 4; ++i)
vector1.push_back(vector<double>(nn - 1));
for (int ii = 0; ii < nn - 1; ii++)
{
vector1[ii][0] = ...;
}
Unsure if it is what you want, but assign could be interesting :
vector<vector<double>> vector1; // initialises an empty vector
// later in the code :
vector<double> v(nn -1, 0.); // creates a local vector of size 100 initialized with 0.
vector1.assign(4, v); // vector1 is now a vector of 4 vectors of 100 double (currently all 0.)

C++ Using 3D Dynamic Arrays and Vectors

I'm new to C++ and getting a bit frustrated with it. Below, in pixelsVector, I am storing each pixel RGB float-value in Pixel and want to dump
all the values to a byte array with pixelsArray so I can output to an image file. HEIGHT and WIDTH refer to the image dimensions. The code below works fine, but I need to specify
the sizes of pixelsArray at run-time, because it may not always be a 500x500 image.
// WIDTH and HEIGHT specified at run-time
vector<vector<Pixel>> pixelsVector (WIDTH, vector<Pixel> (HEIGHT));
...
unsigned char pixelsArray[500][500][3];
for (int i = 0; i < 500; i++)
{
for (int j = 0; j < 500; j++)
{
// Returns RGB components
vector<float> pixelColors = pixelArray[i][j].getColor();
for (int k = 0; k < 3; k++)
{
pixels[i][j][k] = pixelColors.at(k);
}
}
}
// write to image file
fwrite(pixelsArray, 1, 500*500*3, file);
If I put HEIGHT and WIDTH instead of 500 and 500 above, I get an error since they are not constant values. Now using a 3D vector does seem to work, but fwrite won't take a vector for its first argument. I tried using a triple-pointer array but
it doesn't seem to work at all - maybe I was using it wrong. Here it is using a 3D vector for pixelsArray:
vector<vector<Pixel>> pixelsVector (WIDTH, vector<Pixel> (HEIGHT));
...
vector< vector< vector<unsigned char> > > pixelsArray;
for (int i = 0; i < HEIGHT; i++)
{
pixels.push_back(vector< vector<unsigned char> >());
for (int j = 0; j < WIDTH; j++)
{
pixels[i].push_back(vector<unsigned char>());
vector<float> pixelColors;
pixelColors = pixelArray[i][j].getColor();
for (int k = 0; k < 3; k++)
{
pixels[i][j][k] = pixelColors.at(k);
}
}
}
// Error
fwrite(pixelsArray, 1, 500*500*3, file);
Suggestions?
You could use Boost.MultiArray insead of vectors of vectors, which lets you access he underlying memory with the .data() method.
It looks like you are trying to manipulate images, so you might want to consider using Boost.Gil.
From the last code snippet:
vector<vector<Pixel>> pixelsVector (WIDTH, vector<Pixel> (HEIGHT));
Using uppercase names for variables you risk name collisions with macros. In C++ all uppercase names are conventionally reserved for macros.
...
vector< vector< vector<unsigned char> > > pixelsArray;
Presumably this vector is the same as is called pixels below?
If so, then the standard advice is that it helps to post real code.
Anyway, in order to output those bytes in one efficient operation you need the bytes to be contiguously stored in memory. So a vector of vectors of vectors is out. Use a single vector (C++ guarantees contiguous storage for the buffer of a std::vector).
for (int i = 0; i < HEIGHT; i++)
{
pixels.push_back(vector< vector<unsigned char> >());
for (int j = 0; j < WIDTH; j++)
{
pixels[i].push_back(vector<unsigned char>());
At this point you have an inner vector but it's empty, size 0.
vector<float> pixelColors;
pixelColors = pixelArray[i][j].getColor();
Presumably pixelArray is an instance of a class you have defined?
for (int k = 0; k < 3; k++)
{
pixels[i][j][k] = pixelColors.at(k);
}
Here you're trying to assign to non-existent elements of the empty innermost vector. You can either size it properly in advance, or use the push_back method for each value.
In addition, are you sure that the float values are integers in range 0 through 255 (or more generally, 0 through UCHAR_MAX) and not, say, in the range 0 through 1?
Perhaps you need to scale those values.
}
}
// Error
fwrite(pixelsArray, 1, 500*500*3, file);
If pixelsArray had been a (non-empty) vector of bytes, then you could use &pixelsArray[0] to obtain a pointer to the first byte.
Now, I know, the above only dissects some of what's wrong, and doesn't tell you directly what's right. :-)
But some more information would be needed to give example code for doing this, like (1) what are your float values, and (2) what do you want in your file?
Anyway, hope this helps,
– Alf