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

Author Topic: Fastest way to change all pixels in a loop  (Read 1220 times)

0 Members and 1 Guest are viewing this topic.

tarikk

  • Newbie
  • *
  • Posts: 1
    • View Profile
Fastest way to change all pixels in a loop
« on: August 25, 2024, 10:52:29 pm »
I am trying to copy Sebastian Lague's Neural Network project using C++.

I have to assign a color to every pixel on the screen based on a bool variable in a loop. I have a function that works but it works so slow (about 15 fps). I need a faster way to go change pixels.

/* iterates every pixel on the screen and assigns a color to is based
*  on the value of net.Classify() method.
*/

void Visualize(sf::RenderWindow& w, sf::Image& im, NeuralNetwork& net, sf::Texture& tx, sf::Sprite& sp)
{
    // This variable is used for optimization.
    // It allows me to calculate 25 times fewer pixels but the image is grainy
    // In optimal, this variable should be euqal to 1
    int prescalar = 5;

    for (int x = 0; x < w.getSize().x; x += prescalar)
        for (int y = 0; y < w.getSize().y; y += prescalar)
        {
            std::vector<float> f = { (float)x,(float)y };
            int result = net.Classify(f); // return true or false
            sf::Color c;
            if (result)
                c = sf::Color(185, 250, 246);
            else
                c = sf::Color(255, 149, 130);

            for(int xx = 0; xx < prescalar; xx++)
                for(int yy = 0; yy < prescalar; yy++)
                    im.setPixel(x + xx, w.getSize().y - y - 1 - yy, c); // y size math used for left bottom corner to be the (0,0)
        }
    tx.loadFromImage(im);
    sp.setTexture(tx, true);
    w.draw(sp);
}
 

My main looks something like this
int main()
{
    sf::RenderWindow window(sf::VideoMode::getDesktopMode(), "Window Title", sf::Style::Fullscreen);

    sf::Image im;
    im.create(window.getSize().x, window.getSize().y, sf::Color::Black);

    sf::Texture tx;
    sf::Sprite sp;

    NeuralNetwork network();

    // some stuff

    while (window.isOpen())
    {
        // some stuff
        Visualize(window, im, network, tx, sp);
        // some other stuff
    }
}
 

I checked the work times of all functions and this one is the by far longest one (60 to 80 milliseconds). What are the faster options to implement this?
« Last Edit: August 25, 2024, 10:58:24 pm by tarikk »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10991
    • View Profile
    • development blog
    • Email
Re: Fastest way to change all pixels in a loop
« Reply #1 on: August 26, 2024, 11:47:01 pm »
I checked the work times of all functions and this one is the by far longest one (60 to 80 milliseconds). What are the faster options to implement this?
That's not surprising given that the main work, the "Classify" function, is part of that code.
Best to get a profiler to check which exact part of the code takes the longest.

One optimization you can make is to not take/use a whole std::vector to pass two floats.
Constructing a vector is expensive and you'll be using quite a bit more memory than two floats.
Either pass the floats directly, or use something like a tuple or even sf::Vector2f is a better option.

Side note: You shouldn't be using C-style casts anymore. Use static_cast<float> instead of (float).

The most recommended/fastest way is to use your own one dimensional array/vector of pixel values (e.g. std::vector<sf::UInt8>), where four values represent one color (RGBA).
You'll have to do the image wrapping etc. with math, as it's a one dimensional vector.
Then use that data and call update() on the texture.
Finally, you don't have to call setTexture() if all you want is to set the texture rect, you can call setTextureRect().

And it goes without saying, make sure you're running everything in release mode with optimizations.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/