I am currently trying to create a program that blurrs a given image. To do that I get the average rgb-values of all the pixels around one pixel, and then I set the pixel to this value.
The problem is, that if I am at a pixel that is at the border/edge of an image, the program will crash because it tries to get pixel information of pixels that are outside the image (eg. getPixel(-1, 0);).
I could technically do dozens of if-statements, but I think it is no really elegant, fast or easy to maintain. Do you have any other suggestions? Currently I am only blurring every pixel except for the ones at the borders. But this looks a bit off, since it creates a non-fitting outline around the image.
If required, here is my code that blurrs an image:
void Framework::Blurr(unsigned level)
{
unsigned counter = 0;
while (counter < level)
{
for (int y = 1; y < orig.getSize().y - 1; y++)
{
for (int x = 1; x < orig.getSize().x - 1; x++)
{
double r, g, b;
r = (orig.getPixel(x-1, y-1).r + orig.getPixel(x, y-1).r + orig.getPixel(x+1, y-1).r +
orig.getPixel(x, y-1).r + orig.getPixel(x+1, y).r +
orig.getPixel(x-1, y+1).r + orig.getPixel(x, y+1).r + orig.getPixel(x+1, y+1).r) / 8;
g = (orig.getPixel(x-1, y-1).g + orig.getPixel(x, y-1).g + orig.getPixel(x+1, y-1).g +
orig.getPixel(x, y-1).g + orig.getPixel(x+1, y).g +
orig.getPixel(x-1, y+1).g + orig.getPixel(x, y+1).g + orig.getPixel(x+1, y+1).g) / 8;
b = (orig.getPixel(x-1, y-1).b + orig.getPixel(x, y-1).b + orig.getPixel(x+1, y-1).b +
orig.getPixel(x, y-1).b + orig.getPixel(x+1, y).b +
orig.getPixel(x-1, y+1).b + orig.getPixel(x, y+1).b + orig.getPixel(x+1, y+1).b) / 8;
post.setPixel(x, y, sf::Color(r, g, b));
}
}
orig = post;
counter++;
}
text.loadFromImage(post);
sprite.setTexture(text);
}
I suppose the consideration is how pixels at the borders are blurred. Depending on which border and also if it's a corner, the weight's/ratios of each pixel included is affected. This means that border pixels would need to be 'noticed' using conditions.
That or, process them in a separate loop (process all inside pixels - as you have in your code at the moment, process all edge pixels, process all corner pixels). These would outside of the 'for y', of course.
It might be more clear and make more sense to get the nine pixels you need to use 'in advance'. That is, store them in temps (or an array) at the beginning of each x loop. Then, use those temps for the calculations. The bonus thing about this is that you can simply keep the position within range (using min and max, for example) when getting the pixel.
I guess what I would try is something like this:
for (int y = 0; y < orig.getSize().y; ++y)
{
for (int x = 0; x < orig.getSize().x; ++x)
{
double r = g = b = 0;
for (int i = 0u; i < 9; ++i) // 3x3 grid
{
sf::Color pixel = orig.getPixel(
std::min(std::max(x + (i % 3) - 1, 0), orig.getSize().x - 1),
std::min(std::max(y + (i / 3) - 1, 0), orig.getSize().y - 1));
r += pixel.r
g += pixel.g;
b += pixel.b;
}
post.setPixel(x, y, sf::Color(static_cast<sf::Uint8>(r / 9), static_cast<sf::Uint8>(g / 9), static_cast<sf::Uint8>(b / 9)));
}
}
Note that I included the original pixel as well. This is easily removed, though.
Is there a reason for using a while loop for counter instead of a for loop?
Also, I think you middle line of pixels per component is incorrect:
orig.getPixel(x, y-1).r + orig.getPixel(x+1, y).r +
should probably be:
orig.getPixel(x-1, y).r + orig.getPixel(x+1, y).r +