Tutorial 15: Image Rotation
Rotating and Zooming with jit.rota
Jitter provides an easy way to rotate and/or zoom an image with an object called jit.rota. Rotation and zoom are common and useful video effects, and by combining them in different ways you can also achieve a variety of kaleidoscopic effects. jit.rota takes a matrix of video data (or any other sort of image) in its inlet, and sends out a version that has been zoomed, rotated, and otherwise distorted based on the settings of the object's attributes.
The video is a three-second left-to-right camera pan over a set of dishes. However, the jit.movie object has been initialized to , so the movie loops back and forth, giving the illusion of a back-and-forth pan.attribute of the
The jit.rota determines the angle of rotation around a central anchor point.attribute of
Also, in trigonometry we consider a positive change in angle to be a counter-clockwise rotation around the unit circle, whereas in everyday life you might more commonly think of a clockwise motion as being intuitively "positive" or "increasing" (like the passage of time).
So, to convert a clockwise rotation in degrees into the same rotation in radians, you would need to multiply the degree angle by 2π, then divide by -360.
Besides rotating the image by hand, you can also write an automated process in Max that will supply continually changing rotation angles. In the previous chapter we wrote a subpatch called rotate that used the line object to increase the angle of hue rotation continually from 0° to 360°. In this chapter we do something similar, but this time we use the from the metro that's displaying the movie to increase the angle of rotation. To keep it "user-friendly" we show the user degrees of angle rotation rather than radians (we convert degrees to radians inside the subpatch), and we also display the rotation speed as "rotations per second."
We convert what the user specifies as degrees per accum object. Note that a negative degrees per amount works fine, too, and causes a counter-clockwise rotation of the image. When the total rotation angle exceeds 2π (or -2π), a split sends the value to an expr that uses a modulo operation to bring it back into range (resetting the value in the accum object) before sending it to the outlet. When rotation gets turned off, we detect that fact with a sel object, and reset the angle to .into an amount in radians, by multiplying the degrees by 2π and dividing by –360. (See the Technical Detail sidebar above.) When a comes in the left inlet, if rotation is turned on then the gets passed through and it causes an increase of angle rotation to be added into the
Zoom In or Out
The other main feature of jit.rota is its zooming capability. The amount of zoom is determined by jit.rota's and attributes. These permit you to zoom in or out in the horizontal and vertical dimensions independently; or you can zoom both dimensions simultaneously by changing both attributes at once.
When we zoom in on the image—say, with a zoom value of 2—we still retain reasonably good image quality because we've turned jit.rota's attribute on with an message. If you turn off, you will get pixelation when you zoom in. When you're zooming out, has no appreciable effect, so it's pretty much a waste of the computer's time. (See Jitter Tutorial 14 for a discussion of pixelation and interpolation.) However, interpolation does improve the look of rotated images, even when they've been shrunk by zooming out.
Beyond the Edge
When the image does not fill the entire display area because of shrinking or rotation, jit.rota has to decide what to do with the rest of the matrix that lies outside the image area. At present jit.rota is setting all the cell values outside the image area to 0, making them all black. The way that jit.rota handles the cells that lie outside the image boundaries is determined by its attribute. The different available settings are presented in the popup menu labeled Space outside the image in the upper-right corner of the patch. We initialized the value to , which instructs jit.rota to clear all the outlying cells. Here is the meaning of each of the settings:
Ignore: Leave all outlying cells unchanged from their previous values.
Clear: Set all outlying cell values to 0.
Wrap: Begin the image again, as many times as necessary to fill the matrix.
Clip: For all the outlying cells, continue to use the values of the boundary cells of the image.
Fold: Repeat the image, flipped back in the opposite direction.
Some Adjustments—Anchor Point and Offset
Up to now we've been using the center of the image as the anchor point of the rotation. However, you can choose any point for this. The center of rotation is set with the number boxes labeled Anchor point.and attributes. Right now those attributes are set to and (half of the image dimensions), but you can change them in the
In addition, you can move the image to a different location in the output matrix after zooming and rotation take place, using theand attributes.
Mouse control of rotation
We've devised one more way for you to rotate the image.
jit.pwindow tracks your mouse movements and, as long the mouse button is down, it sends coordinate information (and other mouse information) out its right outlet in the form of messages. The first two arguments of the message are the x and y coordinates of the mouse, relative to the upper left corner of jit.pwindow. We use those coordinates to calculate the angle of the mouse relative to the center of the jit.pwindow, and we send that angle to jit.rota as the argument to the attribute.
If we think of the center point of the jit.pwindow as the origin point 0,0, and we think of the current mouse location relative to that as being a point along a circle around the origin, then we can describe a right triangle based on those two points. By taking the arctangent of the mouse's coordinates y/x, we get the angle of the mouse relative to the center of jit.pwindow.
So we take the incoming x and y coordinates, and the first thing we do is convert them so that they're relative to the center of the jit.pwindow. We do that by subtracting 160 from the x dimension coordinate (so the x values will now go from -160 to 160) and multiplying the y coordinate by –1 (so values will increase as we go up, instead of down) then adding 119.5 to it. (If we added exactly 120, then every time we had a y coordinate of 120 from jit.pwindow we'd be trying to divide by 0 in expr, which is an undefined mathematical operation.) Once we have converted the x and y coordinates, we take the arctangent of y/x to get the angle in radians, then multiply that angle value by -1 to make clockwise rotation of the mouse cause clockwise rotation of the image.
This method only works within a 180° span, because the arctangent function can't tell the difference between a mouse location and its opposite point on the circle. (The calculation of y/x will be the same for both points.) So, every time the y coordinate of the mouse goes into the bottom half of the jit.pwindow, we add an offset of -π to the theta angle to distinguish those locations from their counterparts on the opposite side. (That's the last part of the expression.)
Note that this expression only works relative to the point 160,120 in the jit.pwindow. If we wanted to make an expression that works for the central point of any size jit.pwindow, we'd need to get the jit.pwindow's dimensions with a message, and use the values as variables in our expression. As the math books say, "We'll leave that as an exercise for the reader."
The jit.rota object provides an easy way to rotate an image with its attribute, specifying an angle of rotation, in radians. It also provides an easy way to zoom in and out on an image with its and attributes. You can change the central point of the rotation with the and attributes, and you can move the resulting image in the output matrix with the and attributes. You can change the way that jit.rota treats the matrix cells that lie outside of the resulting image with the attribute. Using all of these capabilities in combination, you can get image-duplication and kaleidoscope effects in addition to simple zoom and rotation.
Zooming and rotation involve some rather intensive internal calculation by jit.rota, so these operations make substantial demands on the computer's processor. There are additional attributes, not covered in this tutorial, that give you access to virtually every coefficient in the rotation formula, presenting you even more possibilities for distorting and rotating the image. These are shown in jit.rota reference.
To manage the control of so many attributes at once, you can devise automated Max processes to generate attribute values, and/or interactive controls to change the values with gestures.
|accum||Store, add to, and multiply a number|
|expr||Evaluate a mathematical expression|
|if||Conditional statement in if/then/else form|
|jit.pwindow||Display Jitter data and images|
|jit.movie||Play a QuickTime movie|
|jit.rota||Scale/rotate in 2D|
|split||Look for a range of numbers|