diff options
Diffstat (limited to 'Gem/cMatrix.html')
-rw-r--r-- | Gem/cMatrix.html | 540 |
1 files changed, 270 insertions, 270 deletions
diff --git a/Gem/cMatrix.html b/Gem/cMatrix.html index fe4cd04..0181fc1 100644 --- a/Gem/cMatrix.html +++ b/Gem/cMatrix.html @@ -1,270 +1,270 @@ -<html>
-<head>
-<title>Matrix Operations for Image Processing</title>
-</head>
-<body bgcolor="#ffffff" text="#000000">
-<!--no_print--><br><center><table width=564><tr><td>
-<h2>Matrix Operations for Image Processing</h2>
-<!--no_print--><h3>Paul Haeberli</h3>
-<h3>Nov 1993</h3>
-<img src=../tribar.gif alt="Horiz Bar" width=561 height=3>
-<h3>Introduction</h3>
-<p>
-Four by four matrices are commonly used to transform geometry for 3D
-rendering. These matrices may also be used to transform RGB colors, to scale
-RGB colors, and to control hue, saturation and contrast. The most important
-advantage of using matrices is that any number of color transformations
-can be composed using standard matrix multiplication.
-<p>
-Please note that for these operations to be correct, we really must operate
-on linear brightness values. If the input image is in a non-linear brightness
-space RGB colors must be transformed into a linear space before these
-matrix operations are used.
-
-<h3>Color Transformation</h3>
-RGB colors are transformed by a four by four matrix as shown here:
-
-<pre>
- xformrgb(mat,r,g,b,tr,tg,tb)
- float mat[4][4];
- float r,g,b;
- float *tr,*tg,*tb;
- {
- *tr = r*mat[0][0] + g*mat[1][0] +
- b*mat[2][0] + mat[3][0];
- *tg = r*mat[0][1] + g*mat[1][1] +
- b*mat[2][1] + mat[3][1];
- *tb = r*mat[0][2] + g*mat[1][2] +
- b*mat[2][2] + mat[3][2];
- }
-</pre>
-
-<h3>The Identity</h3>
-This is the identity matrix:
-<pre>
- float mat[4][4] = {
- 1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0,
- };
-</pre>
-Transforming colors by the identity matrix will leave them unchanged.
-
-<h3>Changing Brightness</h3>
-To scale RGB colors a matrix like this is used:
-<pre>
- float mat[4][4] = {
- rscale, 0.0, 0.0, 0.0,
- 0.0, gscale, 0.0, 0.0,
- 0.0, 0.0, bscale, 0.0,
- 0.0, 0.0, 0.0, 1.0,
- };
-</pre>
-Where rscale, gscale, and bscale specify how much to scale the r, g, and b
-components of colors. This can be used to alter the color balance of an image.
-<p>
-In effect, this calculates:
-<pre>
- tr = r*rscale;
- tg = g*gscale;
- tb = b*bscale;
-</pre>
-
-<h3>Modifying Saturation</h3>
-
-
-<h3>Converting to Luminance</h3>
-To convert a color image into a black and white image, this matrix is used:
-<pre>
- float mat[4][4] = {
- rwgt, rwgt, rwgt, 0.0,
- gwgt, gwgt, gwgt, 0.0,
- bwgt, bwgt, bwgt, 0.0,
- 0.0, 0.0, 0.0, 1.0,
- };
-</pre>
-Where rwgt is 0.3086, gwgt is 0.6094, and bwgt is 0.0820. This is the
-luminance vector. Notice here that we do not use the standard NTSC weights
-of 0.299, 0.587, and 0.114. The NTSC weights are only applicable to RGB
-colors in a gamma 2.2 color space. For linear RGB colors the values above
-are better.
-<p>
-In effect, this calculates:
-<pre>
- tr = r*rwgt + g*gwgt + b*bwgt;
- tg = r*rwgt + g*gwgt + b*bwgt;
- tb = r*rwgt + g*gwgt + b*bwgt;
-</pre>
-
-<h3>Modifying Saturation</h3>
-
-To saturate RGB colors, this matrix is used:
-
-<pre>
- float mat[4][4] = {
- a, b, c, 0.0,
- d, e, f, 0.0,
- g, h, i, 0.0,
- 0.0, 0.0, 0.0, 1.0,
- };
-</pre>
-Where the constants are derived from the saturation value s
-as shown below:
-
-<pre>
- a = (1.0-s)*rwgt + s;
- b = (1.0-s)*rwgt;
- c = (1.0-s)*rwgt;
- d = (1.0-s)*gwgt;
- e = (1.0-s)*gwgt + s;
- f = (1.0-s)*gwgt;
- g = (1.0-s)*bwgt;
- h = (1.0-s)*bwgt;
- i = (1.0-s)*bwgt + s;
-</pre>
-One nice property of this saturation matrix is that the luminance
-of input RGB colors is maintained. This matrix can also be used
-to complement the colors in an image by specifying a saturation
-value of -1.0.
-<p>
-Notice that when <code>s</code> is set to 0.0, the matrix is exactly
-the "convert to luminance" matrix described above. When <code>s</code>
-is set to 1.0 the matrix becomes the identity. All saturation matrices
-can be derived by interpolating between or extrapolating beyond these
-two matrices.
-<p>
-This is discussed in more detail in the note on
-<a href="../interp/index.html">Image Processing By Interpolation and Extrapolation</a>.
-<h3>Applying Offsets to Color Components</h3>
-To offset the r, g, and b components of colors in an image this matrix is used:
-<pre>
- float mat[4][4] = {
- 1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- roffset,goffset,boffset,1.0,
- };
-</pre>
-This can be used along with color scaling to alter the contrast of RGB
-images.
-
-<h3>Simple Hue Rotation</h3>
-To rotate the hue, we perform a 3D rotation of RGB colors about the diagonal
-vector [1.0 1.0 1.0]. The transformation matrix is derived as shown here:
-<p>
- If we have functions:<br><br>
-<dl>
-<dt><code>identmat(mat)</code>
-<dd>that creates an identity matrix.
-</dl>
-<dl>
-<dt><code>xrotatemat(mat,rsin,rcos)</code>
-<dd>that multiplies a matrix that rotates about the x (red) axis.
-</dl>
-<dl>
-<dt><code>yrotatemat(mat,rsin,rcos)</code>
-<dd>that multiplies a matrix that rotates about the y (green) axis.
-</dl>
-<dl>
-<dt><code>zrotatemat(mat,rsin,rcos)</code>
-<dd>that multiplies a matrix that rotates about the z (blue) axis.
-</dl>
-Then a matrix that rotates about the 1.0,1.0,1.0 diagonal can be
-constructed like this:
-<br>
-First we make an identity matrix
-<pre>
- identmat(mat);
-</pre>
-Rotate the grey vector into positive Z
-<pre>
- mag = sqrt(2.0);
- xrs = 1.0/mag;
- xrc = 1.0/mag;
- xrotatemat(mat,xrs,xrc);
-
- mag = sqrt(3.0);
- yrs = -1.0/mag;
- yrc = sqrt(2.0)/mag;
- yrotatemat(mat,yrs,yrc);
-</pre>
-Rotate the hue
-<pre>
- zrs = sin(rot*PI/180.0);
- zrc = cos(rot*PI/180.0);
- zrotatemat(mat,zrs,zrc);
-</pre>
-Rotate the grey vector back into place
-<pre>
- yrotatemat(mat,-yrs,yrc);
- xrotatemat(mat,-xrs,xrc);
-</pre>
-The resulting matrix will rotate the hue of the input RGB colors. A rotation
-of 120.0 degrees will exactly map Red into Green, Green into Blue and
-Blue into Red. This transformation has one problem, however, the luminance
-of the input colors is not preserved. This can be fixed with the following
-refinement:
-
-<h3>Hue Rotation While Preserving Luminance</h3>
-
-We make an identity matrix
-<pre>
- identmat(mmat);
-</pre>
-Rotate the grey vector into positive Z
-<pre>
- mag = sqrt(2.0);
- xrs = 1.0/mag;
- xrc = 1.0/mag;
- xrotatemat(mmat,xrs,xrc);
- mag = sqrt(3.0);
- yrs = -1.0/mag;
- yrc = sqrt(2.0)/mag;
- yrotatemat(mmat,yrs,yrc);
- matrixmult(mmat,mat,mat);
-</pre>
-Shear the space to make the luminance plane horizontal
-<pre>
- xformrgb(mmat,rwgt,gwgt,bwgt,&lx,&ly,&lz);
- zsx = lx/lz;
- zsy = ly/lz;
- zshearmat(mat,zsx,zsy);
-</pre>
-Rotate the hue
-<pre>
- zrs = sin(rot*PI/180.0);
- zrc = cos(rot*PI/180.0);
- zrotatemat(mat,zrs,zrc);
-</pre>
-Unshear the space to put the luminance plane back
-<pre>
- zshearmat(mat,-zsx,-zsy);
-</pre>
-Rotate the grey vector back into place
-<pre>
- yrotatemat(mat,-yrs,yrc);
- xrotatemat(mat,-xrs,xrc);
-</pre>
-<h3>Conclusion</h3>
-I've presented several matrix transformations that may be applied
-to RGB colors. Each color transformation is represented by
-a 4 by 4 matrix, similar to matrices commonly used to transform 3D geometry.
-<p>
-<a href="matrix.c">Example C code</a>
-that demonstrates these concepts is provided for your enjoyment.
-<p>
-These transformations allow us to adjust image contrast, brightness, hue and
-saturation individually. In addition, color matrix transformations concatenate
-in a way similar to geometric transformations. Any sequence of
-operations can be combined into a single matrix using
-matrix multiplication.
-<!--no_print--><p>
-<!--no_print--><center>
-<!--no_print--><a href=../index.html#matrix><img src=../gobot.gif width=564 height=25 border=0></a>
-<!--no_print--><br>
-<!--no_print--></center>
-<!--no_print--></td></tr></table></center>
-</body>
-</html>
-
+<html> +<head> +<title>Matrix Operations for Image Processing</title> +</head> +<body bgcolor="#ffffff" text="#000000"> +<!--no_print--><br><center><table width=564><tr><td> +<h2>Matrix Operations for Image Processing</h2> +<!--no_print--><h3>Paul Haeberli</h3> +<h3>Nov 1993</h3> +<img src=../tribar.gif alt="Horiz Bar" width=561 height=3> +<h3>Introduction</h3> +<p> +Four by four matrices are commonly used to transform geometry for 3D +rendering. These matrices may also be used to transform RGB colors, to scale +RGB colors, and to control hue, saturation and contrast. The most important +advantage of using matrices is that any number of color transformations +can be composed using standard matrix multiplication. +<p> +Please note that for these operations to be correct, we really must operate +on linear brightness values. If the input image is in a non-linear brightness +space RGB colors must be transformed into a linear space before these +matrix operations are used. + +<h3>Color Transformation</h3> +RGB colors are transformed by a four by four matrix as shown here: + +<pre> + xformrgb(mat,r,g,b,tr,tg,tb) + float mat[4][4]; + float r,g,b; + float *tr,*tg,*tb; + { + *tr = r*mat[0][0] + g*mat[1][0] + + b*mat[2][0] + mat[3][0]; + *tg = r*mat[0][1] + g*mat[1][1] + + b*mat[2][1] + mat[3][1]; + *tb = r*mat[0][2] + g*mat[1][2] + + b*mat[2][2] + mat[3][2]; + } +</pre> + +<h3>The Identity</h3> +This is the identity matrix: +<pre> + float mat[4][4] = { + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + }; +</pre> +Transforming colors by the identity matrix will leave them unchanged. + +<h3>Changing Brightness</h3> +To scale RGB colors a matrix like this is used: +<pre> + float mat[4][4] = { + rscale, 0.0, 0.0, 0.0, + 0.0, gscale, 0.0, 0.0, + 0.0, 0.0, bscale, 0.0, + 0.0, 0.0, 0.0, 1.0, + }; +</pre> +Where rscale, gscale, and bscale specify how much to scale the r, g, and b +components of colors. This can be used to alter the color balance of an image. +<p> +In effect, this calculates: +<pre> + tr = r*rscale; + tg = g*gscale; + tb = b*bscale; +</pre> + +<h3>Modifying Saturation</h3> + + +<h3>Converting to Luminance</h3> +To convert a color image into a black and white image, this matrix is used: +<pre> + float mat[4][4] = { + rwgt, rwgt, rwgt, 0.0, + gwgt, gwgt, gwgt, 0.0, + bwgt, bwgt, bwgt, 0.0, + 0.0, 0.0, 0.0, 1.0, + }; +</pre> +Where rwgt is 0.3086, gwgt is 0.6094, and bwgt is 0.0820. This is the +luminance vector. Notice here that we do not use the standard NTSC weights +of 0.299, 0.587, and 0.114. The NTSC weights are only applicable to RGB +colors in a gamma 2.2 color space. For linear RGB colors the values above +are better. +<p> +In effect, this calculates: +<pre> + tr = r*rwgt + g*gwgt + b*bwgt; + tg = r*rwgt + g*gwgt + b*bwgt; + tb = r*rwgt + g*gwgt + b*bwgt; +</pre> + +<h3>Modifying Saturation</h3> + +To saturate RGB colors, this matrix is used: + +<pre> + float mat[4][4] = { + a, b, c, 0.0, + d, e, f, 0.0, + g, h, i, 0.0, + 0.0, 0.0, 0.0, 1.0, + }; +</pre> +Where the constants are derived from the saturation value s +as shown below: + +<pre> + a = (1.0-s)*rwgt + s; + b = (1.0-s)*rwgt; + c = (1.0-s)*rwgt; + d = (1.0-s)*gwgt; + e = (1.0-s)*gwgt + s; + f = (1.0-s)*gwgt; + g = (1.0-s)*bwgt; + h = (1.0-s)*bwgt; + i = (1.0-s)*bwgt + s; +</pre> +One nice property of this saturation matrix is that the luminance +of input RGB colors is maintained. This matrix can also be used +to complement the colors in an image by specifying a saturation +value of -1.0. +<p> +Notice that when <code>s</code> is set to 0.0, the matrix is exactly +the "convert to luminance" matrix described above. When <code>s</code> +is set to 1.0 the matrix becomes the identity. All saturation matrices +can be derived by interpolating between or extrapolating beyond these +two matrices. +<p> +This is discussed in more detail in the note on +<a href="../interp/index.html">Image Processing By Interpolation and Extrapolation</a>. +<h3>Applying Offsets to Color Components</h3> +To offset the r, g, and b components of colors in an image this matrix is used: +<pre> + float mat[4][4] = { + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + roffset,goffset,boffset,1.0, + }; +</pre> +This can be used along with color scaling to alter the contrast of RGB +images. + +<h3>Simple Hue Rotation</h3> +To rotate the hue, we perform a 3D rotation of RGB colors about the diagonal +vector [1.0 1.0 1.0]. The transformation matrix is derived as shown here: +<p> + If we have functions:<br><br> +<dl> +<dt><code>identmat(mat)</code> +<dd>that creates an identity matrix. +</dl> +<dl> +<dt><code>xrotatemat(mat,rsin,rcos)</code> +<dd>that multiplies a matrix that rotates about the x (red) axis. +</dl> +<dl> +<dt><code>yrotatemat(mat,rsin,rcos)</code> +<dd>that multiplies a matrix that rotates about the y (green) axis. +</dl> +<dl> +<dt><code>zrotatemat(mat,rsin,rcos)</code> +<dd>that multiplies a matrix that rotates about the z (blue) axis. +</dl> +Then a matrix that rotates about the 1.0,1.0,1.0 diagonal can be +constructed like this: +<br> +First we make an identity matrix +<pre> + identmat(mat); +</pre> +Rotate the grey vector into positive Z +<pre> + mag = sqrt(2.0); + xrs = 1.0/mag; + xrc = 1.0/mag; + xrotatemat(mat,xrs,xrc); + + mag = sqrt(3.0); + yrs = -1.0/mag; + yrc = sqrt(2.0)/mag; + yrotatemat(mat,yrs,yrc); +</pre> +Rotate the hue +<pre> + zrs = sin(rot*PI/180.0); + zrc = cos(rot*PI/180.0); + zrotatemat(mat,zrs,zrc); +</pre> +Rotate the grey vector back into place +<pre> + yrotatemat(mat,-yrs,yrc); + xrotatemat(mat,-xrs,xrc); +</pre> +The resulting matrix will rotate the hue of the input RGB colors. A rotation +of 120.0 degrees will exactly map Red into Green, Green into Blue and +Blue into Red. This transformation has one problem, however, the luminance +of the input colors is not preserved. This can be fixed with the following +refinement: + +<h3>Hue Rotation While Preserving Luminance</h3> + +We make an identity matrix +<pre> + identmat(mmat); +</pre> +Rotate the grey vector into positive Z +<pre> + mag = sqrt(2.0); + xrs = 1.0/mag; + xrc = 1.0/mag; + xrotatemat(mmat,xrs,xrc); + mag = sqrt(3.0); + yrs = -1.0/mag; + yrc = sqrt(2.0)/mag; + yrotatemat(mmat,yrs,yrc); + matrixmult(mmat,mat,mat); +</pre> +Shear the space to make the luminance plane horizontal +<pre> + xformrgb(mmat,rwgt,gwgt,bwgt,&lx,&ly,&lz); + zsx = lx/lz; + zsy = ly/lz; + zshearmat(mat,zsx,zsy); +</pre> +Rotate the hue +<pre> + zrs = sin(rot*PI/180.0); + zrc = cos(rot*PI/180.0); + zrotatemat(mat,zrs,zrc); +</pre> +Unshear the space to put the luminance plane back +<pre> + zshearmat(mat,-zsx,-zsy); +</pre> +Rotate the grey vector back into place +<pre> + yrotatemat(mat,-yrs,yrc); + xrotatemat(mat,-xrs,xrc); +</pre> +<h3>Conclusion</h3> +I've presented several matrix transformations that may be applied +to RGB colors. Each color transformation is represented by +a 4 by 4 matrix, similar to matrices commonly used to transform 3D geometry. +<p> +<a href="matrix.c">Example C code</a> +that demonstrates these concepts is provided for your enjoyment. +<p> +These transformations allow us to adjust image contrast, brightness, hue and +saturation individually. In addition, color matrix transformations concatenate +in a way similar to geometric transformations. Any sequence of +operations can be combined into a single matrix using +matrix multiplication. +<!--no_print--><p> +<!--no_print--><center> +<!--no_print--><a href=../index.html#matrix><img src=../gobot.gif width=564 height=25 border=0></a> +<!--no_print--><br> +<!--no_print--></center> +<!--no_print--></td></tr></table></center> +</body> +</html> + |