1
votes

I have a 2D array of greyscale pixel values that looks like

255 250 250 250 235 251 255 201
255 250 250 250 235 251 255 151
255 250 250 250 235 251 255 151
255 250 250 250 235 251 255 151
255 250 250 250 235 251 255 151

In implementations I have seen online and in other posts, the program will obtain neighboring pixels specifically in an 3x3 window area.

For example,

for (row = 1; row <= numRows; ++row)
{
    for (col = 1; col <= numCols; ++col)
    {
        //neighbor pixel values are stored in window including this pixel 
        window[0] = imageArr[row - 1][col - 1];
        window[1] = imageArr[row - 1][col];
        window[2] = imageArr[row - 1][col + 1];
        window[3] = imageArr[row][col - 1];
        window[4] = imageArr[row][col];
        window[5] = imageArr[row][col + 1];
        window[6] = imageArr[row + 1][col - 1];
        window[7] = imageArr[row + 1][col];
        window[8] = imageArr[row + 1][col + 1];
        
        // do something with window
    }
}

I am trying to implement a more dynamic window size. Ex. If the user wants to find neighboring pixels in an 4x4 area or an 5x5 area

1
The basic answer is yes: add two extra loops that work on the window's dimensions and remove all this hard-wired duplicate code. Take care to avoid overflow. Even in your example here, the bottom and right edges are going to index out of bounds in imageArr. I think you meant to test for < numRows - 1 etc. For even-sized windows obviously the center-point of the window is not symmetric so extra care is needed to define your valid operating space. Cleaner solutions might just use one loop and std::copy_n, memcpy or even std::valarray. - paddy
Thank you for the response. Can you please further elaborate on what you mean by adding another nested for-loop? - Yoseph Ahmed
There are libraries like Eigen that let you extract an arbitrary subarray from a larger array. Useful for stuff like this. Alternately you can use a template function to extract something like std::array<std::array<int,N>,N> from another array given the center row and column. - doug
I think it's time for you to sit down and draw a grid on some paper, then write numbers (0-based) along the top and left edge to represent column and row indices. Now draw a "window" of size N somewhere in there. Think about the window as an image, so you would of course use two loops to go over every value. Its local top-left corner is always at position (0,0). Its top-left corner within the context of the image is related to the value of row and col. You'll get it, I'm sure. - paddy
Personally, I'd avoid all this extra math you're doing that tries to loop over the center point. It just complicates things and adds nothing. Simply run your main loops over the ranges [0, numRows-N) and [0, numCols-N), and the inner two loops both [0, N). If you need to know the center point of the window, then it'll be row+N/2, col+N/2. And of course if window is a 1D array, indexing that with 2D is stock standard and should probably be burned into your brain when you work with row-based images: window[y * N + x] usually. - paddy

1 Answers

1
votes

I wasn't planning on answering this, but I may as well now that I've written extensively in comments.

General advice is to simplify your loop by treating row and col as the top-left corner of your window instead of the center. This makes the math straight-forward (and therefore clearer to anyone reading the code), especially for the case of an even-sized window dimension.

Assuming the window is square (dimension N), which appears to be your requirement, the outer loops become:

for (int row = 0; row < numRows - N; ++row)
{
    for (int col = 0; col < numCols - N; ++col)
    {
        // TODO: copy window

        // Your window's "center" if you need it
        int cx = col + N/2;
        int cy = row + N/2;

        // TODO: Do something with window...
    }
}

Now, let's do the "copy window" loops. This is a simple NxN image copy where the source position is [row + y][col + x]:

// Copy window
for (int y = 0; y < N; ++y)
{
    for (int x = 0; x < N ++x)
    {
        window[y * N + x] = imageArr[row + y][col + x];
    }
}

It's pretty simple to extend this to rectangular windows if you need, which would be a good exercise for you to try. Various optimizations are possible, but I think that's out of scope based on your current level, and I actually don't want to promote optimization to beginners. It's better to learn how to write simple, clear code.