Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Replacing specific color range

Credits go to CGamesPlay, Dustin Dettmer, Indeterminatus, Johan Halmén, Johan Peitz, Matt Weir, miran, and Onewing for helping out!
This thread is locked; no one can reply to it. rss feed Print
Replacing specific color range
GullRaDriel
Member #3,861
September 2003
avatar

Take a look at the picture, all colors except hands are 'pure' colors.

{"name":"591971","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/8\/b8d1678789bd504182193c7391f1b202.png","w":320,"h":240,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/8\/b8d1678789bd504182193c7391f1b202"}591971

I need to replace each of these color by another one, but quickly.

What is the way , faster than getpixel, that I can use ?

Thanks

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Johan Peitz
Member #9
April 2000
avatar

If you're using 8bit I would go for palette changes, but something tells me you are not...

--
johan peitz :: things I made

Johan Halmén
Member #1,550
September 2001

Use palettes. Or prerender, either using a graphic editor (great opportunity to discuss in this thread why Gimp sucks/is great) or during game setup.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

CGamesPlay
Member #2,559
July 2002
avatar

Use palettes, prerender, or use OpenGL.

[append]
Next person to post has to add something to the list!

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Onewing
Member #6,152
August 2005
avatar

Quote:

Use palettes, prerender, or use OpenGL.

Or use getpixel to build an array and then use the array to putpixel back the colors with a given offset to change your colors, as long as your image doesn't...change. :)

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Dustin Dettmer
Member #3,935
October 2003
avatar

There are gradients there... Ya good luck. Easier to redo the art.

Matt Weir
Member #7,476
July 2006
avatar

Gradients can be overcome by converting to HSL and not using the lightness but there will be problems if any of the gradients fades to pure black. The human brain is pretty good at putting imaginary boundries in images.

As far as I can think, getpixel is the only way and it will be slow. I can think of a few ways to optimize but all sacrifice accuracy.

+1 for finding another way.

Matt.

Johan Halmén
Member #1,550
September 2001

Solder a switch to your monitor cable, which switches the r, g and b channels.
I win!

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

GullRaDriel
Member #3,861
September 2003
avatar

I made some tests, and it is working (as expected) with getpixel/putpixel.

I will perhaps try to use the "block data transfer" method.

Here is the result, the colors are random and take the gradient :
[img http://www.allegro.cc/files/attachment/591972]

And here is the code :

#SelectExpand
1#include <allegro.h> 2 3BITMAP *in , *out , *buf; 4 5int x , y, it , c , cc, r, g , b , r1 , b1 , g1 , c1 , c2 , c3 , c4 , c5 ,c6,c7 ; 6 7int main( int argc , char *argv[] ){ 8 9allegro_init(); 10install_keyboard(); 11install_mouse(); 12 13 14set_color_depth( 32 ); 15 16set_gfx_mode( GFX_DIRECTX_WIN , 320 , 240 , 0 , 0 ); 17 18in = load_bitmap( "test.bmp" , NULL ); 19 20out = create_bitmap( in -> w , in -> h ); 21 22buf = create_bitmap( SCREEN_W , SCREEN_H ); 23clear( buf ); 24clear( out ); 25 26 c1 = makecol( rand()%255 , rand()%255 , rand()%255 ); 27 c2 = makecol( rand()%255 , rand()%255 , rand()%255 ); 28 c3 = makecol( rand()%255 , rand()%255 , rand()%255 ); 29 c4 = makecol( rand()%255 , rand()%255 , rand()%255 ); 30 c5 = makecol( rand()%255 , rand()%255 , rand()%255 ); 31 c6 = makecol( rand()%255 , rand()%255 , rand()%255 ); 32 c7 = makecol( rand()%255 , rand()%255 , rand()%255 ); 33 34 for( x = 0 ; x < in -> w ; x ++ ) 35 { 36 for( y = 0 ; y < in -> h ; y ++ ) 37 { 38 cc = -1; 39 40 c = getpixel( in , x , y ); 41 r = getr( c ); 42 g = getg( c ); 43 b = getb( c ); 44 45 if( r > 88 && b == 0 && g == 0 ) /* rouge tete */ 46 cc = c1 ; 47 if( r > 88 && b > 0 && g == 0 ) /* roste cou */ 48 cc = c2 ; 49 if( r == 0 && b > 0 && g > 0 ) /* bleu manche */ 50 cc = c3 ; 51 if( r > 88 && g > 0 && b == 0) /* veste */ 52 cc = c4 ; 53 if( b > 0 && r == 0 && g == 0 ) /*pantalon*/ 54 cc = c5 ; 55 if( r > 88 && b > 0 && g > 0 ) /*mains*/ 56 cc = c6 ; 57 if( r > 0 && r <= 88 && b == 0 && g == 0 ) 58 cc = c7; 59 if( cc != -1 ) 60 { 61 62 r1 = getr( cc ); 63 g1 = getg( cc ); 64 b1 = getb( cc ); 65 66 67 if( r > 0 ) 68 { 69 it = r; 70 } 71 72 if( g > 0 ) 73 { 74 it = g ; 75 } 76 77 if( b > 0 ) 78 { 79 it = b ; 80 } 81 82 r1 = (r1 * it)/255 ; 83 g1 = (g1 * it)/255 ; 84 b1 = (b1 * it)/255 ; 85 86 if( r1 < 0 ) r1 = 0; 87 if( g1 < 0 ) g1 = 0; 88 if( b1 < 0 ) b1 = 0; 89 if( r1 > 255 ) r1 = 255; 90 if( g1 > 255 ) g1 = 255; 91 if( b1 > 255 ) b1 = 255; 92 93 putpixel( out , x , y , makecol( r1 , g1 , b1 ) ); 94 } 95 } 96 } 97do{ 98 99if( key[KEY_SPACE] ) 100{ 101 clear( out ); 102 103 c1 = makecol( rand()%255 , rand()%255 , rand()%255 ); 104 c2 = makecol( rand()%255 , rand()%255 , rand()%255 ); 105 c3 = makecol( rand()%255 , rand()%255 , rand()%255 ); 106 c4 = makecol( rand()%255 , rand()%255 , rand()%255 ); 107 c5 = makecol( rand()%255 , rand()%255 , rand()%255 ); 108 c6 = makecol( rand()%255 , rand()%255 , rand()%255 ); 109 c7 = makecol( rand()%255 , rand()%255 , rand()%255 ); 110 111 for( x = 0 ; x < in -> w ; x ++ ) 112 { 113 for( y = 0 ; y < in -> h ; y ++ ) 114 { 115 cc = -1; 116 117 c = getpixel( in , x , y ); 118 r = getr( c ); 119 g = getg( c ); 120 b = getb( c ); 121 122 if( r > 88 && b == 0 && g == 0 ) /* rouge tete */ 123 cc = c1 ; 124 if( r > 88 && b > 0 && g == 0 ) /* roste cou */ 125 cc = c2 ; 126 if( r == 0 && b > 0 && g > 0 ) /* bleu manche */ 127 cc = c3 ; 128 if( r > 88 && g > 0 && b == 0) /* veste */ 129 cc = c4 ; 130 if( b > 0 && r == 0 && g == 0 ) /*pantalon*/ 131 cc = c5 ; 132 if( r > 88 && b > 0 && g > 0 ) /*mains*/ 133 cc = c6 ; 134 if( r > 0 && r <= 88 && b == 0 && g == 0 ) 135 cc = c7; 136 if( cc != -1 ) 137 { 138 139 r1 = getr( cc ); 140 g1 = getg( cc ); 141 b1 = getb( cc ); 142 143 144 if( r > 0 ) 145 { 146 it = r; 147 } 148 149 if( g > 0 ) 150 { 151 it = g ; 152 } 153 154 if( b > 0 ) 155 { 156 it = b ; 157 } 158 159 r1 = (r1 * it)/255 ; 160 g1 = (g1 * it)/255 ; 161 b1 = (b1 * it)/255 ; 162 163 if( r1 < 0 ) r1 = 0; 164 if( g1 < 0 ) g1 = 0; 165 if( b1 < 0 ) b1 = 0; 166 if( r1 > 255 ) r1 = 255; 167 if( g1 > 255 ) g1 = 255; 168 if( b1 > 255 ) b1 = 255; 169 170 putpixel( out , x , y , makecol( r1 , g1 , b1 ) ); 171 } 172 } 173 } 174} 175 176stretch_blit( out , buf , 0 , 0 , out -> w , out -> h , 0 , 0 , buf -> w , buf -> h ); 177 178blit( buf , screen , 0 , 0 , 0 , 0 , buf->w , buf->h ); 179 180}while( !key[KEY_ESC ] ); 181 182allegro_exit(); 183 184}END_OF_MAIN()

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

miran
Member #2,407
June 2002

I only skimmed over the code but I didn't see any rgb2hsv and vice versa conversions so I'm guessing you're not doing it right. What you want to do is this:

For each pixel:

1. Read colour (RGB format)
2. Convert to HSV
3. Rotate H by a certain number of degrees.
4. Convert back to RGB.
5. Write colour back to image.

--
sig used to be here

GullRaDriel
Member #3,861
September 2003
avatar

Thanks for your help, but there is no need for me to use any other conversion than makecol and getX :-)

The color value of the input picture is here for two reason: having the form to fill with a color, and picking the value as a percentage from 0 to 255.

The whole thing is working as expected, it just need some king of optimisation as it will cause some load time.

Here is the new version, where default replacement color is on screen for us to verify that it is using it correctly.

Before:
591976

After:
{"name":"591975","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/c\/e\/cefcd7e9c42f3ac91cf96ab1e48b02b6.jpg","w":806,"h":625,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/c\/e\/cefcd7e9c42f3ac91cf96ab1e48b02b6"}591975

Executable + source (Win32) ( 7z archive )

I am waiting for give the cookies. Please post me the answer ;-) huhuhu

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Indeterminatus
Member #737
November 2000
avatar

As requested, a post so you can hand out cookies.

_______________________________
Indeterminatus. [Atomic Butcher]
si tacuisses, philosophus mansisses

GullRaDriel
Member #3,861
September 2003
avatar

;-p

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Matt Weir
Member #7,476
July 2006
avatar

Your pictures look like they contain a large ammount of dead space. If your checking every pixel in the large space perhaps you could divide and conquer. Only check every nth pixel (in both dimensions) if the nth pixel is one that needs to be changed then go back n/2 and check that pixel (and so on). You value for n would have to be one where you won't missed anything important so if your working on a picture with skinny lines it won't help but even at n=2 you'll save a lot of time. Basically trading precision for speed.

Matt.

Andrei Ellman
Member #3,434
April 2003

Quote:

What is the way , faster than getpixel, that I can use ?

_getpixel
If the colour-depth is known, you might want to use getr8, getr16, getr24, getr32 etc. instead of getr.

Quote:

r1 = (r1 * it)/255 ;

If you don't mind the result being in the range 0-254 instead of 0-255, you can divide by using a shift. The code would then become.r1 = (r1 * it)>>8;. While not as accurate as the /255 method, it will be a lot faster.

Also, you might want to consider using 8-bit graphics and using colour-map tables and draw_lit_sprite().

AE.

--
Don't let the illegitimates turn you into carbon.

GullRaDriel
Member #3,861
September 2003
avatar

Matt Weir: This is only a test picture extracted from an animation, the picture when in it final form is 'clipped' to the nearest non-masked pixel. Anyway thanks for the tip !

Andrei: I will try the _getpixel way. Also: the >>8 seems good too.

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

James Stanley
Member #7,275
May 2006
avatar

GIMP rules.

GullRaDriel
Member #3,861
September 2003
avatar

Yeah perhaps. But GIMP does not do real time painting in my code.

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Go to: