SFML community forums

Help => General => Topic started by: jdm1891 on April 17, 2016, 02:41:42 pm

Title: [SOLVED] Creating array from image
Post by: jdm1891 on April 17, 2016, 02:41:42 pm
I'm trying to create an array of tileID', using pixels in an image as input(green pixels-grass, blue pixels-water)
as a way to make maps for my game visually. So far it's not working

When I compile this project The tiles seem randomly placed.

Arrays(and representing 2d spaces with a 1d arrays) confuse me easily , so I tried to use the same thing that was used on the tilemap example(i*j*width), which I am also using

#include "ImageToTileID.h"
#include <SFML/Graphics.hpp>
#include <string>
#include <vector>

TileID * ImageToTileID::ConvertToArray(std::string filepath)
{
        sf::Image image;

        //Load the image from filepath provided
        image.loadFromFile(filepath);

        std::map<TileID, sf::Color> mapToColor;
        //Define list!!! Must update when adding a tile!!!
                //grass is green
                mapToColor[TileID::GRASS] = sf::Color(0, 255, 0, 255);
                mapToColor[TileID::WATER] = sf::Color(0, 0, 255, 255);
       
        //Checks if all tiles have been mapped!
                if (mapToColor.size() != (int)TileID::NUMBER_OF_TYPES)
                {
                        return nullptr;
                }

        //Creates the container for data to return
        std::vector<TileID> container(image.getSize().x*image.getSize().y);

        for (int i = 0; i < image.getSize().x; i++)
        {
                for (int j = 0; j < image.getSize().y; j++)
                {
                        if (image.getPixel(i,j) == mapToColor[TileID::GRASS])
                        {
                                container[i + j*image.getSize().x] = TileID::GRASS;
                        } else

                        if (image.getPixel(i, j) == mapToColor[TileID::WATER])
                        {
                                container[i + j*image.getSize().x] = TileID::WATER;
                        }
                }
        }
        //Return pointer to the first element of the vector
        TileID * result = &container[0];
        return result;
}
 

The reason I didn't use image.getPixelsPtr, is because I don't understand where they got the size from(width*height*4) where does the 4 come into play?
Title: Re: Creating array from image
Post by: Laurent on April 17, 2016, 03:07:11 pm
The "container" array is a local variable, it is destroyed as soon as the function returns. The consequence is that you return a dangling pointer (points to something that was destroyed) and you get, as you noticed, random results (could also be a crash or whatever). You can for example return the vector itself if you want to avoid this problem.

Quote
where does the 4 come into play?
4 components (bytes) per pixel : red, green, blue and alpha.

One more comment: you're using associative containers (std::map) the wrong way. If you switch key and value (ie. std::map<color, tile_id>) you can directly do "container[...] = mapToColor[pixel]".
Title: Re: Creating array from image
Post by: jdm1891 on April 17, 2016, 03:25:34 pm
Thank you, it's so obvious now! I can't believe I missed it!

also I have 2 more problems:

I get this error when switching TileID and sf::Color

error C2678: binary '<': no operator found which takes a left-hand operand of type 'const sf::Color' (or there is no acceptable conversion)


also the picture, while now consistent, does not match the picture I provide:
https://imgur.com/MSxLH9v is the result
https://imgur.com/NPuqUgO is the input picture

from what I can tell, my mapping is wrong, but I'm not sure where
Title: Re: Creating array from image
Post by: Mr_Blame on April 17, 2016, 03:36:10 pm
Well, thats because std::map uses operator of comparison in its functions and sf::Colour doesn't have overlapping ad of it.
Title: Re: Creating array from image
Post by: jdm1891 on April 17, 2016, 03:42:52 pm
So is there anyway to fix that? without editing the sfml code
Title: Re: Creating array from image
Post by: Nexus on April 17, 2016, 04:13:37 pm
Where do you compare colors? The map in your code has a tile ID as key, not a color.

Are you familiar with the STL and its comparison functors? If not, you should read that up, it's basic C++ knowledge...
Title: Re: Creating array from image
Post by: jdm1891 on April 17, 2016, 04:28:07 pm
Maybe I am misunderstanding?

I am comparing colours on the line
image.getPixel(i,j) == mapToColor[TileID::GRASS]
where mapToColor[TileID::GRASS] is equal to sf::Color(0, 255, 0, 255]

I am somewhat familiar with what you mentioned, but from what I know you can only declare them in the class? in this case that would be the sf::Color class
Title: Re: Creating array from image
Post by: Nexus on April 17, 2016, 04:49:45 pm
Follow the compiler's error message. It mentions operator<, not operator==.

No. On one hand, you can define operators globally (bad idea here), on the other you can pass your own comparison functor. As I said, read up on this topic...
Title: Re: Creating array from image
Post by: Laurent on April 17, 2016, 07:30:00 pm
Whether you handle it manually or through your own operator< or custom predicate, you can use the fact that sf::Color can easily be converted from/to a sf::Uint32, which is itself easily comparable ;)
Title: Re: Creating array from image
Post by: Hapax on April 17, 2016, 11:14:09 pm
Isn't the comparison happening because the map (http://www.cplusplus.com/reference/map/map/) is automatically sorted? Since sorting by colours here isn't required, you could instead try unordered_map (http://www.cplusplus.com/reference/unordered_map/unordered_map/).
Title: Re: Creating array from image
Post by: Laurent on April 18, 2016, 06:11:22 am
unordered_map will require a hash function.
Title: Re: Creating array from image
Post by: Hapax on April 18, 2016, 01:00:16 pm
Indeed. My mistake.
Title: Re: Creating array from image
Post by: jdm1891 on April 18, 2016, 09:44:10 pm
Everyone thanks for the help!

I managed to fix the code(I had x&y coords mixed up)