C++: Reshape vector to 3D array - c++

Edit: I have uploaded the vector to Drive as a text file, in case anyone want to have a look: https://drive.google.com/file/d/0B0wsPU8YebRQbDUwNFYza3ljSnc/view?usp=sharing
I'm trying to reshape my vector h into a 3D array. h contains 295788 elements. In this case height = 314, width = 314 and depth = 3.
Basically what I'm trying to do is what MATLAB does with its reshape function.
h = reshape(h, height, width, depth)
This is my attempt so far, but when I print it all I see is zeroes, which is not right. I have double checked that h contains the numbers I'm expecting.
vector<vector<vector<double> > > array3D;
int height = 314, width = 314, depth = 3;
// Set up sizes
array3D.resize(height);
for (int i = 0; i < height; ++i) {
array3D[i].resize(width);
for (int j = 0; j < width; ++j)
array3D[i][j].resize(depth);
}
for (int i = 0; i < height; i++)
{
array3D[i][0][0] = h[i];
for (int j = 0; j < width; j++)
{
array3D[i][j][0] = h[i+j];
for (int k = 0; k < depth; k++)
{
array3D[i][j][k] = h[i+j+k];
}
}
}
Printing:
for (vector<vector<vector<double>>>::const_iterator i = array3D.begin(); i != array3D.end(); ++i)
{
for (vector<vector<double>>::const_iterator j = i->begin(); j != i->end(); ++j)
{
for (vector<double>::const_iterator k = j->begin(); k != j->end(); ++k)
{
cout << *k << ' ';
}
}
}
So my question is, how do I convert my vector into a 3D array properly?

I managed to do this by using Eigen::Tensor as suggested by Henri Menke. I ended up creating an array for the initial 314x314x3 matrix, and then another one for the 300x300x3 matrix. It's neither fast nor pretty, but for now that is what I could come up with. Looks like this.
For clarification: margin is calculated further up in the code, but in this example with the 314x314x3 matrix it's margin=7. h is a vector with 295788 elements. nrh=314, nch=314 and nradii=3.
Tensor<int, 3> t(nrh, nch, nradii);
int counter = 0;
for (int k = 0; k < nradii; k++)
{
for (int col = 0; col < nch; col++)
{
for (int row = 0; row < nrh; row++)
{
t(row, col, k) = h[counter];
counter += 1;
}
}
}
int height = nrh - margin * 2;
int width = nch - margin * 2;
int depth = nradii;
Tensor<int, 3> out(height, width, depth);
int count1 = 0, count2 = 0, count3 = 0;
for (int k = 0; k < depth; k++)
{
for (int j = margin; j < nch - margin; j++)
{
for (int i = margin; i < nrh - margin; i++)
{
out(count1, count2, count3) = t(i, j, k);
count1 += 1;
}
count1 = 0;
count2 += 1;
}
count2 = 0;
count3 += 1;
}
Edit: Solution #2 with Tensor.slice()
int height = nrh - margin * 2;
int width = nch - margin * 2;
int depth = nradii;
Tensor<int, 3> tensor(height, width, depth);
DSizes<ptrdiff_t, 3> indices(margin, margin, 0);
DSizes<ptrdiff_t, 3> sizes(height, width, nradii);
tensor = t.slice(indices, sizes);

How about:
array3D[i][j][k] = h[i*(depth*width)+j*depth+k];
That may or may not be scanning the vector in the correct order.
Notice how when the index k resets the index j increments so you move on exactly one until the index j resets in which case i increments and the same. It's easy to show this calculation reads every element exactly once.
I'd normally expect a width, height then depth and you're scanning in the opposite order!
Footnote: Depending on the application is may be worthwhile to just access the vector using this approach. In general it turns out to be faster than accessing a vector of vectors of vectors. That can be relevant when dealing with massive arrays.

