# Imgtools - manipulate Tk photo images

Home

Documentation

Development

The math behind it

## The math behind image transformations

On this page we present some of the math behind image transformations.

It is by no means a complete guide on image processing. It is just a collection of some aspects that were not obvious to figure out. For my own reference and for everyone interested in the topic.

### Overview

Very short overview how scaling and rotating images is done:

1. Determine the size of the destination image
2. Calculate values for each pixel of the destination image:
1. Apply coordinate translation, i.e. find out the position of the destination pixel relative to the source image.
2. Calculate the values for the destination pixel, interpolating from the surrounding source pixels

Top

### Rotation: Size of destination image

When rotating an image, the size of the destination image is not given. There are different approaches to determine that size. We are going to have a closer look at three of them (those available in imgtools), but there are yet other approaches not mentioned here.

Top

#### Keep size

Make the destination image the same size as the original one. Unless the angle of rotation is a multiple of 180°, there will be empty areas in the resulting image and, at the same time, not all of the source image will be visible.

From the mathematical point of view, this is the simplest variant for sure. There's nothing to calculate!

Top

#### No clipping

With this approach, we make the destination image large enough to contain all of the source image. This implies that the blank areas can become a considerable portion of the image.

This rotation method looks like this:

The dashed rectangle represents the rotated source image, the outer one is our destination image. θ is the angle of rotation, ${w}_{s}$ and ${h}_{s}$ are the width and height of the source image respectively. ${w}_{d}$ and ${h}_{d}$ are the sizes of the destination image - the sizes we need to calculate.

Let's see how we can calculate them:

$\begin{array}{c}\underset{̲}{\text{Calculate}\phantom{\rule{0.5em}{0ex}}a,b,c\phantom{\rule{0.5em}{0ex}}\text{and}\phantom{\rule{0.5em}{0ex}}d\mathrm{:}}\hfill \\ a={w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)\\ b={h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)\\ c={w}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)\\ d={h}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)\\ \\ \underset{̲}{\text{Now for}\phantom{\rule{0.5em}{0ex}}{w}_{d}\phantom{\rule{0.5em}{0ex}}\text{and}\phantom{\rule{0.5em}{0ex}}{h}_{d}\mathrm{:}}\hfill \\ {w}_{d}=a+b\\ {w}_{d}={w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)+{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)\\ \\ {h}_{d}=c+d\\ {h}_{d}={w}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)+{h}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)\\ \end{array}$

There is a problem with the formula above, though: it is valid only for the interval 0° ≤ θ ≤ 90°. For greather values of θ we get slightly different formulas (the derivation of these formulae is left as an excercise for the reader :-)):

$\begin{array}{c}\underset{̲}{\text{For 90°}\le \mathrm{\theta }\le \text{180°}}\hfill \\ {w}_{d}={w}_{s}\left(-\mathrm{cos}\left(\mathrm{\theta }\right)\right)+{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)\\ {h}_{d}={w}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)+{h}_{s}\left(-\mathrm{cos}\left(\mathrm{\theta }\right)\right)\\ \\ \underset{̲}{\text{For 180°}\le \mathrm{\theta }\le \text{270°}}\hfill \\ {w}_{d}={w}_{s}\left(-\mathrm{cos}\left(\mathrm{\theta }\right)\right)+{h}_{s}\left(-\mathrm{sin}\left(\mathrm{\theta }\right)\right)\\ {h}_{d}={w}_{s}\left(-\mathrm{sin}\left(\mathrm{\theta }\right)\right)+{h}_{s}\left(-\mathrm{cos}\left(\mathrm{\theta }\right)\right)\\ \\ \underset{̲}{\text{For 270°}\le \mathrm{\theta }\le \text{360°}}\hfill \\ {w}_{d}={w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)+{h}_{s}\left(-\mathrm{sin}\left(\mathrm{\theta }\right)\right)\\ {h}_{d}={w}_{s}\left(-\mathrm{sin}\left(\mathrm{\theta }\right)\right)+{h}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)\end{array}$

The difference between the formulae is only in the negation of the sin() and cos() values for some cases. Negation occurs exactly in those intervals where the corresponding function is negative. This means that we always get positive values for +/-sin(θ) and +/-cos(θ), which is handy, since negative distances are kinda hard to handle ;-).

It also means that we can derive a one-for-all formula:

$\begin{array}{c}{w}_{d}={w}_{s}|\mathrm{cos}\left(\mathrm{\theta }\right)|+{h}_{s}|\mathrm{sin}\left(\mathrm{\theta }\right)|\\ \\ {h}_{d}={w}_{s}|\mathrm{sin}\left(\mathrm{\theta }\right)|+{h}_{s}|\mathrm{cos}\left(\mathrm{\theta }\right)|\end{array}$

Top

#### No blank areas

Clip away all blank areas: make the the destination image small enough so there are no blank areas, yet try to make the destination image as large as possible. For angles of rotation that are not a multiple of 90°, portions of the source image will not be visible in the destination image.

This means that we have to inscribe a rectangle into the rotated source, such that each of its corners touches a side of the source rectangle.

The image above shows the rotated source rectangle (green, dashed lines) and the destination rectangle we have to calculate (blue lines). ${w}_{s}$ and ${h}_{s}$ are the width and height of the source image, ${w}_{d}$ and ${h}_{d}$ are the dimensions of the destination image. a, b, c and d are distances needed in the equations below.

And here's some math!

$\begin{array}{c}\underset{̲}{a,b,c\phantom{\rule{0.5em}{0ex}}\text{and}\phantom{\rule{0.5em}{0ex}}d\phantom{\rule{0.5em}{0ex}}\text{are:}}\hfill \\ a={h}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)\\ b={w}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)\\ c={w}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)\\ d={h}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)\\ \\ \underset{̲}{\text{We have:}}\hfill \\ \left\{\begin{array}{c}{w}_{s}=a+b\\ {h}_{s}=c+d\end{array}\\ \left\{\begin{array}{c}{w}_{s}={h}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)+{w}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)\\ {h}_{s}={w}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)+{h}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)\end{array}\\ \left\{\begin{array}{c}{w}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)={w}_{s}-{h}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)\\ {h}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)={h}_{s}-{w}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)\end{array}\\ \left\{\begin{array}{c}{w}_{d}=\frac{{w}_{s}}{\mathrm{cos}\left(\mathrm{\theta }\right)}-{h}_{d}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\\ {h}_{d}=\frac{{h}_{s}}{\mathrm{cos}\left(\mathrm{\theta }\right)}-{w}_{d}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\end{array}\\ \\ \underset{̲}{\text{In each equation substitute}\phantom{\rule{0.5em}{0ex}}{w}_{d}\phantom{\rule{0.5em}{0ex}}\text{or}\phantom{\rule{0.5em}{0ex}}{h}_{d}\phantom{\rule{0.5em}{0ex}}\text{from the other}}\hfill \\ \left\{\begin{array}{c}{w}_{d}=\frac{{w}_{s}}{\mathrm{cos}\left(\mathrm{\theta }\right)}-\left(\frac{{h}_{s}}{\mathrm{cos}\left(\mathrm{\theta }\right)}-{w}_{d}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\right)\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\\ {h}_{d}=\frac{{h}_{s}}{\mathrm{cos}\left(\mathrm{\theta }\right)}-\left(\frac{{w}_{s}}{\mathrm{cos}\left(\mathrm{\theta }\right)}-{h}_{d}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\right)\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\end{array}\\ \left\{\begin{array}{c}{w}_{d}-{w}_{d}\frac{{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)}{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}=\frac{{w}_{s}}{\mathrm{cos}\left(\mathrm{\theta }\right)}-{h}_{s}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}\\ {h}_{d}-{h}_{d}\frac{{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)}{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}=\frac{{h}_{s}}{\mathrm{cos}\left(\mathrm{\theta }\right)}-{w}_{s}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}\end{array}\\ \left\{\begin{array}{c}{w}_{d}\frac{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)-{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)}{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}=\frac{{w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)}{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}\\ {h}_{d}\frac{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)-{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)}{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}=\frac{{h}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{w}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)}{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}\end{array}\\ \\ \underset{̲}{\text{With:}}\phantom{\rule{0.5em}{0ex}}{\mathrm{cos}}^{2}\left(\mathrm{\alpha }\right)-{\mathrm{sin}}^{2}\left(\mathrm{\alpha }\right)=\mathrm{cos}\left(2\mathrm{\alpha }\right)\hfill \\ \left\{\begin{array}{c}{w}_{d}=\frac{{w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)}{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}\cdot \frac{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(2\mathrm{\theta }\right)}\\ {h}_{d}=\frac{{h}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{w}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)}{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}\cdot \frac{{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(2\mathrm{\theta }\right)}\end{array}\\ \left\{\begin{array}{c}{w}_{d}=\frac{{w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(2\mathrm{\theta }\right)}\\ {h}_{d}=\frac{{h}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{w}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(2\mathrm{\theta }\right)}\end{array}\end{array}$

As for the "no clipping" method, these formulas are valid only in the interval [0°, 90°]. To find a formula that's valid for all angles, we can figure out the other three, just as we did above, and then derive the "grand equation". Long story short, here it is:

$\begin{array}{c}{w}_{d}=\frac{{w}_{s}|\mathrm{cos}\left(\mathrm{\theta }\right)|-{h}_{s}|\mathrm{sin}\left(\mathrm{\theta }\right)|}{\mathrm{cos}\left(2\mathrm{\theta }\right)}\\ \\ {h}_{d}=\frac{{h}_{s}|\mathrm{cos}\left(\mathrm{\theta }\right)|-{w}_{s}|\mathrm{sin}\left(\mathrm{\theta }\right)|}{\mathrm{cos}\left(2\mathrm{\theta }\right)}\end{array}$

They even look similar to the "no clipping" ones, they must be correct, right?

Uhm, let's try it out. Say we have a source image of size 800x600, and we rotate it by 10°. We get a destination image of 728x481 (rounded values) - looks good.

Another try: same image, but this time we rotate it by 40°. Ouch! The result is 1308 by -314. A negative height can't be right! And the width is way too large - not good either. So what's wrong?

We didn't say so, but we assumed that there always is a rectangle that fits into our rotated source and touches its sides with all four corners. This assumption, alas, is wrong.

As we can see from the graphic, the destination image gets narrower with growing angle. At some point, our destination rectangle will be just a line that goes from one corner of the source to the opposite one. Past that point, there's no way to draw a rectangle that fits our requirements. If we keep rotating, at some point we will get a valid result again.

The limits for valid results are the angles formed by the diagonal of the source rectangle and its sides. For 0° ≤ θ ≤ 90° our formulas give valid results if:

$\begin{array}{c}\mathrm{\theta }<\mathrm{arctan}\left(\frac{a}{b}\right)\vee \mathrm{\theta }>\mathrm{arctan}\left(\frac{b}{a}\right)\\ \hfill \text{(}\vee \phantom{\rule{0.5em}{0ex}}\text{means "or" )}\\ \text{Where}\phantom{\rule{0.5em}{0ex}}a\phantom{\rule{0.5em}{0ex}}\text{is the smaller value of}\phantom{\rule{0.5em}{0ex}}{w}_{s}\phantom{\rule{0.5em}{0ex}}\text{and}\phantom{\rule{0.5em}{0ex}}{h}_{s}\\ \text{and}\phantom{\rule{0.5em}{0ex}}b\phantom{\rule{0.5em}{0ex}}\text{is the larger value of}\phantom{\rule{0.5em}{0ex}}{w}_{s}\phantom{\rule{0.5em}{0ex}}\text{and}\phantom{\rule{0.5em}{0ex}}{h}_{s}\end{array}$

Obvously, the requirement that destination touches source with all four corneres does not work - looks like we need to take another approach. What if only two corners of the destination image must touch source edges and the other two must be inside it? With that we face another problem, though: we won't get a unique result. For any combination of width, height and angle, there is an infinite number of rectangles that meet our requirements.

If we add the condition that the area of our destination image must be maximised, we might get a good result. This requirement makes perfect sense - after all we want to keep as much as possible of the original image!

As a first step we need to find a way to express ${h}_{d}$ in terms of ${w}_{d}$ (it could be the other way around as well). We begin with a graphical representation of the problem:

We can see that the destination rectangle must touch the longer sides of source. If it touches the shorter sides, it will not be completely inscribed in source. This means that what we are going to find out next, is valid only if ${w}_{s}$ < ${h}_{s}$ . As usual, for this first step, we consider the interval 0° ≤ θ ≤ 90° for the angle.

$\begin{array}{c}\underset{̲}{\text{The distances}\phantom{\rule{0.5em}{0ex}}a,b,c\phantom{\rule{0.5em}{0ex}}\text{and}\phantom{\rule{0.5em}{0ex}}d\phantom{\rule{0.5em}{0ex}}\text{are:}}\hfill \\ a={w}_{d}\mathrm{tan}\left(\mathrm{\theta }\right)={w}_{d}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\\ b=\frac{{w}_{d}}{\mathrm{cos}\left(\mathrm{\theta }\right)}\\ c={w}_{s}-b={w}_{s}-\frac{{w}_{d}}{\mathrm{cos}\left(\mathrm{\theta }\right)}\\ d=\frac{c}{\mathrm{sin}\left(\mathrm{\theta }\right)}=\left({w}_{s}-\frac{{w}_{d}}{\mathrm{cos}\left(\mathrm{\theta }\right)}\right)\cdot \frac{1}{\mathrm{sin}\left(\mathrm{\theta }\right)}=\frac{{w}_{s}}{\mathrm{sin}\left(\mathrm{\theta }\right)}-\frac{{w}_{d}}{\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)}\\ d=\frac{{w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{w}_{d}}{\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)}\\ \\ \underset{̲}{\text{Now we can express}\phantom{\rule{0.5em}{0ex}}{h}_{d}\phantom{\rule{0.5em}{0ex}}\text{in terms of}\phantom{\rule{0.5em}{0ex}}{w}_{d}\text{:}}\hfill \\ {h}_{d}=a+d\\ {h}_{d}={w}_{d}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}+\frac{{w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{w}_{d}}{\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)}\\ {h}_{d}=\frac{{w}_{d}{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)+{w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{w}_{d}}{\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)}\\ {h}_{d}=\frac{-{w}_{d}\left[1-{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)\right]+{w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)}{\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)}\\ \\ \underset{̲}{\text{With:}}\phantom{\rule{0.5em}{0ex}}1-{\mathrm{sin}}^{2}\left(\mathrm{\alpha }\right)={\mathrm{cos}}^{2}\left(\mathrm{\alpha }\right)\hfill \\ {h}_{d}=\frac{-{w}_{d}\left[{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)\right]+{w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)}{\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)}\\ {h}_{d}=\frac{\mathrm{cos}\left(\mathrm{\theta }\right)\left({w}_{s}-{w}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)\right)}{\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)}\\ {h}_{d}=\frac{{w}_{s}-{w}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)}{\mathrm{sin}\left(\mathrm{\theta }\right)}\end{array}$

