Trouble writing to 4D vector in C++ (no viable overloaded '=') - c++

The issue I am facing is that via the openCV library I am reading in a series of images as their own "Mat" format: an image matrix.
Basically I need to write any pixel value that's > 0 as "true" to a 4D vector and any that == 0 as "false".
Why 4 dimensions?
vector<vector<vector<bool>>>pointVector;
The 3 vector levels refer to X,Y,Z axes. Bool is just the true/false. The images are Y by Z and are stacked in 3D along axis X.
Basically we have a series of images representing points that are stacked in 3D.
(Poor explanation? Probably)
Anyway, the issue comes in my function to read the points in a single photo then write them out to the 4D vector.
Note: xVal is a global storing the ID number of the photo addressed. It's used for the X dimension (layers of images).
Int lineTo3DVector (Mat image)
{
// Takes in matrix and converts to 4D vector.
// This will be exported and all vectors added together into a point cloud
vector<vector<vector<bool>>>pointVector;
for (int x=0; x<image.rows; x++)
{
for (int y = 0; y<image.cols; y++)
{
if((image.at<int>(x,y)) > 0)
{
pointVector[xVal*image.cols*image.rows + x*image.cols + y] = true;
}
}
}
}
I haven't finished writing all of the function because the if statement intended to write pointVector at address xVal, x, y with bool 'true' throws up an error saying:
No viable overloaded '='
Any idea what's going wrong? I've scoured the web and given myself a headache trying to dig up info (yeah, noob in the deep-end again) so any suggestions would be appreciated.

You're accessing only the first vector (the outer one), without actually accessing any of the vectors inside.
The syntax would be pointVector[x][y][z] = true, where x, y and z are the values you want to use to access the three nested vectors.
What you want is:
pointVector[xVal][x][y] = true
What you were using is a way to access a 3D array that is laid out in memory as a 1D array, but it's not what you want in your case.
Make sure you don't go out of bounds
Make sure the elements you are accessing actually exist! If the code you have shown is the actual code, pointVector will have no elements when you try to use it.
To fix that, you have to resize all the vectors (outer and inner). This can get cumbersome, and you may want to go with the 1D approach, i.e. allocate a large, one-dimensional bool array and access it using the method you were using (largeArray[xVal*image.cols*image.rows + x*image.cols + y]).
1D approach
In the following code numberOfValues is the maximum number of elements you will access.
int lineTo3DVector (Mat image)
{
// Takes in matrix and converts to 4D vector.
// This will be exported and all vectors added together into a point cloud
std::vector<bool> pointVector;
pointVector.resize(numberOfValues);
for (int x=0; x < image.rows; x++)
{
for (int y = 0; y < image.cols; y++)
{
if(image.at<int>(x,y) > 0)
{
pointVector[xVal*image.cols*image.rows + x*image.cols + y] = true;
}
}
}
// Return whatever.
}

Related

How do you compare elements of a vector within a 3 Dimensional vector in c++

I am trying to loop through a three-dimensional vector. I have one vector containing multiple vectors of x and y coordinates. Lets call the parent vector v0, the vector containing the coordinates v1, and the pair of coordinates v2.
For any v2 in any v1, if the x value of v2 is equal to the x value of another v2 in any v1, I want to add the y values of the v2. if a v2 doesn't have any matching y values, add it to the y value at the point in the next v1 (I already have a function that does this)
In the end I only have one v1 which I will render.
The size of a v1 is unknown, but will always have some v2 with the same x value as a v2 in another v1
The context is essentially I have a set of graphs that I want to "add" to make fractal noise. I am successfully generating the set of graphs, but am unsure how to add them.
Here is my code so far
(also for those unfamiliar with sfml, sf::vector2f is just a vector of two floats.
These are the coordinates. you can access the value of a coordinate with vec.y/vec.x)
void Noise() {
std::vector<sf::Vector2f> finalGraph;
std::vector<sf::Vector2f> singleNoise;
std::vector < std::vector<sf::Vector2f>> allGraphVec;
float persistance = 0.5;
int nOOPM1 = 4;
//generates the graphs to be added
for (int i = 0; i < nOOPM1; i++) {
float frequency = pow(2, i);
float amplitude = pow(persistance, i);
singleNoise =
this->generateNoise(frequency, 300 * amplitude);
allGraphVec.emplace_back(singleNoise);
}
//Do what I described above over here
//This is pseudoCode I have no idea what Im doing here
for(auto &v : allGraphVec){
if(v1 has a v2 == to another v1's v2){
add the v2
take the added value and put it in finalgraph
}
}
//this function just draws a line between each point in the graph, making it a graph not a series of points
for (std::vector<sf::Vector2f>& v : allGraphVec) {
v = this->interpolateNoise(v, 3, 1000);
}
//this will be rendered
this->graphToBeRendered = finalGraph
};
Sorry if this is a bit confusingšŸ˜….
I'm going to answer the question in parts.
So if i understand correctly you have a list of multiple two dimensional points. You currently have this vector: vector<vector<vector<Vector 2f>>> which after translation means you have a list of a list of a list of objects with 2 float values.
What you described in text, from what i understand, is meant to be a vector<vector<vector 2f>> which is a list of lists of objects with two float values.
You can imagine the difference between these lines of code that:
vector<vector<Vector2f>> is a 2D table like in excel where each cell has two values x and y
vector<vector<vector<Vector2f>>> is on the other hand a stacked up version of the previous one on top of each other. So imagine an excel sheet like before, on top of another excel sheet making an excel sheet cube
As you can see this is all getting confusing really quickly...
First things first. Looping...
Easiest way to loop through a vector is to use for(auto &v : vector) and to do it to multiple at the same time:
for(auto &v0 : vector) for(auto &v1 : vector) for(auto &v2 : vector)
The above case would be used to loop through the triple vector. For the rest of the answer i'll assume the thing you want to do is the double vector of double floats.
for(auto &v0 : vector)
{
for(auto &v1 : vector)
{
//do the thing
}
}
To do the task we need to loop through every item in that vector one by one and check if the v2 x exists in another point.
Next is to actually do the thing. We need to find if that number exists in the vector. like going through any list there are many methods some fast some slow. I'll continue using the method i used previously - just plainly going through the vector.
Finding the number x. To find the number x we need to, yes you guessed it go through the vector again. This time to make it less eye straining lets do it in a function:
void findMe(vector 2f &point, vector<vector<vector 2f>> &vec)
{
bool found = false;
for(auto &v0 : vec)
{
for(auto &v1 : vec)
{
if (&v1 != point) //check if we are at the point we are searching
{
if (point.x == v1.x)
{
point.y += v1.y; //i think this is what you wanted. you didnt specify what to add to what
found = true; // check flag
}
}
}
}
if (found == false)
{
//add to next point. you can do this by going through the loop finding the next element and adding it there, by saving the next element or by sending it to the function as parameter. your choice.
}
}
Adding to vector. Removing from vector.
You can add something to a vector by using the emplace_back() function.
eg. adding 5 to vector of ints:
vec.emplace_back(5);
when you have objects you can add them via empty constructor:
vec.emplace_back(sf::vector 2f())
vec.emplace_back({2,5})
vec.emplace_back(sf::vector 2f(5,2)) this should work too i think.
to add vector of vectors vec.emplace_back(vector<vector<vector 2f>>())
Removing:
vec.erase(vec.begin() + offset) //where offset is the index of the item in the vector you want to delete.
IMPORTANT!!!:
remember you need to add item to vector before you use the item or index.
I hope this answer helps. Comment under this if i made any mistakes. I wrote this all from the top of my head and havent teste it in IDE.

Data analysis - memory bug c++

