- Restruct folder tree
This commit is contained in:
parent
39999df6a8
commit
4d31605318
5419 changed files with 527223 additions and 18 deletions
270
src/Gem/doc/cMatrix.html
Normal file
270
src/Gem/doc/cMatrix.html
Normal file
|
@ -0,0 +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>
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue