Sepia algorithm

Recently, I wanted to produce sepia images digitally that would ressemble the prints we toned in the lab in the days of film.

I didn't find good options at first, nor good algorithms. So with a bit of experimentation, I came up with the algorithm described below.

For this blog, I'll use the following image, a pre-desaturated version as input to the sepia algos:

Searching the web, I found the following algorithm which, apparently, comes from Microsoft :

   newRed =   0.393*R + 0.769*G + 0.189*B
   newGreen = 0.349*R + 0.686*G + 0.168*B
   newBlue =  0.272*R + 0.534*G + 0.131*B
I found this transform many times on the web.

GIMP 2.10 appears to use this same algorithm in Colors -> Desaturate -> Sepia... Here's the result along with a standard (luminance-based) desaturation of the sepia. This gives following:


To my liking, this is too yellow. But the bigger problem is that if you desaturate again, you get a result that is significantly brighter than the original desaturation, meaning that this sepia toning affects luminance.

I think that a sepia toning should preserve luminance, or perhaps one of the other measures in Colors -> Desaturate.

Then I tried a little experiment in GIMP:

This suggested that three parallel straight curves with taperings at the ends seems to do the trick. So I wrote an algorithm with two parameters: the distance between the red and green lines, and between the green and blue lines. Varying these two parms (within reasonable limits) allows one to vary the sepia tint. The assumption is that the red curve is highest (on the "curves" graph) and blue curve lowest.

   rg = 19  # distance between red and green lines -- my default values
   gb = 27  # distance between green and blue lines
   # overall, a distance of about 50 between red and blue seems about right
We now calculate by how much the red line is above the desaturated value (luminance) by requiring that luminance be preserved. This gives the following equations:
   # ar is adjustment for red that we want to compute; l is and arbritrary luminance
   # the following equation expresses the wish that luminance be invariant
   # ie. luminance of sepia is same as luminance of original
   (l + ar) * .30  +  (l + ar - rg) * .59  +  (l + ar - rg - gb) * .11  ==  l
   # remove 'l'
   ar * .30  +  (ar - rg) * .59  +  (ar - rg - gb) * .11  ==  0
   # regroup things
   ar - rg * 0.70 - gb * 0.11 == 0
   # isolate ar
   ar = rg * 0.70 + gb * 0.11
   # adjustments for green and blue are now simply
   ag = ar - rg
   ab = ar - rg - gb
and the conversion becomes simply:
   l = (30*r + 59*g + 11*b)   # compute luminance of pixel
   r = l + ar                 # new sepia values of RGB
   g = l + ag
   b = l + ab
The tapering off at the ends is left as an exercise for the reader :-). This gives the resulting image, and the following re-desaturation (same as original):


I think this is better than GIMP's algorithm. After this work, I discovered that Preview (MacOS) does quite a good job: nice color, perhaps a tad darker.


P.S. Here's the original in color... (note that I used something else than luminance to do the initial desaturation in this case -- the reds were too dark otherwise):

P.P.S. I might have confused some terms, eg. "luminosity", "luminance". In the above discussion, "luminance" means "lum = (30*r + 59*g + 11*b)" and I think that matches GIMP's "Colors -> Desaturate -> Luminance".

Email:  (franšais, English, Deutsch).