Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: sf::Image get every pixel around a pixel without crashing  (Read 1570 times)

0 Members and 2 Guests are viewing this topic.

D4RKS0UL23

  • Newbie
  • *
  • Posts: 1
    • View Profile
sf::Image get every pixel around a pixel without crashing
« on: October 28, 2017, 03:26:42 pm »
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);
}

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10998
    • View Profile
    • development blog
    • Email
Re: sf::Image get every pixel around a pixel without crashing
« Reply #1 on: October 28, 2017, 04:43:48 pm »
You can't really get around have at least one checking function (e.g. bool outOfBounds(x, y)) and then side have four if statements that check all sides.

But really if you want a blur function, you'd use a shader instead CPU processing.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: sf::Image get every pixel around a pixel without crashing
« Reply #2 on: October 28, 2017, 04:45:46 pm »
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 +
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

 

anything