Section 4.1 - Having fun with colours

We will now start studying inter-referencing, i.e. accessing another picture to render a project.

In this section we will only modify the colours of the original pictures.

Open any picture (if possible some colourful one, not just black and white) with the change size mode.

Then create a new project, with same size than the original picture.

Set the following equations, just to copy the original picture..
Here each pixel of project one will read the same pixel of project zero.

r(1,x,y)=r(0,x,y)
g(1,x,y)=g(0,x,y)
b(1,x,y)=b(0,x,y)

We will now create a negative version of project one. As each component range from 0 to 255, just do 255-x to have the negative version:

r(1,x,y)=255-r(0,x,y)
g(1,x,y)=255-g(0,x,y)
b(1,x,y)=255-b(0,x,y)

Now, black and white. To have the intensity of a colour, make the mean value of all components (r+g+b)/3 and apply it to all components of the resulting picture to get black 'n' white result:

r(1,x,y)=(r(0,x,y)+g(0,x,y)+b(0,x,y))/3
g(1,x,y)=(r(0,x,y)+g(0,x,y)+b(0,x,y))/3
b(1,x,y)=(r(0,x,y)+g(0,x,y)+b(0,x,y))/3

Note that each component has the same equation, so you can only render the red one and copy it to other components, applying Copy Red output mode to green and blue.

Now, what about dividing the colour by its intensity? This sometimes results in strange effects, but it sometimes may look nice... Create a new project so that picFX will not have to recalculate the intensity (we will just reuse the result of previous rendering).
When you divide a colour component by its intensity (and multiply by 85 to have something to see ;-), the whole picture will have the same intensity (except black areas).:

r(2,x,y)=85*r(0,x,y)/r(1,x,y)
g(2,x,y)=85*g(0,x,y)/r(1,x,y)
b(2,x,y)=85*b(0,x,y)/r(1,x,y)

Colour Extraction

Suppose you have a picture where you would like to apply an effect only at some precise places, being e.g. blue.
You would have to use what I call a mask, i.e. a picture of intensity 255 or as high as possible where we want the effect to act, and lower elsewhere.

We will first try to get one precise colour, i.e. only that exact colour will be in the mask and everything else will be out. This is quite easy.
You can for example take a magicWB backdrop (I took MarbleSpecky, for instance). I did not include it in the distribution for copyright reasons.

If you evaluate abs(rgb-cst), you will have zero when rgb is equal to cst, and something bigger otherwise. So if you write min(1,abs(rgb-cst)), you will have one if abs(rgb-cst) is larger or equal to one (in this case, if rgb is different from cst), and abs(rgb-cte) otherwise (in this case, zero).

This means that the above function will be equal to zero only when rgb is equal to cst.

To have a mask directely on the three components, just add three absolute values, one for each component, and then do the min() stuff:

r(1,x,y)=min(1,abs(r(0,x,y)-r)+abs(g(0,x,y)-g)+abs(b(0,x,y)-b))

Of course you have to replace r, g and b by the components you want (click in the window of project zero to read the colour under the pixel!)

You will see later how to combine project, but if you're eager to know it, try the following:

r(3,x,y)=r(2,x,y)*r(1,x,y)+r(0,x,y)*(1-r(1,x,y))
g(3,x,y)=g(2,x,y)*r(1,x,y)+g(0,x,y)*(1-r(1,x,y))
b(3,x,y)=b(2,x,y)*r(1,x,y)+b(0,x,y)*(1-r(1,x,y))

project zero is still our source picture;
project one is the mask (I assumed it was only zero/one here, i.e. that you didn't multiply it by 255. If you did, just divide the whole expression by 255 (or whatever you put)).
project two is the picture you want to put where the (r,g,b) colour of project one was, and project three is the destination...



Now some hints if you want to do some more complicated stuff, extracting colour having some precise features (e.g. having red component between 100 and 150 and so on).

Note that masks are not required to be full/none, there can be intermediary values in this mask (i.e. this mask works a little like an alpha channel).

* You have already seen how to get a single colour, you can use it to take colours between wider bounds:

max(0,min(1,abs(c(0,x,y)-c)-h)))

c is the component you are working on, the c variable is the mean value you want to take, and h is the tolerance (ie the range in which you want to accept values: you go from c-h to c+h). We have to put both min and max functions, as the abs()-h function goes below zero. Like before the function is zero when the component is inside the range, one otherwise.

Now, if you want to take all three components, like before you add the absolute values: 

max(0,min(1,abs(r(0,x,y)-r)+abs(g(0,x,y)-g)+abs(b(0,x,y)-b)-h)))

Note now that h will be the sum of the allowed mistakes. If for instance (r,g,b) is (50,100,200) and h is 10, you will have for instance (52,102,197) in the mask, as the total distance is 2+2+3=7, which is smaller than ten. However, (55,105,205) will not be in the mask, as the sum is here 5+5+5=15, which is larger than ten (even if all three distances are smaller than 10)...

The disadvantage of this way is that the mask is full and then suddenly zero when we get though a bound. It would be better to have a slighter slope.

* You can either use the way I showed you with implicit equations, an equation of the form

r(0,x,y)=t, which turns to k/((s-t)^2+l) (k is a factor, s is the source, r(0,x,y) in the previous example; t is the target, ie. the value where we want the mask to be the higher and l lets you adjust the slope.
(The maximum value comes when s gets to t and is k/l)

* You can also use something like max(0,l-k*(x-c)^2): here l is the maximum value you want it to have (usually 255!), k is a factor, the bigger it is the quicker you will get to zero. X and c are as before.
This one has the advantage to have really no mask when you get far enough from c, unlike the previous.

If all this is not enough to let you make the mask you want, you can try to use the x and y vars. (e.g. if the mask you want is only at a given distance from a point, make a second mask that contains just this circle and multiply both to get what you want.

Another example: if you have a picture where the background is a spread, then you can try to simulate the spread using equations, and then, in the mask, take the places where your spread and the source picture are similar, to get the background.

There are lots of other possibilities to make a mask from the colour. If for instance you want parts of the picture that look blue, (red < green < blue), then you can do something like

(tanh(green-red)+tanh(blue-green)+2)/4,

which will be one for blue areas and zero for others, having a smooth transition between them (unless the colour changes suddenly, of course) (remember that tanh(z) is about -1 when z is negative, and about +1 when z is positive)...

As usual, training is the best teacher :-)

And of course, you can also use another paint package to draw your mask, if you don't manage to do it otherwise...


Index

Chapter three: Simple graphs for a start

3.1: Monochrome Graphs
3.2: Implicit Functions
3.3: Playing with hyperbolic tangents

Chapter four: Inter-referencing

4.1: Having fun with colours
4.2: Convolutions
4.3: Linear transformations