If we repeat this operation for the other three quadrants, we can determine a formula that's valid for any value of θ:

${h}_{d}=\frac{{w}_{s}-{w}_{d}|\mathrm{cos}\left(\mathrm{\theta }\right)|}{|\mathrm{sin}\left(\mathrm{\theta }\right)|}$

With that, we can express the area of the destination image as a function of ${w}_{d}$ . As it tunrs out, it's a quadratic function with negative a, which means it has a maximum and we can calculate the value of ${w}_{d}$ and ${h}_{d}$ at this maximum.

$\begin{array}{c}\text{Express the area of destination as a function}\phantom{\rule{0.5em}{0ex}}{s}_{\left({w}_{d}\right)}\hfill \\ s={w}_{d}\cdot {h}_{d}\\ s={w}_{d}\frac{{w}_{s}-{w}_{d}|\mathrm{cos}\left(\mathrm{\theta }\right)|}{|\mathrm{sin}\left(\mathrm{\theta }\right)|}\\ s=-\frac{|\mathrm{cos}\left(\mathrm{\theta }\right)|}{|\mathrm{sin}\left(\mathrm{\theta }\right)|}{{w}_{d}}^{2}+\frac{{w}_{s}}{|\mathrm{sin}\left(\mathrm{\theta }\right)|}{w}_{d}\\ \\ \text{The maximum of a quadratic function can be found at:}\hfill \\ {x}_{\mathit{max}}=\frac{-b}{2a}\\ \text{Ergo, the width for which destination has maximal area is:}\hfill \\ {w}_{d}=-\frac{{w}_{s}}{|\mathrm{sin}\left(\mathrm{\theta }\right)|}\cdot \frac{1}{2\left(-\frac{|\mathrm{cos}\left(\mathrm{\theta }\right)|}{|\mathrm{sin}\left(\mathrm{\theta }\right)|}\right)}\\ {w}_{d}=-\frac{{w}_{s}}{|\mathrm{sin}\left(\mathrm{\theta }\right)|}\cdot \left(-\frac{|\mathrm{sin}\left(\mathrm{\theta }\right)|}{2|\mathrm{cos}\left(\mathrm{\theta }\right)|}\right)\\ {w}_{d}=\frac{{w}_{s}}{2|\mathrm{cos}\left(\mathrm{\theta }\right)|}\\ \\ \text{This allows us to calculate}\phantom{\rule{0.5em}{0ex}}{h}_{d}\phantom{\rule{0.5em}{0ex}}\text{as well:}\hfill \\ {h}_{d}=\frac{{w}_{s}-{w}_{d}|\mathrm{cos}\left(\mathrm{\theta }\right)|}{|\mathrm{sin}\left(\mathrm{\theta }\right)|}\\ {h}_{d}=\frac{{w}_{s}}{|\mathrm{sin}\left(\mathrm{\theta }\right)|}-\frac{{w}_{s}}{2|\mathrm{cos}\left(\mathrm{\theta }\right)|}\cdot \frac{|\mathrm{cos}\left(\mathrm{\theta }\right)|}{|\mathrm{sin}\left(\mathrm{\theta }\right)|}\\ {h}_{d}=\frac{2{w}_{s}-{w}_{s}}{2|\mathrm{sin}\left(\mathrm{\theta }\right)|}\\ {h}_{d}=\frac{{w}_{s}}{2|\mathrm{sin}\left(\mathrm{\theta }\right)|}\end{array}$

