<?xml version='1.0' encoding='UTF-8'?>

<?xml-stylesheet href="./_c74_tut.xsl" type="text/xsl"?>
<chapter name="Tutorial 6: Adjust Color Levels">
<setdocpatch name="06jAdjustColorLevels" patch="06jAdjustColorLevels.maxpat"/>

<previous name="jitterchapter05">ARGB Color</previous>
<next name="jitterchapter07">Image Level Adjustment</next>
<parent name="jitindex">Jitter Tutorials</parent>



<h1>Tutorial 6: Adjust Color Levels</h1>
<h2>jit.scalebias</h2>
<p>This tutorial elaborates on the color discussion of the previous chapter, and introduces an object that is specially designed for modifying the ARGB color planes of a matrix: <o>jit.scalebias</o>.</p>
<p>The term <i>scale</i> in this instance refers to the process of scaling values by a certain factor; that is, <i>multiplying</i> them by a given amount. The term <i>bias</i> refers to offsetting values by <i>adding</i> an amount to them. By combining the processes of multiplication and addition, you can achieve a linear mapping of input values to output values.</p>
<p>Because <o>jit.scalebias</o> is concerned with modifying ARGB color information in an image, it handles only 4-plane matrices of the <i>char</i> data type. (See Tutorial 5 for a discussion of ARGB color and <i>char</i> data.)</p>

<h3>Math with char data</h3>
<p>As mentioned in the previous chapter, 8-bit <i>char</i> data can be represented as whole number values from 0 to 255 or as fractional values from 0 to 1. In <i>Tutorial 2</i>, for example, we saw that the <o>jit.print</o> object reports <i>char</i> data as integer values from 0 to 255. However, in many cases where we modify <i>char</i> values within a matrix (by changing one of its attributes), the Jitter object will expect to receive the attribute value as a <m>float</m>. Because this can be a little confusing, we've provided a demonstration in this tutorial patch.</p>

<bullet>Open the tutorial patch. Click on the <o>patcher</o> <m>explain_scalebias</m> object in the middle of the patch to see the contents of the subpatch <i>[explain_scalebias]</i>.</bullet>

<illustration><img src="images/jitterchapter06a.png"/>A demonstration of <m>float</m> math on <i>char</i> data.</illustration>

<p>In the above example, we have created a very small matrix. It has 4 planes of <i>char</i> data, but it has only a single cell. This will to allow us focus on what happens to a single numerical value in the matrix. You can see that we have set the value in plane 2 (the green plane) to <m>100</m>. At the left side of the example, you can see how this whole number value would be represented as a fractional value between 0 and 1: in this case it's <m>0.392</m>, which is 100/255 of the way from 0 to 1.</p>

<p>The <o>jit.scalebias</o> object will multiply the values by a certain amount&#x2014;specified by the <m>scale</m> attribute&#x2014;and then will add a certain amount to the values&#x2014;specified by the <m>bias</m> attribute. When that matrix is altered by the <o>jit.scalebias</o> object, all of the values will be treated as <m>float</m>s for purposes of calculation, then will be re-stored in the matrix as <i>char</i> data.</p>

