SFML community forums

Help => Graphics => Topic started by: Weeve on February 01, 2013, 02:38:16 am

Title: Changing the Hue of a Sprite
Post by: Weeve on February 01, 2013, 02:38:16 am
Since sf::Sprite.SetColor() is only for editing current color values, should I manually edit the pixels of the image each time, then reload them into the Sprite, or should I have three separate images of the different hues, and swap to a different image when needed, and use SetColor() to modify the color values? I would like the most efficient method, and I don't mind low level work, I'm used to it :-)

also, if I do end up writing a SetHue() function for a sf::Sprite, would sfml integrate it for me, so that I can avoid code bloat?
Title: Re: Changing the Hue of a Sprite
Post by: thePyro_13 on February 01, 2013, 03:57:46 am
Try using something like this HSL colour class(from the sfml github wiki) (https://github.com/SFML/SFML/wiki/Source%3A-HSL-Color)

getColour() from the sprite, convert it into a HSL colour object, modify the hue, and then convert it back.

The github code comes with functions to convert back and forth between HSL colour objects and sfml colour objects.
Title: Re: Changing the Hue of a Sprite
Post by: Weeve on February 01, 2013, 04:27:29 am
Mmk, am going manual pixel edit route, then, and the colors don't have to be more accurate than 10/255, so I will  do something similar to HSL, but alot cheaper in computations :-) ty for recommendation to go manual route
Title: Re: Changing the Hue of a Sprite
Post by: Laurent on February 01, 2013, 08:11:13 am
That was not a recommendation to edit pixels manually at all, he said to use setColor -- but with the helper functions of the wiki so that you can work with HSL instead of RGB.

I don't see why you would have to edit pixels manually since you have a function that changes the overall color of the sprite for free.
Title: Re: Changing the Hue of a Sprite
Post by: masskiller on February 01, 2013, 04:54:06 pm
Quote
so I will  do something similar to HSL, but alot cheaper in computations :-) ty for recommendation to go manual route

My class can work well for preprocessing of images (else it will be painfully slow), but as Laurent said, you can perfectly use it with sf::Color and try to experiment your way to the desired outcome. However if you want full control over the hue change you can perfectly use a hue shifting shader. There's plenty in the net and the algorithm is the same, what changes is the mainly the notation of it.

If you know GLSL you can even make your own by looking at the source of the conversions, that way it can work in a more intuitive way and have it work fast in repeated run-time.
Title: Re: Changing the Hue of a Sprite
Post by: Weeve on February 01, 2013, 05:39:55 pm
so if I use setColor(), since its a RGB subtraction of the images color, and not a hue function, how would that work? for instance, if I use SetColor(255,0,0) on a blue object, I then have a black/white object, since the original object had no red in it.

I thought his reccomendation was to use GetColor() initially to find the current hue?

the implementation I was thinking of was to loop through the pixels one time, and seperate out the amount of non grey color, and change the non grey color to my desired RGB, as it would save all of the computations to HSL, where accuracy matters little, but speed is a slight concern  :) .Which is basically what HSL does, except dumbed down to save a few computations, that I shouldn't be worried about in the first place, but for some reason am (function only runs 10 times a second, about)
Title: Re: Changing the Hue of a Sprite
Post by: masskiller on February 01, 2013, 05:45:14 pm
The problem is that when you modify the image you have to re-bind the texture, and that takes more time than image processing. That is what actually makes it slow. The shader approach works around that.

I dislike the getColor/setColor approach because the default color of a sprite is white, which may or may not have saturation and therefore doesn't matter if you change the hue. To actually make a change you need to do lots of trial and error with the color filter, and probably only one image will get some benefit from that. The shader is the standard and best way of doing things fast.

Moreover, you can program your shader to skip unnecessary computations anyway.
Title: Re: Changing the Hue of a Sprite
Post by: Weeve on February 01, 2013, 06:02:13 pm
Sfml has shaders? it should be interesting learning about shaders then ;D
Title: Re: Changing the Hue of a Sprite
Post by: masskiller on February 01, 2013, 07:49:49 pm
sf::Shader from 2.0 has support for both Fragment and Vertex shaders written in GLSL.
Title: Re: Changing the Hue of a Sprite
Post by: Ancurio on February 01, 2013, 10:21:44 pm
Try using something like this HSL colour class(from the sfml github wiki) (https://github.com/SFML/SFML/wiki/Source%3A-HSL-Color)

getColour() from the sprite, convert it into a HSL colour object, modify the hue, and then convert it back.

The github code comes with functions to convert back and forth between HSL colour objects and sfml colour objects.

I tried the algorithm in the link above, and the results were horrendous. I would show you screenshots if I still had them,
but somehow for me it didn't work out at all.

I ended up using this (http://stackoverflow.com/questions/9234724/how-to-change-hue-of-a-texture-with-glsl) (first answer) shader to draw the whole texture into a second render texture, and use that instead.
I think using a hue shift shader on each draw call is way too expensive though..
Title: Re: Changing the Hue of a Sprite
Post by: masskiller on February 02, 2013, 03:28:19 am
How did you use it? When I created the class I tested it many times and it worked fine with sf::Image and the console output of the values were mostly correct. The algorithm isn't mine, I took it from another website, but in per-pixel color shifting there were no issues after debugging. Also note that the formula is quite hard to follow, I had tons of hard to track errors when I first programmed it.
Title: Re: Changing the Hue of a Sprite
Post by: Ancurio on February 02, 2013, 09:35:37 pm
I don't remember that well, maybe I even used it wrong? All I did was something along

for each pixel x, y do
    sf::Color c = image.getColor(x, y)
    HSL hsl = TurnToHsl(c);
    hsl.Hue += some_shift;
    c = hsl.TurnToRGB();
    image.setColor(x, y, c);
end

Ah, now I remember that some macro epsilon wasn't set. It looked like some sort of float comparison tolerance, so I set it to a very low number (0.0001 or something). Maybe that was the reason? Anyway, it's good to know you wrote that code, maybe I'll come back at you for some support =P (I will need to do image manipulation in software soon).
Title: Re: Changing the Hue of a Sprite
Post by: masskiller on February 03, 2013, 02:17:06 am
It depends on what you want to do with the image and the image itself. For example there are cases where shifting the hue does nothing or nearly nothing (gray and near gray colors) as they have little to no saturation. In a colorful image it actually has a purpose to shift the hue for color purposes. In the case you want to colorize an image a set in stone saturation helps get more consistent results.

Most of my tests when I first programmed it were with color codes and plain colored images, and since they turned fine after extensive debugging I just uploaded the class and forgot about it. I'm gonna make a more extensive testing of the algorithm with more complex images and see if I get odd results.

Here's the original algorithm written in pseudo-code:

http://www.easyrgb.com/index.php?X=MATH&H=18#text18 (http://www.easyrgb.com/index.php?X=MATH&H=18#text18)
http://www.easyrgb.com/index.php?X=MATH&H=19#text19 (http://www.easyrgb.com/index.php?X=MATH&H=19#text19)

The raw formula came from wikipedia's entry on HSL and HSV, but it's rather confusing unless you are really into pure math notations.

Quote
I set it to a very low number (0.0001 or something). Maybe that was the reason?

The EPSILON is fine as a low number because it's precisely for float comparison, so there should be no problems with it unless the EPSILON value wasn't defined.

Edit: After checking for more algorithms I found a very interesting one, which uses an approach similar to YUV coloring to convert it. If it turns out to be more effective or efficient I'll change the class to use that. Here's the link if you're interested.

http://www.quasimondo.com/archives/000696.php (http://www.quasimondo.com/archives/000696.php)
Title: Re: Changing the Hue of a Sprite
Post by: Foaly on February 03, 2013, 07:08:27 pm
Wow the last link looks very intersting! If you happen to find the time to investigate if it's more efficient then the "normal" method, then I would be interested in the results too!
Title: Re: Changing the Hue of a Sprite
Post by: Ancurio on February 03, 2013, 10:30:42 pm
It depends on what you want to do with the image and the image itself. For example there are cases where shifting the hue does nothing or nearly nothing (gray and near gray colors) as they have little to no saturation. In a colorful image it actually has a purpose to shift the hue for color purposes. In the case you want to colorize an image a set in stone saturation helps get more consistent results.

Most of my tests when I first programmed it were with color codes and plain colored images,and since they turned fine after extensive debugging I just uploaded the class and forgot about it. I'm gonna make a more extensive testing of the algorithm with more complex images and see if I get odd results.

My use case is almost exclusively hue shifting of normal, multi-colored images,
to get new variations and "looks" out of them.
An example would be to take an image of a flower bouquet and use hue shifting to
get interesting new flower colors, while keeping each flower's differences.
Title: Re: Changing the Hue of a Sprite
Post by: masskiller on February 09, 2013, 01:30:30 am
After some testing I found out what you meant, for simple images the algorithm works just fine, however there are some pixels that don't get converted correctly (or even not at all) in more complex images which causes it too look very bad. I'm gonna delve further to see if I can fix it and otherwise I'll try the other method to see if it works better.

Edit: I just finished fixing it, it was a problem with float accuracy and other values that weren't correctly passed, the new algorithm uses double and a lower EPSILON for maximum accuracy in all pixels, I'll upload it around midnight if I am still awake or tomorrow. I still have to try the other algorithm and check versus photoshop hue shifting, but at least it now can process big images without producing annoying pixel artifacts.

2nd Edit: It's in the wiki now.