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.
In GDI +, color matrix transformation is an important means to process the color of an image, including color scaling, cropping, rotating, and moving. In GDI +, the color matrix colormatrix is defined as a two-dimensional floating-point array of 5*5, which is arranged as follows:
According to the color matrix transformation function, the following lists the formulas for scaling, rotation, cutting, translation, and all transformations. In the formula, uppercase argb indicates the existing values of each color component, lower-case argb indicates the new value after calculation.
1. color scaling: Color scaling is simple, that is, based on the given proportional value, a new component value is calculated based on the existing component values of A, R, G, and B in the image pixel. This proportional value is the other four values except M55 on the main diagonal line of colormatrix:
R = r * M11
G = g * m22
B = B * M33
A = A * m44
2. Color Cutting: In general, the R, G, and B components of an image increase or decrease the color weight in proportion to the other color weight is cut. In fact, this expression is not complete, and the component of the pixel is also involved!
Taking the red component R as an example, if you want to cut by the green component G, then m21 is the shear ratio value, and m21 * g gets the shear volume of G to R. Similarly, m31 * B and M41 * A can obtain the shear volumes of B and A to R respectively. The total shear volumes are the total shear volumes of R. Expressed:
R = g * m21 + B * m31 + A * M41
G = r * m12 + B * M32 + A * M42
B = r * M13 + G * M23 + A * m43
A = r * m14 + G * M24 + B * m34
3. Color RotationThe description of color rotation is complex. In the image pixels, two of them are used for calculation based on a certain angle and the other one is the color rotation. Take the red component R and green component G as an example to rotate 60 degrees around the blue component G:
M11 = cos (60) = 0.5, M12 = sin (60) = 0.866, m21 =-sin (60) =-0.866, m22 = cos (60) = 0.5, then, R and G get the following rotation values:
R = r * M11 (0.5) + G * m21 (-0.866)
G = r * M12 (0.866) + G * m22 (0.5)
From the above formula, the so-called color rotation volume is actually the scaling volume of the two rotating components plus the shear volume of the other party! From an operational perspective, it has nothing to do with other components.
4. Color Translation: The scaling, cutting, and rotation above belong to the linear transformation of colors (both the accumulation and multiplication operations), while the translation is a non-linear transformation of colors, that is, an addition to each color component: the translation of each component of the image pixel is represented by the so-called virtual bit, that is, the value of each 5th row. The value of the virtual row of each component plus the column is the color translation, the essence is to adjust the brightness value of this component nonlinear. Use the formula to indicate the translation volume of each component:
R = R + m51 x 255;
G = G + m52 * 255;
B = B + m53 * 255;
A = a + m54x 255;
5. Complete transformation: The formula for completely changing the color matrix is:
R = r * M11 + G * m21 + B * m31 + A * M41 + m51 * 255
G = r * m12 + G * m22 + B * M32 + A * M42 + m52 * 255
B = r * M13 + G * M23 + B * M33 + A * m43 + m53 * 255
A = r * m14 + G * M24 + B * m34 + A * m44 + M54 * 255
Technically, this formula indicates the new value of each component of the color, equals to the product of the values of the first four rows of the corresponding column in colormatrix and the current values of R, G, A, and B plus the product of the values of the first 5th rows and the constant 255, the virtual column (5th columns) does not have any effect.
The following is the color matrix transformation code.
// ----------------------------------------------------------------------------- Forceinlineint checkvalue (INT value) {return (Value &~ 0xff) = 0? Values: value> 255? 255: 0;} // define void imagesetcolormatrix (bitmapdata * DEST, const bitmapdata * Source, colormatrix * matrix) {int im [5] [5]; bool scale = true; for (INT I = 0; I <5; I ++) {for (Int J = 0; j <4; j ++) // does not include the virtual column {if (I = 4) // translates im [4] [J] = (INT) (matrix-> M [4] [J] * 255 + 0.5); else // scale and cut im [I] [J] = (INT) (matrix-> M [I] [J] * 256 + 0.5); if (I! = J & im [I] [J]) scale = false ;}// obtain the data processing parameters pargbquad PD, PS; uint width, height; int dstoffset, srcoffset; getdatacopyparams (DEST, source, width, height, PD, PS, dstoffset, srcoffset); If (scale) // process scaling {for (uint y = 0; y
The code is completely written in C ++, which is less efficient than the assembly code in "Delphi Image Processing-color matrix transformation.
It should be noted that the effect of color matrix transformation in this article is different from that in Delphi Image Processing-color matrix transformation, which is not a language difference, instead, "Delphi Image Processing-color matrix transformation" is modeled on the effect of GDI + color matrix transformation in the Windows XP environment, the code in this article implements the effect of GDI + color matrix transformation in the Windows 7 environment. That is to say, the GDI + color matrix transformation in Windows 7 and Windows XP is somewhat different, the difference mainly lies in the data saturation processing method. XP adopts the truncation method when scaling and transforming, while other transformations adopt the saturation method, while win7 uses the saturation method all, the saturation accuracy is higher than that of XP. Especially when the conversion result is a negative number, for example, in XP, we often use the GDI + color matrix RGB main diagonal line to scale to 1 to display the reversed image, in Windows 7, it is all black! In fact, using the GDI + color matrix, the diagonal line of the RGB column is-1 to display the reversed diagram itself should be a bug, I have mentioned this in the article "completely revealing the secrets of GDI + colormatrix" for a long time.
The following is an example program written in BCB similar to "Delphi Image Processing-color matrix transformation", where the "Reversed" button is still retained. Of course, the running is a black image instead of a reversed image:
Header file:
// Define # ifndef mainh # define mainh // --------------------------------------------------------------------------- # include <classes. HPP> # include <controls. HPP> # include <stdctrls. HPP> # include <forms. HPP> # include <buttons. HPP> # include <extctrls. HPP> # include <grids. HPP> # include "BMP data. H "//---------------------------------------------- Using class tform1: Public tform {__ published: // ide-managed componentstlabel * label1; using * handle; tspeedbutton * speedbutton1; tspeedbutton * speedbutton2; tspeedbutton * speedbutton3; tspeedbutton * speedbutton4; tstringgrid * stringgrid1; Comment * bitbtn1; tbitbtn * bitbtn3; Comment * handle; void _ fastcall formcreate (tobject * sender); void _ fastcall formdestroy (tobject * sende R); void _ fastcall bitbtn1click (tobject * sender); void _ fastcall bitbtn2click (tobject * sender); void _ fastcall bitbtn3click (tobject * sender ); void _ fastcall paintbox1paint (tobject * sender); void _ fastcall stringgrid1drawcell (tobject * sender, int ACOl, int Arow, trect & rect, tgriddrawstate State ); void _ fastcall speedbutton2click (tobject * sender); void _ fastcall speedbutton3click (tobject * sender); V Oid _ fastcall speedbutton1click (tobject * sender); void _ fastcall speedbutton4click (tobject * sender); void _ fastcall else (tobject * sender, int ACOl, int Arow, unicodestring & value); void _ fastcall stringgrid1setedittext (tobject * sender, int ACOl, int Arow, const unicodestring value); Private: // user declarationsbitmap * source; // bitmap * DEST of the source image; // bitmapdata srcdata of the adjusted image; bitmapda Ta dstdata; colormatrix matrix; void _ fastcall initcolormatrix (void); double _ fastcall checkfloatstr (string Str); public: // user declarations _ fastcall tform1 (tcomponent * owner) ;__ fastcall ~ Tform1 (void) ;}; // ----------------------------------------------------------------------------- extern package tform1 * form1; // define # endif
Code file:
// ----------------------------------------------------------------------------- # Include <VCL. h> # pragma hdrstop # include "Main. H "// ----------------------------------------------------------------------------- # pragma package (smart_init) # pragma resource "*. DFM "tform1 * form1; ulong gdiplustoken; // your _ fastcall tform1: tform1 (tcomponent * Owner): tform (owner) {gdiplus: gdiplusstartupinput; gdiplusstartup (& gdiplustoken, & blank, null);} // fastcall tform1 ::~ Tform1 (void) {gdiplusshutdown (gdiplustoken);} // define void _ fastcall tform1: formcreate (tobject * sender) {// mount the image from the file to tmpbitmap * TMP = new Bitmap (L ".. \\.. \ media \ 100_0349.jpg "); gdiplus: rect (0, 0, TMP-> getwidth (), TMP-> getheight ()); // create new source and target image data to srcdata and dstdatagetbitmapdata (rect. width, rect. height, & srcdata); getbitmapdata (R ECT. width, rect. height, & dstdata); // lock and copy the TMP image data to srcdata and dstdatatmp-> lockbits (& rect, imagelockmoderead | imagelockmodewrite | cursor, pixelformat32bppargb, & srcdata ); TMP-> unlockbits (& srcdata); TMP-> lockbits (& rect, imagelockmoderead | imagelockmodewrite | delimiter, pixelformat32bppargb, & dstdata); TMP-> unlockbits (& dstdata ); delete TMP; // create a bitmap sou with the image data srcdata and dstdata respectively. RCE and DEST // Note: The image data structure is used for data processing, and the bitmap is used for display, so that the data structure and bitmap can be bound, // avoid locking and unlocking each time image data is processed. Source = new Bitmap (srcdata. width, srcdata. height, srcdata. stride, pixelformat32bppargb, (byte *) srcdata. scan0); DEST = new Bitmap (dstdata. width, dstdata. height, dstdata. stride, pixelformat32bppargb, (byte *) dstdata. scan0); initcolormatrix ();} // --------------------------------------------------------------------------- void _ fastcall Tform1: formdestroy (tobject * sender) {Delete DEST; Delete source; freebitmapdata (& dstdata); freebitmapdata (& srcdata);} // define void _ fastcall tform1 :: initcolormatrix (void) {for (INT I = 0; I <5; I ++) {for (Int J = 0; j <5; j ++) matrix. M [I] [J] = (I = J )? 1.0: 0.0; }}// invalid void _ fastcall tform1: bitbtn1click (tobject * sender) {imagesetcolormatrix (& dstdata, & srcdata, & matrix ); paintbox1-> invalidate (); stringgrid1-> cells [stringgrid1-> Col] [stringgrid1-> row] = floattostr (matrix. M [stringgrid1-> row] [stringgrid1-> Col]); stringgrid1-> invalidate (); stringgrid1-> setfocus ();} // define void _ fastcall tform1 :: bitbtn2click (tobject * sender) {initcolormatrix (); bitbtn1-> click ();} // define void _ fastcall tform1: bitbtn3click (tobject * sender) {close () ;}// your void _ fastcall tform1: paintbox1paint (tobject * sender) {gdiplus: Graphics g (paintbox1-> canvas-> handle); G. drawimage (source, 10, 10); G. drawimage (DEST, srcdata. width + 20, 10);} // specify double _ fastcall tform1: checkfloatstr (string Str) {double result = 0; int Len = Str. length (); If (LEN = 0) return result; bool dec = false; bool neg = false; int I = 1; string S = ""; if (STR [I] = '-' | STR [I] = '+') {If (STR [I ++] = '-') neg = true ;}for (; I <= Len; I ++) {If (STR [I] = '. ') {If (DEC) break; dec = true;} else if (STR [I] <'0' | STR [I]> '9') break; S + = STR [I];} If (S. length ()> 0) {If (NEG) S = "-" + S; Result = S. todouble ();} return result;} // invalid void _ fastcall tform1: stringgrid1drawcell (tobject * sender, int ACOl, int Arow, trect & rect, tgriddrawstate state) {string text = format ("%. 2f ", & tvarrec (matrix. M [Arow] [ACOl]), 0); stringgrid1-> canvas-> fillrect (rect); stringgrid1-> canvas-> pen-> color = clbtnshadow; stringgrid1-> canvas-> rectangle (rect); inflaterect (& rect,-2,-2); drawtext (stringgrid1-> canvas-> handle, text. t_str (), text. length (), & rect, dt_right);} // define void _ fastcall tform1: stringgrid1getedittext (tobject * sender, int ACOl, int Arow, unicodestring & value) {value = format ("%. 2f ", & tvarrec (matrix. M [Arow] [ACOl]), 0);} // invalid void _ fastcall tform1: stringgrid1setedittext (tobject * sender, int ACOl, int Arow, const unicodestring value) {matrix. M [Arow] [ACOl] = checkfloatstr (value);} // define void _ fastcall tform1: speedbutton2click (tobject * sender) {initcolormatrix (); for (INT I = 0; I <3; I ++) matrix. M [4] [I] = 0.1; bitbtn1-> click ();} // define void _ fastcall tform1: speedbutton3click (tobject * sender) {initcolormatrix (); for (INT I = 0; I <3; I ++) matrix. M [I] [I] =-1.0; bitbtn1-> click ();} // define void _ fastcall tform1: speedbutton1click (tobject * sender) {initcolormatrix (); for (INT I = 0; I <3; I ++) {matrix. M [0] [I] = 0.30; matrix. M [1] [I] = 0.59; matrix. M [2] [I] = 0.11;} bitbtn1-> click ();} // define void _ fastcall tform1: speedbutton4click (tobject * sender) {initcolormatrix (); matrix. M [3] [3] = 0.5; bitbtn1-> click ();}//---------------------------------------------------------------------------
Running interface:
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".