This is the relevant code:
void init(int f, int h, std::vector<std::vector<double> > **offsets) {
for (int i = 0; i < 2 * h + 1; i++) { // for all frames
// vector of (x, y, d)'s
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
random_offsets(offsets[y][x]);
print_vecs(offsets[y][x]);
}
}
}
}
int main(int argc, char **argv) {
int h = 6;
Halide::Runtime::Buffer<uint8_t> frame[2*h + 1];
int f = 6;
for (int i = -h; i < h; i++) {
frame[i] = load_image("test1/small/" + std::to_string(f + i) + ".png");
}
W = frame[0].width();
H = frame[0].height();
std::vector<std::vector<double> > offsets[H][W];
init(6, h, offsets);
return 0;
}
I create an offsets 2d array and pass it into the init function. But this gives the following error upon compilation:
note: candidate function not viable: no known conversion from 'std::vector<std::vector<double> > [H][W]' to
'std::vector<std::vector<double> > **' for 3rd argument
void init(int f, int h, std::vector<std::vector<double> > **offsets) {
How can I fix this?
After following one of the comments and changing to vector ...(H, vector...)...
I have the following code altogether:
void random_offsets(std::vector<std::vector<double> > &offsets) {
for (int i = 0; i < k; i++) {
std::vector<double> offset;
offset.push_back(W/3 * ((double) rand() / (RAND_MAX)) * 2 - 1);
offset.push_back(W/3 * ((double) rand() / (RAND_MAX)) * 2 - 1);
offsets.push_back(offset);
}
}
void init(int f, int h, std::vector<std::vector<double> > &offsets) {
for (int i = 0; i < 2 * h + 1; i++) { // for all frames
// vector of (x, y, d)'s
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
random_offsets(offsets[y][x]);
print_vecs(offsets[y][x]);
}
}
}
}
int main(int argc, char **argv) {
int h = 6;
Halide::Runtime::Buffer<uint8_t> frame[2*h + 1];
int f = 6;
for (int i = -h; i < h; i++) {
frame[i] = load_image("test1/small/" + std::to_string(f + i) + ".png");
}
W = frame[0].width();
H = frame[0].height();
std::vector<std::vector<double>> offsets(H, std::vector<double>(W));
init(6, h, offsets);
return 0;
}
But I get the following error:
init.cpp:43:2: error: no matching function for call to 'random_offsets'
random_offsets(offsets[y][x]);
^~~~~~~~~~~~~~
init.cpp:14:6: note: candidate function not viable: no known conversion from 'std::__1::__vector_base<double, std::__1::allocator<double> >::value_type'
(aka 'double') to 'std::vector<std::vector<double> > &' for 1st argument
void random_offsets(std::vector<std::vector<double> > &offsets) {
^
Seems like what I really needed was, assuming that the 2d array of 2d vectors is not going to work, was:
std::vector<std::vector<std::vector<std::vector<double> > > > offsets(H, std::vector<std::vector<std::vector<double> > > (W, std::vector<std::vector<double> > (k, std::vector<double> (3))));
This std::vector<std::vector<double> > **offsets doesn't do what you think it does. This is a pointer to a pointer to a std::vector.... What you are likely looking for is pass by reference:
void init(int f, int h, std::vector<std::vector<double> > &offsets)
This fits how you are calling this function and how you use the object internally.
There is a pretty good overview of this here: What's the difference between passing by reference vs. passing by value? but I would highly recomend that you investigate a good c++ book here: The Definitive C++ Book Guide and List
Related
Started learning TBB recently. I'm trying to implement compressed sparse row multiplication (datatype std::complex<int>) in parallel using TBB. Here is my code :
struct CSR {
std::vector<std::complex<int>> values;
std::vector<int> row_ptr={0};
std::vector<int> cols_index;
int rows;
int cols;
int NNZ;
};
std::vector<std::complex<int>> tbb_multiply(const CSR& A,
const CSR& B) { // B here is transpose
std::vector<std::complex<int>> result(A.rows * B.rows, 0);
tbb::parallel_for(0,A.rows,[=](int i){
for (int j = A.row_ptr[i]; j < A.row_ptr[i + 1]; j++) {
int Ai = A.cols_index[j];
std::complex<int> Avalue = A.values[j];
for (int k = 0; k < B.rows; k++) {
std::complex < int > sum(0, 0);
for (int l = B.row_ptr[k]; l < B.row_ptr[k + 1]; l++)
if (Ai == B.cols_index[l]) {
sum += Avalue * B.values[l];
break;
}
if (sum != std::complex < int >(0, 0)) {
result[i * B.rows + k] = sum;
}
}
}
});
return result;
}
When compiling it I get the next error :
error: passing ‘const value_type’ {aka ‘const std::complex’} as ‘this’ argument discards qualifiers [-fpermissive] result[i * B.rows + k] = sum;
You capture by-value which makes result const (since a lambda isn't mutable by default). Since you also aim to return result, I suggest that you capture by-reference instead:
tbb::parallel_for(0, A.rows,[&](int i){
// ^
I am currently building a median filter in C++. I have a decent amount of experience with other languages but C++ and its pointers confuse me. I am building a function which takes in a 2D array of RGB values of an image. The function may not be 100% yet but I just cannot get past returning the 2d array. My input parameters is the row major version of the image array and the filter size and the output is the pointer to the filtered 2D array. It has the following error when debugging >"Cannot convert 'int (*)[size]' to 'int"
Can you possibly walk me through this error and how to deal with it?
Also if you spot any other peculiarities please mention it, it would be greatly appreciated!
int** seq_medFilter(int image[][3], int filter)
{
int output[640 * 480][3];
int rows = 640;
int cols = 480;
int fil_arr_size = pow((2 * filter + 1), 2);
for (int i = 0; i<rows*cols; ++i)
{
int temp[fil_arr_size][3];
//edge cases excluded
int current_col = i / cols;
int current_row = i%cols;
if (current_col < filter || current_col > cols - filter - 1 || current_row < filter || current_row > rows - filter - 1)
{
for (int j = 0; j<3; j++) {
output[i][j] = image[i][j];
}
}
else
{
// just for a filter size of one now
int pos_x = i / cols - filter;
int pos_y = i%cols - filter;
for (int x = 0; x< fil_arr_size - 1; ++x)
{
for (int j = 0; j<3; j++) {
temp[x][j] = image[pos_x*cols + pos_y][j];
}
pos_x += 1;
if (pos_x == (2 * filter + 1))
{
pos_x = pos_x - (2 * filter + 1);
pos_y += 1;
}
}
int N = sizeof(temp) / sizeof(temp[0]);
sort(temp, temp + N);
for (int j = 0; j<3; j++) {
output[i][j] = temp[N / 2][j];
}
}
}
return output;
}
int main()
{
return 0;
}
The issue is that you cannot return a int output[][] as an int **. They are considered different types, but also, output is a local variable, and thus cannot be returned as a pointer without causing UB.
You could use a vector instead, like so:
std::vector<std::vector<int>> seq_medFilter(int image[][3], int filter)
{
std::vector<std::vector<int>> output( 640 * 480, std::vector<int>( 3 ) );
//...
If you insist on using pointers, then you can used unique_ptr/shared_ptr, or use new, though I would say that all three of these options are worse than just using a vector here.
You could also use an std::array
Example:
std::array<std::array<int, 3>, 640*480> seq_medFilter(int image[][3], int filter)
Then, where you declare output, you would change its type to
std::array<std::array<int, 3>, 640*480> output;
Note that the line:
int temp[fil_arr_size][3];
Is not valid in standard C++ (see here).
For completeness, using the pointer method, you would keep your function head the same, but then use:
int **output = new int*[640*480];
for ( size_t idx = 0; idx < 640*480; ++idx ) {
output[idx] = new int[3];
}
Again, I don't recommend this method.
I have two overloaded functions: "ChooseElements", which chooses elements from passed array, and "SortElements", which sorts elements of passed array. One pair works with INT data, and another one with FLOAT.
int * ChooseElements(int * X, int n, int & m)
{
int * Y = NULL;
for (int i = 0; i < n; i++)
{
if (X[i] > 0)
{
if (Y == NULL)
{
m = 1;
Y = new int[1];
Y[0] = X[i];
}
else
{
m++;
Y = (int *)realloc(Y, sizeof(int) * m);
Y[m - 1] = X[i];
}
}
}
return Y;
}
float * ChooseElements(float * X, int n, int & m)
{
float * Y = NULL;
for (int i = 0; i < n; i++)
{
if (X[i] > 0)
{
if (Y == NULL)
{
m = 1;
Y = new float[1];
Y[0] = X[i];
}
else
{
m++;
Y = (float *)realloc(Y, sizeof(float) * m);
Y[m - 1] = X[i];
}
}
}
return Y;
}
and
int * SortElements(int m, int *& Y)
{
for (int i = 1; i < m; i++)
{
for (int j = 0; j < m - i; j++)
{
if (Y[j] > Y[j + 1])
{
int Temp = Y[j];
Y[j] = Y[j + 1];
Y[j + 1] = Temp;
}
}
}
return Y;
}
float * SortElements(int m, float *& Y)
{
for (int i = 1; i < m; i++)
{
for (int j = 0; j < m - i; j++)
{
if (Y[j] > Y[j + 1])
{
float Temp = Y[j];
Y[j] = Y[j + 1];
Y[j + 1] = Temp;
}
}
}
return Y;
}
What I want to do is pass first function as argument to second one. Like that:
int n, m;
int * X = NULL, * Y = NULL;
/* ...
Some code in which n and X are initialized
... */
Y = SortElements(m, ChooseElements(X, n, m));
However, when I try to do that, Visual Studio 2017 tells me:
no instance of overloaded function "SortElements" matches the argument list
argument types are: (int, int *)
If I do this instead:
Y = ChooseElements(X, n, m);
Y = SortElements(m, Y);
everything works fine.
If I remove overloads and leave only INT pair and once again try
int n, m;
int * X = NULL, * Y = NULL;
/* ...
Some code in which n and X are initialized
... */
Y = SortElements(m, ChooseElements(X, n, m));
I get another problem:
int *ChooseElements(int *X, int n, int &m)
initial value of reference to non-const value must be an lvalue
What am I doing wrong? My teacher asks for a function which uses another function as an argument. What I have written does not work, and I have no idea what could be done here.
In your int * SortElements(int m, int *& Y)
function you are using : int *& Y. So you have a reference to a int pointer. My guess is that you don't need that.
You can just use int * Y as a parameter as a solution.
Int *& Y - needs an lvalue(like your variable Y) but your ChooseElements function returns only a temporary object(rvalue) because you are returning by value.
First off, let me say that everything works like a charm, but the memory deallocation. Maybe it's pure coincidence that I do not have any problems and my basic understanding is wrong.
Also, please refrain from telling me "Use std::vector instead" or the like, as I want to learn and understand the basics first!
Now to the code:
class Test
{
public:
Test(const unsigned int xDim, const unsigned int yDim, const unsigned int zDim);
~Test();
private:
unsigned int xDim, yDim, zDim;
TestStructure **testStructure;
void init();
int to1D(int x, int y, int z) { return x + (y * xDim) + (z * xDim * yDim); }
}
cpp:
Test::Test(const unsigned int xDim, const unsigned int yDim, const unsigned int zDim)
{
this->xDim = xDim;
this->yDim = yDim;
this->zDim = zDim;
this->testStructure = new TestStructure *[xDim * yDim * zDim];
init();
}
void Test::init()
{
for(int x = 0; x < xDim; x++)
for(int y = 0; y < yDim; y++)
for(int z = 0; z < zDim; z++)
{
this->testStructure[to1D(x, y, z)] = new TestStructure(
x - xDim / 2,
y - yDim / 2,
z - zDim / 2);
...
}
Now for the destructor I tried two ways:
Test::~Test()
{
for(int x = 0; x < xDim; x++)
for(int y = 0; y < yDim; y++)
for(int z = 0; z < zDim; z++) {
free(this->testStructure[to1D(x, y, z)]);
}
free(this->testStructure);
}
and
Test::~Test()
{
for(int a = 0; a < xDim * yDim * zDim; a++) {
free(this->testStructure[a]);
}
free(this->testStructure);
}
I am pretty sure the second is like the first, but In both cases I get:
==3854==ERROR: AddressSanitizer: alloc-dealloc-mismatch (operator new vs free) on 0x62100008e900
Where are my mistakes? Throw them at my face and let me learn!
edit: Basic mistake: use delete (for new) instead of free (for malloc).
Replacing the frees above with deletes leads to:
==4076==ERROR: AddressSanitizer: new-delete-type-mismatch on 0x60600002c300 in thread T0:
edit2:
Pardon me, with delete[] for the array part it leads to:
==4138==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62100008e8f8 at pc 0x000000480b3d bp 0x7ffc5bcbc0f0 sp 0x7ffc5bcbc0e0
edit3/SOLUTION: Did it the wrong way. This seems to work:
Test::~Test()
{
for(int a = 0; a < xDim * yDim * zDim; a++) {
delete(this->testStructure[a]);
}
delete[] this->testStructure;
}
Big thanks #SomeProgrammerDude
this is a part of my original code, the code is too big to put it all in here,
anyway my question is only related to Sads 4D matrix,
I don't want to use the int**** like it was suggested to me in my previous question
int main()
{
//4D matrix
int**** Sads = new int***[inputImage->HeightLines];
for (size_t i = 0; i < inputImage->HeightLines; i++)
{
Sads[i] = new int**[inputImage->WidthColumns];
for (size_t j = 0; j < inputImage->WidthColumns; j++)
{
Sads[i][j] = new int*[W_SIZE];
for (size_t k = 0; k < W_SIZE; k++)
{
Sads[i][j][k] = new int[W_SIZE];
}
}
}
ProcessRowsLoop(20, 1904, Sads);
}
void ProcessRowsLoop(int m_support, int m_height, int**** sads)
{
for (int row_in = m_support - 1; row_in < m_Height_in; row_in += BNLM_OUT_SZ)
{
ProcessRow( &Sads[indexRow]);
}
}
void ProcessRow(int**** sads)
{
int m_SAD_00[W_SIZE][W_SIZE];
int m_SAD_01[W_SIZE][W_SIZE];
int m_SAD_10[W_SIZE][W_SIZE];
int m_SAD_11[W_SIZE][W_SIZE];
RunAlgo(m_support, m_SAD_00, m_SAD_01, m_SAD_10, m_SAD_11, m_CP_00, m_CP_01, m_CP_10, m_CP_11, m_ColumnSADUp, m_ColumnSADDown);
for (size_t i = 0; i < W_SIZE; i++)
{
for (size_t j = 0; j < W_SIZE; j++)
{
Sads[0][m_col_out][i][j] = (m_SAD_00[i][j] + color_penalty_weight * m_CP_00[i][j]) / (sqrt(m_sigma_patch[0][0] / pow(mnm, 2)));
Sads[0][m_col_out + 1][i][j] = (m_SAD_01[i][j] + color_penalty_weight * m_CP_01[i][j]) / (sqrt(m_sigma_patch[0][1] / pow(mnm, 2)));
Sads[1][m_col_out][i][j] = (m_SAD_10[i][j] + color_penalty_weight + m_CP_10[i][j]) / (sqrt(m_sigma_patch[1][0] / pow(mnm, 2)));
Sads[1][m_col_out + 1][i][j] = (m_SAD_11[i][j] + color_penalty_weight + m_CP_11[i][j]) / (sqrt(m_sigma_patch[1][1] / pow(mnm, 2)));
}
}
}
In my new code I would like to replace the 4D matrix int**** Sads, with
struct VectorFourD
{
private:
int _width, _height;
int _w_size;
std::vector<int> _vec;
public:
VectorFourD(int width, int height, int size) : _width(width), _height(height), _w_size(size), _vec(totalSize())
{
}
auto totalSize() const-> int
{
return _width * _height * _w_size * _w_size;
}
int* at(int a)
{
return _vec.data() + (a * _height * _w_size * _w_size);
}
int* at(int a, int b)
{
return at(a) + (b * _w_size * _w_size);
}
int *at(int a, int b, int c)
{
return at(a, b) + (c* _w_size);
}
int& at(int a, int b, int c, int d)
{
return *(at(a, b, c) + d);
}
};
you can see that i'm iterating two lines at the same time in the function processrow()
running over
Sads[0][m_col_out][i][j], Sads[0][m_col_out + 1][i][j],
Sads[1][m_col_out][i][j], Sads[1][m_col_out + 1][i][j]
at the same time, my question is how do I change my code to work with the new 4dvector for example
int main()
{
VectorFourD SadsVec = VectorFourD(inputImage->HeightLines, inputImage->WidthColumns, W_SIZE);
ProcessRowsLoop(20, 1904, SadsVec);
}
also change the function void ProcessRowsLoop(int m_support, int m_height, VectorFourD* SadsVec)
but i don't know how to continue from here, can you please help?