Search code examples
c++convolutiongraphical-programming

Convolution on c++


I'm trying to implement a convolution function in c++. When I use it, it either crashes my program, or it convolves but it shifts my pixels.

for (int y = 1; y < m_imageHeight - 1; y++)
{
    for (int x = 1; x < m_imageWidth - 1; x++)
    {
        float sumRed = 0, sumGreen = 0, sumBlue = 0;

        // Applying the filter
        for (int k = 0; k < rows; k++)
        {
            for (int l = 0; l < cols; l++)
            {
                int posImage = ((y - 1 - k) * m_imageWidth + (x - 1 - l)) * 3;
                sumRed += m_copyImage[posImage] * filter[k][l];
                sumGreen += m_copyImage[posImage + 1] * filter[k][l];
                sumBlue += m_copyImage[posImage + 2] * filter[k][l];
            }
        }

        // Clamps the result
        sumRed = std::max(std::min(sumRed, 255.0f), 0.0f);
        sumGreen = std::max(std::min(sumGreen, 255.0f), 0.0f);
        sumBlue = std::max(std::min(sumBlue, 255.0f), 0.0f);

        // Updates the pixel on the original image
        int pos = (y * m_imageWidth + x) * 3;
        m_myImage[pos] = static_cast<unsigned char>(sumRed);
        m_myImage[pos + 1] = static_cast<unsigned char>(sumGreen);
        m_myImage[pos + 2] = static_cast<unsigned char>(sumBlue);
    }
}

Solution

  • I don't code in C++, so take this with a grain of salt, but: could the issue be your for loops for rows and cols? I'm guessing they are what convolute your image, and them starting at 0 is probably what is shifting your pixels. This is because starting at zero for each loop takes points in a rectangle with the target point being the corner rather than the center. Starting at -rows / 2 and -cols / 2 or something of the sort would fix that issue.

    Additionally, regarding the crashing, I believe that it because of accessing memory outside your image. This would happen if rows or cols causes your program to look for pixels beyond the given amount of your image. Fix this by adding guards that skip the loop if y + k ends up being larger than your image height and vice versa.

    Edit: In short, dividing by two helps center the convolution rectangle around the center point. Let's look at an example, with starting at 0. In this example, let's just look at cols, and say that cols is 5. + will represent each column, while 0 will represent the target point.

        + + + + +
        0
    

    As you can see, starting at 0, we have the columns extend way past the target point, with nothing before it. Now, we will start -cols / 2 before the target point, which is equal to -2.

    + + + + +
        0 
    

    So, by starting the columns at this point, we effectively make it centered around the target point. The same applies for the rows.