Delphi图像处理 -- RGB与HSL转换
阅读提示:
《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。
《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。
尽可能保持二者内容一致,可相互对照。
本文代码必须包括文章《Delphi图像处理 -- 数据类型及公用过程》中的ImageData.pas单元。
const _fc0: Single = 0.0; _fcd5: Single = 0.5; _fc1: Single = 1.0; _fc2: Single = 2.0; _fc6: Single = 6.0; _fc60: Single = 60.0; _fc255: Single = 255.0; _fc360: Single = 360.0; _fc510: Single = 510.0; procedure ColorToHSL(var H, S, L: Single; Color: TARGB); var rgbMax: LongWord; asm push eax push edx push ecx movzx ecx, Color.TARGBQuad.Blue movzx edx, Color.TARGBQuad.Green movzx eax, Color.TARGBQuad.Red cmp ecx, edx // ecx = rgbMax jge @@1 // edx = rgbMin xchg ecx, edx @@1: cmp ecx, eax jge @@2 xchg ecx, eax @@2: cmp edx, eax cmova edx, eax mov rgbMax, ecx mov eax, ecx add ecx, edx // ecx = rgbMax + rgbMin sub eax, edx // delta = rgbMax - rgbmin cvtsi2ss xmm0, ecx divss xmm0, _fc510 pop edx movss [edx], xmm0 // *L = (rgbMax + rgbMin) / 255 / 2 jnz @@3 pop ecx // if (delta == 0) pop edx // { mov [ecx], eax // *H = *S = 0 mov [edx], eax // return jmp @@Exit // } @@3: comiss xmm0, _fcd5 jb @@4 neg ecx add ecx, 510 // if (L < 128) ecx = 510 - ecx @@4: pop edx cvtsi2ss xmm0, eax cvtsi2ss xmm1, ecx movaps xmm2, xmm0 divss xmm0, xmm1 movss [edx], xmm0 // *S = delta / ecx mov eax, rgbMax cmp al, Color.TARGBQuad.Red jne @@5 movzx eax, Color.TARGBQuad.Green movzx edx, Color.TARGBQuad.Blue xor ecx, ecx // if (R == rgbMax) eax = G - B; add = 0 jmp @@7 @@5: cmp al, Color.TARGBQuad.Green jne @@6 movzx eax, Color.TARGBQuad.Blue movzx edx, Color.TARGBQuad.Red mov ecx, 120 // if (G == rgbMax) eax = B - R; add = 120 jmp @@7 @@6: movzx eax, Color.TARGBQuad.Red movzx edx, Color.TARGBQuad.Green mov ecx, 240 // if (B == rgbMax) eax = R - G; add = 240 @@7: sub eax, edx cvtsi2ss xmm0, eax cvtsi2ss xmm1, ecx mulss xmm0, _fc60 divss xmm0, xmm2 addss xmm0, xmm1 // H = eax * 60 / delta + add comiss xmm0, _fc0 jae @@8 addss xmm0, _fc360 @@8: pop eax movss [eax], xmm0 @@Exit: end; function HSLToColor(H, S, L: Single): TARGB; asm movss xmm0, H comiss xmm0, _fc0 jae @@1 addss xmm0, _fc360 jmp @@2 @@1: comiss xmm0, _fc360 jb @@2 subss xmm0, _fc360 @@2: movss xmm3, _fc1 divss xmm0, _fc60 cvtss2si edx, xmm0 // index = Round(H) cvtsi2ss xmm1, edx subss xmm0, xmm1 // extra = H - index comiss xmm0, _fc0 // if (extra < 0) // 如果index发生五入 jae @@3 // { dec edx // index -- addss xmm0, xmm3 // extra ++ @@3: // } test edx, 1 jz @@4 movaps xmm1, xmm0 movaps xmm0, xmm3 subss xmm0, xmm1 // if (index & 1) extra = 1 - extra @@4: movss xmm2, S movss xmm4, L minss xmm2, xmm3 minss xmm4, xmm3 maxss xmm2, _fc0 maxss xmm4, _fc0 pslldq xmm0, 4 // max mid min movlhps xmm0, xmm3 // xmm0 = 0.0 1.0 extra 0.0 movaps xmm1, xmm0 subss xmm3, xmm2 movss xmm2, _fcd5 pshufd xmm2, xmm2, 0 pshufd xmm3, xmm3, 0 subps xmm1, xmm2 mulps xmm1, xmm3 subps xmm0, xmm1 // xmm0 = xmm0 - (xmm0 - 0.5) * (1.0 - S); movaps xmm1, xmm0 subss xmm4, xmm2 mulss xmm4, _fc2 // xmm4 = (L - 0.5) * 2 comiss xmm4, _fc0 jb @@5 movss xmm0, _fc1 pshufd xmm0, xmm0, 0 subps xmm0, xmm1 // if (xmm4 >= 0) xmm0 = 1 - xmm0 @@5: movss xmm3, _fc255 pshufd xmm4, xmm4, 0 pshufd xmm3, xmm3, 0 mulps xmm0, xmm4 addps xmm0, xmm1 mulps xmm0, xmm3 // xmm0 = (xmm0 + xmm0 * xmm4) * 255 jmp @@jmpTable[edx*4].Pointer @@jmpTable: dd offset @@H60 dd offset @@H120 dd offset @@H180 dd offset @@H240 dd offset @@H300 dd offset @@H360 @@H360: // 300 - 359 pshufd xmm0, xmm0, 11100001b jmp @@H60 @@H300: // 240 - 299 pshufd xmm0, xmm0, 11010010b jmp @@H60 @@H240: // 180 - 239 pshufd xmm0, xmm0, 11000110b jmp @@H60 @@H180: // 120 - 179 pshufd xmm0, xmm0, 11001001b jmp @@H60 @@H120: // 60 - 119 pshufd xmm0, xmm0, 11011000b @@H60: // 0 - 59 cvtps2dq xmm0, xmm0 packssdw xmm0, xmm0 packuswb xmm0, xmm0 movd eax, xmm0 or eax, 0ff000000h end;
《Delphi图像处理》系列使用GDI+单元下载地址和说明见文章《GDI+ for VCL基础 -- GDI+ 与 VCL》。
因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com
这里可访问《Delphi图像处理 -- 文章索引》。