<?xml version='1.0' encoding='UTF-8'?>

<?xml-stylesheet href="./_c74_tut.xsl" type="text/xsl"?>
<chapter name="Tutorial 49: Colorspaces">
<setdocpatch name="49jColorspaces" patch="49jColorspaces.maxpat"/>

<previous name="jitterchapter48">Frames of MSP signals</previous>
<next name="jitterchapter50">Procedural Texturing &amp; Modeling</next>
<parent name="jitindex">Jitter Tutorials</parent>



<h1>Tutorial 49: Colorspaces</h1>

<techdetail>
	<i>Note:</i> Some techniques described in this tutorial are outdated. Users are recommended to use <o>jit.movie</o> with <b>output_texture</b> enabled instead of uyvy colormode for efficiency of uploading movie frames to the GPU. See the <link type="vignette" module="core" name="jitter_gl_texture_output">GL Texture Output</link> article for more information.
</techdetail>

<p>In order to generate and display matrices of video data in Jitter, we make some assumptions about how the digital image is represented. For many typical uses (as covered by earlier tutorials) we encode color images into 4-plane matrices of type <m>char</m>. These planes represent the alpha, red, green, and blue color channels of each cell in that matrix. This type of color representation (ARGB) is useful as it closely matches both the way we see color (through color receptors in our eyes tuned to red, green, and blue) and the way computer monitors, projectors, and televisions display it. <i><link type="tutorial" module="jit" name="jitterchapter05">Tutorial 5:</link> ARGB Color</i> examines the rationale behind this system and explains how you typically manipulate this data.</p>

<p>It's important to note, however, that ARGB is not the only way to represent color information in a digital form. This tutorial examines one of several different ways of representing color image information in Jitter matrices, along with a discussion of several alternatives available to us for different uses. Along the way we'll look at a simple, efficient way to texture video onto an OpenGL plane to take advantage of hardware accelerated post-processing of the video image.</p>

<div>
<techdetail>Software Requirement: In order to use the <m>uyvy</m> <m>colormode</m> in Jitter under QuickTime version 6.5 and earlier, your media needs to be compressed with a codec that uses a YUV colorspace (discussed in depth below).  QuickTime media compressed with codecs using an RGB colorspace (e.g. PICT files or Planar RGB video files) cannot be decompressed by <o>jit.movie</o> in the <m>uyvy</m> <m>colormode</m> used in this Tutorial.  QuickTime version 7 and later will allow you to work in the <m>uyvy</m> <m>colormode</m> regardless of the colorspace in which your media is encoded.</techdetail>
</div>
<bullet>Open the tutorial patch.</bullet>
<p>At first glance, this patch looks very similar to the one we used in <i><link type="tutorial" module="jit" name="jitterchapter12">Tutorial 12:</link> Color Lookup Tables</i>. It reads a file into a <o>jit.movie</o> object, sending the matrices out into a <o>jit.charmap</o> object, where we can alter the color mapping of the different planes in an arbitrary manner by creating a matrix (<m>themap</m>) that serves as a color lookup table. The processed matrix is then displayed.</p>

<bullet>Click the <o>message</o> box labeled <m>read colorwheel.jpg</m>. Click the <o>toggle</o> labeled <i>Display</i> connected the <o>qmetro</o> object at the top of the patch. You should see the colorwheel appear both in the <o>jit.pwindow</o> and in the window created by the <o>jit.window</o> object.</bullet>
<p>Though it isn't immediately obvious (yet), the image matrix in our patch is being generated and manipulated according to a different system of color than the ARGB mapping we're accustomed to. The <o>jit.movie</o> object in this patch is transmitting matrices using a <m>colormode</m> called <m>uyvy</m>. This means that are image processing chain is working with data in a different colorspace than we usually work in, called YUV 4:2:2. In addition to transmitting color according to a different coordinate system than we usually use (YUV instead of ARGB), this mode of transmission uses a technique called <i>chroma subsampling</i> to reduce (by half!) the amount of data transmitted for an image of a given size.</p>

<h2>Color Lookup with a Twist</h2>
<bullet>Try manipulating the <o>multislider</o> objects at the right of the patch. Notice that they have an effect on how color is mapped in the image. You may get the sense that the three <o>multislider</o> objects correspond to the mapping of green, red, and blue in the matrix, respectively. Try zeroing the leftmost (black-on-white) <o>multislider</o> (i.e. set all of its values to <m>0</m>). Notice that the image disappears. Click on the <o>button</o> labeled <i>normal</i> to put everything back. Try zeroing the other two <o>multislider</o>s in turn, then setting them to straight horizontal lines across the middle of their range.</bullet>
<illustration><img src="images/jitterchapter49a.png"/>Manipulating the color.</illustration>
<p>The YUV colorspace is a luminance/chrominance color system&#x2014;it separates the luminosity of a given color from the chromatic information used to determine its hue. It stores the luminosity of a given pixel in a luminance channel (<i>Y</i>). The <i>U</i> channel is then created by subtracting the <i>Y</i> from the amount of blue in the color image. The <i>V</i> channel is created by subtracting the <i>Y</i> from the amount of red in the color image. The <i>U</i> and <i>V</i> channels (representing chrominance) are then scaled by different factors. As a result, low values of <i>U</i> and <i>V</i> will expose shades of green, while a constant medium value of both will give a grayscale image. One can convert color values from RGB to YUV using the following formula:</p>

<p>            Y = 0.299R + 0.587G + 0.114B</p>

<p>            U = 0.492(B - Y)</p>

<p>            V = 0.877(R - Y)</p>

<p>Note that the <i>U</i> and <i>V</i> components in this color space are usually signed (i.e. they can be negative numbers if the luminosity exceeds the blue or red amount, as it does with hues such as orange, green, and cyan). Jitter matrices store unsigned <m>char</m> data, so the <i>U</i> and <i>V</i> values are represented in the range of 0-255, with 128 as the center point of the chromatic space.</p>

<illustration><img src="images/jitterchapter49b.png"/>The YUV color space with a constant midrange Y value.</illustration>
<p>The specific implementation of the YUV colorspace used in our Tutorial patch is called YUV 4:2:2. Jitter objects that need to interpret matrix data as video (e.g. <o>jit.movie</o>, <o>jit.pwindow</o>, etc.) can generate and display this colorspace when their <m>colormode</m> attribute is set to <m>uyvy</m>. This <m>colormode</m> uses something called <i>chroma subsampling</i> to store two adjacent color pixels into a single cell (referred to as a &#x201C;macro-pixel&#x201D;). Because our eyes are more attuned to fine gradations in luminosity than in color, this is an efficient way to perform data reduction on an image, in effect cutting in half the amount of information needed to convey the color with reasonable accuracy. In this system, each cell in a Jitter matrix contains four planes that represent two horizontally adjacent pixels: plane <m>0</m> contains the <i>U</i> value for both pixels; plane <m>1</m> contains the <i>Y</i> value for the first pixel; plane <m>2</m> contains the <i>V</i> value for both pixels; plane <m>3</m> contains the <i>Y</i> value for the second pixel. The ordering of the planes (<m>uyvy</m>) means that we can alter the luminosity of the image by adjusting planes <m>1</m> and <m>3</m> (for alternating pixel columns), but we can change the chrominance of pixels only in pairs (by adjusting planes <m>0</m> and <m>2</m>).</p>

<div>
<techdetail><i>Historical Note</i>: Luminance-chrominance color encoding (where the luminosity of the image is transmitted separately from the hue or chrominance of the image) has its roots in the history of color television broadcasting. When color TV's were introduced in the United States in 1953, it was necessary to provide a means for television consumers with monochrome (black-and-white) TV sets to still be able to watch the programming. As a result, it was decided to simply add color information (in the form of a subcarrier) to the original broadcast signal, which already contained the luminosity of the image as grayscale. The result was called YIQ (for luminosity-intermodulation-quadrature), and is the colorspace used in broadcast NTSC color television. The equivalent on PAL television systems is the YUV colorspace under discussion here.</techdetail>
</div>
<p>The following illustration shows how the conversion from ARGB to UYVY is handled in Jitter. Our <o>jit.movie</o> object performs this translation for us when necessary (see the box below), but the <o>jit.argb2uyvy</o> and <o>jit.uyvy2argb</o> objects will convert any matrix between colorspaces. Note that the alpha channel is lost in the conversion and that chromatic information is averaged across pairs of horizontal cells in the ARGB original, creating a slight loss in color information.</p>

<div>
<techdetail>Because the UYVY color system uses a macro-pixel, each cell in the matrix actually represents two horizontally adjacent pixels in the image; for example, a 320x240 pixel image becomes a 160x240 cell matrix when output as UYVY. When processing these matrices, it's important to keep that in mind, as Jitter objects that process matrices based on <i>spatial</i> information (e.g. those that do scaling, rotation, convolution, etc.) will treat these pairs of pixels as a single unit. When working with these types of processes it may be easier to work in a <m>colormode</m> that uses a full resolution pixel, e.g. ARGB or AYUV (a full-resolution YUV colorspace also supported by Jitter). </techdetail>
</div>
<p>(note that a new, empty alpha channel is also created).</p>

<illustration><img src="images/jitterchapter49c.png"/>A 4x4 grid of random values converted from ARGB to UYVY and back again.</illustration>
<div>
<techdetail>Many commercial video codecs use YUV 4:2:2 (or similar chroma subsampling systems such as 4:1:1 and 4:2:0) as their native video format. As a result, <o>jit.movie</o> can decompress these files faster in the <m>uyvy</m> colormode than when outputting matrices in the normal ARGB format. The matrices thus generated are also half the size, giving a performance increase to any Jitter patches that can take advantage of this system. Codecs such as Photo-JPEG, DVCPRO, and NTSC DV all use some form of subsampled YUV codec as their native color format.</techdetail>
</div>
<p>With this in mind, we can understand the processing going on in our patch. The <o>jit.movie</o> sends matrices in the <m>uyvy</m> 4-plane <m>char</m> format to the <o>jit.charmap</o>, which processes the data and sends it onwards. The <o>jit.fpsgui</o> tells us that the <m>dim</m> of the matrices being sent to it are 160x240, which makes sense now that we understand the macro-pixel data reduction that accompanies the switch in <m>colormode</m>. In addition, we can now see why the matrix <m>themap</m> has one <o>jit.fill</o> object feeding both planes <m>1</m> and <m>3</m>; these correspond to the two <i>Y</i> values in the macro-pixel, which we want to share the same lookup table.</p>

<h2>Color tinting and saturation</h2>
<bullet>Set the <o>multislider</o> objects to their normal curve by clicking the <o>button</o> object labeled <i>normal</i>. Above the patcher objects labeled <i>brco</i>, adjust the number box controlling the contrast for the <i>Y</i> channel until it reads <m>-1</m>.</bullet>
<illustration><img src="images/jitterchapter49d.png"/>Inverted Y color table.</illustration>
<p>Because the luminosity is separate from the chrominance in our new colorspace, it is a simple matter to invert the brightness of pixels without affecting their hue. This would be a more involved procedure if working in ARGB.</p>

<bullet>Normalize the <o>multislider</o> objects again, and adjust the <o>number</o> box objects for the <i>U</i> and <i>V</i> channels' contrast. Try setting them both to <m>-1</m>, then to <m>0</m>. Normalize their contrast settings and set the brightness values both to <m>-1</m>.</bullet>
<illustration><img src="images/jitterchapter49e.png"/>Different U and V settings.</illustration>
<p>By inverting the <i>U</i> and <i>V</i> channels' color lookup, we perform a 180-degree hue rotation on the image. Setting both of these channels to a constant value <i>desaturates</i> the image so that it appears at a constant chroma, or hue, according to the Cartesian space shown earlier in this tutorial. Values of <m>0</m> will desaturate the image to greyscale; values of <m>-1</m> will make the entire image appear green.</p>

<bullet>Do some freehand drawing in the <o>multislider</o> objects. Try to get a feel for how different ranges of the char range results in different effects on different channels.</bullet>
<div>
<techdetail>In addition to YUV 4:2:2 (<m>colormode uyvy</m>) and ARGB (<m>colormode argb</m>, the default for most objects), Jitter objects exist that generate matrices in a number of other colorspaces. Examples include <m>grgb</m> (a chroma subsampled RGB colorspace similar to uyvy), <m>ayuv</m> (a full-resolution YUV colorspace with an alpha channel), <m>luma</m> (a 1-plane char grayscale format), and <m>ahsl</m> (alpha, hue, saturation, luminosity). Conversion objects are typically named <i>jit.x2y</i>, e.g. <o>jit.argb2uyvy</o>. In addition, the <o>jit.colorspace</o> object supports translation to and from a variety of 4-plane <m>char</m> colorspaces (including approximations of floating-point colorspaces such as L*a*b*). A good place to begin for more information on colorspaces (and the numerical representation of color in general) is the Wikipedia article on the subject.</techdetail>
</div>

<h2>Videoplane</h2>
<bullet>Notice that the output of the <o>jit.pwindow</o> in our patch doesn't go directly to a <o>jit.window</o> object. Instead, it goes to an object called <o>jit.gl.videoplane</o>. Click on the <o>message</o> box labeled <m>read track1.mov</m>. The processed image should switch to a movie. Normalize the color lookup tables on the right by clicking the <o>button</o> labeled <i>normal</i>.</bullet>
<p>The <o>jit.gl.videoplane</o> object textures the Jitter matrix sent into its inlet onto a plane in an OpenGL drawing context. Our drawing context (<m>colorspace</m>) is being driven by the <o>jit.gl.render</o> object at the top of the patch, and is viewable through the <o>jit.window</o> object's window. If you need to review the basics of OpenGL rendering in Jitter, a look at <i><link type="tutorial" module="jit" name="jitterchapter30">Tutorial 30:</link> Drawing 3D text</i> will fill you in on the basics of creating a rendering system. One thing of note is that the <m>ortho</m> attribute of <o>jit.gl.render</o>, when set to <m>2</m>, renders our scene in an orthographic projection (i.e. there is no sense of depth). Also note that the <o>jit.gl.videoplane</o> object, not the <o>jit.window</o>, needs to be told to interpret texture matrices as <m>uyvy</m> through its <m>colormode</m> attribute. In our patch we really aren't using OpenGL for 3D modeling; but we are taking advantage of some features of hardware accelerated texture mapping.</p>

<bullet>Click on the <o>message</o> box containing the text <m>dim 16 16</m> (next to the <o>jit.pwindow</o> object).</bullet>
<p>Notice that the <o>jit.pwindow</o> object shows a massively downsampled and pixelated image (It's actually processed as an 8x16 matrix since we're still in <m>uyvy</m> mode).  The <o>jit.window</o> object, however, shows an image where the pixels are smoothly interpolated into one another (the effect is similar to upsampling in a <o>jit.matrix</o> object with the <m>interp</m> attribute set to <m>1</m>).</p>

<illustration><img src="images/jitterchapter49f.png"/>Hardware interpolation of a small matrix applied as a texture.</illustration>
<p>This interpolation is occurring on the hardware Graphics Processing Unit (GPU), and is one of the many advantages to using OpenGL to display video, as it causes no performance penalty on the main CPU of our computer.</p>

<bullet>Click on the <o>message</o> box containing the text <m>dim 320 240</m>. This will set the size of the matrices back to the normal resolution we've been using: 320x240 pixels, output as 160x240 cells per matrix because of the <m>colormode</m>. One the right of the patch, click on the <o>toggle</o> attached to the <o>message</o> box labeled <m>fullscreen $1</m> (alternately, hit the ESC key on your keyboard).</bullet>
<p>When you send a <o>jit.window</o> object into <m>fullscreen</m> mode, the <o>jit.gl.videoplane</o> upsamples the texture even further, giving you the smoothest possible interpolation for your display.</p>

<bullet>Hit the ESC key to trigger the <o>toggle</o> again, taking the <o>jit.window</o> out of <m>fullscreen</m>.</bullet>
<h2>Videoplane Post-Processing</h2>
<bullet>Adjust the red, green, and blue <o>number</o> box objects attached to the <o>pak</o> object connected to the <o>jit.gl.videoplane</o> object.  Note than even though the applied texture is mapped in YUV <m>colorspace</m>, the <o>jit.gl.videoplane</o> responds to <m>color</m> attributes in floating-point RGBA. Manipulate the <o>number</o> box labeled <i>rotate</i>.</bullet>
<illustration><img src="images/jitterchapter49g.png"/>Some examples of GPU processing on a videoplane.</illustration>
<p>We can see that the <m>color</m> and <m>rotate</m> attributes (as well as <m>scale</m>, <m>blend_enable</m>, etc.) of most OpenGL objects also apply to <o>jit.gl.videoplane</o>. As a result, <o>jit.gl.videoplane</o> is an incredibly useful object for video processing, as it allows us to apply processing to the image directly on the GPU.</p>

<h2>Summary</h2>
<p>The <o>jit.movie</o> object can output matrices in a number of colorspaces beyond ARGB. The YUV 4:2:2 colorspace can be used by setting the <m>colormode</m> attribute of the objects that support it (<o>jit.movie</o>, <o>jit.pwindow</o> and <o>jit.window</o>) to <m>uyvy</m>. The <m>uyvy</m> <m>colormode</m> has the advantage of using a macro-pixel chroma subsampling to cut the data rate in half, allowing for matrices to be processed faster in the Jitter matrix processing chain. Since the data output in this colorspace is still 4 planes of <m>char</m> information, standard objects such as <o>jit.charmap</o> can be used to manipulate the matrix, albeit with different results.</p>

<p>The <o>jit.gl.videoplane</o> object accepts matrices (including <m>uyvy</m> matrices) as textures that are then mapped onto a plane in the OpenGL drawing context named by the object. GPU accelerated processing of the image can therefore be done directly on the plane, including color tinting, blending, spatial transformation, etc. In <i><link type="tutorial" module="jit" name="jitterchapter41">Tutorial 41:</link> Shaders</i> we saw ways to apply entire processing algorithms to objects in the drawing context, further expanding the possibilities of using the GPU for processing in Jitter.</p>

	<seealsolist>
		<seealso display="GL Texture Output" module="core" name="jitter_gl_texture_output" type="vignette" />
		<seealso name="jit.argb2uyvy">Converts ARGB to UYVY</seealso>
		<seealso name="jit.charmap">256 point input to output map</seealso>
		<seealso name="jit.fill">Fill a matrix with a list</seealso>
		<seealso name="jit.gencoord">Evaluates a procedural basis function graph</seealso>
		<seealso name="jit.gl.render">Render Open GL</seealso>
		<seealso name="jit.gl.videoplane">GL accelerated video plane</seealso>
		<seealso name="jit.matrix">The Jitter Matrix!</seealso>
		<seealso name="jit.noise">Generate white noise</seealso>
		<seealso name="jit.pwindow">In-Patcher Window</seealso>
		<seealso name="jit.movie">Play or edit a movie</seealso>
		<seealso name="jit.uyvy2argb">Converts UYVY to ARGB</seealso>
		<seealso name="multislider">Multiple slider and scrolling display</seealso>
	</seealsolist>
	</chapter>