I am a data scientist, currently working on some C++ code to extract triplet particles from a rather large text file containing 2D coordinate data of particles in ~10āµ consecutive frames. I am struggling with a strange memory error that I don't seem to understand.
I have a vector of structs, which can be divided into snippets defined by their frame. For each frame, I build an array with unique ID's for each individual coordinate pair, and if at any point the coordinate pair is repeated, the coordinate pair is given the old coordinate pair. This I then use later to define whether the particle triplet is indeed a trimer.
I loop over all particles and search forward for any corresponding coordinate pair. After I'm done, and no particles were found, I define this triplet to be unique and push the coordinates into a vector that corresponds to particle IDs.
The problem is: after the 18th iteration, at line trimerIDs[i][0] = particleCounter; , the variable trimerCands (my big vector array) suddenly becomes unreadable. Can this be that the vector pointer object is being overwritten? I put this vector fully on the heap, but even if I put it on stack, the error persists.
Do any of you have an idea of what I might be overlooking? Please note that I am rather new at C++, coming from other, less close to the metal, languages. While I think I understand how stack/heap allocations work, especially with respect to vectors/vector structs, I might be very wrong!
The error that Eclipse gives me in the variables tab is:
Failed to execute MI command:
-data-evaluate-expression trimerCands
Error message from debugger back end:
Cannot access memory at address 0x7fff0000000a
The function is as follows.
struct trimerCoords{
float x1,y1,x2,y2,x3,y3;
int frame;
int tLength1, tLength2, tLength3;
};
void removeNonTrimers(std::vector<trimerCoords> trimerCands, int *trCandLUT){
// trimerCands is a vector containing possible trimers, tLengthx is an attribute of the particle;
// trCandLUT is a look up table array with indices;
for (int currentFrame = 1; currentFrame <=framesTBA; currentFrame++){ // for each individual frame
int nTrimers = trCandLUT[currentFrame] - trCandLUT[currentFrame-1]; // get the number of trimers for this specific frame
int trimerIDs[nTrimers][3] = {0}; // preallocate an array for each of the inidivual particle in each triplet;
int firstTrim = trCandLUT[currentFrame-1]; // first index for this particular frame
int lastTrim = trCandLUT[currentFrame] - 1; // last index for this particular frame
bool found;
std::vector<int> traceLengths;
traceLengths.reserve(nTrimers*3);
// Block of code to create a unique ID array for this particular frame
std::vector<Particle> currentFound;
Particle tempEntry;
int particleCounter = 0;
for (int i = firstTrim; i <= lastTrim; i++){
// first triplet particle. In the real code, this is repeated three times, for x2/y2 and x3/y3, corresponding to the
tempEntry.x = trimerCands[i].x1;
tempEntry.y = trimerCands[i].y1;
found = false;
for (long unsigned int j = 0; j < currentFound.size(); j++){
if (fabs(tempEntry.x - currentFound[j].x) + fabs(tempEntry.y - currentFound[j].y) < 0.001){
trimerIDs[i][0] = j; found = true; break;
}
}
if (found == false) {
currentFound.push_back(tempEntry);
traceLengths.push_back(trimerCands[i].tLength1);
trimerIDs[i][0] = particleCounter;
particleCounter++;
}
}
// end block of create unique ID code block
compareTrips(nTrimers, trimerIDs, traceLengths, trimerfile_out);
}
}
If anything's unclear, let me know!

C++: std::vector - std::find & std::distance query