As stated before, this formula works only if ${w}_{s}$ < ${h}_{s}$ . For the case where ${w}_{s}$ > ${h}_{s}$ we get similar formulas:

$\begin{array}{c}\underset{̲}{{h}_{d}\phantom{\rule{0.5em}{0ex}}\text{in terms of}\phantom{\rule{0.5em}{0ex}}{w}_{d}\phantom{\rule{0.5em}{0ex}}\text{for}\phantom{\rule{0.5em}{0ex}}{h}_{s}<{w}_{s}}\hfill \\ {h}_{d}=\frac{{h}_{s}-{w}_{d}|\mathrm{sin}\left(\mathrm{\theta }\right)|}{|\mathrm{cos}\left(\mathrm{\theta }\right)|}\\ \\ \underset{̲}{\text{This gives us:}}\hfill \\ {w}_{d}=\frac{{h}_{s}}{2|\mathrm{sin}\left(\mathrm{\theta }\right)|}\\ {h}_{d}=\frac{{h}_{s}}{2|\mathrm{cos}\left(\mathrm{\theta }\right)|}\end{array}$

Is that it? Do these formula always give us valid results? Nope. Consider this:

Turns out that the maximise-area approach works well if the angle is close to 45°. As we go towards 0° or 90°, at some point the destination rectangle reaches out of source!

