Color Management: remove hardcoded ACES ODT tonemap

This tonemap was added as a temporary option only and if it'll be
needed again, it'll be better to implement is as either a spline
in OCIO or as a film response curve (as some of such curves were
added as a presets for RGB curves in Mango production SVN).

Also revert changes made to IMB_buffer_byte_from_float since it's
not actually needed anymore and makes it's clearer changes against
trunk.
This commit is contained in:
Sergey Sharybin
2012-09-04 12:32:12 +00:00
parent e15f352831
commit 3b9c3604c6
4 changed files with 28 additions and 381 deletions

View File

@@ -392,15 +392,6 @@ void IMB_buffer_byte_from_byte(unsigned char *rect_to, const unsigned char *rect
int width, int height, int stride_to, int stride_from);
void IMB_buffer_float_clamp(float *buf, int width, int height);
/* converting pixel buffers using tonecurve */
typedef void (*imb_tonecurveCb) (float rgbOut[3], const float rgbIn[3]);
void IMB_buffer_byte_from_float_tonecurve(unsigned char *rect_to, const float *rect_from,
int channels_from, float dither, int profile_to, int profile_from, int predivide,
int width, int height, int stride_to, int stride_from,
imb_tonecurveCb tonecurve_func);
/**
* Change the ordering of the color bytes pointed to by rect from
* rgba to abgr. size * 4 color bytes are reordered.

View File

@@ -75,9 +75,6 @@ typedef struct ConstProcessorRcPtr {
/* define this to allow byte buffers be color managed */
#undef COLORMANAGE_BYTE_BUFFER
#undef COLORMANAGE_USE_ACES_ODT
#define ACES_ODT_TONECORVE "ACES"
/* ** list of all supported color spaces, displays and views */
#ifdef WITH_OCIO
@@ -582,11 +579,6 @@ void IMB_colormanagement_init(void)
OCIO_configRelease(config);
#ifdef COLORMANAGE_USE_ACES_ODT
/* special views, which does not depend on OCIO */
colormanage_view_add(ACES_ODT_TONECORVE);
#endif
#endif
BLI_init_srgb_conversion();
@@ -737,44 +729,7 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle)
return linear_buffer;
}
#ifdef COLORMANAGE_USE_ACES_ODT
static void *do_display_buffer_apply_tonemap_thread(void *handle_v)
{
DisplayBufferThread *handle = (DisplayBufferThread *) handle_v;
imb_tonecurveCb tonecurve_func = (imb_tonecurveCb) handle->processor;
float *buffer = handle->buffer;
unsigned char *display_buffer = handle->display_buffer;
int channels = handle->channels;
int width = handle->width;
int height = handle->tot_line;
int dither = handle->dither;
int predivide = handle->predivide;
float *linear_buffer = display_buffer_apply_get_linear_buffer(handle);
IMB_buffer_byte_from_float_tonecurve(display_buffer, linear_buffer, channels, dither,
IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB,
predivide, width, height, width, width,
tonecurve_func);
if (linear_buffer != buffer)
MEM_freeN(linear_buffer);
return NULL;
}
static void display_buffer_apply_tonemap(ImBuf *ibuf, unsigned char *display_buffer,
imb_tonecurveCb tonecurve_func)
{
display_buffer_apply_threaded(ibuf, ibuf->rect_float, (unsigned char *)ibuf->rect,
display_buffer, tonecurve_func,
do_display_buffer_apply_tonemap_thread);
}
#endif
static void *do_display_buffer_apply_ocio_thread(void *handle_v)
static void *do_display_buffer_apply_thread(void *handle_v)
{
DisplayBufferThread *handle = (DisplayBufferThread *) handle_v;
ConstProcessorRcPtr *processor = (ConstProcessorRcPtr *) handle->processor;
@@ -856,9 +811,9 @@ static ConstProcessorRcPtr *create_display_buffer_processor(const char *view_tra
return processor;
}
static void display_buffer_apply_ocio(ImBuf *ibuf, unsigned char *display_buffer,
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings)
static void colormanage_display_buffer_process(ImBuf *ibuf, unsigned char *display_buffer,
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings)
{
ConstProcessorRcPtr *processor;
const float gamma = view_settings->gamma;
@@ -870,33 +825,12 @@ static void display_buffer_apply_ocio(ImBuf *ibuf, unsigned char *display_buffer
if (processor) {
display_buffer_apply_threaded(ibuf, ibuf->rect_float, (unsigned char *) ibuf->rect,
display_buffer, processor, do_display_buffer_apply_ocio_thread);
display_buffer, processor, do_display_buffer_apply_thread);
}
OCIO_processorRelease(processor);
}
static void colormanage_display_buffer_process(ImBuf *ibuf, unsigned char *display_buffer,
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings)
{
#ifdef COLORMANAGE_USE_ACES_ODT
const char *view_transform = view_settings->view_transform;
if (!strcmp(view_transform, ACES_ODT_TONECORVE)) {
/* special case for Mango team, this does not actually apply
* any input space -> display space conversion and just applies
* a tonecurve for better linear float -> sRGB byte conversion
*/
display_buffer_apply_tonemap(ibuf, display_buffer, IMB_ratio_preserving_odt_tonecurve);
}
else
#endif
{
display_buffer_apply_ocio(ibuf, display_buffer, view_settings, display_settings);
}
}
/*********************** Threaded color space transform routines *************************/
typedef struct ColorspaceTransformThread {
@@ -1845,14 +1779,6 @@ void IMB_colormanagement_view_items_add(EnumPropertyItem **items, int *totitem,
ColorManagedDisplay *display = colormanage_display_get_named(display_name);
ColorManagedView *view;
#ifdef COLORMANAGE_USE_ACES_ODT
/* OCIO_TODO: try to get rid of such a hackish stuff */
view = colormanage_view_get_named(ACES_ODT_TONECORVE);
if (view) {
colormanagement_view_item_add(items, totitem, view);
}
#endif
if (display) {
LinkData *display_view;
@@ -1901,8 +1827,7 @@ void IMB_colormanagement_colorspace_items_add(EnumPropertyItem **items, int *tot
static void partial_buffer_update_rect(unsigned char *display_buffer, const float *linear_buffer, int display_stride,
int linear_stride, int linear_offset_x, int linear_offset_y,
int channels, int dither, int predivide, int profile_from,
ConstProcessorRcPtr *processor, imb_tonecurveCb tonecurve_func,
int xmin, int ymin, int xmax, int ymax)
ConstProcessorRcPtr *processor, int xmin, int ymin, int xmax, int ymax)
{
int x, y;
@@ -1928,12 +1853,7 @@ static void partial_buffer_update_rect(unsigned char *display_buffer, const floa
}
else
#endif
if (tonecurve_func) {
IMB_buffer_byte_from_float_tonecurve(display_buffer + display_index, linear_buffer + linear_index,
channels, dither, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB,
predivide, 1, 1, 1, 1, tonecurve_func);
}
else {
{
IMB_buffer_byte_from_float(display_buffer + display_index, linear_buffer + linear_index, channels,
dither, IB_PROFILE_SRGB, profile_from, predivide, 1, 1, 1, 1);
}
@@ -1948,23 +1868,22 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
int predivide = ibuf->flags & IB_cm_predivide;
int dither = ibuf->dither;
int profile_from = ibuf->profile;
int display;
int *display_buffer_flags;
#ifdef WITH_OCIO
int display;
int *display_buffer_flags;
BLI_lock_thread(LOCK_COLORMANAGE);
if (ibuf->rect && ibuf->rect_float) {
/* update byte buffer created by legacy color management */
partial_buffer_update_rect((unsigned char *) ibuf->rect, linear_buffer, ibuf->x, stride, offset_x, offset_y,
channels, dither, predivide, profile_from, NULL, xmin, ymin, xmax, ymax);
}
if (!ibuf->display_buffer_flags) {
/* there's no cached display buffers, so no need to iterate though bit fields */
if (ibuf->rect && ibuf->rect_float) {
/* update byte buffer created by legacy color management */
partial_buffer_update_rect((unsigned char *) ibuf->rect, linear_buffer, ibuf->x, stride, offset_x, offset_y,
channels, dither, predivide, profile_from, NULL, NULL, xmin, ymin, xmax, ymax);
}
BLI_unlock_thread(LOCK_COLORMANAGE);
return;
@@ -2011,21 +1930,12 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
if (display_buffer) {
const char *view_name = IMB_colormanagement_view_get_indexed_name(view_index);
ConstProcessorRcPtr *processor = NULL;
imb_tonecurveCb tonecurve_func = NULL;
#ifdef COLORMANAGE_USE_ACES_ODT
if (!strcmp(view_name, ACES_ODT_TONECORVE)) {
tonecurve_func = IMB_ratio_preserving_odt_tonecurve;
}
else
#endif
{
processor = create_display_buffer_processor(view_name, display_name, exposure, gamma);
}
processor = create_display_buffer_processor(view_name, display_name, exposure, gamma);
partial_buffer_update_rect(display_buffer, linear_buffer, buffer_width, stride,
offset_x, offset_y, channels, dither, predivide, profile_from,
processor, tonecurve_func, xmin, ymin, xmax, ymax);
processor, xmin, ymin, xmax, ymax);
if (processor)
OCIO_processorRelease(processor);
@@ -2040,13 +1950,8 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
}
MEM_freeN(display_buffer_flags);
#else
(void) display;
(void) display_buffer_flags;
#endif
BLI_lock_thread(LOCK_COLORMANAGE);
if (ibuf->rect && ibuf->rect_float) {
/* update byte buffer created by legacy color management */
partial_buffer_update_rect((unsigned char *) ibuf->rect, linear_buffer, ibuf->x, stride, offset_x, offset_y,
channels, dither, predivide, profile_from, NULL, NULL, xmin, ymin, xmax, ymax);
}
BLI_unlock_thread(LOCK_COLORMANAGE);
}

View File

@@ -38,15 +38,10 @@
#include "imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_filter.h"
#include "IMB_allocimbuf.h"
#include "MEM_guardedalloc.h"
#ifdef WITH_OCIO
#include <ocio_capi.h>
#endif
/**************************** Interlace/Deinterlace **************************/
void IMB_de_interlace(ImBuf *ibuf)
@@ -190,13 +185,11 @@ MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], DitherContext
}
/* float to byte pixels, output 4-channel RGBA */
void IMB_buffer_byte_from_float_tonecurve(uchar *rect_to, const float *rect_from,
int channels_from, float dither, int profile_to, int profile_from, int predivide,
int width, int height, int stride_to, int stride_from,
imb_tonecurveCb tonecurve_func)
void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
int channels_from, float dither, int profile_to, int profile_from, int predivide,
int width, int height, int stride_to, int stride_from)
{
float tmp[4];
float corrected[4];
int x, y;
DitherContext *di;
@@ -207,9 +200,6 @@ void IMB_buffer_byte_from_float_tonecurve(uchar *rect_to, const float *rect_from
if (dither)
di = create_dither_context(width, dither);
if (!tonecurve_func)
tonecurve_func = copy_v3_v3;
for (y = 0; y < height; y++) {
if (channels_from == 1) {
/* single channel input */
@@ -234,8 +224,7 @@ void IMB_buffer_byte_from_float_tonecurve(uchar *rect_to, const float *rect_from
else if (profile_to == IB_PROFILE_SRGB) {
/* convert from linear to sRGB */
for (x = 0; x < width; x++, from += 3, to += 4) {
tonecurve_func(corrected, from);
linearrgb_to_srgb_v3_v3(tmp, corrected);
linearrgb_to_srgb_v3_v3(tmp, from);
rgb_float_to_uchar(to, tmp);
to[3] = 255;
}
@@ -271,37 +260,25 @@ void IMB_buffer_byte_from_float_tonecurve(uchar *rect_to, const float *rect_from
if (dither && predivide) {
for (x = 0; x < width; x++, from += 4, to += 4) {
tonecurve_func(corrected, from);
corrected[3] = from[3];
linearrgb_to_srgb_ushort4_predivide(us, corrected);
linearrgb_to_srgb_ushort4_predivide(us, from);
ushort_to_byte_dither_v4(to, us, di);
}
}
else if (dither) {
for (x = 0; x < width; x++, from += 4, to += 4) {
tonecurve_func(corrected, from);
corrected[3] = from[3];
linearrgb_to_srgb_ushort4(us, corrected);
linearrgb_to_srgb_ushort4(us, from);
ushort_to_byte_dither_v4(to, us, di);
}
}
else if (predivide) {
for (x = 0; x < width; x++, from += 4, to += 4) {
tonecurve_func(corrected, from);
corrected[3] = from[3];
linearrgb_to_srgb_ushort4_predivide(us, corrected);
linearrgb_to_srgb_ushort4_predivide(us, from);
ushort_to_byte_v4(to, us);
}
}
else {
for (x = 0; x < width; x++, from += 4, to += 4) {
tonecurve_func(corrected, from);
corrected[3] = from[3];
linearrgb_to_srgb_ushort4(us, corrected);
linearrgb_to_srgb_ushort4(us, from);
ushort_to_byte_v4(to, us);
}
}
@@ -343,15 +320,6 @@ void IMB_buffer_byte_from_float_tonecurve(uchar *rect_to, const float *rect_from
clear_dither_context(di);
}
void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
int channels_from, float dither, int profile_to, int profile_from, int predivide,
int width, int height, int stride_to, int stride_from)
{
IMB_buffer_byte_from_float_tonecurve(rect_to, rect_from, channels_from, dither, profile_to, profile_from, predivide,
width, height, stride_to, stride_from, NULL);
}
/* byte to float pixels, input and output 4-channel RGBA */
void IMB_buffer_float_from_byte(float *rect_to, const uchar *rect_from,
int profile_to, int profile_from, int predivide,

View File

@@ -31,11 +31,8 @@
* \ingroup imbuf
*/
#include <math.h>
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "IMB_imbuf_types.h"
@@ -602,217 +599,3 @@ void IMB_premultiply_alpha(ImBuf *ibuf)
IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y);
}
/* Tonecurve corrections */
/* code of rdt_shaper_fwd and ratio_preserving_odt_tonecurve belongs to
* ACES project (https://github.com/ampas/aces-dev)
*/
/* === ODT SPLINE === */
/*
* Algorithm for applying ODT tone curve in forward direction.
*
* vers 1.0 Doug Walker 2012-01-23
* modified by Scott Dyer 2012-02-28
*/
/* Input and output are in linear (not log) units. */
static float rdt_shaper_fwd(float x)
{
/* B-spline coefficients.
* The units are density of the output.
*/
const float COEFS0 = -0.008f;
const float COEFS1 = -0.00616f;
const float COEFS2 = 0.026f;
const float COEFS3 = 0.185f;
const float COEFS4 = 0.521f;
const float COEFS5 = 0.993f;
const float COEFS6 = 1.563f;
const float COEFS7 = 2.218f;
const float COEFS8 = 2.795f;
const float COEFS9 = 3.36f;
const float COEFS10 = 4.0f; /* NB: keep this less than or equal to -log10(FLARE) */
/* The locations of these control points in OCES density space are:
* -1., -0.79, -0.44, -0.01, 0.48, 1.01, 1.58, 2.18, 2.82, 3.47, 4.15, 4.85
*/
/* The flare term allows the spline to more rapidly approach zero
* while keeping the shape of the curve well-behaved in density space.
*/
const float FLARE = 1e-4f;
/* The last control point is fixed to yield a specific density at the
* end of the knot domain.
*/
/* const float COEFS11 = 2. * (-log10(FLARE) - 0.001) - COEFS10; */
/* Note: Apparently a CTL bug prevents calling log10() here, so
* you'll need to update this manually if you change FLARE.
*/
const float COEFS11 = COEFS10 + 2.0f * (4.0f - COEFS10);
/* The knots are in units of OCES density. */
const unsigned int KNOT_LEN = 11;
const float KNOT_START = -0.9f;
const float KNOT_END = 4.484256f;
/* The KNOT_POW adjusts the spacing to put more knots near the toe (highlights). */
const float KNOT_POW = 1.0f / 1.3f;
const float OFFS = KNOT_START;
const float SC = KNOT_END - KNOT_START;
/* KNOT_DENS is density of the spline at the knots. */
const float KNOT_DENS[11] = {
(COEFS0 + COEFS1) / 2.0f,
(COEFS1 + COEFS2) / 2.0f,
(COEFS2 + COEFS3) / 2.0f,
(COEFS3 + COEFS4) / 2.0f,
(COEFS4 + COEFS5) / 2.0f,
(COEFS5 + COEFS6) / 2.0f,
(COEFS6 + COEFS7) / 2.0f,
(COEFS7 + COEFS8) / 2.0f,
(COEFS8 + COEFS9) / 2.0f,
(COEFS9 + COEFS10) / 2.0f,
(COEFS10 + COEFS11) / 2.0f
};
/* Parameters controlling linear extrapolation. */
const float LIGHT_SLOPE = 0.023;
const float CROSSOVER = pow(10,-KNOT_END);
const float REV_CROSSOVER = pow(10.0f, -KNOT_DENS[ KNOT_LEN - 1]) - FLARE;
const float DARK_SLOPE = REV_CROSSOVER / CROSSOVER;
/* Textbook monomial to basis-function conversion matrix. */
/*const*/ float M[3][3] = {
{ 0.5f, -1.0f, 0.5f},
{-1.0f, 1.0f, 0.5f},
{ 0.5f, 0.0f, 0.0f}
};
float y;
/* Linear extrapolation in linear space for negative & very dark values. */
if (x <= CROSSOVER) {
y = x * DARK_SLOPE;
}
else {
float in_dens = -log10(x);
float out_dens;
float knot_coord = (in_dens - OFFS) / SC;
if (knot_coord <= 0.0f) {
/* Linear extrapolation in log space for very light values. */
out_dens = KNOT_DENS[0] - (KNOT_START - in_dens) * LIGHT_SLOPE;
}
else {
/* For typical OCES values, apply a B-spline curve. */
int j;
float t;
float cf[3], monomials[3], v[3];
knot_coord = ( KNOT_LEN - 1) * pow( knot_coord, KNOT_POW);
j = knot_coord;
t = knot_coord - j;
/* Would like to do this: */
/* float cf[ 3] = { COEFS[ j], COEFS[ j + 1], COEFS[ j + 2]}; */
/* or at least: */
/* cf[0] = COEFS[j]; */
/* cf[1] = COEFS[j + 1]; */
/* cf[2] = COEFS[j + 2]; */
/* But apparently CTL bugs prevent it, so we do the following: */
if (j <= 0) {
cf[0] = COEFS0; cf[1] = COEFS1; cf[2] = COEFS2;
}
else if (j == 1) {
cf[0] = COEFS1; cf[1] = COEFS2; cf[2] = COEFS3;
}
else if (j == 2) {
cf[0] = COEFS2; cf[1] = COEFS3; cf[2] = COEFS4;
}
else if (j == 3) {
cf[0] = COEFS3; cf[1] = COEFS4; cf[2] = COEFS5;
}
else if (j == 4) {
cf[0] = COEFS4; cf[1] = COEFS5; cf[2] = COEFS6;
}
else if (j == 5) {
cf[0] = COEFS5; cf[1] = COEFS6; cf[2] = COEFS7;
}
else if (j == 6) {
cf[0] = COEFS6; cf[1] = COEFS7; cf[2] = COEFS8;
}
else if (j == 7) {
cf[0] = COEFS7; cf[1] = COEFS8; cf[2] = COEFS9;
}
else if (j == 8) {
cf[0] = COEFS8; cf[1] = COEFS9; cf[2] = COEFS10;
}
else {
cf[0] = COEFS9; cf[1] = COEFS10; cf[2] = COEFS11;
}
monomials[0] = t * t;
monomials[1] = t;
monomials[2] = 1.0f;
mul_v3_m3v3(v, M, cf);
out_dens = dot_v3v3( monomials, v);
}
y = pow(10.0f, -out_dens) - FLARE;
}
return y;
}
void IMB_ratio_preserving_odt_tonecurve(float rgbOut[3], const float rgbIn[3])
{
float acesIn[3], acesOut[3];
float rec709_to_aces[3][3] = {{0.4395770431f, 0.0895979404f, 0.0174174830f},
{0.3839148879f, 0.8147120476f, 0.1087378338f},
{0.1765103489f, 0.0956883803f, 0.8738504052f}};
float aces_to_rec709[3][3] = {{ 2.5219228268f, -0.2754705548f, -0.0159884077f},
{-1.1370280981f, 1.3698303699f, -0.1477921605f},
{-0.3849000633f, -0.0943564922f, 1.1637737751f}};
/* The "ratio preserving tonecurve" is used to avoid hue/chroma shifts.
* It sends a norm through the tonecurve and scales the RGB values based on the output.
*/
const float NTH_POWER = 2.0f;
const float TINY = 1e-12f;
float numerator, denominator;
float normRGB, normRGBo;
mul_v3_m3v3(acesIn, rec709_to_aces, (float *) rgbIn);
numerator = pow(acesIn[0], NTH_POWER) + pow(acesIn[1], NTH_POWER) + pow(acesIn[2], NTH_POWER);
denominator = pow(acesIn[0], NTH_POWER - 1) +
pow(acesIn[1], NTH_POWER - 1) +
pow(acesIn[2], NTH_POWER - 1);
/* use of max function to avoid divide by zero */
denominator = MAX2(TINY, denominator);
normRGB = numerator / denominator;
if (normRGB <= 0.0f) {
normRGB = TINY;
}
normRGBo = rdt_shaper_fwd(normRGB);
acesOut[0] = acesIn[0] * normRGBo / normRGB;
acesOut[1] = acesIn[1] * normRGBo / normRGB;
acesOut[2] = acesIn[2] * normRGBo / normRGB;
mul_v3_m3v3(rgbOut, aces_to_rec709, (float *) acesOut);
}