Actually, your the structure of your code is already ok, however, there are two mistakes:
The lines
array3D[i][0][0] = h[i];
and
array3D[i][j][0] = h[i+j];
are pointless. You are overwriting those entries later on with the line
array3D[i][j][k] = h[i+j+k];
The index calculation for h[] is wrong: You must multiply the row index by the length of a row before adding the cell index. The assignment should look like this:
array3D[i][j][k] = h[(i*width+j)*depth+k];
Otherwise, you will get the same result for (i, j, k) == (3, 2, 1) as for (i, j, k) == (1, 3, 2), which is obviously wrong. In the index calculation above, I have assumed that k is the fastest changing dimension. If that is not the order in which your data is stored in h, you need to change the positions of i, j, and k and adjust the factors accordingly.
Putting this together, your assignment loop should read:
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int k = 0; k < depth; k++) {
array3D[i][j][k] = h[(i*width+j)*depth+k];
}
}
}
Slightly off-topic:
If you were using C instead of C++, you could "simply" do this:
size_t dataSize;
//Create a real 3D array with the dimensions (height, width, depth).
double (*array3D)[width][depth] = malloc(dataSize = height*sizeof(*array3D));
//Copy over the data from the file.
memcpy(array3D, h, dataSize);
//Print the array contents:
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int k = 0; k < depth; k++) {
printf("%d ", array3D[i][j][k]);
}
}
}
This uses a real 3D array instead of an array of pointers to arrays of pointers to arrays of doubles (which is roughly what a vector<vector<vector<double>>> is). However, this cannot be done in C++ as C++ does not allow for array types with dynamic sizes as C does.

Related

Why there are two types of buffer?

I have two buffers and I want to calculate the centroid in x and y.
The first one is obtain by an external camera:
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int index1 = i + j * width;
centroid[0] += ((double)i) * ((double)buffer1[index1]);
centroid[1] += ((double)j) * ((double)buffer1[index1]);
}}
The second one is obtain by a buffer generated by me:
char buffer2[width][height] = {0};
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int index2 = j + i * height;
centroid[0] += ((double)i) * ((double)buffer2[index2]);
centroid[1] += ((double)j) * ((double)buffer2[index2]);
}}
Both buffers have the same width an height. Both algorithm works successfully.
The strange thing is they use a different index, so index1 work for buffer1 and index2 work for buffer2. If I swap the indexes, index1 for buffer2 and index2 for buffer1 the centroid is wrong.
The question is: are there two different encoding methods for buffers and in particular for camera buffers? If yes, is there a way to convert one into the other?

Working with small 2D parts of big 2D array and moving around it

I have one big 2D array and I want change values in smaller 2D. I can't just get some results.
I have something like that (for 16x16 array f.e.)
int Down8 = 0;
int Right8 = 0;
for (int Down = 0; Down < 16; Down+8)
{
for (int Right = 0; Right < 16; Right+8)
{
Right8 = Right;
Down8 = Down;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
matrixZ[j][i] = TEST[Right8][Down8];
Right++;
}
Down++;
Right8 = Right;
}
dctTransform(matrixZ);
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
matrixZ[j][i] = matrixZ[j][i] / Quant50[j][i];
}
}
zigZagMatrix(matrixZ, 8, 8);
}
}
For 2D 16x16 my function zigZagMatrix should return 4 lines into file (because 16x16 array has 4 8x8 arrays) but only returns 2. 640x480 array should return 4800 lines ( 640/8*480/8 ), returns 60.
Where am I blind/wrong?
All functions I have works with 8x8 array so all of it is loops problem.

How do I change the values in a 2d array using 1d array?

I want to make the values of num[] replace all of the a[][] values when one of the numbers equal k. So all the values of num correspond to each place at k. So for example when k reaches 20 if there is a 20 in the 2d array I want to replace all 20's with whatever is in num[19], but whenever I try it that, they all become skewed numbers and I can't find the reason why. Are my for loops set up wrong or what else could be the problem?
#include<iostream>
int main(){
//other code that uses a file to make 2d array
int width, height, maxval;
fin >> P2 >> width >> height >> maxval;
int **a = new int *[height];
for (int i = 0; i < height; i++)
a[i] = new int[width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
fin >> a[i][j];
}
}
}
void eq(int **a, int h, int w) {
int num[255];
double num1[255];
double prob[255], cumul[255]{ 0 };
double x, y, z=0;
for (int k = 1; k <= 255; k++)
{
int temp = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {//counts the repeated pixel values
if (pix[i][j] == k)
{
temp += 1;
}
}
}
num1[k - 1] = temp;
}
for (int i = 0; i < 255; i++) {
prob[i] = (num1[i] / (height*width));//show the decimal number of how many pixel values are in the image over the total
cout << prob[i] << endl;
}
for (int i = 0; i < 255; i++) {
y = prob[i];
x = y + z;
z = x;// adds all the probabilities to make the sum
cumul[i] =x;
cout << cumul[i] << endl;
}
for (int i = 0; i < 255; i++) {
num[i] =floor(cumul[i]*255);// converts the cumulative number to the new pixel value and sets it in a array
}
for (int k = 1; k <= 255; k++) {//loop that is not coming out right
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if (a[i][j] == k)
{
a[i][j] =num[k-1];
}
}
}
}
}
Basically I am making a function that deals with histogram equalization to make a pgm image clearer. In the main function I am calling a pgm file and setting all the pixel values into a 2d array. So the num[] is the part where I make the new pixel values, but for some reason whenever I call for example a[0][0] I should be getting something that is not zero or 255 since both of those values mean that none of the pixels had that corresponding intensity, but whenever I call it I get 255 or some other random number.
If i understand what you want to do, this line :
a[i][j] =num[i];
should be :
a[i][j] =num[k-1];
Because you want:
if( a[i][j] = k = 20){
a[i][j] = num[k-1 = 19]
}