To give context to my question I will describe what it is I am ultimately trying to achieve - I am developing a game, I have a .obj model that I am using as my terrain and I must update the players height as they traverse the terrain (because the terrain is far from flat). I am achieving this currently by doing the following - when I load the mesh (terrain.obj) I store all its vertices (each vertex is a Vector3f object that has an x y and z value) in a std::vector<Vector3f> meshVertices, then every second in the "main game loop" I loop through every one of the Vector3f objects in meshVertices and check its x and z value against the players x and z value, if they are colliding I set the players height as the y value of the matched Vector3f object.
This system actually works and updates my players height as they traverse through the terrain, the only issue is this - my approach of checking every single mesh vertex against player position every second kills my frame rate, I need a much better system.
I will now describe my new optimized approach in the attempt of saving my frame rate - Firstly, when creating the mesh I don't just store each Vector3f vertex in a single std::vector<Vector3f>, I store the x y and z values of each Vector3f vertex of the mesh in three seperate std::vector<Vector3f>'s, named meshVerticesX, mechVerticesY and meshVerticesZ. These std::vector's can be seen in the following code:
for (Vector3f currentVertex : meshVertices) {
meshVerticesX.push_back((int)currentVertex.GetX());
}
for (Vector3f currentVertex : meshVertices) {
meshVerticesZ.push_back((int)currentVertex.GetZ());
}
for (Vector3f currentVertex : meshVertices) {
meshVerticesY.push_back((int)currentVertex.GetY());
}
Now every second I get the x and z value of the players position (casted to an int because I feel like making this system work with int values and not float values will be much easier for comparisons later) and then send them to functions that check to see if they exist in the before mentioned meshVerticesX and mechVerticesZ by returning a bool, the code responsible for this is as follows:
int playerPosX = (int) freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->GetX();
int playerPosZ = (int) freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->GetZ();
bool x = meshObjects[0]->checkMeshVerticesX(playerPosX);
bool z = meshObjects[0]->checkMeshVerticesZ(playerPosZ);
The functions checkMeshVerticesX and checkMeshVerticesZ are as follows:
bool Mesh::checkMeshVerticesX(int playerPosX)
{
return std::find(meshVerticesX.begin(), meshVerticesX.end(), playerPosX) != meshVerticesX.end();
}
bool Mesh::checkMeshVerticesZ(int playerPosZ)
{
return std::find(meshVerticesZ.begin(), meshVerticesZ.end(), playerPosZ) != meshVerticesZ.end();
}
Using the returned boolean values (true if the players position was in the respective std::vector or false if it was not) I then call another function (getMeshYHeight) that also gets passed the players x and z position that then checks the index of the respective std::vector's (meshVerticesX & meshVerticesZ) were the match was found, then checks if these indexes are equal and if so returns an int of that index from the meshVerticesY std::vector mentioned earlier, this code can be seen in the following:
if (x == true & z == true) {// boolean values returned by checkMeshVerticesX & checkMeshVerticesZ
int terrainVertexYHeight = meshObjects[0]->getMeshYHeight(playerPosX, playerPosZ);
freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->SetY(terrainVertexYHeight);
}
The function getMeshYHeight is as follows:
int Mesh::getMeshYHeight(int playerXPos, int playerZPos) {//15/2/20
auto iterX = std::find(meshVerticesX.begin(), meshVerticesX.end(), playerXPos) != meshVerticesX.end();
auto iterZ = std::find(meshVerticesZ.begin(), meshVerticesZ.end(), playerZPos) != meshVerticesZ.end();
int indexX = std::distance(meshVerticesX.begin(), iterX);
int indexZ = std::distance(meshVerticesZ.begin(), iterZ);
if (indexX == indexZ)
{
return meshVerticesY[indexX];
}
}
The idea here is that if the index from the meshVerticesX and meshVerticesZ std::vectors's for the original check match, then they must be the x and z values from an original Vector3f object when I first made the mesh as described earlier, and so that same index in meshVerticesY must contain that same Vector3f's objects y value, therefore return it and use it to set the players height.
The issue is that I cant even test if this works because the line of code int indexX = std::distance(meshVerticesX.begin(), iterX); gives an error saying the arguments supplied to std::distance are wrong (it says iterX is a bool instead of an int which is what I thought it would be).
So my question is - Firstly, if I diden't have this error would my approach even work? and if so, how can I fix the error?
I kind of lost track of your logic somewhere in the middle there, but to address the issue at hand: iterX is a bool!
auto iterX = std::find(...) != meshVerticesX.end();
In this statement, find returns an iterator, which you compare to another iterator, meshVerticesX.end(). The result of that expression (the comparison operator) is a bool, which is then assigned to iterX, so auto deduces that iterX needs to be of type bool.
could you convert your terrain's x,y coordinates to ints, you may need to scale it, then when you load the mesh you could just store the z value for every x,y point (you may have to take some sort of average over the 1x1 square). Now you don't have to look for collisions, instead for each object in the game you can just look up it's z value by it's (scaled) x,y coordinates.

