{"id":26,"date":"2013-04-15T15:37:21","date_gmt":"2013-04-15T19:37:21","guid":{"rendered":"http:\/\/www.tks-designs.com\/blog\/?p=26"},"modified":"2013-05-22T11:38:46","modified_gmt":"2013-05-22T15:38:46","slug":"luminance-curves","status":"publish","type":"post","link":"https:\/\/www.tks-designs.com\/blog\/?p=26","title":{"rendered":"Luminance Curves"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/grayscale_curve-perceptual.jpg\" alt=\"grayscale_curve-perceptual\" width=\"600\" height=\"100\" class=\"alignnone size-full wp-image-78\" srcset=\"https:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/grayscale_curve-perceptual.jpg 600w, https:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/grayscale_curve-perceptual-300x50.jpg 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>Often in compositing, I will need to take one set of values and convert it to a different set of values. Say I have a linear image, with luminance values in a range from 0 &#8211; 4.589:<\/p>\n<table width=\"200\">\n<tbody>\n<tr>\n<td>Input:<\/td>\n<td>Output:<\/td>\n<\/tr>\n<tr>\n<td>0<\/td>\n<td>0<\/td>\n<\/tr>\n<tr>\n<td>4.589<\/td>\n<td>1<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If I want to do some fancy operation on that image based on it&#8217;s luminance, I&#8217;ll probably want to convert that range to 0-1, so it&#8217;s easier to work with. The easiest and most straight-forward type of conversion is a linear one, of course, where we simply divide all the luminance values by the largest value, giving us a range of values between 0 and 1:<\/p>\n<p><!--more--><\/p>\n<pre><code>0.0 \/ 4.589 = 0\r\n0.1 \/ 4.589 = .021\r\n0.5 \/ 4.589 = .1\r\n0.9 \/ 4.589 = .19\r\n1.0 \/ 4.589 = .217\r\n\r\n...\r\n4.589 \/ 4.589 = 1<\/code><\/pre>\n<p>There are two problems with this solution. First, our perception of luminance is not at all linear. Here&#8217;s an image of a gradient where 0 is black, and 1 is white (a <em>linear<\/em> curve):<code><br ><\/code><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-75\" alt=\"grayscale_curve\" src=\"http:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/grayscale_curve\" width=\"600\" height=\"100\" \/><br \/>\nNow, find the point where it looks 50% gray (half way between white and black). I bet you didn&#8217;t pick a point directly in the center! Look at how quickly the values appear to go completely white. For most people, the <em>perceptual<\/em> mid-point is at about .18 (about a quarter of the way from the left). If we make a gradient with .18 in the center, it starts to look more gradual:<code><br ><\/code><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-78\" alt=\"grayscale_curve-perceptual\" src=\"http:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/grayscale_curve-perceptual.jpg\" width=\"600\" height=\"100\" srcset=\"https:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/grayscale_curve-perceptual.jpg 600w, https:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/grayscale_curve-perceptual-300x50.jpg 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>The second problem with this method is that it treats values greater than 1 as of equal weight as values below, but to our eyes anything at 1.0 or higher is simply white. We don&#8217;t want to crunch the values and lose all that valuable data, though, because you never know what we&#8217;ll need to do to the image down the pipeline. So what we need is a <strong>better curve<\/strong> that more accurately represents how we <em>visually see<\/em> the range of luminance values in the image.<\/p>\n<p>With a little bit of experimentation (and a lot of help from OSX&#8217;s Grapher application) I was able to come up with some mathematical equations creating different kinds of curves:<br \/>\n<div id=\"attachment_90\" style=\"width: 590px\" class=\"wp-caption center\"><a href=\"http:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/curves.gif\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-90\" class=\"size-large wp-image-90\" alt=\"curves\" src=\"http:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/curves-1024x739.gif\" width=\"580\" height=\"418\" srcset=\"https:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/curves-1024x739.gif 1024w, https:\/\/www.tks-designs.com\/blog\/wp-content\/uploads\/2013\/04\/curves-300x216.gif 300w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/a><p id=\"caption-attachment-90\" class=\"wp-caption-text\">where the x-axis is your input values, and the y-axis is your ouput values (here 0-1)<\/p><\/div><\/p>\n<p>On this chart, if we use our shorthand [ .5 linear luminance == .18 perceived luminance ] we can see that the visual perception curve lies somewhere around the square root curve. Before we plug in our values, though, we&#8217;ll need to eliminate (or correct) any values above one (temporarily, of course) with a simple if statement:<\/p>\n<pre><code>if (inputLuma >= 1 ):\r\n\toutputLuma = 1\r\nelse:\r\n\toutputLuma = inputLuma\r\n<\/pre>\n<p><\/code><\/p>\n<p>Now, we plug in our new range (from 0-1) and convert it <em>back<\/em> to 0-1 using a different interpolation that more accurately represents human perception (here, our square root curve). In this case, since the top range value [\u03b1 in the above graph] of the input is 1, you could eliminate the (x\/\u03b1) elements.<\/p>\n<p><pre><code>sqrt(<span style=\"color: #0000ff;\">0.00<\/span>) = 0.0\r\nsqrt(<span style=\"color: #0000ff;\">0.18<\/span>) = 0.42\r\nsqrt(<span style=\"color: #0000ff;\">0.25<\/span>) = 0.5\r\nsqrt(<span style=\"color: #0000ff;\">0.50<\/span>) = 0.70\r\nsqrt(<span style=\"color: #0000ff;\">0.75<\/span>) = 0.86\r\nsqrt(<span style=\"color: #0000ff;\">1.00<\/span>) = 1.0<\/pre>\n<p><\/code><\/p>\n<p>Now we have a range of values, from 0-1, weighted appropriately based upon perceived luminance (more values in the darker end, fewer in the lighter end). <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Often in compositing, I will need to take one set of values and convert it to a different set of values. Say I have a linear image, with luminance values in a range from 0 &#8211; 4.589: Input: Output: 0 0 4.589 1 If I want to do some fancy operation on that image based <span class=\"ellipsis\">&hellip;<\/span> <span class=\"more-link-wrap\"><a href=\"https:\/\/www.tks-designs.com\/blog\/?p=26\" class=\"more-link\"><span>Continue Reading &rarr;<\/span><\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"kia_subtitle":"being an exploration on converting values from one set to another using curves","footnotes":""},"categories":[13,2,9,12],"tags":[],"class_list":["post-26","post","type-post","status-publish","format-standard","hentry","category-animation","category-houdini","category-math","category-technical-direction"],"_links":{"self":[{"href":"https:\/\/www.tks-designs.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/26","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tks-designs.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tks-designs.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tks-designs.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tks-designs.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=26"}],"version-history":[{"count":100,"href":"https:\/\/www.tks-designs.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/26\/revisions"}],"predecessor-version":[{"id":260,"href":"https:\/\/www.tks-designs.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/26\/revisions\/260"}],"wp:attachment":[{"href":"https:\/\/www.tks-designs.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=26"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tks-designs.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=26"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tks-designs.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=26"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}