Comparing pixels in alpha-trimmed filter

I have the following problem. I have written code for alpha-trimmed filter in opencv library. I think that it is properly constructed but I don't know how to compare two 3 channels pixels during sorting a 'window with pixels'. In my code it is done but comparing two but it is impossible for vectors. I assume that i should compare it one channel and after second and so on. Have you any hints for me, or could you propose some modifications in my code. This is my code.
int alphatrimmed(Mat img, int alpha)
{
Mat img9 = img.clone();
const int start = alpha;
const int end = 9 - alpha;
//going through whole image
for (int i = 1; i < img.rows - 1; i++)
for (int j = 1; j < img.cols-1; j++)
{
int k = 0;
Vec3b element[9];
//selecting elements
for (int m = i - 1; m < i + 2; m++)
for (int n = j - 1; n < j + 2; n++)
element[k++] = img.at<Vec3b>(m*img.cols + n);
for (int i = 0; i < end; i++)
{
int min = i;
for (int j = i + 1; j < 9; j++)
if (element[j] < element[min])
min = j;
Vec3b temp = element[i];
element[i] = element[min];
element[min] = temp;
}
const int result = (i - 1)*(img.cols - 2) + j - 1;
img9.at<Vec3b>(result) = element[start];
for (int j = start + 1; j < end; j++)
img9.at<Vec3b>(result) += element[j];
img9.at<Vec3b>(result) /= 9 - alpha;
}
namedWindow("AlphaTrimmed Filter", WINDOW_AUTOSIZE);
imshow("AlphaTrimmed Filter", img9);
return 0;
}
Thank you for your time spent on solving my problem.

better algorithm for counting points in grids

Suppose I have a point P in [0,1]*[0,1], and [0,1] is divided into m(say 200) grids. I use A[m][m] to indicate whether [a small square centred at P with length 2h] covers each grid or not. So for a point P, A[i][j] is either (increase by) 1 or 0.
Suppose I have n such points(P1,...,Pn), I want to calculate A(for each point Pi, I redo the above procedure, adding 1 or not). How can I do this efficiently(with C++) rather than writing 3 layers of for loops to check for each grid and each point(So O(nm^2))?
I tried the naive 3 for loops with C++. It takes longer time than using some of the vectorized operations(like vector<= number for comparing n numbers together, A[bool vector, bool vector] for subsetting) in R.
Since C++ is generally faster than R, is there any smart way to implement this process?
#include <Rcpp.h>
#include <cmath>
using namespace Rcpp;
// [[Rcpp::export]]
double myfun(NumericVector u, NumericVector v)
{
double n = u.size();
double A[200][200] = {0};
double pos[200];
int i = 0, j = 0, k = 0;
for (i = 0; i < 200; i++)
{
pos[i] = (double)i / 201;
}
for (k = 0; k < n; k++)
{
for (i = 0; i < 200; i++)
{
for (j = 0; j < 200; j++)
{
if ( (fabs(u[k] - pos[i]) <= h) && (fabs(v[k] - pos[j]) <=h ) )
{
A[i][j]++;
}
}
}
}
double s = 0, avg = 0;
for (i = 0; i <200; i++)
{
for (j = 0; j < 200; j++)
{
s += A[i][j];
}
}
avg = s / (200 * 200);
return (avg);
}
The two inner loops only determine index of the point in your grid. But you can compute the index directly:
int i = (int)(u[k]*200);
int j = (int)(v[k]*200);
You probably also need to check that i and j don't reach the index 200. This only happens though, when u[k] == 1.0 or v[k] == 1.0.
double n = u.size();
double A[200][200] = {0};
for (int k = 0; k < n; k++)
{
int i = (int)(u[k]*200);
int j = (int)(v[k]*200);
if (i == 200)
i = 199;
if (j == 200)
j = 199;
A[i][j]++;
}