:: [Frei0r] [PATCH] Unbreak the levels…
Top Page
Delete this message
Reply to this message
Author: Steinar H. Gunderson
Date:  
To: frei0r
Subject: [Frei0r] [PATCH] Unbreak the levels plugin's luma mode
As per discussion here, I dug briefly into the levels plugin and fixed the
worst part of it. Patch attached.

/* Steinar */
--
Homepage: http://www.sesse.net/

>From 85f12e46ab35cfa18a17e39635c2c6f37b2775b9 Mon Sep 17 00:00:00 2001
From: "Steinar H. Gunderson" <sgunderson@???>
Date: Sun, 23 Sep 2012 11:34:31 +0200
Subject: [PATCH] =?UTF-8?q?Unbreak=20the=20levels=20plugin's=20=E2=80=9Cluma?=
=?UTF-8?q?=E2=80=9D=20mode.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When used in the default “luma” mode, levels plugin was effectively trying to
approximate the value-to-value map, including pow, subtractions, etc., by a
single multiplication (except in the case of all-zero input, in which case
it would simply correctly look up in the map). The calculated luma value would
then be used to decide which multiplication factor to use.

This is obviously not going to work; the typical result would be that
when using black output level > 0, very dark but non-zero pixels (e.g. #000100)
would be amplified a lot and create colored artifacts in such areas.
Simply let the “luma” mode apply the curve equally to all color channels,
which is probably what the user expected. The histogram still shows the
actual calculate luma, though.

There's a lot of performance work to do on this plugin, e.g. move the
switch out of the inner loop, but at least it should give slightly more
sensible output now.
---
src/filter/levels/levels.c | 36 ++++++++++++++----------------------
1 files changed, 14 insertions(+), 22 deletions(-)

diff --git a/src/filter/levels/levels.c b/src/filter/levels/levels.c
index 33f9723..5dcd984 100644
--- a/src/filter/levels/levels.c
+++ b/src/filter/levels/levels.c
@@ -216,22 +216,22 @@ void f0r_update(f0r_instance_t instance, double time,

unsigned char* dst = (unsigned char*)outframe;
const unsigned char* src = (unsigned char*)inframe;
- int b, g, r;
- int luma;
+ int r, g, b;

double levels[256];
- int map[256];
- double mapLuma[256];
+ unsigned int map[256];

double inScale = inst->inputMax != inst->inputMin?inst->inputMax - inst->inputMin:1;
double exp = inst->gamma == 0?1:1/inst->gamma;
double outScale = inst->outputMax - inst->outputMin;

   for(int i = 0; i < 256; i++) {
-    double v = i / 255.;
-    double w = pow((v - inst->inputMin) / inScale, exp) * outScale + inst->outputMin;
-    map[i] = CLAMP(w,0,1) * 255;
-    mapLuma[i] = i == 0?w:w / v;
+    double v = i / 255. - inst->inputMin;
+    if (v < 0.0) {
+        v = 0.0;
+    }           
+    double w = pow(v / inScale, exp) * outScale + inst->outputMin;
+    map[i] = CLAMP0255(lrintf(w * 255.0));
   }


   if (inst->showHistogram)
@@ -244,15 +244,13 @@ void f0r_update(f0r_instance_t instance, double time,
     g = *src++;
     b = *src++;


-    if (inst->channel == CHANNEL_LUMA)
-      luma = CLAMP0255((unsigned int)(b * .114 + g * .587 + r * .299));
     if (inst->showHistogram) {
-      int intencity = 
+      int intensity = 
         inst->channel == CHANNEL_RED?r:
         inst->channel == CHANNEL_GREEN?g:
         inst->channel == CHANNEL_BLUE?b:
-        luma;
-      int index = CLAMP0255(intencity);
+            CLAMP0255(b * .114 + g * .587 + r * .299);
+      int index = CLAMP0255(intensity);
       levels[index]++;
       if (levels[index] > maxHisto)
         maxHisto = levels[index];
@@ -275,15 +273,9 @@ void f0r_update(f0r_instance_t instance, double time,
       *dst++ = map[b];
       break;
     case CHANNEL_LUMA:
-      if (luma == 0) {
-        *dst++ = mapLuma[luma];
-        *dst++ = mapLuma[luma];
-        *dst++ = mapLuma[luma];
-      } else {
-        *dst++ = CLAMP0255((unsigned int)(r * mapLuma[luma]));
-        *dst++ = CLAMP0255((unsigned int)(g * mapLuma[luma]));
-        *dst++ = CLAMP0255((unsigned int)(b * mapLuma[luma]));
-      }
+      *dst++ = map[r];
+      *dst++ = map[g];
+      *dst++ = map[b];
       break;
     }


--
1.7.7.3