Implement 2d array coordinates in 1d array in C++ - c++

The code inside the for loop is for the x and y (j and i) "coordinates" from a 2d array. How could I implement this neighbor/index finding in a 1d array?
I think I could implement it for the first four equations. But i'm confused as how to implement up-left etc.
for(int i=0; i<cols*rows; i++){
//Counts current index's 8 neigbour int values
int count=0;
int x = i%cols;
int y = i/rows;
//rows y i
//cols x j
count+= [grid][i][(j-1+cols)%cols] //left
+[grid][i][(j+1+cols)%cols] //right
+[grid][(i-1+rows)%rows][j] //up
+[grid][(i+1+rows)%rows][j] //down
+[grid][(i-1+rows)%rows][ (j-1+cols)%cols] //up-left
+[grid][(i+1+rows)%rows][ (j+1+cols)%cols] //down-right
+[grid][(i+1+rows)%rows][ (j-1+cols)%cols] //down-left
+[grid][(i-1+rows)%rows][ (j+1+cols)%cols] ;//up-right
}

Starting with a 1-D vector:
int rows = 10;
int cols = 10;
vector<int> grid(rows * cols);
You can manage this in different ways, example
for(int y = 0; y < rows; y++)
{
for(int x = 0; x < cols; x++)
{
int point = grid[y * rows + x];
}
}
Where you can access any point at any given x and y in a 2-dimensional plane.
Top-left is:
x = 0;
y = 0;
bottom-right is
x = cols - 1;
y = rows - 1;
And so on.

Use a function like this
inline int idx(const int i, const int j, const int rows) const
{
return i * rows + j;
}
to convert the 2d indices to 1d indices.
This way you don't have to change your algorithm.
Usage would be grid[idx(i, (j-1+cols)%cols, rows)].

The basic formula for computing the 1d coordinate from the 2d index pattern is usually one of the following:
row_index * row_length + column_index
column_index * column_length + row_index
Which one applies to your case depends on whether you would like to have a row-based or column-based memory layout for your 2d array. It makes sense to factor out the computation of this index into a separate function, as suggested in the other answer.
Then you just need to fill in the values somehow.
You could do it like this, for example:
// iterate big picture
// TODO: make sure to handle the edge cases appropriately
for (int i_row = 1; i_row < n_rows - 1; i_row++) {
for (int i_col = 1; i_col < n_cols -1; i_col++) {
// compute values
dst[i_row*n_cols+i_col] = 0;
for (int r = i_row-1; r < i_row+2; r++) {
for (int c = i_col-1; c < i_col+2; c++) {
dst[i_row*n_cols+i_col] += src[r*n_cols + c];
}
}
}
}
Assuming src and dst are distinct 1d vectors of size n_rows*n_cols...

Related