Flip picture horizontal c++ without 2d array

I would like to know if there is anyway to horizontally flip an image without the use of a 2d array. Something similar to this:
for (int x = 0; x < width/2; x++) {
for (int y = 0; y < height; y++) {
int temp = pixelData[x][y];
pixelData[x][y]=pixelData[width-x][y]
pixelData[width-x][y]=temp;
}
}
You can use a single pointer into the image.
You will need to know the distance (amount to increment the pointer) between the end of one raster line (scanline) to the next. So after you increment past the end of a raster line, add the distance to the pointer, so you end up at the left most column on the next raster line.
With modern systems, that have smart GPUs, you may have better efficiency by copying an image to a 2d-array, transforming it, then putting it back. Smarter GPUs may have a mirroring function along with bit-blitting.

How to copy elements of 2D matrix to 1D array vertically using c++

I have a 2D matrix and I want to copy its values to a 1D array vertically in an efficient way as the following way.
Matrice(3x3)
[1 2 3;
4 5 6;
7 8 9]
myarray:
{1,4,7,2,5,8,3,6,9}
Brute force takes 0.25 sec for 1000x750x3 image. I dont want to use vector because I give myarray to another function(I didnt write this function) as input. So, is there a c++ or opencv function that I can use? Note that, I'm using opencv library.
Copying matrix to array is also fine, I can first take the transpose of the Mat, then I will copy it to array.
cv::Mat transposed = myMat.t();
uchar* X = transposed.reshape(1,1).ptr<uchar>(0);
or
int* X = transposed.reshape(1,1).ptr<int>(0);
depending on your matrix type. It might copy data though.
You can optimize to make it more cache friendly, i.e. you can copy blockwise, keeping track of the positions in myArray, where the data should go to. The point is, that you brute force approach will most likely make each access to the matrix being off-cache, which has a tremendous performance impact. Hence it is better to copy vertical/horizontal taking the cache line size into account.
See the idea bbelow (I didn't test it, so it has most likely bugs, but it should make the idea clear).
size_t cachelinesize = 128/sizeof(pixel); // assumed cachelinesize of 128 bytes
struct pixel
{
char r;
char g;
char b;
};
array<array<pixel, 1000>, 750> matrice;
vector<pixel> vec(1000*750);
for (size_t row = 0; row<matrice.size; ++row)
{
for (size_t col = 0; col<matrice[0].size; col+=cachelinesize)
{
for (size_t i = 0; i<cachelinesize; ++i)
{
vec[row*(col+i)]=matrice[row][col+i]; // check here, if right copy order. I didn't test it.
}
}
}
If you are using the matrix before the vertical assignment/querying, then you can cache the necessary columns when you hit each one of the elements of columns.
//Multiplies and caches
doCalcButCacheVerticalsByTheWay(myMatrix,calcType,myMatrix2,cachedColumns);
instead of
doCalc(myMatrix,calcType,myMatrix2); //Multiplies
then use it like this:
...
tmpVariable=cachedColumns[i];
...
For example, upper function multiplies the matrix with another one, then when the necessary columns are reached, caching into a temporary array occurs so you can access elements of it later in a contiguous order.
I think Mat::reshape is what you want. It does not copying data.