Add extra value into vector element

Using findNonZero, I stored all the relevant (int) pixels coordinates [x,y] in std::vector<Point>. So there is a [x,y] for each elements in vector.

Now that I want to add a user-defined z-value into the all elements in vector, (same z for all in vector), so that i could get all (x,y,z) in an element.

I am stuck. I search through internet doesn't seems like this is the appropriate way.

then there's this piece of code I found it somewhere on the internet, forgetting the link. May I know, is this a better practice to store? But how do I implement it into findNonZero pixels?

Please do let me know if i am not explaining myself clear. Im not a native speaker, but i can try to explain myself better.

 
std::vector<std::vector<std::vector<double>>> Array3D(X, std::vector<std::vector<double>>(Y, std::vector<double>(Z)));


Thank you.

*Just in case anyone wondering, I will use all the stored elements in vector to plot a model later.
Last edited on
Why don't you use a struct store the pixel?
1
2
3
4
5
struct Point3D
{
  double x = 0, y = 0, z = 0;
};
vector<Point3D> pixels;
Thanks Thomas1965, sorry for late reply, my mistake for not noticing a new reply.

Oh, the reason I am using vector in the first place because when I searched for the way to store dynamic array ( as I have no idea how many points are going to be stored) , vector is the first thing and only thing came up.

May I know, is it true that I can only go with the vector method now?
Later, I am going to pass these stored 3d points to opengl to plot a 3d model.

Any reply is appreciated, I am totally new in this field so thank you !
Normally the vector is the best option for dynamic memory.
Use it unless you have good reason to use a different container.
Thank you Thomas1965.

1. So may I just conclude that Struct is not for dynamic array?

2. Would you have a look the code below?
It's my attempt to add the extra value (z) into the 3 dimensional vector. I have no idea what went wrong, but there is errors and there is no similar case on the internet that can help (Or did I miss anything?). :(

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "iostream"
#include <vector>
#include <direct.h>
#include <algorithm> // for copy
#include <iterator> // for ostream_iterator


using namespace cv;
using namespace std;

Mat pic, gray;
int rows, cols;

string path_in = "C:/Users/Dell/Desktop/";
string path_out = "C:/Users/Dell/Desktop/New Folder/";


int main(int argc, char** argv)
{
	vector<cv::String> fn;
	vector<cv::String> fo;
	glob(path_in + "*.jpg", fn, false);
	glob(path_out + "*.jpg", fo, false);

	size_t count = fn.size();
	for (size_t i = 1; i < 2; i++) //try for an image first, if works, then try for all images in folder
	{
		pic = imread(fn[i], CV_LOAD_IMAGE_COLOR);

		cvtColor(pic, gray, CV_BGR2GRAY);
		Canny(gray, gray, 50, 150, 3);
		
		threshold(gray, bw, 128.0, 255.0, THRESH_BINARY);
		
		std::vector<Vec3d> myVec;
		for (double r = 0.0; r < bw.rows; r++)
		{
			for (double c = 0.0; c < bw.cols; c++)
			{
				if (bw.at<uchar>(r, c) > 0.0) // white pixels
				{
					myVec.push_back(Vec3d(r, c, 3.1209)); //add them to vector3d
				}
			}
		}
		
	}	
		
	system("PAUSE");
	//return 0;
}	


