Reading Tips:
《Delphi Image ProcessingThe series focuses on efficiency. The general code is Pascal, and the core code is BaSm.
The C ++ image processing series focuses on code clarity and readability, all using C ++ code.
Make sure that the two items are consistent and can be compared with each other.
The code in this article must include the imagedata. Pas unit in "Delphi Image Processing-data type and public process.
Recently, after finishing previous articles《Delphi Image Processing-color phase/saturation adjustment"After finishing the article, I suddenly thought of it yesterday.《Delphi Image Processing-color phase/saturation adjustment"There is still room for optimization in the code, because in my several articles on image color/saturation adjustment, I have been writing code based on SHL, in fact, the color phase/saturation adjustment function of Photoshop is also based on SHL, but after all, the color phase/saturation adjustment of Photoshop is not SHL adjustment, whether it is brightness, hue or saturation, there is a lot of independence between them, the relationship between them is loose, not like SHL, the relationship between the three is very tight, in《Delphi Image Processing-color phase/saturation adjustment"In this article, the brightness part has been adjusted independently, but there are still some relationships between the color and the saturation part, mainly sharing the S and l parts of the pixel, but in fact, it is very troublesome to adjust the color phase with SHL. It is much easier to adjust the color phase with SHV (of course, this only refers to the SSE code I use. If it is not the SSE code, it's hard to say, because《Delphi Image Processing-color phase/saturation adjustment.In the color phase adjustment code of the article, only the median value is calculated, and the maximum and minimum values are retained, which saves a lot of code ). After writing the improved code, I wanted to overwrite the updates.《Delphi Image Processing-color phase/saturation adjustment"But I think the previous code is retained as well. Therefore, the improved code can be used as a continuation for comparison between the two:
Procedure getbrighttable (bright: integer; var table: tgraytable); ASM push ebx cmp eax,-255 jge @ 1 mov eax,-255 JMP @ 2 @ 1: CMP eax, 255 jle @ 2 mov eax, 255 @ 2: Push eax mov EBX, 255 fild dword ptr [esp] fwait mov [esp], EBX fidiv dword ptr [esp] // bright/255 fwait XOR ECx, ECx test eax, eax JG @ loop xor ebx, EBX // mask = bright> 0? 255: 0 @ loop: mov [esp], ECx XOR [esp], EBX fild dword ptr [esp] fmul ST (0), ST (1) fistp dword ptr [esp] fwait mov eax, [esp] add eax, ECx mov [edX], Al // table [I] = (I ^ mask) * bright/255 Inc edX Inc ECx CMP ECx, 256 JB @ loop Ffree st pop eax pop ebxend; Procedure hsbsetbright (VAR data: timagedata; const table: tgraytable ); ASM push EBP push ESI push EDI push EBX mov ESI, EDX call _ setdataregs MoV EBP, EDX @ yloop: Push ECx @ xloop: movzx eax, [EDI]. targbquad. blue movzx edX, [EDI]. targbquad. green mov Al, [ESI + eax] mov DL, [ESI + EDX] mov [EDI]. targbquad. blue, Al mov [EDI]. targbquad. green, DL movzx eax, [EDI]. targbquad. red mov Al, [ESI + eax] mov [EDI]. targbquad. red, Al add EDI, 4 loop @ xloop pop ECx add EDI, EBX dec EBP jnz @ yloop pop EBX pop EDI pop ESI pop ebpend; Procedure hsbsethueandsat Uration (VAR data: timagedata; HV, SV: integer); const _ FC2: single = 2.0; _ FC4: single = 4.0; _ fc6: single = 6.0; _ fc128: single = 128.0; var hv0: integer; Fhv: single; width, height, datoffset: integer; ASM push ESI push EDI push EBX push ECx mov hv0, EDX call _ setdataregs mov width, ECX mov height, EDX mov datoffset, EBX pop EBX // SV pxor xmm7, xmm7 pxor xmm3, xmm3 // xmm3 are cleared, facilitating the mov eax, 1 during color phase processing or operations Optional xmm6, eax mov eax, 60 cvtsi2ss xmm5, hv0 cvtsi2ss xmm4, eax divss xmm5, xmm4 movss Fhv, xmm5 // Fhv = HV/60 mov eax, 255 Gb/s xmm5, EBX cvtsi2ss xmm4, eax divss xmm5, xmm4 movss xmm4, xmm5 // xmm4 = xmm5 = SV/255 test EBX, EBX jle @ 1 movaps xmm5, xmm6 // If (Sv> 0) subss xmm5, xmm4 // xmm5 = 1/(1-xmm4)-1 rcpss xmm5, xmm5 subss xmm5, xmm6 @ 1: pshufd xmm5, xmm5, 0 @ yloop: P Ush width @ xloop: movzx ECx, [EDI]. targbquad. blue movzx edX, [EDI]. targbquad. green movzx eax, [EDI]. targbquad. red CMP ECx, EDX // ECx = rgbmax jge @ 3 // edX = rgbmin xchg ECx, EDX @ 3: CMP ECx, eax jge @ 4 xchg ECx, eax @ 4: CMP edX, eax cmova edX, eax mov eax, ECx sub eax, edx jz @ next // If (delta = 0) Continue cvtsi2ss xmm3, eax // xmm3 = delta = rgbmax-rgbmin CMP hv0, 0 JNE @ 6 movd xmm0 ,[ EDI] punpcklbw xmm0, xmm7 punpcklwd xmm0, xmm7 cvtdq2ps xmm0, xmm0 JMP @ 20 @ 6: // adjust the color by HSV, Which is 40% faster than HSL movss xmm2, fhv // Add = Fhv CMP Cl, [EDI]. targbquad. red JNE @ 8 // If (r = rgbmax) eax = G-B movzx eax, [EDI]. targbquad. green movzx ESI, [EDI]. targbquad. blue JMP @ 10 @ 8: CMP Cl, [EDI]. targbquad. green JNE @ 9 movzx eax, [EDI]. targbquad. blue movzx ESI, [EDI]. targbquad. red addss xmm2, _ FC2 // If (G = rgbmax) eax = B-r; add + = 2 JMP @ 10 @ 9: movzx eax, [EDI]. targbquad. red movzx ESI, [EDI]. targbquad. green addss xmm2, _ FC4 // If (B = rgbmax) eax = r-g; add + = 4 @ 10: Sub eax, ESI cvtsi2ss xmm1, eax divss xmm1, xmm3 addss xmm1, xmm2 // H = eax/Delta + Add Comiss xmm1, xmm7 Jae @ 11 addss xmm1, _ fc6 // If (H <0) H + = 6 JMP @ 12 @ 11: Comiss xmm1, _ fc6 JB @ 12 subss xmm1, _ fc6 // else if (H> = 6) H-= 6 @ 12: cvtss2si ESI, xmm1 // Index = round (h) cvtsi2ss xmm2, ESI subss xmm1, xmm2 // extra = H-index Comiss xmm1, xmm7 // If (extra <0) // If the index is five-entry Jae @ 13 // {dec ESI // index -- addss xmm1, xmm6 // extra ++ @ 13: //} test ESI, 1 jnz @ 14 movaps xmm2, xmm1 movss xmm1, xmm6 subss xmm1, xmm2 // If (index & 1) = 0) Extra = 1-extra @ 14: mulss xmm1, xmm3 // xmm1 = delta * ex Tra ready xmm1, 4 orps xmm1, xmm3 movlhps xmm1, xmm7 // xmm1 = 0 0 Delta * extra Delta ready xmm0, ECx // xmm0 = V = rgbmax pshufd xmm0, xmm0, 0 // xmm0 = V v subps xmm0, xmm1 // xmm0-xmm1 = Nan v t p jmp @ jmptable [ESI * 4]. pointer @ jmptable: dd offset @ h60 dd offset @ H120 dd offset @ h180 dd offset @ h240 dd offset @ H300 dd offset @ h360 dd offset @ h60 // when H = 6.0 hours, index = 6 due to SSE judgment error, which should actually be 0 @ @ H360: // 300-359 (v, P, T) pshufd xmm0, xmm0, 111081b JMP @ h60 @ H300: // 240-299 (T, P, v) pshufd xmm0, xmm0, 11010010b JMP @ h60 @ h240: // 180-239 (P, T, v) pshufd xmm0, xmm0, 11000110b JMP @ h60 @ h180: // 120-179 (p, V, T) pshufd xmm0, xmm0, 11001001b JMP @ h60 @ H120: // 60-119 (T, V, p) pshufd xmm0, xmm0, 11011000b @ h60: // 0-59 (v, T, P) test EBX, EBX je @ 25 @ 20: // adjust the saturation. Add ECx, EDX // ECx = rgbmar + rgbmin cvtsi2ss xmm2, ECx divss xmm2, _ FC2 // xmm3 = L = ECx/2 pshufd xmm2, xmm2, 0 movaps xmm1, xmm0 subps xmm0, xmm2 // rgb0 = RGB-l test EBX, EBX jle @ 23 // If the saturation increment is positive, calculate the saturation by SHL to control the new saturation limit Comiss xmm2, _ fc128 // If (Sv> 0) JB @ 21 // {neg ECx add ECx, 510 // If (L> = 128) ECx = 510-ECx @ 21: cvtsi2ss xmm2, ECx divss xmm3, xmm2 // s = delta/ECx addss xmm3, xmm4 Comiss xmm3, xmm6 JB @ 23 subss xmm3, xmm4 // If (xmm4 + S)> = 1) rcpss xmm2, xmm3 // rgb0 = rgb0 * (1/s-1) subss xmm2, xmm6 // else pshufd xmm2, xmm2, 0 /// the memory has been calculated and stored in xmm5. mulps xmm0, xmm2 // rgb0 = rgb0 * (1/(1-xmm4)-1) JMP @ 24 //} @ 23: // else mulps xmm0, xmm5 // rgb0 = rgb0 * FSV @ 24: addps xmm0, xmm1 // RGB + = rgb0 @ 25: cvtps2dq xmm0, xmm0 packssdw xmm0, xmm7 packuswb xmm0, xmm7 mov Al, [EDI]. targbquad. alpha movd [EDI], xmm0 mov [EDI]. targbquad. alpha, Al @ next: Add EDI, 4 Dec width jnz @ xloop add EDI, datoffset pop width dec height jnz @ yloop pop EBX pop EDI pop esiend; procedure imagehsbadjustment (VAR data: timagedata; hvalue, svalue, bvalue: integer); var brighttab: tgraytable; begin if hvalue> 180 then hvalue: = 180 else if hvalue <-180 then hvalue: =-180; If svalue> 255 then svalue: = 255 else if svalue <-255 then svalue: =-255; if bvalue <> 0 then getbrighttable (bvalue, brighttab); If (svalue> 0) and (bvalue <> 0) Then hsbsetbright (data, brighttab ); if (hvalue <> 0) or (svalue <> 0) then begin hsbsethueandsaturation (data, hvalue, svalue); end; If (svalue <= 0) and (bvalue <> 0) Then hsbsetbright (data, brighttab); end;
From the code structure above, the colors, saturation, and brightness are basically "independent". Needless to say, the brightness is independent early, the sharing between the color and saturation is only the maximum and Difference values of the pixel RGB values (ECx and xmm3 in the hsbsethueandsaturation process ). After a simple test, the improved code speed is improved a lot. The time for adjusting the color, saturation, and brightness is only equivalent《Delphi Image Processing-color phase/saturation adjustment"The adjustment time of the color part in.
Finally, I despise csdn. Recently I have been sorting out and modifying previous articles. Each article has added 4-5 tags again, but within a few days, the tag of the article is gone, I thought I did not set it up. I added it again. A few days later, I lost it! If you don't have such a person, you despise csdn again.
For details about the use of GDI + units and descriptions in the "Delphi image processing" series, see the article 《GDI + for VCL basics-GDI + and VCL.
Due to limited levels, errors are inevitable. Correction and guidance are welcome. Email Address:Maozefa@hotmail.com
Here, you can access "Delphi Image Processing-Article Index".