Generate circle around certain point of a 2D matrix [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 months ago.
Improve this question
I am trying to make a height map using randomly generated values in console using c++.
I have an array [50, 50] that is initialized as all 0s.
matrix = new int[rows * columns];
for (int i = 0; i < rows; i++) {
for (int k = 0; k < columns; k++) {
matrix[i * columns + k] = 0;
}
}
I use a loop to generate random points in the array and store the position of those points in a vector.
std::vector<int> sprinklePeaks(int peakDensity, int dimension) {
int count = 0;
std::vector<int> peaks;
for (int i = 0; i < peakDensity; i++) {
int peakIndex = randomize(0, dimension);
matrix[peakIndex] = randomize(69, 99);
peaks.push_back(peakIndex);
}
return peaks;
}
Problem: I am trying to generate a circle with a random radius around these points and fill the circle with randomly generated values, increasing as they approach the center, my circle generation seems to have the right coordinates for the center but the distance is wrong and no values get added to the matrix.
void circleGen(std::vector<int> peaks, int dimensions) {
for (int i = 0; i < peaks.size(); i++) {
int radius = randomize(5, 15);
int area = 3.14159 * radius * radius;
int index = peaks[i];
int x = index / 50;
int y = index % 50;
// std::cout << "Peak: " << peaks[i] << "\n";
// std::cout << "Peak Coordinates: [" << x << ", " << y << "]\n";
int peakHeight = matrix[peaks[i]];
for (int k = 0; k < radius * 2; k++) {
for (int j = 0; j < radius * 2; j++) {
int distance = sqrt((i - radius) * (i - radius) + (j - radius) * (j - radius));
matrix[x - j * columns + y - k] = randomize(10, 20);
}
}
}
}
First issue could be that you don't have bounds checking. I assume you should not change the matrix (and more importantly the surrounding memory) if coordinates are out of the bounds.
Second issue I see is that you calculate distance, but then you don't use this value.
Third issue could be that you want to add to the matrix cell, not replace the value. In line matrix[x - j * columns + y - k] = randomize(10, 20); maybe it should be += instead of =. And distance should participate in the right-side. Or you want to replace, but only if new value is greater than the existing value.
Fourth, as Andrej in the comments mentioned, the math to calculate the index in the matrix is wrong. Should use parentheses, (x - j) * columns + y - k

How to return a 2D array in C++ using pointers, the error I get is "Cannot convert 'int (*)[size]' to 'int**'

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.

Traverse Mat as 64x64 per iteration

Good day,
I am looking for a nested for loop to traverse the image of size 512x512 as 64x64 per iteration. My goal is to determine the element of each sub-region, such as performing number of edge count.
In this following code, I have tried to iterate per 64 row and 64 col (expect 8 times each to hit 512). Within the nested for loop, I have placed vec3b as a test run and I aware that the entire cycle of my code is repeating an identical pattern rather than traverse entire image.
int main()
{
char imgName[] = "data/near.jpg"; //input1.jpg, input2.jpg, near.jpg, far.jpg
Mat sourceImage = imread(imgName);
resize(sourceImage, sourceImage, Size(512, 512));
for (int t_row = 0; t_row < sourceImage.rows; t_row += 64)
{
for (int t_col = 0; t_col < sourceImage.cols; t_col += 64)
{
for (int row = 0; row < 64; row++)
{
for (int col = 0; col < 64; col++)
{
Vec3b bgrPixel = sourceImage.at<Vec3b>(row, col);
cout << bgrPixel << endl;
}
}
}
}
return 0;
}
If you actually want to have 64x64 sub-images per iteration, make use of OpenCV's Rect, like so:
const int w = 64;
const int h = 64;
for (int i = 0; i < int(sourceImage.size().width / w); i++)
{
for (int j = 0; j < int(sourceImage.size().height / h); j++)
{
cv::Mat smallImage = sourceImage(cv::Rect(i * w, j * h, w, h));
// Pass smallImage to any function...
}
}
You are iterating over
Vec3b bgrPixel = sourceImage.at<Vec3b>(row, col);
with 0 <= row < 64 and 0 <= col < 64. You are right that you iterate 64 times over the same region.
It should be
Vec3b bgrPixel = sourceImage.at<Vec3b>(t_row + row, t_col + col);

grayscale Laplace sharpening implementation

I am trying to implement Laplace sharpening using C++ , here's my code so far:
img = imread("cow.png", 0);
Mat convoSharp() {
//creating new image
Mat res = img.clone();
for (int y = 0; y < res.rows; y++) {
for (int x = 0; x < res.cols; x++) {
res.at<uchar>(y, x) = 0.0;
}
}
//variable declaration
int filter[3][3] = { {0,1,0},{1,-4,1},{0,1,0} };
//int filter[3][3] = { {-1,-2,-1},{0,0,0},{1,2,1} };
int height = img.rows;
int width = img.cols;
int filterHeight = 3;
int filterWidth = 3;
int newImageHeight = height - filterHeight + 1;
int newImageWidth = width - filterWidth + 1;
int i, j, h, w;
//convolution
for (i = 0; i < newImageHeight; i++) {
for (j = 0; j < newImageWidth; j++) {
for (h = i; h < i + filterHeight; h++) {
for (w = j; w < j + filterWidth; w++) {
res.at<uchar>(i,j) += filter[h - i][w - j] * img.at<uchar>(h,w);
}
}
}
}
//img - laplace
for (int y = 0; y < res.rows; y++) {
for (int x = 0; x < res.cols; x++) {
res.at<uchar>(y, x) = img.at<uchar>(y, x) - res.at<uchar>(y, x);
}
}
return res;
}
I don't really know what went wrong, I also tried different filter (1,1,1),(1,-8,1),(1,1,1) and the result is also same (more or less). I don't think that I need to normalize the result because the result is in range of 0 - 255. Can anyone explain what really went wrong in my code?
Problem: uchar is too small to hold partial results of filerting operation.
You should create a temporary variable and add all the filtered positions to this variable then check if value of temp is in range <0,255> if not, you need to clamp the end result to fit <0,255>.
By executing below line
res.at<uchar>(i,j) += filter[h - i][w - j] * img.at<uchar>(h,w);
partial result may be greater than 255 (max value in uchar) or negative (in filter you have -4 or -8). temp has to be singed integer type to handle the case when partial result is negative value.
Fix:
for (i = 0; i < newImageHeight; i++) {
for (j = 0; j < newImageWidth; j++) {
int temp = res.at<uchar>(i,j); // added
for (h = i; h < i + filterHeight; h++) {
for (w = j; w < j + filterWidth; w++) {
temp += filter[h - i][w - j] * img.at<uchar>(h,w); // add to temp
}
}
// clamp temp to <0,255>
res.at<uchar>(i,j) = temp;
}
}
You should also clamp values to <0,255> range when you do the subtraction of images.
The problem is partially that you’re overflowing your uchar, as rafix07 suggested, but that is not the full problem.
The Laplace of an image contains negative values. It has to. And you can’t clamp those to 0, you need to preserve the negative values. Also, it can values up to 4*255 given your version of the filter. What this means is that you need to use a signed 16 bit type to store this output.
But there is a simpler and more efficient approach!
You are computing img - laplace(img). In terms of convolutions (*), this is 1 * img - laplace_kernel * img = (1 - laplace_kernel) * img. That is to say, you can combine both operations into a single convolution. The 1 kernel that doesn’t change the image is [(0,0,0),(0,1,0),(0,0,0)]. Subtract your Laplace kernel from that and you obtain [(0,-1,0),(-1,5,-1),(0,-1,0)].
So, simply compute the convolution with that kernel, and do it using int as intermediate type, which you then clamp to the uchar output range as shown by rafix07.

How to pass 2D char array to function?

I am working on a board game and have a 2d char array for board in my main:
char board[*size][*size];
for(int i = 0; i < *size; i++) {
for(int j = 0; j < *size; j++) {
board[i][j] = ".";
}
}
I want to use this in my function named playerOneMove(?), change some of its elements and than bring back to main again to use it in playerTwoMove(?)
I can do this with 1D integer arrays but i couldn't make this work. I just want to learn the method, not full code.
The best way to learn is by looking at code.
The below code passes a 2D array. Study it.
#include <iostream>
#include <cstdio>
using namespace std;
// Returns a pointer to a newly created 2d array the array2D has size [height x width]
int** create2DArray(unsigned height, unsigned width){
int** array2D = 0;
array2D = new int*[height];
for (int h = 0; h < height; h++){
array2D[h] = new int[width];
for (int w = 0; w < width; w++){
// fill in some initial values
// (filling in zeros would be more logic, but this is just for the example)
array2D[h][w] = w + width * h;
}
}
return array2D;
}
int main(){
printf("Creating a 2D array2D\n");
printf("\n");
int height = 15;
int width = 10;
int** my2DArray = create2DArray(height, width);
printf("Array sized [%i,%i] created.\n\n", height, width);
// print contents of the array2D
printf("Array contents: \n");
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++)
{
printf("%i,", my2DArray[h][w]);
}
printf("\n");
}
// important: clean up memory
printf("\n");
printf("Cleaning up memory...\n");
for ( h = 0; h < height; h++){
delete [] my2DArray[h];
}
delete [] my2DArray;
my2DArray = 0;
printf("Ready.\n");
return 0;
}
Here's just math formulas for converting any kind of 2d array (width = height OR width != height) where x, y - indexes of 2d array; index - index of 1d array.
That's for base 1 - first 2d element has index 11 (x=1, y=1).
Guess you may implement it wherever you wish.
2D to 1D
index = width * (x-1) + y
1D to 2D
x = (index / width) + 1
y = ((index - 1) % width) + 1
For base 0 - 1st element indexes x=0, y=0
2D to 1D
index = width * x + y
1D to 2D
x = index / width
y = (index - 1) % width