Consider the point just before the destination image with maximised area starts becoming too large. In the example above, that's at about 17.26°. At this point, destination touches source with all four corners. Sounds familiar? Right, we've calculated that already. Looks like that effort was not vain, after all! Notice that there is another similar "turning point" somewhere between 45° and 90°, and two more in each of the other quadrants.

We are getting close to the solution for our problem. For angles between 0° and the first turning point, we well use the 4-corners approach we explored before. Between the turning points, the 2-corners-with-maximised-surface approach will give us a good result. After that, it's gonna be 4-corners again.

We have to figure out one last thing: where are these turning points?

$\begin{array}{c}\underset{̲}{\text{For}\phantom{\rule{0.5em}{0ex}}{w}_{s}<{w}_{h}\phantom{\rule{0.5em}{0ex}}\text{and}\phantom{\rule{0.5em}{0ex}}0°\le \mathrm{\theta }\le 90°\phantom{\rule{0.5em}{0ex}}\text{we have:}}\hfill \\ \text{4 corners variant:}\phantom{\rule{0.5em}{0ex}}{w}_{d}=\frac{{w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(2\mathrm{\theta }\right)}\\ \text{2 corners variant:}\phantom{\rule{0.5em}{0ex}}{w}_{d}=\frac{{w}_{s}}{2\mathrm{cos}\left(\mathrm{\theta }\right)}\\ \\ \underset{̲}{\text{The intersection point of the two functions is:}}\hfill \\ \frac{{w}_{s}}{2\mathrm{cos}\left(\mathrm{\theta }\right)}=\frac{{w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(2\mathrm{\theta }\right)}\\ {w}_{s}\mathrm{cos}\left(2\mathrm{\theta }\right)=2\mathrm{cos}\left(\mathrm{\theta }\right)\left({w}_{s}\mathrm{cos}\left(\mathrm{\theta }\right)-{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)\right)\\ {w}_{s}\mathrm{cos}\left(2\mathrm{\theta }\right)=2{w}_{s}{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)-2{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)\\ \\ \underset{̲}{\text{With:}}\phantom{\rule{0.5em}{0ex}}\mathrm{cos}\left(2\mathrm{\alpha }\right)={\mathrm{cos}}^{2}\left(\mathrm{\alpha }\right)-{\mathrm{sin}}^{2}\left(\mathrm{\alpha }\right)\hfill \\ {w}_{s}\left[{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)-{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)\right]=2{w}_{s}{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)-2{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)\\ 2{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)=2{w}_{s}{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)-{w}_{s}{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)+{w}_{s}{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)\\ 2{h}_{s}\mathrm{sin}\left(\mathrm{\theta }\right)\mathrm{cos}\left(\mathrm{\theta }\right)={w}_{s}{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)+{w}_{s}{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)\\ \\ \underset{̲}{\text{With:}}\phantom{\rule{0.5em}{0ex}}{\mathrm{cos}}^{2}\left(\mathrm{\alpha }\right)+{\mathrm{sin}}^{2}\left(\mathrm{\alpha }\right)=1\hfill \\ \underset{̲}{\text{and:}}\phantom{\rule{0.5em}{0ex}}\mathrm{sin}\left(\mathrm{\alpha }\right)\mathrm{cos}\left(\mathrm{\alpha }\right)=\frac{1}{2}\mathrm{sin}\left(2\mathrm{\alpha }\right)\hfill \\ 2{h}_{s}\cdot \frac{1}{2}\mathrm{sin}\left(2\mathrm{\theta }\right)={w}_{s}\left[{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)+{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)\right]\\ {h}_{s}\mathrm{sin}\left(2\mathrm{\theta }\right)={w}_{s}\cdot 1\\ \mathrm{sin}\left(2\mathrm{\theta }\right)=\frac{{w}_{s}}{{h}_{s}}\\ \\ \underset{̲}{\text{For any value of}\phantom{\rule{0.5em}{0ex}}\mathrm{\theta }\phantom{\rule{0.5em}{0ex}}\text{that beomes:}}\hfill \\ |\mathrm{sin}\left(2\mathrm{\theta }\right)|=\frac{{w}_{s}}{{h}_{s}}\\ \\ \underset{̲}{\text{And for}\phantom{\rule{0.5em}{0ex}}{w}_{s}>{h}_{s}\mathrm{:}}\hfill \\ |\mathrm{sin}\left(2\mathrm{\theta }\right)|=\frac{{h}_{s}}{{w}_{s}}\end{array}$

Phew, that was some work. But we've got it now!

To sum it up: to find the dimensions for our destination image, we need first to find out on which side of those turning points we are. Depending on that, we will use either the 4-corners or the 2-corners variant. Formally, that would be:

$\begin{array}{c}\text{Let}\phantom{\rule{0.5em}{0ex}}r=\frac{a}{b}\phantom{\rule{0ex}{0ex}}\hfill \\ \text{Where}\phantom{\rule{0.5em}{0ex}}a\phantom{\rule{0.5em}{0ex}}\text{is the shorter side,}\phantom{\rule{0.5em}{0ex}}b\phantom{\rule{0.5em}{0ex}}\text{the longer side of the source image}\hfill \\ \\ \underset{̲}{\text{If}\phantom{\rule{0.5em}{0ex}}|\mathrm{sin}\left(2\mathrm{\theta }\right)|

If we plot that, we get a pretty funny curve. Mountains!!

Top

### Rotation and coordinate translation

Coordinate translation means to transform the coordinates of a point in the destination image to coordinates relative to the source image. To picture what that means, imagine to rotate the source image by θ degrees. Then lay the (not rotated) destination image over that. Now, take a needle and punch it through both images at the position we need to translate. Last, remove the needle and destination image and look where the needle punched the original image. The coordinages of that point in the source image are our translated coordinates. And it is from the source values at that point (and those near it) that we will calculate values for our destination pixel.

If we want to avoid all that needle punching and let our computer do the work instead, we need to express that in more algebraic terms. First, a drawing:

We have two sets of coordinate axes here: the continuos lines are the axes of the destination image, the dashed lines the ones of the rotated source image.

P is a point for which we know the coordinates in destination. Those coordinates are the distances ${x}_{d}$ and ${y}_{d}$ . We need to find the coordinates in terms of source, ${x}_{s}$ and ${y}_{s}$ . While the origin for both coordinate systems is the same, the axes are rotated by θ degrees. That's why the source coordinates are going to be different.

$\begin{array}{c}\underset{̲}{\text{Calculate}\phantom{\rule{0.5em}{0ex}}a,b,c\phantom{\rule{0.5em}{0ex}}\text{and}\phantom{\rule{0.5em}{0ex}}d\mathrm{:}}\hfill \\ a={x}_{d}\mathrm{tan}\left(\mathrm{\theta }\right)={x}_{d}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\\ b=\frac{{x}_{d}}{\mathrm{cos}\left(\mathrm{\theta }\right)}\\ c={y}_{d}-a={y}_{d}-{x}_{d}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\\ d=c\cdot \mathrm{sin}\left(\mathrm{\theta }\right)=\left[{y}_{d}-{x}_{d}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\right]\mathrm{sin}\left(\mathrm{\theta }\right)={y}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)-{x}_{d}\frac{{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\\ \\ \underset{̲}{\text{With that we can calculate}\phantom{\rule{0.5em}{0ex}}{x}_{s}\phantom{\rule{0.5em}{0ex}}}\hfill \\ {x}_{s}=b+d\\ {x}_{s}=\frac{{x}_{d}}{\mathrm{cos}\left(\mathrm{\theta }\right)}+{y}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)-{x}_{d}\frac{{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\\ {x}_{s}=\frac{{x}_{d}-{x}_{d}{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}+{y}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)\\ {x}_{s}=\frac{{x}_{d}\left(1-{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}+{y}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)\\ \underset{̲}{\text{With:}}\phantom{\rule{0.5em}{0ex}}1-{\mathrm{sin}}^{2}\left(\mathrm{\theta }\right)={\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)\hfill \\ {x}_{s}=\frac{{x}_{d}{\mathrm{cos}}^{2}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}+{y}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)\\ {x}_{s}={x}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)+{y}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)\\ \\ \underset{̲}{{y}_{s}\phantom{\rule{0.5em}{0ex}}\text{is a a little simpler:}}\hfill \\ {y}_{s}=c\cdot \mathrm{cos}\left(\mathrm{\theta }\right)\\ {y}_{s}=\left[{y}_{d}-{x}_{d}\frac{\mathrm{sin}\left(\mathrm{\theta }\right)}{\mathrm{cos}\left(\mathrm{\theta }\right)}\right]\mathrm{cos}\left(\mathrm{\theta }\right)\\ {y}_{s}={y}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)-{x}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)\end{array}$

These equations are not quite what we want yet. You might have noticed that with those calculations our image will be rotated around the origin of the coordinate system. This means that we would rotate our image around the upper left corner, since in digital images the coordinate (0,0) refers to that corner. But... We want to rotate our image around the center!

In order to achieve this, we transform the destination coordinates to make them relative to the center of the image, apply the formula we just found and transform the result back to coordinates relative to the upper left corner.

In order to transform coordinages so they are relative to the center we must substract the distance from the pixel at (0,0) to the center of the image. Similarly, to transform back to a system relative to the top leftmost pixel, we add that distance.

At first thought, you'd probably say that this distance is half of width and height. Close, but wrong.

The center of an image is at the point that's exactly in the middle of the top leftmost and the bottom rightmost pixels.

$\begin{array}{c}\text{The coordinates of the top leftmost pixel are:}\phantom{\rule{0.5em}{0ex}}\left(0,0\right)\hfill \\ \text{The coordinages of the bottom rightmost pixel are:}\phantom{\rule{0.5em}{0ex}}\left(w-1,h-1\right)\hfill \\ \phantom{\rule{2em}{0ex}}\text{where}\phantom{\rule{0.5em}{0ex}}w\phantom{\rule{0.5em}{0ex}}\text{and}\phantom{\rule{0.5em}{0ex}}h\phantom{\rule{0.5em}{0ex}}\text{are width and heigth.}\\ \\ \text{The middle point}\phantom{\rule{0.5em}{0ex}}C\phantom{\rule{0.5em}{0ex}}\text{between two coordinates is:}\hfill \\ C=\left(\frac{x2-x1}{2},\frac{y2-y1}{2}\right)\\ \text{In consequence, the center}\phantom{\rule{0.5em}{0ex}}O\phantom{\rule{0.5em}{0ex}}\text{of an image has coordinates:}\hfill \\ O=\left(\frac{w-1}{2},\frac{h-1}{2}\right)\\ \text{Wich are, by definition, the distances of the center from the origin.}\hfill \\ \\ \text{With that we can transform coordinates:}\hfill \\ {x}_{\mathit{dO}}\phantom{\rule{0.5em}{0ex}}\text{and}\phantom{\rule{0.5em}{0ex}}{y}_{\mathit{dO}}\phantom{\rule{0.5em}{0ex}}\text{are coordinates in destination, relative to the center:}\hfill \\ {x}_{\mathit{dO}}={x}_{d}-\frac{{w}_{d}-1}{2}\\ {y}_{\mathit{dO}}={y}_{d}-\frac{{h}_{d}-1}{2}\\ \\ \text{Similarly, source coordinates relative to the upper left corner}\hfill \\ \text{can be calculated from source coordinates relative to the center:}\hfill \\ {x}_{s}={x}_{\mathit{sO}}+\frac{{w}_{s}-1}{2}\\ {y}_{s}={y}_{\mathit{sO}}+\frac{{h}_{s}-1}{2}\\ \\ \text{Apply translation to the coordinates relative to the center:}\hfill \\ {x}_{\mathit{sO}}={x}_{\mathit{dO}}\mathrm{cos}\left(\mathrm{\theta }\right)+{y}_{\mathit{dO}}\mathrm{sin}\left(\mathrm{\theta }\right)\\ {y}_{\mathit{sO}}={y}_{\mathit{dO}}\mathrm{cos}\left(\mathrm{\theta }\right)-{x}_{\mathit{dO}}\mathrm{sin}\left(\mathrm{\theta }\right)\\ \\ \text{Transform to coordinates relative to the upper left corner and resolve:}\hfill \\ {x}_{s}={x}_{\mathit{sO}}+\frac{{w}_{s}-1}{2}={x}_{\mathit{dO}}\mathrm{cos}\left(\mathrm{\theta }\right)+{y}_{\mathit{dO}}\mathrm{sin}\left(\mathrm{\theta }\right)+\frac{{w}_{s}-1}{2}\\ {x}_{s}=\left({x}_{d}-\frac{{w}_{d}-1}{2}\right)\mathrm{cos}\left(\mathrm{\theta }\right)+\left({y}_{d}-\frac{{h}_{d}-1}{2}\right)\mathrm{sin}\left(\mathrm{\theta }\right)+\frac{{w}_{s}-1}{2}\\ {x}_{s}={x}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)+{y}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)-\frac{{w}_{d}-1}{2}\mathrm{cos}\left(\mathrm{\theta }\right)-\frac{{h}_{d}-1}{2}\mathrm{sin}\left(\mathrm{\theta }\right)+\frac{{w}_{s}-1}{2}\\ \\ {y}_{s}={y}_{\mathit{sO}}+\frac{{h}_{s}-1}{2}={y}_{\mathit{dO}}\mathrm{cos}\left(\mathrm{\theta }\right)-{x}_{\mathit{dO}}\mathrm{sin}\left(\mathrm{\theta }\right)+\frac{{h}_{s}-1}{2}\\ {y}_{s}=\left({y}_{d}-\frac{{h}_{d}-1}{2}\right)\mathrm{cos}\left(\mathrm{\theta }\right)-\left({x}_{d}-\frac{{w}_{d}-1}{2}\right)\mathrm{sin}\left(\mathrm{\theta }\right)+\frac{{h}_{s}-1}{2}\\ {y}_{s}={y}_{d}\mathrm{cos}\left(\mathrm{\theta }\right)-{x}_{d}\mathrm{sin}\left(\mathrm{\theta }\right)-\frac{{h}_{d}-1}{2}\mathrm{cos}\left(\mathrm{\theta }\right)+\frac{{w}_{d}-1}{2}\mathrm{sin}\left(\mathrm{\theta }\right)+\frac{{h}_{s}-1}{2}\end{array}$

Top

### Interpolation

Now we know how to translate the coordinates of a destination pixel, i.e. we know its position in the source image. Most likely that position is not going to be an integer value, which means that it is somewhere in between known data points in the source image. To get a realistic value for our destination pixel, we must interpolate from the surrounding source pixels.

There are different flavours of interpolation, with different caracteristics in quality and computing time.

The most common interpolation methods in image processing are:

• (Bi-)Cubic spline interpolation (there are different sub-types, the most common is the Catmull-Rom spline)
• Lanczos interpolation
• Linear interpolation
• Nearest neighbour

There are lots of documents about this topic on the net, so we won't go in more detail here. Here are a few pointers you might find useful or interesting:

Top

Contact | Hosting: | | Last updated: September 2017