Convert rgb to hsv

Just starting out? Need help? Post your questions and find answers here.
User avatar
mk-soft
Always Here
Always Here
Posts: 6207
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Convert rgb to hsv

Post by mk-soft »

I translate this code from C++ to Purebasic.
Please checked and optimize this code

Code: Select all

;-TOP

; Source Link: https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both

Structure rgb
  r.d;       // a fraction between 0 and 1
  g.d;       // a fraction between 0 and 1
  b.d;       // a fraction between 0 and 1
EndStructure

Structure hsv
  h.d;       // angle in degrees
  s.d;       // a fraction between 0 and 1
  v.d;       // a fraction between 0 and 1
EndStructure

Procedure rgb2hsv(*in.rgb, *out.hsv)
  
  Protected.d min, max, delta;
  
  If *in\r < *in\g
    If *in\r < *in\b
      min = *in\r
    Else
      min = *in\b
    EndIf
  Else
    If *in\g < *in\b
      min = *in\g
    Else
      min = *in\b
    EndIf
  EndIf
  
  If *in\r > *in\g
    If *in\r > *in\b
      max = *in\r
    Else
      max = *in\b
    EndIf
  Else
    If *in\g > *in\b
      max = *in\g
    Else
      max = *in\b
    EndIf
  EndIf
  
  *out\v = max;                                // v
  delta = max - min;
  If delta < 0.00001
    *out\s = 0;
    *out\h = 0; // undefined, maybe nan?
    ProcedureReturn 0
  EndIf
  If max > 0.0 ; NOTE: If Max is == 0, this divide would cause a crash
    *out\s = delta / max
  Else
    ; If max is 0, then r = g = b = 0              
    ; s = 0, h is undefined
    *out\s = 0.0;
    *out\h = NaN(); its now undefined
    ProcedureReturn 0
  EndIf
  
  If *in\r >= max ; > is bogus, just keeps compilor happy
    *out\h = ( *in\g - *in\b ) / delta ; between yellow & magenta
  ElseIf *in\g >= max
    *out\h = 2.0 + ( *in\b - *in\r ) / delta ; between cyan & yellow
  Else
    *out\h = 4.0 + ( *in\r - *in\g ) / delta ; between magenta & cyan
  EndIf
  *out\h * 60.0                            ; degrees
  If( *out\h < 0.0 )
    *out\h + 360.0;
  EndIf    
EndProcedure

Procedure hsv2rgb(*in.hsv, *out.rgb)
  
  Protected.d hh, p, q, t, ff;
  Protected.i i              ;
  
  If *in\s <= 0.0 ;       // < is bogus, just shuts up warnings
    *out\r = *in\v;
    *out\g = *in\v;
    *out\b = *in\v;
    ProcedureReturn
  EndIf
  hh = *in\h;
  If hh >= 360.0
    hh = 0.0;
  EndIf
  hh / 60.0            ;
  i = hh               ;
  ff = hh - i          ;
  p = *in\v * (1.0 - *in\s);
  q = *in\v * (1.0 - (*in\s * ff));
  t = *in\v * (1.0 - (*in\s * (1.0 - ff)));
  
  Select i 
    Case 0:
      *out\r = *in\v;
      *out\g = t    ;
      *out\b = p    ;
    Case 1:
      *out\r = q;
      *out\g = *in\v;
      *out\b = p    ;
    Case 2:
      *out\r = p;
      *out\g = *in\v;
      *out\b = t    ;
    Case 3:
      *out\r = p;
      *out\g = q;
      *out\b = *in\v;
    Case 4:
      *out\r = t;
      *out\g = p;
      *out\b = *in\v;
    Case 5:
    Default:
      *out\r = *in\v;
      *out\g = p    ;
      *out\b = q    ;
  EndSelect
  ProcedureReturn     
EndProcedure

Macro NormRGB(Color, sRGB)
  sRGB\r = Red(Color) / 255.0
  sRGB\g = Green(Color) / 255.0
  sRGB\b = Blue(Color) / 255.0
EndMacro

Macro ScaleRGB(sRGB)
  RGB(sRGB\r*255, sRGB\g*255, sRGB\b*255)
EndMacro

