Modify Hue on an image
BlitzMax Forums/BlitzMax Programming/Modify Hue on an image
| ||
Is is possible somehow? Reason I'm asking is I have 1 player image with animation. This player is blue per default, and has white eyes. I wish to have him appear red in the game. Thus I cannot use setcolor before I draw the player to make him red, because his eyes would become reddish as well (and it would be best if he was grayscale to begin with I guess). But if I was able to modify the hue value, I could easily make him red, purple, green, whatever, without the white eyes changing. |
| ||
There's some code ( not BMax, but should be easy enough to follow ) here to convert back and forth between RGB and HSV, so I guess you could convert to HSV, change the hue and convert back to RGB? http://www.cs.rit.edu/~ncs/color/t_convert.html |
| ||
Or you could draw the eyes on afterwards. |
| ||
I'd rather start the game out by converting/calculating them, rather than having to issue two draw commands instead of one. Thanks gabriel, looking into it now! |
| ||
Just make the parts of the image grey which have to be colorized... If the eyes are totally white (255,255,255) and the pupils black (0,0,0) there will be no problems... or just make them like (255,255,250) - so you will not see a difference to perfect white. The function below will colorize all grey parts to the given rgb-values. You can easily change it to color pixmaps and so on. Function ARGB_Alpha:Int(ARGB:Int) Return Int((ARGB & $FF000000:Int) / $1000000:Int) End Function Function ARGB_Red:Int(ARGB:Int) Return Int((ARGB & $00FF0000:Int) / $10000:Int) End Function Function ARGB_Green:Int(ARGB:Int) Return Int((ARGB & $0000FF00:Int) / $100:Int) End Function Function ARGB_Blue:Int(ARGB:Int) Return (ARGB & $000000FF:Int) End Function Function ARGB_Color:Int(alpha:Int,red:Int,green:Int,blue:Int) Return (Int(alpha*$1000000)+Int(blue*$10000)+Int(green*$100)+Int(RED)) End Function 'returns true if the given pixel is monochrome (grey) Function isMonochrome(argb:Int) Try Local alpha:Int = ARGB_Alpha(argb) Local red:Int = ARGB_Red(argb) Local green:Int = ARGB_Green(argb) Local blue:Int = ARGB_Blue(argb) '250 If (red = green) And (red = blue)And(alpha <> 0)And(red<250) Then Return green Return 0 Catch a$ Print "ismonochrome exception:"+a$ EndTry End Function 'colorizes an TImage (may be an AnimImage when given cell_width and height) Function ColorizeTImage:TImage(_image:TImage, r:Int,g:Int,b:Int, cell_width:Int=0,cell_height:Int=0,first_cell:Int=0,cell_count:Int=1, flag:Int=0) If _image <> Null Local mypixmap:TPixmap=LockImage(_image) Local mypixmap2:TPixmap = TPixmap.Create(_image.width,_image.height, mypixmap.format,1) mypixmap2 = mypixmap.Copy() Local mypixelptr2:Int Ptr = Int Ptr(mypixmap2.PixelPtr(0,0)) Local mypixelptr2backup:Int Ptr = mypixelptr2 For Local my_x=0 To ((mypixmap2.width)*(mypixmap2.height)) ' If Mypixelptr2[0] = Null Then Exit Local colortone:Int = isMonochrome(mypixelptr2[0]) If colortone > 0 And mypixelptr2[0] <> 0 mypixelptr2[0] = ARGB_Color(ARGB_Alpha(mypixelptr2[0]),Int(colortone*r/255), Int(colortone*g/255), Int(colortone*b/255)) EndIf mypixelptr2:+1 If mypixelptr2 = mypixelptr2backup+(mypixmap2.pitch Shr 2) mypixelptr2backup=mypixelptr2 EndIf Next UnlockImage(_image) If cell_width > 0 And cell_count > 0 Then Return LoadAnimImage(mypixmap2, cell_width, cell_height, first_cell,cell_count, flag) Return LoadImage(mypixmap2) EndIf End Function Hope this works for you. bye mB |
| ||
I wrote an HSV library a few years back which should you to do what you want. However, it was for Blitz Plus, but it should be easy to convert. Have a look on my old website, it may be of some use to you: [url]http://www.aurora-soft.co.uk/blitz/colourSpace.asp[/url] |
| ||
Hey ghost dancer, thanks man, it's exactly what I need. Now only if I could get it working ;). I'm not too sharp on BlitzPlus (never used it), but I tried to convert it to bmax anyway. It runs but gives a weird problem, noted in my comments in the first few lines. I think I'm either calling your functions incorrectly, or I misunderstood something about the temp pointer in rgb2hsv(). I'm still trying to learn about pointers, so it's pretty exotic for me :p Can you see what I did wrong you think? Strict Local myrgb = rgb(100,150,200) Print "Red color of 'rgb' should be 100, it is: "+getred(myrgb) 'prints out: 255 Local myhsv:hsv = New hsv myhsv = rgb2hsv(myrgb,myhsv) Print "HSV values from myrgb: "+myhsv.h+" "+myhsv.s+" "+myhsv.v 'prints out: -1.#IND0000 0.000000000 1.00000000 Local newrgb = hsv2rgb(myhsv.h,myhsv.s,myhsv.v) Print "myrgb converted to hsv, and back to rgb: "+newrgb 'prints out: 16777215 '-----------begin ghost dancer's code, converted to bmax------------------- 'create a custom Type For HSV colour Type hsv Field h#, s#, v# End Type '------------------------------------------------------------------- Function getRed(rgb) '------------------------------------------------------------------- 'Get red component of RGB colour value ' 'Parameters: 'rgb - RGB value that you want the red component from ' 'Return value: 'red value (0 To 255) '------------------------------------------------------------------- rgb = rgb Shr 16 And $ff Return rgb' Shr 16 And $ff End Function '------------------------------------------------------------------- Function getGreen(rgb) '------------------------------------------------------------------- 'Get green component of RGB colour value ' 'Parameters: 'rgb - RGB value that you want the green component from ' ';Return value: 'green value (0 To 255) '------------------------------------------------------------------- Return (rgb Shr 8) And $ff End Function '------------------------------------------------------------------- Function getBlue(rgb) '------------------------------------------------------------------- 'Get blue component of rgb colour value ' 'Parameters: 'rgb - RGB value that you want the blue component from ' 'Return value: 'blue value (0 To 255) '------------------------------------------------------------------- Return rgb And $ff End Function '------------------------------------------------------------------- Function rgb(r, g, b) '------------------------------------------------------------------- 'Convert R,G,B components To single RGB value ' 'Parameters: 'r - red value 'g - green value 'b - blue value ' 'Return value: 'rgb value '------------------------------------------------------------------- Return (r Shl 16) + (g Shl 8) + b End Function '------------------------------------------------------------------- Function rgb2hsv:hsv(rgb, temphsv:hsv) '------------------------------------------------------------------- 'Convert RGB To HSV ' 'Parameters: 'rgb - RGB value that you want convert 'temphsv.hsv - Added in V2.01, it is required To prevent the ' memory leakage problem. This needs To be the same ' hsv Type pointer that the Function returns to. ' e.g. myhsv.hsv = New hsv ' myhsv = rgb2hsv($ff0000, myhsv) ' 'Return value: 'custom hsv Type defined in this library '------------------------------------------------------------------- ' ;RGB components in range 0 To 1 Local r# = getRed(rgb) / 255.0 Local g# = getGreen(rgb) / 255.0 Local b# = getBlue(rgb) / 255.0 ' ;Min value Local minVal# If r < g Then minVal# = r Else minVal# = g If b < minVal Then minVal = b ' ;Max value Local maxVal# If r > g Then maxVal# = r Else maxVal# = g If b > maxVal Then maxVal = b ' ;calculate difference Local diff# = maxVal - minVal temphsv.v = maxVal If maxVal = 0 Then temphsv.s = 0 temphsv.h = -1 ';h is undefined Else temphsv.s = diff / maxVal If r = maxVal Then temphsv.h = (g - b) / diff ElseIf g = maxVal Then temphsv.h = 2 + (b - r) / diff Else temphsv.h = 4 + (r - g) / diff EndIf temphsv.h = temphsv.h * 60 If temphsv.h < 0 Then temphsv.h = temphsv.h + 360 EndIf Return temphsv End Function ';------------------------------------------------------------------- Function hsv2rgb(h#, s#, v#) '------------------------------------------------------------------- 'Convert HSV To RGB ' 'Parameters: 'h# - hue (in degrees, 0 To 350) 's# - saturation (0.0 To 1.0) 'v# - value (brightness, 0.0 To 1.0) ' 'Return value: 'rgb value '------------------------------------------------------------------- Local r#,g#,b#,f#,p#,q#,t#,i# If s = 0 Then ' ;saturation of 0 = grey r# = v ; g# = v ; b# = v Else h = h / 60 i = Floor(h) f# = h - i p# = v * (1 - s) q# = v * (1 - s * f) t# = v * (1 - s * (1 - f)) Select i Case 0 r# = v g# = t b# = p Case 1 r# = q g# = v b# = p Case 2 r# = p g# = v b# = t Case 3 r# = p g# = q b# = v Case 4 r# = t g# = p b# = v Default r# = v g# = p b# = q End Select EndIf r = r * 255 g = g * 255 b = b * 255 Return rgb(r, g, b) End Function |
| ||
I'm guessing it's the bit shifting since Blitz Plus didn't have alpha. Can't really test it at the moment but I'll try and have a proper look later for you. |
| ||
Thank you very much for taking the time Ghost Dancer, I really appreciate it :) |
| ||
OK, you were using And instead of &. So, this is what it should look like:'------------------------------------------------------------------- Function getRed(rgb) '------------------------------------------------------------------- 'Get red component of RGB colour value ' 'Parameters: 'rgb - RGB value that you want the red component from ' 'Return value: 'red value (0 To 255) '------------------------------------------------------------------- Return rgb Shr 16 & $ff End Function '------------------------------------------------------------------- Function getGreen(rgb) '------------------------------------------------------------------- 'Get green component of RGB colour value ' 'Parameters: 'rgb - RGB value that you want the green component from ' ';Return value: 'green value (0 To 255) '------------------------------------------------------------------- Return (rgb Shr 8) & $ff End Function '------------------------------------------------------------------- Function getBlue(rgb) '------------------------------------------------------------------- 'Get blue component of rgb colour value ' 'Parameters: 'rgb - RGB value that you want the blue component from ' 'Return value: 'blue value (0 To 255) '------------------------------------------------------------------- Return rgb & $ff End Function |
| ||
Thank you! I got it working now, sort of. I merged some of your code with Michael's code to rebuild an image, while changing the hue value inbetween. However I can't seem to understand how the "formula" is for blitzmax's pixmaps are.. They have alpha, and your code, ghost dancer, does not take that in account.. I'll have to know the formula to be able to rewrite it so it does :) |
| ||
I think my code will basically ignore any alpha information, so if you don't need the alpha it shouldn't be a problem. If you do need the alpha info, then that would have to be accounted for in the rgb <-> hsv conversions. Off the top of my head, I'm guessing it would just alter the saturation and/or the value (brightness) in the hsv model. |
| ||
Nah I just get a black image if I don't account for alpha >.< No idea what the formula is so I can include alpha in your rbg2hsv and hsv2rgb? |
| ||
If you read the pixel-color first... then just read its alpha-value and set again after your hsv-conversion. bye MB |
| ||
Is this what you mean michael? I took out argb values in seperate variables from the pixmap, then converted rgb to hsv and modified hue, then converted back to rgb and added alpha again. It did change the color, but the eyes (about 200 to 255 rgb..white) would somehow end up being black ? |
| ||
When some pixels went black, you forgot to read their intensity... if you modify the hue, the saturation has to be constant (the intensity of the color) - otherwise it would get black. if you use: read pixel read alpha convert rgb 2 hsv modify hue convert hsv 2 rgb reset alpha write pixel it would be a nice overhead, but would have to function I think. But if you just use my functions, you would not have to change the hue, for just being able to colorize grey parts... everything with r=g=b could be colorized and to leave "grey looking parts" you will have to change the parts color to eg. r-4,g,b (so it is not grey any longer). bye MB |