<p>The <m>scale</m> and <m>bias</m> attributes are set here with the <m>scale 2.0</m> and <m>bias 0.2</m> messages. The scaling factor (the multiplier)is 2.0 in this case, and the bias (the offset that gets added afterward) is 0.2. So, to understand what is going on inside <o>jit.scalebias</o>, we have to think of the green value as 0.392 times 2.0 plus 0.2, which equals 0.984. The <o>jit.iter</o> object reports the values in each plane of each cell (there's only one cell in this matrix), and we can see that the value (when stored in the matrix as a <i>char</i>) is <m>251</m> (or 0.984 on a scale from 0 to 1).</p>

<p>(Just as a mental exercise, can you calculate the values <o>jit.scalebias</o> will produce in the red and blue planes in the above example? Since the values in those planes in the original matrix are 0, the values in the resultant matrix will be 0 times 2.0 plus 0.2, which equals 0.2, which is equal to 51 on a scale from 0 to 255. So the RGB values being displayed by the <o>jit.pwindow</o> object at the bottom are 51 251 51.)</p>

<h3>More examples</h3>
<p>If the preceding explanation was crystal clear to you, you might want to skip over these additional examples. But in case you're still not totally clear on how math operations with <i>char</i> data (and <o>jit.scalebias</o> in particular) work, here are a few more examples. </p>

<bullet>One by one, click on each of the presets in the <o>preset</o> object, proceeding from left to right. In the paragraphs below we explain each of the preset examples.</bullet>
<ol>

<li>The value in the green plane of the original matrix is 255. (This is equal to 1.0 on a scale from 0 to 1.) The <o>jit.scalebias</o> object multiplies this by 0.5, which results in an internal value of 127.5; however, when storing the value as a char, <o>jit.scalebias</o> truncates (chops off) the fractional part, and stores the value as 127.</li>

<div>
<techdetail>This yields a rather imprecise result. (127 on a scale from 0 to 255 is equal to 0.498 on a scale from 0 to 1, as opposed to the 0.5 we would expect.) But that's the best we can do with 8-bit <i>char</i> data. In cases where you need greater precision than that, <i>char</i> data is not for you. You would need to use a matrix of <i>long</i>, <i>float32</i>, or <i>float64</i> data, and use <o>jit.op </o><m>@op *</m> and <o>jit.op </o><m>@op +</m> objects instead.</techdetail>
</div>
<li>The original value is 100, and we double it (scaling factor 2.0) and get the expected result of 200. There is no loss of precision in this case.</li>

<li>The original value is 100 (0.392). We scale it by a factor of 1.0, which leaves it unchanged, then we add -0.2 to it&#x2014;that is, we subtract 0.2 from it&#x2014;to get a result of 49 (that is, 0.192).</li>

<li>0.392 times 2.0 plus 0.2 = 0.984. On a scale from 0 to 255, that's 251.</li>

<li>This example and the next one show what happens when the result of the multiplication and addition operations exceeds the capacity of an 8-bit <i>char</i>. <o>jit.scalebias</o> will simply clip (limit) the result to the maximum  or minimum limit of a <i>char</i>. Here, 0.392 times 4.0 equals 1.568 (that is, 100 times 4 equals 400), so the result is set to the maximum allowable, 255.</li>

<li>In the other direction, 0.392 minus 0.5 equals -0.108, so the result is set to 0.</li>
</ol>

<p>It's noteworthy that these imprecisions and limits only occur at the point when the result is re-stored as a <i>char</i>. Up until then, the values are calculated internally as <i>float</i>s, so the precision is retained. Even though the multiplication takes the internal value beyond the 0-1 range, no limiting occurs internally, and the addition operation can bring it back into range. Here, 0.392 times 3.0 (= 1.176) minus 0.5 equals 0.676. When this is stored as a <i>char</i>, however, a small imprecision occurs. 0.676 on a scale from 0 to 255 equals 172.38, but the fractional part is truncated and the stored value is 172 (i.e., 0.675). For no change, the scaling factor should be 1 and the bias offset should be 0.</p>

<p>Try some more values yourself, until you're satisfied that you understand <o>jit.scalebias</o> and the results that occur with 8-bit <i>char</i> data. When you have finished, close the <i>[explain_scalebias]</i> window.</p>

<h3>Adjust Color Levels of Images</h3>

<p>Now let's apply <o>jit.scalebias</o> to color images. In the top left corner of the tutorial patch, you can see a familiar configuration: a <o>jit.movie</o> object with a <m>read</m> <o>message</o> box to load in a movie and a <o>metro</o> object to trigger <m>jit_matrix</m> messages from <o>jit.movie</o>. In this patch we'll modify the matrices with multiplications and additions in <o>jit.scalebias</o>.</p>

<illustration><img src="images/jitterchapter06b.png"/>Load in a picture or a movie.</illustration>

<bullet>Click on the <o>message</o> box <m>read chilis.jpg</m> to read in a JPEG picture. Note that we're reading a still image&#x2014;not a video&#x2014;into the <o>jit.movie</o> object. QuickTime can handle a wide variety of media formats, including still images in PICT or JPEG format. <o>jit.movie</o> treats still images just as if they were 1-frame-long videos.</bullet>
<p>The output of <o>jit.movie</o> will go to <o>jit.scalebias</o> for processing, and will then be displayed in the <o>jit.pwindow</o>. (You can ignore the <o>jit.matrix</o> object for now. We'll discuss its use later in this chapter.) The <i>scale</i> and <i>bias</i> values can be changed by modifying the <m>scale</m> and <m>bias</m> attributes of <o>jit.scalebias</o>.</p>

<bullet>Click on the <o>toggle</o> to start the <o>metro</o>. Try dragging on the <o>number</o> box above the <m>scale $1</m> <o>message</o> box, to increase the value of the <i>scale</i> attribute to <m>1.25</m>.</bullet>

<illustration><img src="images/jitterchapter06h.png"/><img src="images/jitterchapter06c.png"/>Boost the brightness of the image; with <m>scale</m>, higher values get boosted more.</illustration>

<p>This will increase all non-zero values in all four planes of the image by a factor of 1.25 (a 25% increase). Note that multiplication has the effect of increasing larger values by a greater amount than smaller values. For example, if the red value of a particular cell in the original matrix is 200, it will be increased to 250 (a net increase of 50), while the blue value of the same cell might be 30 and would be increased to 37 (a net increase of 7).</p>

<bullet>Try increasing the <i>scale</i> attribute to a very large value, such as <m>20</m>. Values that were 13 or greater in the original matrix will be pushed to the maximum of  255 (and even the very small values will be increased to a visible level), creating an artificially "overexposed" look.</bullet>
<bullet>Try decreasing the <i>scale</i> attribute to a value between 0 and 1. As you would expect, this darkens the image. A <i>scale</i> value of 0 or less will set all values to 0.</bullet>
<bullet>Return the <i>scale</i> attribute to <m>1</m>. Now try adjusting the <i>bias</i> attribute. This adds a constant amount to all values in the matrix. Positive values lighten the image, and negative values darken it.</bullet>

<illustration><img src="images/jitterchapter06d.png"/>Boost (or reduce) the level of all values by a constant amount.</illustration>

<bullet>Here are a couple of more extreme <i>scale</i> and <i>bias</i> settings you might want to try. Set the <i>scale</i> value to 40 and the <i>bias</i> value to -20. This has the effect of pushing almost all values to either 255 or 0, leaving only a few colors other than white or black. Now try setting the <i>scale</i> value to -1 and the <i>bias</i> value to 1. This has the effect of inverting the color scheme by making all high values low and all low values high. Reducing the <i>scale</i> value even further (to, say, -4 or -8) creates a similar inversion, but only values that were low in the original will be boosted back into the 0-1 range by the positive <i>bias</i> value.</bullet>

<h3>Adjust planes individually</h3>

<p>You can adjust the levels in each plane individually in <o>jit.scalebias</o>, using the attributes <m>ascale</m>, <m>abias</m>, <m>rscale</m>, <m>rbias</m>, etc.</p>

<bullet>Set the <i>scale</i> value back to <m>1</m> and the <i>bias</i> value back to <m>0</m>. Then experiment with adjusting each color plane independently by providing new values for the appropriate attributes.</bullet>

<illustration><img src="images/jitterchapter06e.png"/>Adjust levels for each color plane</illustration>

<p>We've made the process a bit more interactive by giving you a controller that lets you adjust the scaling of all three color planes at once. When you click or drag in the <o>swatch</o> object, it sends out a three-item <m>list</m> representing the RGB color values at the point where your mouse is located. Those values were once expressed on a scale from 0 to 255, but this has been changed to produce values from 0.0 to 1.0. (There is a checkbox in the inspector to provide the old style output if desired.) We  use <o>unpack</o> to break that <m>list</m> into three separate <m>floats</m>, and we use those values to alter the <m>rscale</m>, <m>gscale</m>, and <m>bscale</m> attributes of <o>jit.scalebias</o>.</p>

<illustration><img src="images/jitterchapter06f.png"/>Values from <o>swatch</o> used as attribute values for <o>jit.scalebias</o></illustration>

<bullet>Drag on the <o>swatch</o> object to scale the RGB planes all at the same time. Since this produces scaling values in the range 0 to 1, you're effectively reducing all the levels, so this will generally darken the resulting image somewhat.</bullet>
<bullet>You can try all of these operations on different images. Read in some other colorful images such as <i>colorswatch.pict</i> or <i>wheel.mov</i>  and experiment with adjusting the color levels.</bullet>

<h2>Reassign planes of a matrix</h2>
<p>In the previous tutorial we used <o>jit.unpack</o> and <o>jit.pack</o> to reassign the planes of a matrix. There is another way to do that, using the <m>planemap</m> attribute of the <o>jit.matrix</o> object. In this example, we pass the matrix output of <o>jit.movie</o> through a <o>jit.matrix</o> object just to demonstrate the <m>planemap</m> attribute.</p>

<illustration><img src="images/jitterchapter06g.png"/>We can reassign the planes of a matrix as it goes through <o>jit.matrix</o></illustration>

<p>The <m>planemap</m> attibute of <o>jit.matrix</o> allows us to <i>map</i> (assign) any plane of the incoming matrix to any plane of the outgoing matrix. The word <m>planemap</m> is followed by as many numbers as there are planes in the matrix (four in this case). Each place in the list stands for an output plane (the first place stands for output plane 0, the second place for output plane 1, etc.), and the value of that number states the input plane that will be assigned to it. By default, the <m>planemap</m> values are <m>0 1 2 3</m> (etc.), so that each plane in the input matrix is assigned to the same plane in the output matrix. But we can change those assignments as we like. For example, if we send <o>jit.matrix</o> the message <m>planemap 0 3 2 1</m>, we are assigning input plane 3 to output plane 1 (since the value 3 is in the list location for output plane 1), and input plane 1 to output plane 3. Effectively, we're swapping the red and blue color planes of the image.</p>

<bullet>Click on the <o>message</o> box <m>read wheel.mov</m> and start the <o>metro</o> to display the movie. (Set the <m>scale</m> attribute of <o>jit.scalebias</o> to <m>1</m> and the <m>bias</m> attribute to <m>0</m>, so that you're seeing an unaltered image in the <o>jit.pwindow</o>.) Now, in the bottom right portion of the patch, click on the <o>message</o> box <m>planemap 0 3 2 1</m> to swap the red and blue planes in the matrix. Click on the <o>message</o> box <m>planemap 0 1 2 3</m> to go back to the normal plane mapping. If we set all three of the RGB output planes to the same input plane, we get equal values in all three RGB planes, resulting in a greyscale image.</bullet><br/>

<bullet>Click on the <o>message</o> box <m>planemap 0 1 1 1</m> to see this effect. The value <m>1</m> is in the list location for each of the three RGB planes, so the red plane of the original is used for all three RGB planes of the output matrix. To rotate through all of the different color plane rotations, we've filled a <o>coll</o> object with various plane mappings (similarly to the way we did in the previous chapter), and we will send those assignments to the <o>jit.matrix</o> to change the settings of its <m>planemap</m> attribute.</bullet><br/>

<bullet>Double-click on the <o>patcher</o> r<m>otatecolorplanes</m> object to see the contents of the subpatch. It simply counts from 1 to 6, to step through the different mappings stored in the <o>coll</o> object in the main patch. (And when it's turned off it sends out the number <m>1</m> to reset to the default plane mapping.) Close the <i>[rotatecolorplanes]</i> window.</bullet><br/>

<bullet>Click on the <o>toggle</o> above the <o>patcher</o> <m>rotatecolorplanes</m> object to step through the different plane mappings at the rate of one setting per second. Change the rate <o>number</o> box above the right inlet to a smaller value (say, <m>80</m>) to see a flickering effect from rapid plane reassignment.</bullet><br/>
<p>In the next tutorial chapter, you'll see how to rotate image hue in a subtler way, using <o>jit.hue</o>, and you'll see other ways to adjust color levels with the <o>jit.brcosa</o> object.</p>

<h2>Reading and Importing Images</h2>
<p>In this tutorial patch, we loaded three different kinds of images into the <o>jit.movie</o> object: PICT and JPEG still images, and a movie. It may seem a little strange to read still images into an object made for playing movies, but in fact QuickTime can read many types of media files, and <o>jit.movie</o> knows how to read them all. (You could even read an AIFF audio file into <o>jit.movie</o>, listen to it with <m>start</m> and <m>stop</m> messages, jump to different locations with the <m>time</m> attribute, etc.! Of course, you won't see any visual matrix info in that case.)</p>

<p>For still images, it's just as easy to load them directly into a <o>jit.matrix</o> object with the <m>importmovie</m> message, as demonstrated in <i>Tutorial 3</i>. If you import a movie that way, only one frame of the movie will be stored in the <o>jit.matrix</o>.</p>

<p>In this patch, we used <o>jit.movie</o> to load in all the images. The first reason is because one of the things we wanted to load was a movie (not just one frame of the movie). The second reason is because we wanted to demonstrate the <m>planemap</m> attribute of <o>jit.matrix</o>. The <m>planemap</m> attribute is only appropriate if there is an actual input matrix (a <m>jit_matrix</m> message coming in the left inlet). If we imported the images directly into <o>jit.matrix</o> with <m>importmovie</m>, the <m>planemap</m> attribute would have no effect.</p>

<h2>Summary</h2>
<p>The <o>jit.scalebias</o> object uses multiplication and addition to modify all the values in a particular plane of a 4-plane <i>char</i> matrix&#x2014;or all planes at the same time. The <m>scale</m> attribute is a factor by which each value in the matrix will be multiplied; the <m>bias</m> attribute is an amount to be added to each value after the multiplication takes place. The <m>scale</m> and <m>bias</m> attributes affect all four planes of the matrix. To affect only one plane at a time, use the attributes for that particular plane, such as <m>ascale</m>, <m>abias</m>, <m>rscale</m>, <m>rbias</m>, etc.</p>

<p>You must supply the values for these attributes as <m>float</m>s (numbers containing a decimal point). To perform the multiplication and addition operations, <o>jit.scalebias</o> treats the <i>char</i> values as fractional values in the range 0 to 1, performs the math with <i>float</i>s, then converts the results back to <i>char</i>s (whole numbers from 0 to 255) when re-storing them. Results that exceed the range 0 to 1 will be limited to 0 or 1 before being converted back to <i>char</i>.</p>

<p>You can reassign planes of a matrix using the <m>planemap</m> attribute of <o>jit.matrix</o>. The arguments to <m>planemap</m> are the output planes listed in order, and the values in the list are the input planes to be assigned to each output plane. So, for example to assign the plane 1 of an input matrix to all four planes of the output matrix, the attribute setting should be <m>planemap 1 1 1 1</m>.</p>

<p><o>jit.scalebias</o> provides a powerful tool for adjusting color levels in a 4-plane <i>char</i> (ARGB color) matrix. More such tools are presented in the next tutorial chapter.</p>
	<seealsolist>
		<seealso display="Video and Graphics Tutorial 9: Building live video effects" module="Video and Graphics" name="jitterchapter00k_Building live video effects" type="tutorial" />		
		<seealso name="jit.iter">Iterate a matrix as a series of Max lists/values</seealso>
		<seealso name="jit.matrix">The Jitter Matrix!</seealso>
		<seealso name="jit.pwindow">In-Patcher Window</seealso>
		<seealso name="jit.movie">Play or edit a movie</seealso>
		<seealso name="jit.scalebias">Multiply and add </seealso>
		<seealso name="metro">send bangs at regular intervals</seealso>
		<seealso name="preset">Store and recall the settings of other objects</seealso>
		<seealso name="swatch">Color swatch for RGB color selection and display</seealso>
		<seealso name="vexpr">Evaluate a mathematical expression on lists</seealso>
	</seealsolist>
</chapter>
