Reading Tips:
The C ++ image processing series focuses on code clarity and readability, all using C ++ code.
《Delphi Image ProcessingThe series focuses on efficiency. The general code is Pascal, and the core code is BaSm.
Make sure that the two items are consistent and can be compared with each other.
The code in this article must include "C ++ Image Processing-data types and common functions"The header file of BMP data. h in this article.
The image black and white adjustment function of Photoshop CS is achieved through proportional adjustment of 6 colors, including red, yellow, green, blue, and foreign red. Color images can be converted to high-quality black and white photos in a more refined manner.
The formula for calculating the Photoshop CS image black/white adjustment function is as follows:
Gray = (max-min) * ratio_max + (mid-min) * ratio_max_mid + min
In the formula, gray is the pixel gray value, and Max, mid, and min are the maximum, middle, and minimum values of the pixel R, G, and B respectively, ratio_max is the component color (monochrome) ratio represented by Max, and ratio_max_mid is the compound color ratio formed by the two component colors of Max and mid.
The gray scale value calculated using the formula above is very different from the gray scale calculation method we usually use. Generally, the gray scale formula is used to directly multiply each color component by the corresponding ratio, for example, gray = 0.3r + 0.59G + 0.11b, and the above formula is based on the color component represented by the minimum value, use the difference between the maximum value and the minimum value to represent the monochrome part (red, green, and blue), and use the difference between the middle value and the minimum value to represent the secondary part (yellow, blue, and foreign red ), multiply the monochrome and compound colors by the corresponding ratio, and then add the minimum value to get the gray value. For each individual pixel, you only need to use two of the above six color ratios to calculate the gray value. In the calculation process, you can select the corresponding monochrome and secondary color ratio based on the pixel RGB relationship. For example, the relationship between pixel RGB values is r> G> B, and the maximum monochrome ratio is r red, the compound color ratio is the compound color yellow formed by the maximum R and the middle G.
It is not complicated to use the program code to implement the above grayscale calculation formula. The difficulty is to select the corresponding monochrome and compound Color Ratio Based on the pixel RGB relationship.
An additional coloring function is added to the black/white adjustment function of Photoshop images. This function is actually implemented using the principle of layer color mixing mode. I have introduced the principle of the layer Color Mixing Mode and Its Implementation Code in "Delphi Image Processing-image color mixing, you can refer to these articles.
The following is the BaSm code that uses Delphi to Realize Image black and white adjustment, including the gray image coloring function code:
Type tbwparams = array [0 .. 5] of single; // eax, EDX, ECx = R, G, B ESI, SDI, EBX = rindex, gindex, bindexprocedure comparergb; ASM CMP eax, ECX Jae @ 1 xchg eax, ECx xchg ESI, EBX @ 1: CMP eax, EDX Jae @ 2 xchg eax, EDX xchg ESI, EDI @ 2: CMP ECx, edX jbe @ 3 xchg ECx, EDX xchg EBX, EDI @ 3: end; // In: ESI = srcpixel, EDI = dstpixel, eax = gray // out: [EDI] = mixercolorprocedure colormix; const grayconst: array [0 .. 2] of intege R = (113,604,307); var gray, max_min: longword; ASM push ESI push EDI mov gray, eax movzx ECx, [esi]. targbquad. blue movzx edX, [esi]. targbquad. green movzx eax, [esi]. targbquad. red xor ebx, EBX // blue index mov EDI, 1 // green index mov ESI, 2 // red index call comparergb // comparergb (red, green, blue) sub eax, ECX // max-min jnz @ 4 pop EDI mov eax, gray mov [EDI]. targbquad. blue, Al mov [EDI]. Targbquad. green, Al mov [EDI]. targbquad. red, Al JMP @ exit @ 4: Sub edX, ECx // mid-min mov max_min, eax mov ECx, eax sub eax, EDX imul eax, grayconst [EDI * 4]. integer imul ECx, grayconst [EBX * 4]. integer add eax, ECx add eax, 512 // Nmax = gray + SHR eax, 10 // (max_min-mid_min) * grayconst [midindex] + Add eax, gray // max_min * grayconst [minindex] CMP eax, 255 ja @ 5 mov ECx, eax sub ECx, max_min // Nmin = Nmax-max_min JS @ 6 Add edX, ECx // nmid = Nmin + mid_min JMP @ 8 @ 5: // Nmax> 255 SHL edX, 10 // huecoef = (mid_min <10)/max_min mov eax, max_min xchg eax, EDX Mul divtab [edX * 4]. integer push edX mov ECx, grayconst [EDI * 4]. integer imul edX, ECx SHR edX, 10 // V0 = (YS [mid. index] * huecoef)> 10 Add ECx, grayconst [EBX * 4]. integer sub ECx, EDX // V1 = ys [mid. index] + ys [Min. index]- V0 add edX, grayconst [ESI * 4]. integer mov eax, edx shl edX, 8 sub edX, eax mov eax, gray SHL eax, 10 sub eax, EDX mov edX, ECx SHR edX, 1 add eax, edX Mul divtab [ECx * 4]. integer mov ECx, EDX // Nmin = (gray <10)-(YS [Max. index] + V0) * Pop eax // 255 + (V1> 1)/V1 XOR edX, 255 imul edX, eax add edX, 512 SHR edX, 10 Add edX, ECX // nmid = Nmin + (255 ^ newmin) * huecoef + 512)> 10) mov EA X, 255 // Nmax = 255 JMP @ 8 @ 6: // Nmin <0 SHL edX, 10 // huecoef = (mid_min <10)/max_min mov eax, max_min xchg eax, EDX Mul divtab [edX * 4]. integer push edX imul edX, grayconst [EDI * 4]. integer add edX, 512 SHR edX, 10 // TMP = ys [Max. index] + (YS [mid. index] * huecoef + 512)> 10) add edX, grayconst [ESI * 4]. integer mov eax, gray SHL eax, 10 mov ECx, edx shr edX, 1 add eax, EDX Mul divtab [ECx * 4]. Integer mov eax, EDX // Nmax = (gray <10) + (TMP> 1)/tmp pop edX imul edX, eax add edX, 512 SHR edX, 10 // nmid = (Nmax * huecoef + 512)> 10 mov ECx, 1 // Nmin = 1 @ 8: mov ah, DL pop edX mov [edX + esi], Al mov [edX + EDI], Ah mov [edX + EBX], CL mov EDI, EDX @ Exit: Pop esiend; // adjust the image black/white. // Adjust the bwparams parameter to be an array pointer with the number of elements equal to 6. Values: red, yellow, green, blue, and foreign red procedure imageblackwhite (var dest: timagedata; const Source: timagedata; const bwparams: tbwparams); overload; var I: integer; width, height: integer; dstoffset, srcoffset: integer; Params: array [0 .. 5] of integer; begin for I: = 0 to 5 do // the floating-point black and white parameters are converted to Integers and exchanged between the blue and the magenta position Params [I]: = round (bwparams [I] * 1024); Params [3]: = Params [3] XOR Params [5]; Params [5]: = par AMS [5] XOR Params [3]; Params [3]: = Params [3] XOR Params [5]; ASM push ESI push EDI push EBX mov eax, DEST mov edX, source call _ setcopyregs mov width, ECx mov height, EDX mov dstoffset, EBX mov srcoffset, eax @ yloop: Push width @ xloop: Push ESI push EDI movzx ECx, [esi]. targbquad. blue movzx edX, [esi]. targbquad. green movzx eax, [esi]. targbquad. red mov EBX, 4 // blue index mov EDI, 2 // green Index Xor esi, ESI // red index call comparergb // comparergb (red, green, blue) sub eax, EDX // max-mid sub edX, ECX // mid-min add EDI, ESI dec EDI imul eax, Params [ESI * 4]. integer imul edX, Params [EDI * 4]. integer add eax, EDX // gray = (max-mid) * Params [maxindex] + Add eax, 512 // (mid-min) * Params [maxindex + midindex-1] + SAR eax, 10 // 512)> 10) + min add eax, ECx JNS @ 1 XOR eax, eax JMP @ 2 @ 1: CMP eax, 255 JB @ 2 mov eax, 255 @ 2: Pop EDI pop ESI mov [EDI]. targbquad. blue, Al mov [EDI]. targbquad. green, Al mov [EDI]. targbquad. red, Al add EDI, 4 Add ESI, 4 Dec width JNE @ xloop pop width add EDI, dstoffset add ESI, srcoffset dec height jnz @ yloop pop EBX pop EDI pop ESI end; // adjust the image in black and white. // Adjust the bwparams parameter to be an array pointer with the number of elements equal to 6. Values: red, yellow, green, green, blue, and foreign red procedure imageblackwhite (VAR data: timagedata; const bwparams: tbwparams); overload; begin imageblackwhite (data, data, bwparams); end; // grayscale image dyeing. Procedure imageargbtint (VAR data: timagedata; argb: longword); var width, height: integer; dataoffset: integer; mixtable: array [0 .. 255] of targbquad; ASM push ESI push EDI push EBX push eax push edX // create grayscale dyeing table mixtable SHR edX, 24 cvtsi2ss xmm6, EDX mov edX, 255 cvtsi2ss xmm0, edX divss xmm6, xmm0 pshufd xmm6, xmm6, 0 // xmm6 = argb. alpha/255 mov edX, 1 movd xmm5, EDX pshufd xmm5, xmm5, 0 // xmm5 = 1 pxor xmm4, xmm4 // xmm4 = 0 pxor xmm7, xmm7 Lea ESI, [esp] Lea EDI, mixtable XOR eax, eax @ calcmixtable: push eax // mixtable [I]. RGB = I + colormix (& argb, I) * argb. alpha/255 call colormix movd xmm0, [EDI] // xmm0 = colormix (& argb, I) punpcklbw xmm0, xmm7 punpcklwd xmm0, xmm7 psubd xmm0, xmm4 // xmm0-= I cvtdq2ps xmm0, xmm0 mulps xmm0, xmm6 // xmm0 = xmm0 * argb. alpha/255 cvtps2dq xmm0, XMM 0 paddd xmm0, xmm4 // xmm0 + = I paddd xmm4, xmm5 // I ++ packssdw xmm0, xmm7 packuswb xmm0, xmm7 movd [EDI], xmm0 // mixtable [I] = xmm0 pop eax add EDI, 4 Inc eax CMP eax, 256 JB @ calcmixtable pop edX pop eax call _ setdataregs Lea eax, mixtable @ yloop: push ECx @ xloop: movzx ESI, [EDI]. targbquad. blue Lea ESI, [eax + ESI * 4] movsw movsb // PD. RGB = mixtable [PD. blue] Inc EDI loop @ xloop pop ECx add E Di, EBX dec edX jnz @ yloop pop EBX pop EDI pop esiend; // grayscale image dyeing. Procedure imagecolortint (VAR data: timagedata; color: tcolor); ASM bswap edX SHR edX, 8 or edX, 0ff000000h call imageargbtintend;
The Code contains two black and white image adjustment processes: the copy form of image data and the Self-processing black and white adjustment process. There are also two dyeing processes, which correspond to the argb color and VCL color tcolor respectively. The dyeing process adopts the color table search method, which is very efficient, that is, the processing speed of pure Pascal code is also quite fast. If the opacity of the color is not taken into account, the SSE code in the process can be deleted.
The following is a simple example of dyeing PNG images after black and white removal:
procedure TForm1.Button1Click(Sender: TObject);var bmp: TGpBitmap; g: TGpGraphics; data: TImageData;begin bmp := TGpBitmap.Create('..\..\media\xmas_011.png'); data := LockGpBitmap(bmp); ImageBlackWhite(data, BWColors); ImageArgbTint(data, $ffff0000); UnlockGpBitmap(bmp, data); g := TGpGraphics.Create(PaintBox1.Canvas.Handle); g.DrawImage(bmp, 0, 0); g.Free; bmp.Free;end;
Run the following command:
The source image is on the left, and the black and white gray are processed on the right, and then colored in red. It is necessary to note that the dyeing process processes not only black and white images, but also any gray images.
I originally wrote a Delphi program that imitates the Photoshop black and white adjustment function, but the code is long, in addition, a demo program with the same interface already exists in "C ++ Image Processing-Application of Image black and white adjustment", and there are several running interfaces, so no code will be pasted here. If you are interested, refer to this article.
Due to limited levels, errors are inevitable. Correction and guidance are welcome. Email Address:Maozefa@hotmail.com
Here, you can access "C ++ Image Processing-Article Index".