I have these 2 errors in the code. And nothing I found online that can helps.
- conversion from double to int possible loss of data (which im clueless coz I was going to use double data type for storing.
- binary '=': no operator found which takes a right-hand operand of type 'cv::Vec<double,3>' (or there is no acceptable conversion)


*just in case it's relevant, as I see it is easier to have all the 3 x,y,z values in same data type for plotting opengl vertex. And my z value is either double or float.


Thanks again.
1. So may I just conclude that Struct is not for dynamic array?

No, you can use structs with dynamic arrays as well. The point is that you don't need dynamic arrays since the vector class is easier to use and much more powerful.

What is this var bw you use ?
Hi Thomas1965,


Ah, thanks for the information . That sort of explain why vector is the first thing came up last time. Aha !

Apologize that I took the wrong code part , bw should be declared in May as well .
Bw store pixels value of only 1 and 255. From there I took out all the white pixels (255) pixels coordinates to be stored in vector3d with given z value .

The code got the mentioned error even after declaring bw .
Thank you .

*btw , do you suggest this is the right way to do? Or there is a better way to store all these 3 points ?
I think a struct is the best way to use though I am not anymore sure what you want to store.
From the code you showed I assume you want to store pixels deom an image ???

x, y, z should specify the location in 3D environment. If you need to store the color you can add it to a struct as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
typedef uint8_t Byte; // #include <cstdint> http://en.cppreference.com/w/cpp/header/cstdint

struct Location
{
  int x, y, z; // maybe float or double
}

struct Color
{
   Byte red, green, blue; // RGB color model  
};

struct Pixel
{
  Location location;
  Color color;
};

// OR

struct Pixel
{
  int x, y, z; // maybe float or double
  Byte red, green, blue; // RGB color model  
};

// store the whole image
vector<Pixel> image;


Hi Thomas1965,

Thank you . After changing the double to int in my r and c declaration , I left with only the second error now .

Well , please allow me to further explain myself , I believe my code can be painful to see . I am not even close in achieving what I want.

After converting my picture into binary image of having only value of 1 and 255 . I am going to store the white pixels’ coordinate (x, y) as my vector 3D (x, y) values. So I go through each row in bw to find these coordinates.
Then in the vector 3D , I’m giving a user-defined z-value . [finger crossed that you can see the connection with the code]

For eg , using my current image, I’m getting white pixels’ coordinates as below :
(5, 345)
(5, 346)
(5, 347)
(5, 348)

I want to get these values in vector
(5, 345, 3.1209)
(5, 346, 3.1209)
(5, 347, 3.1209)
(5, 348, 3.1209)

At this point, you might wondering , so what’s next ?
After getting the above results in my vector3d, I am going to pass those values to OpenGL for plotting vertices . That’s what I am trying to achieve though I am not sure if it’s workable .

Thanks again !
Last edited on
OK now it's a bit clearer.
You actually could do it much easier:

1
2
3
4
5
6
7
struct Pixel
{
  int x, y;
  const double val = 3.1209; // maybe find a better name, not sure what it means
};

vector<Pixel> pixels;


I am going to pass those values to OpenGL for plotting vertices . That’s what I am trying to achieve though I am not sure if it’s workable

I have never used OpenGL so I can't tell if it's possible.
What format does OpenGL expect ?
Thank you Thomas1965 !

May I just confirm with you that , I shall replace my entire std::vector with struct ?
So is my code for adding the extra value 3.1209 not applicable ?

I am unable to see the connection to add 3.1209 then have them all 3 values as x, y, z together yet.
While looking forward for your reply, I am going to read more regarding on struct, then try out how to implement your previous code to mine .

I’m going to input my values to OpenGL like the link below . So I will have 3 double points for plotting the vertices.
https://msdn.microsoft.com/en-us/library/windows/desktop/dd374172(v=vs.85).aspx
So a struct is basically a class where members are by default public. To make life easier, make a Pixel constructor. From your description it seems like that last value never changes, so perhaps just an (x,y) constructor?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <vector>
using namespace std;

struct Pixel
{
    Pixel(int x, int y) : x(x), y(y)
    {
    }
    
    int x, y;
    const double val = 3.1209;
};

int main() 
{
    vector<Pixel> vec;
    for (int y=345; y<=348; ++y)
    {
        vec.emplace_back(5, y);
    }
    
    std::cout << "My vector values:" << endl;
    for (auto& p : vec)
    {
        cout << "(" << p.x << ", " << p.y << ", " << p.val << ")" << endl;
    }
}


Can run this snippet at https://repl.it/repls/MedicalAdmirableOutput

My vector values:
(5, 345, 3.1209)
(5, 346, 3.1209)
(5, 347, 3.1209)
(5, 348, 3.1209)

Thank you icy1.

Sorry, myself got carried away .

Let say I have a bunch of not-fixed x and y coordinates , how to I emplace back or push back an extra value ? I know how to cout them like you mentioned in the previous post . As you may see from my previous post of my attempt to get it done , also the desired output that I’m hoping to get . Currently the one that I’m using is vector<point> class having 2 values in it , then I change it to vec3d in attempt to have 3 values . But having error mentioned above .

My output at the end of the day , should have 3 values in my vector instead of two (now).
The “val” variable should be some user defined value. But I’m stuck in gettin it done . :(

Thank you .
Last edited on
should have 3 values in my vector instead of two
You have the values in the struct and the structs in the vector.

The “val” variable should be some user defined value.

Didn't you say val is constant?

Can you show us the current code and the full error messages.
Hi Thomas1965,

"val" is the value I defined as z in my code.
kinda from the beginning i was hoping it to be user-defined value,
but in my code, I set it as 3.1209 as I have yet to put cin for user-input.
I'll do it once I am able to add the extra z value into vector (which i was having problem)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "iostream"
#include <vector>
#include <direct.h>
#include <algorithm> // for copy
#include <iterator> // for ostream_iterator

using namespace cv;
using namespace std;

Mat pic, gray, bw;
int rows, cols;

string path_in = "C:/Users/Dell/Desktop/";
string path_out = "C:/Users/Dell/Desktop/New Folder/";


int main(int argc, char** argv)
{
	vector<cv::String> fn;
	vector<cv::String> fo;
	glob(path_in + "*.jpg", fn, false);
	glob(path_out + "*.jpg", fo, false);

	size_t count = fn.size();
	for (size_t i = 0; i < 1; i++) //try for an image first, if works, then try for all images in folder
	{
		pic = imread(fn[i], CV_LOAD_IMAGE_COLOR);
		cout << fn[i] << endl;

		cvtColor(pic, gray, CV_BGR2GRAY);
		//Canny(gray, gray, 50, 150, 3);

		threshold(gray, bw, 128.0, 255.0, THRESH_BINARY);

		//attempt
		//std::vector<Point> myVec;
		std::vector<Vec3d> myVec;
		for (int r = 0; r < bw.rows; r++)
		{
			for (int c = 0; c < bw.cols; c++)
			{
				if (bw.at<uchar>(r, c) > 0) // white pixels
				{
					double z = 3.1209;
					//myVec.push_back(Point(r, c));
					myVec.push_back(Vec3d(r, c, z)); //add them to vector3d

					//cout << " : " << myVec.at<Vec3d>myVec.r << " , " << myVec.at<Vec3d>myVec.c << " , " << z << endl;
				}
			}
		}


		//::copy(myVec.begin(), myVec.end(), std::ostream_iterator<Point>(std::cout << " " << std::endl));
		std::copy(myVec.begin(), myVec.end(), std::ostream_iterator<Vec3d>(std::cout << " " << std::endl));
		std::cout << "size: " << myVec.size() << '\n';

		//attempt
		/*
		std::vector<Point> myVec;
		findNonZero(bw == 255, myVec);
		std::copy(myVec.begin(), myVec.end(), std::ostream_iterator<Point>(std::cout << " " << std::endl));
		std::cout << "size: " << myVec.size() << '\n';
		*/

		//attempt
		/*
		Mat myVec;
		findNonZero(bw, myVec);
		const double z = 3.1209;
		for (int p = 0; p < myVec.total(); p++)
		{
		//myVec.push_back((myVec.at<Point>(p).x), myVec.at<Point>(p).y);
		//myVec.emplace_back(r, c);
		cout << p << " : " << myVec.at<Point>(p).x << " , " << myVec.at<Point>(p).y << " , " << z << endl;
		}
		*/

		waitKey(0);
	}

	system("PAUSE");
	//return 0;
}


Then I realised I am able to add this extra z = 3.1209 value into my vector !

1. But I found out "Point3d" is able to store three xyz coordinates too .
I can't find any info on what is the difference between Point3d and Vec3d, Would you shed me some lights ?

2. in most cases, the z value in a vector (of ONE image) will be the same. And different between another image. But I have no idea how to change z value for a different image. (first image has 100 entries while second image has 99 entries (not fixed), at current, i am having all entries in same vector). Do you have any suggestions on getting it right way?

Thank you, appreciate your help !
Last edited on
I am struggling to understand what you want to do.
This is as far as I understand, tell if I am wrong.

You have some images and want to store all the white pixels (x and y coordinates in a vector)
To this vector belongs a value called z which belongs to this particular image.

If my assumption is correct I would create a class Image that stores the pixels, the z value and maybe the filename like so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Point
{
  int X;
  int Y;
};

class Image
{
public:
  Image(string filename, const double z) : mFilename(filename), mZ(z)
  {}
private:
  string mFilename;
  vector<Point> mPoints;
  const double mZ;
};

In this way you can easily create an Image object for each image and have a different z value.
Then you can implement a load and save function as a member function of the Image class.

@Glaucous, I'm also not sure where your "z" value is supposed to come from. I found this for inherently 3D images, which explains that for 3D cv::Mat classes, the at() function would return a Vec3f: https://stackoverflow.com/questions/33858570/get-x-y-z-cord-from-cvmat .

OpenCV basic structures documentation shows Vec3f and Vec3d are just three-element vectors of floats or doubles: https://docs.opencv.org/trunk/dc/d84/group__core__basic.html#ga370d94209693b5b13437ab4991cabf73

But since your image doesn't appear to be 3D, and indeed your code appears to be 2D matrices consisting of unsigned char values from 0-255, where 0 is likely Black and 255 is White, I'm again unsure where your "z" is coming from.

For storage of many 3D points, you could reuse the OpenCV structures as in your latest, vector<Vec3d> or vector<Vec3f>. As I said above, if your source matrix was 3D, you could easily push_back these if they fit some criteria.
Hi Thomas1965 and icy1 ,

Thank you Thomas ! You’re absolutely correct on what I’m tryna to get .
May I ask, in the suggested code of yours, does it means I will have a lot of vectors? Let’s say I have 1000 image, then I will also create 1000 class ? If that’s the case, Is it possible to have vector in a loop like in image, “i” so that I could easily refer? I tried to name it as myVec[i], but it is not working that way .

Thank you for the input, icy1 . I guess I could go along with Vec3d now , further proceed and see .
Apologize that I am not able to explain myself too well. I did a lot of translation as a non native speaker . Hope that you could understand what is z this way .
xyz coordinates is going to help in rendering object’s surface in 3D space . So I presume that z is the depth which user is going to provide after some calculation . So each image has different depth, z .

Assume that for Image A, x and y coordinates shared a same z coordinate (assume), then Image B have another depth value .


Thanks !
Let’s say I have 1000 image, then I will also create 1000 class ?
It depends, if you can process them one by one you create only one Image class inside a loop and use it.
If you need to process them all at once you can have a vector<Image> where the vector contains 1000 images. If you go for this approach make sure to check that you have enough memory.
Topic archived. No new replies allowed.