Accessing a pixel in SFML

3

I'm developing a project where I should access a pixel from an image and put them in a new RGB array, for this I am using the SFML library, my difficulty is in logic, I know that a pixel is the smallest point of an image and this library gives me access to them through the code:

const sf::Uint8* pixels = imagem.getPixelsPtr();

By the documentation the library stores the pixels in a vector.

What I'm doing is this: knowing the height and width of it, I'm going through a loop and try to get the pixels!

// Descobre o tamanho da imagem
sf::Vector2u tam = imagem.getSize();
int largura = tam.x;
int altura  = tam.y;

for(int i = 0; i < largura ; i++)
{
    for(int j = 0; j < altura; j++)
    {
        ///METODO DA BIBLIOTECA SFML, PARA ACESSAR O PIXEL.
        const sf::Uint8* pixels = imagem.getPixelsPtr();
    }
}

How do I convert this image to RGB and put it in another vector?

    
asked by anonymous 09.05.2014 / 18:46

3 answers

1

The simplest way to do this is by using the getPixel(x, y) of% by%. Just call her inside your loop:

for(int i = 0; i < largura ; i++)
{
    for(int j = 0; j < altura; j++)
    {
        sf::Color px = imagem.getPixel(i, j);
        sf::Uint8 r = px.r;
        sf::Uint8 g = px.g;
        sf::Uint8 b = px.b;
        sf::Uint8 a = px.a;
    }
}

Alternatively (much better in performance), use sf::Image . / a> as suggested in the question:

const sf::Uint8* ptr = imagem.getPixelsPtr();
for(int i = 0; i < largura ; i++)
{
    for(int j = 0; j < altura; j++)
    {
        sf::Uint8 r = ptr[4 * (j * largura + i) + 0];
        sf::Uint8 g = ptr[4 * (j * largura + i) + 1];
        sf::Uint8 b = ptr[4 * (j * largura + i) + 2];
        sf::Uint8 a = ptr[4 * (j * largura + i) + 3];
    }
}

This function returns a pointer to a list of pixels. Each consists of 4 components, the RGBA. It is important to note that this pointer is only valid while the image is not edited. If anything changes the image, this list can be reallocated and moved. Do not save for longer than necessary.

    
09.05.2014 / 19:09
1

A pixel is really the smallest point in an image, but what the library returns, through the const sf::Uint8* pixels pointer are the R, G, B, and A components of pixels (according to documentation ).

Every 4% of Uint8 , you have a pixel itself. So, if you want to copy the pixels to another vector, you do not even need to use manual loops, you can use the memcpy function of the C itself to do this.

The vector where you should copy the image must be the size of 4 * largura * altura bytes:

sf::Uint8* novoVetor = new sf::Uint8[4 * largura * altura];

Next, just copy the bytes of the pointer returned by the getPixelsPtr() function using memcpy :

memcpy(novoVetor, imagem.getPixelsPtr(), 4 * largura * altura);

For performance reasons, give preference to functions that return multiple pixels at a time, such as getPixelsPtr() , rather than using multiple getPixel(x, y) .

Now, if you prefer to use a manually created loop, instead of using memcpy , you can do this:

sf::Uint8* novoVetor = new sf::Uint8[4 * largura * altura];
const sf::Uint8* pixels = imagem.getPixelsPtr();
int tamanho = 4 * largura * altura;
for (int i = 0; i < tamanho; i++) {
    novoVetor[i] = pixels[i];
}

Still, if you prefer, you can perform typecast , and work with integer vector. Since each integer of type int , or unsigned int has 4 bytes, you can effectively store 1 pixel per vector element:

unsigned int* novoVetor = new unsigned int[largura * altura];
const unsigned int* pixels = (const unsigned int*)imagem.getPixelsPtr();
int tamanho = largura * altura;
for (int i = 0; i < tamanho; i++) {
    novoVetor[i] = pixels[i];
}
    
09.05.2014 / 19:10
1

Another solution is as follows:

Check the original image size before converting.

sf::Uint32 sz = img.getSize().x * img.getSize().y;

Create a structure to store pixels in RGB. It could be a vector of sf::Uint8 . But, I used a std::vector<sf::Uint8> .

// Vetor que armazenará os pixels.
std::vector<sf::Uint8> rgb_pixels;
rgb_pixels.reserve(sz * 3); // reserva o espaço do tamanho da imagem RGB.

Finally, copy the pixels of the original image and store it in the RGB vector.

// O ponteiro dos pixel originais em RGBA.
const sf::Uint8* img_pixels = img.getPixelsPtr();

// Armazena os pixels RGBA em um std::vector RGB:
for(sf::Uint32 i = 0u; i < (sz * 4); i += 4)
{
    // Pega o pixel da imagem original em RGBA na mesma posição que será copiada.
    const sf::Uint8* rgba = reinterpret_cast<const sf::Uint8*>(&img_pixels[i]);

    // Armazena no vetor de RGB
    rgb_pixels.push_back(rgba[0]); // r
    rgb_pixels.push_back(rgba[1]); // g
    rgb_pixels.push_back(rgba[2]); // b

    // Não armazena o rgba[3] pois você quer RGB, não RGBA.
    // rgb_pixels.push_back(rgba[3]); // a
}

Finally, if you want to access the pointer in const sf::Uint8* just call:

const sf::Uint8* rgb_ptr = rgb_pixels.data();
    
09.05.2014 / 19:50