Author Topic: RGBRotate  (Read 2689 times)

guga

  • Moderator
  • Member
  • *****
  • Posts: 1346
  • Assembly is a state of art.
    • RosAsm
RGBRotate
« on: June 01, 2014, 01:51:09 PM »
This is an excellent example of rotating the hue using only matrices. It is way better transformation.

Code: [Select]

;;

http://stackoverflow.com/questions/8507885/shift-hue-of-an-rgb-color

The RGB color space describes a cube. It is possible to rotate this cube around the diagonal axis from (0,0,0) to (255,255,255)
to effect a change of hue.

Note that some of the results will lie outside of the 0 to 255 range and will need to be clipped.
I finally got a chance to code this algorithm.
It's in Python but it should be easy to translate to the language of your choice.
The formula for 3D rotation came from http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
Edit: If you saw the code I posted previously, please ignore it.
I was so anxious to find a formula for the rotation that I converted a matrix-based solution into a formula, not realizing
that the matrix was the best form all along.
I've still simplified the calculation of the matrix using the constant sqrt(1/3) for axis unit vector values,
but this is much closer in spirit to the reference and simpler in the per-pixel calculation apply as well.
from math import sqrt,cos,sin,radians

def clamp(v):
    if v < 0:
        return 0
    if v > 255:
        return 255
    return int(v + 0.5)

class RGBRotate(object):
    def __init__(self):
        self.matrix = [[1,0,0],[0,1,0],[0,0,1]]

    def set_hue_rotation(self, degrees):
        cosA = cos(radians(degrees))
        sinA = sin(radians(degrees))
        self.matrix[0][0] = cosA + (1.0 - cosA) / 3.0
        self.matrix[0][1] = 1./3. * (1.0 - cosA) - sqrt(1./3.) * sinA
        self.matrix[0][2] = 1./3. * (1.0 - cosA) + sqrt(1./3.) * sinA
        self.matrix[1][0] = 1./3. * (1.0 - cosA) + sqrt(1./3.) * sinA
        self.matrix[1][1] = cosA + 1./3.*(1.0 - cosA)
        self.matrix[1][2] = 1./3. * (1.0 - cosA) - sqrt(1./3.) * sinA
        self.matrix[2][0] = 1./3. * (1.0 - cosA) - sqrt(1./3.) * sinA
        self.matrix[2][1] = 1./3. * (1.0 - cosA) + sqrt(1./3.) * sinA
        self.matrix[2][2] = cosA + 1./3. * (1.0 - cosA)

    def apply(self, r, g, b):
        rx = r * self.matrix[0][0] + g * self.matrix[0][1] + b * self.matrix[0][2]
        gx = r * self.matrix[1][0] + g * self.matrix[1][1] + b * self.matrix[1][2]
        bx = r * self.matrix[2][0] + g * self.matrix[2][1] + b * self.matrix[2][2]
        return clamp(rx), clamp(gx), clamp(bx)

;;

[RotationMatrix:
 RotationMatrix.Data0_0: R$ 0
 RotationMatrix.Data0_1: R$ 0
 RotationMatrix.Data0_2: R$ 0
 RotationMatrix.Data1_0: R$ 0
 RotationMatrix.Data1_1: R$ 0
 RotationMatrix.Data1_2: R$ 0
 RotationMatrix.Data2_0: R$ 0
 RotationMatrix.Data2_1: R$ 0
 RotationMatrix.Data2_2: R$ 0]

[Float_SquareRoot_OneThird: R$ 0.577350269189625764509148780501957455647601751270126876018602] ; sqrt(1/3)

[TmpRotate.Red: R$ 0]
[TmpRotate.Green: R$ 0]
[TmpRotate.Blue: R$ 0]
[TmpAngle: R$ 0]

[TmpRotateRatio: R$ 0]