Define rgb1.RGB
Define hsv1.hsv
Define color.i

color = $73B966

Debug "Color = " + Hex(color)

Debug "RGB2HSV"
NormRGB(color, rgb1)
rgb2hsv(rgb1, hsv1)
With hsv1
  Debug "H = " + \h
  Debug "S = " + \s
  Debug "V = " + \v
EndWith

Debug "HSV2RGB"
hsv2rgb(hsv1, rgb1)
With rgb1
  Debug "R = " + \r
  Debug "G = " + \g
  Debug "B = " + \b
EndWith

Debug "Color = " + Hex(ScaleRGB(rgb1))
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
acreis
Enthusiast
Enthusiast
Posts: 204
Joined: Fri Jun 01, 2012 12:20 am

Re: Convert rgb to hsv

Post by acreis »

Hi

Once done it

Code: Select all

EnableExplicit

;[size=12] RGB2HSL proc uses esi edi ebx, dwRGB:DWORD 
;-- ------------------------------------------------------------! 
; By Greg Hoyer aka "Iblis" ! 
; ! 
; RGB2HSL converts a COLORREF oriented dword filled with 8bit ! 
; Red/Green/Blue values (00ggbbrr) to a similarly oriented ! 
; dword filled with Hue/Saturation/Luminance values (00llsshh) ! 
; This procedure returns the full range, from 0-255. This ! 
; offers slightly more precision over Windows' "color picker" ; 
; common dialog, which displays HSL values ranging from 0-240. ! 
; ! 
; It is important to note that true HSL values are normally ! 
; represented as floating point fractions from 0.0 to 1.0. ! 
; As such, this algorithm cannot be used to do the precise, ! 
; consistent conversions that may be required by heavy-duty ! 
; graphics applications. To get the decimal fraction for ! 
; the returned values, convert the Hue, Saturation, and/or ! 
; Luminance values to floating point, and then divide by 255. ! 
;--------------------------------------------------------------! 
ProcedureDLL.i RGBHSL(RGB)
  
  ;On x86 processors, the available volatile registers
  ;are: eax, ecx And edx. 
  ;All others must be always preserved
  
  
; EAX - Accumulator Register ******
; EBX - Base Register        ******
; ECX - Counter Register     ******
; EDX - Data Register        ****** 
; ESI - Source Index         ******
; EDI - Destination Index    ******
; EBP - Base Pointer
; ESP - Stack Pointer
  
  ! push esi
  ! push edi
  ! push ebx
  
! movzx esi, byte [p.v_RGB + 14] 
! movzx edi, byte [p.v_RGB + 13] 
! movzx ebx, byte [p.v_RGB + 12] 


! mov cl, -1 
! cmp esi, edi 
! ja cmp1 
! xchg esi, edi 
! neg cl 
! shl cl, 1 
! cmp1: 
! cmp edi, ebx 
! jb cmp2 
! xchg edi, ebx 
! neg cl 
! cmp2:
! cmp esi, ebx 
! ja cmp3 
! xchg esi, ebx 
! Not cl 
! cmp3: 
! neg ebx 
! add ebx, esi 
! mov eax, edi 
! add edi, esi 
! jz done_rgbhsl 
! sub esi, eax 
! jz done_rgbhsl 
! mov eax, esi 
! shl eax, 8 
! sub eax, esi 
! push edi 
! cmp edi, $FF 
! jbe csat 
! neg edi 
! add edi, 510 
! csat: 
! XOr edx, edx 
! div edi 
! pop edi 
! shr edi, 1 
! shl eax, 8 
! Or edi, eax 
! add cl, 3 
! jnc noneg 
! neg ebx 
! noneg: 
! shl cl, 2 
! mov eax, $13135DB9 
! shr eax, cl 
! And eax, 7 
! mul esi 
! add eax, ebx 
! mov ebx, eax 
! shl eax, 8 
! sub eax, ebx 
! mov ebx, esi 
! shl esi, 1 
! lea ebx, [ebx*4+esi] 
! XOr edx, edx 
! div ebx 
! shl eax, 16 
! Or eax, edi 
! done_rgbhsl: 
! bswap eax 
! shr eax, 8 


  !pop ebx
  !pop edi
  !pop esi
  
  
  ProcedureReturn 
  