Proc RGBRotate:
    Arguments @pColorData, @Angle
    Local @TmpStorage, @TmpAngle, @TmpColorRed, @TmpColorGreen, @TmpColorBlue
    Uses ebx, esi

    mov esi D@pColorData
    lea ebx D@TmpColorRed | move D$ebx D$esi
    lea ebx D@TmpColorGreen | move D$ebx D$esi
    lea ebx D@TmpColorBlue | move D$ebx D$esi
    lea ebx D@TmpStorage
    movzx eax B$esi+RGBTRIPLE.rgbtRedDis | mov D$ebx eax | fild F$ebx | fstp R$TmpRotate.Red
    movzx eax B$esi+RGBTRIPLE.rgbtGreenDis | mov D$ebx eax | fild F$ebx | fstp R$TmpRotate.Green
    movzx eax B$esi+RGBTRIPLE.rgbtBlueDis | mov D$ebx eax | fild F$ebx | fstp R$TmpRotate.Blue

    lea ebx D@TmpAngle | move D$ebx D@Angle | fild F$ebx | fmul R$Degree_Radian | fstp R$TmpAngle

    R$TmpRotateRatio = (1 - cos(R$TmpAngle)) * R$Float_OneThird
    R$RotationMatrix.Data0_0 = (cos(R$TmpAngle) + R$TmpRotateRatio); * R$GrayRedFactor_Rec709 ; seting the gray factor keep luma while not touching saturtion
    R$RotationMatrix.Data0_1 = (R$TmpRotateRatio - (R$Float_SquareRoot_OneThird*sin(R$TmpAngle))); * R$GrayGreenFactor_Rec709
    R$RotationMatrix.Data0_2 = (R$TmpRotateRatio + (R$Float_SquareRoot_OneThird*sin(R$TmpAngle))); * R$GrayBlueFactor_Rec709

    R$RotationMatrix.Data1_0 = R$RotationMatrix.Data0_2
    R$RotationMatrix.Data1_1 = R$RotationMatrix.Data0_0
    R$RotationMatrix.Data1_2 = R$RotationMatrix.Data0_1

    R$RotationMatrix.Data2_0 = R$RotationMatrix.Data0_1
    R$RotationMatrix.Data2_1 = R$RotationMatrix.Data0_2
    R$RotationMatrix.Data2_2 = R$RotationMatrix.Data0_0

    lea ebx D@TmpStorage
    fld R$TmpRotate.Red | fmul R$RotationMatrix.Data0_0 | fld R$TmpRotate.Green | fmul R$RotationMatrix.Data0_1 | faddp ST1 ST0
    fld R$TmpRotate.Blue | fmul R$RotationMatrix.Data0_2 | faddp ST1 ST0 | fistp F$ebx | On D$ebx <s 0, mov D$ebx 0 | On D$ebx > 255, mov D$ebx 255 | mov eax D$ebx | mov B$esi+RGBTRIPLE.rgbtRedDis al

    fld R$TmpRotate.Red | fmul R$RotationMatrix.Data1_0 | fld R$TmpRotate.Green | fmul R$RotationMatrix.Data1_1 | faddp ST1 ST0
    fld R$TmpRotate.Blue | fmul R$RotationMatrix.Data1_2 | faddp ST1 ST0 | fistp F$ebx | On D$ebx <s 0, mov D$ebx 0 | On D$ebx > 255, mov D$ebx 255 | mov eax D$ebx | mov B$esi+RGBTRIPLE.rgbtGreenDis al

    fld R$TmpRotate.Red | fmul R$RotationMatrix.Data2_0 | fld R$TmpRotate.Green | fmul R$RotationMatrix.Data2_1 | faddp ST1 ST0
    fld R$TmpRotate.Blue | fmul R$RotationMatrix.Data2_2 | faddp ST1 ST0 | fistp F$ebx | On D$ebx <s 0, mov D$ebx 0 | On D$ebx > 255, mov D$ebx 255 | mov eax D$ebx | mov B$esi+RGBTRIPLE.rgbtBlueDis al

EndP


Example of usage:
Code: [Select]

[hBitsInMemory: D$ 0]  ; a variable to store the pixel in an ARGB form

         mov esi D$hBitsInMemory
         call RGBRotate esi, 260 ;<--- Angle always in degrees

Btw: SOmeone knows how to achieve the hue angle using this sort of matrix ? For the reverted operation
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

dedndave

  • Member
  • *****
  • Posts: 8827
  • Still using Abacus 2.0
    • DednDave
Re: RGBRotate
« Reply #1 on: June 01, 2014, 02:25:46 PM »
Christian Graus wrote several articles
whether or not you find exactly what you're looking for, you'll enjoy his articles   :t

http://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=6556

another one, i haven't had time to look at it closely

http://www.codeproject.com/Articles/426172/My-Photo-Editor