;! ret 
;! 
;! RGB2HSL endp 

EndProcedure

ProcedureDLL.i HSLRGB(HSL) 

; HSL2RGB proc uses esi edi ebx, dwHSL:DWORD 
; !--------------------------------------------------------------! 
; ! By Greg Hoyer aka "Iblis" ! 
; ! ! 
; ! HSL2RGB does the opposite of RGB2HSL. It converts a ! 
; ! Hue/Saturation/Luminance (00llsshh) dword back into its ! 
; ! corresponding RGB COLORREF (00bbggrr). This function is ! 
; ! intented to be used exclusively with RGB2HSL (see above) ! 
; ! ! 
; ! If you're using this for your own custom color-chooser ; 
; ! dialog, remember that the values are in the range of 0-255. ! 
; ! If you MUST emulate the Windows' color-chooser, convert HSL ; 
; ! values this way before you display them: ! 
; ! ! 
; ! display_value = ( x * 240 ) / 255 ! 
; ! ! 
; ! ...where x represents any one of the HSL values. ! 
; !--------------------------------------------------------------! 


; EAX - Accumulator Register ******
; EBX - Base Register        ******
; ECX - Counter Register     ******
; EDX - Data Register        ****** 
; ESI - Source Index         ******
; EDI - Destination Index    ******
; EBP - Base Pointer
; ESP - Stack Pointer
  
  ! push esi
  ! push edi
  ! push ebx

! movzx ebx, byte [p.v_HSL+14] 
! lea esi, [ebx*2] 
! movzx edi, byte [p.v_HSL+13] 
! XOr eax, eax 
! mov cl, 1 
! cmp bl, $7F 
! ja lcase 
! dec al 
! XOr ecx, ecx 
! lcase: 
! add eax, edi
! mul ebx 
! Or ecx, ecx 
! jz scase 
! neg eax 
! mov ecx, ebx 
! add ecx, edi 
! mov edx, ecx 
! shl ecx, 8 
! sub ecx, edx 
! add eax, ecx 
! scase: 
! XOr edx, edx 
! XOr ecx, ecx 
! dec cl 
! mov edi, ecx 
! div ecx 
! jz done_hslrgb 
! mov ecx, eax 
! sub esi, eax 
! movzx eax, byte [p.v_HSL+12] 
! mov ebx, eax 
! shl eax, 1 
! lea eax, [ebx*4+eax] 
! XOr edx, edx 
! div edi 
! mov ebx, eax 
! mov eax, ecx 
! sub eax, esi 
! mul edx 
! push ebx 
! mov ebx, ecx 
! shl ebx, 8 
! sub ebx, ecx 
! sub ebx, eax 
! xchg eax, ebx 
! XOr edx, edx 
! div edi 
! shl eax, 24 
! Or ecx, eax 
! mov eax, esi 
! shl eax, 8 
! sub eax, esi 
! shl esi, 16 
! Or ecx, esi 
! add eax, ebx 
! XOr edx, edx 
! div edi 
! mov ch, al 
! mov eax, ecx 
! pop ecx 
! cmp cl, 6 
! jz done_hslrgb 
! Or ecx, ecx 
! jz done_hslrgb 
! bswap eax 
! rol eax, 8 
! xchg ah, al 
! dec ecx 
! jz done_hslrgb 
! ror eax, 8 
! xchg ah, al 
! dec ecx 
! jz done_hslrgb 
! rol eax, 8 
! xchg ah, al 
! dec ecx 
! jz done_hslrgb 
! bswap eax 
! rol eax, 8 
! xchg ah, al 
! dec ecx 
! jz done_hslrgb 
! ror eax, 8 
! xchg ah, al 
! done_hslrgb: 
! And eax, $FFFFFF 





 !pop ebx
  !pop edi
  !pop esi
  
 

ProcedureReturn 

;! ret 

;HSL2RGB endp [/size]
EndProcedure
infratec
Always Here
Always Here
Posts: 7582
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Convert rgb to hsv

Post by infratec »

User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 539
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: Convert rgb to hsv

Post by BasicallyPure »

BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
Post Reply