== Sequencer ==
New feature: color balance aka 3-way-color-correction aka lift/gamma/gain on input (folded into byte -> float conversion, so _very_ fast in that case). Interface is inspired from Rebel CC (but not as complete yet, you can't choose white and black points right now). Bugfix: clamp color seperated wave form display correctly.
This commit is contained in:
@@ -3468,6 +3468,12 @@ static void direct_link_scene(FileData *fd, Scene *sce)
|
||||
} else {
|
||||
seq->strip->proxy = 0;
|
||||
}
|
||||
if (seq->flag & SEQ_USE_COLOR_BALANCE) {
|
||||
seq->strip->color_balance = newdataadr(
|
||||
fd, seq->strip->color_balance);
|
||||
} else {
|
||||
seq->strip->color_balance = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
END_SEQ
|
||||
|
||||
@@ -1505,6 +1505,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
|
||||
if(seq->flag & SEQ_USE_PROXY && strip->proxy) {
|
||||
writestruct(wd, DATA, "StripProxy", 1, strip->proxy);
|
||||
}
|
||||
if(seq->flag & SEQ_USE_COLOR_BALANCE && strip->color_balance) {
|
||||
writestruct(wd, DATA, "StripColorBalance", 1, strip->color_balance);
|
||||
}
|
||||
if(seq->type==SEQ_IMAGE)
|
||||
writestruct(wd, DATA, "StripElem", strip->len, strip->stripdata);
|
||||
else if(seq->type==SEQ_MOVIE || seq->type==SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND)
|
||||
|
||||
@@ -69,6 +69,15 @@ typedef struct StripTransform {
|
||||
int yofs;
|
||||
} StripTransform;
|
||||
|
||||
typedef struct StripColorBalance {
|
||||
float lift[3];
|
||||
float gamma[3];
|
||||
float gain[3];
|
||||
int flag;
|
||||
float exposure;
|
||||
float saturation;
|
||||
} StripColorBalance;
|
||||
|
||||
typedef struct StripProxy {
|
||||
char dir[160];
|
||||
int format;
|
||||
@@ -86,6 +95,7 @@ typedef struct Strip {
|
||||
StripCrop *crop;
|
||||
StripTransform *transform;
|
||||
StripProxy *proxy;
|
||||
StripColorBalance *color_balance;
|
||||
TStripElem *tstripdata;
|
||||
TStripElem *tstripdata_startstill;
|
||||
TStripElem *tstripdata_endstill;
|
||||
@@ -248,7 +258,11 @@ typedef struct SpeedControlVars {
|
||||
#define SEQ_USE_PROXY 32768
|
||||
#define SEQ_USE_TRANSFORM 65536
|
||||
#define SEQ_USE_CROP 131072
|
||||
#define SEQ_USE_COLOR_BALANCE 262144
|
||||
|
||||
#define SEQ_COLOR_BALANCE_INVERSE_GAIN 1
|
||||
#define SEQ_COLOR_BALANCE_INVERSE_GAMMA 2
|
||||
#define SEQ_COLOR_BALANCE_INVERSE_LIFT 4
|
||||
|
||||
/* seq->type WATCH IT: SEQ_EFFECT BIT is used to determine if this is an effect strip!!! */
|
||||
#define SEQ_IMAGE 0
|
||||
|
||||
@@ -889,50 +889,113 @@ static void seq_panel_filter_video()
|
||||
|
||||
|
||||
uiDefButBitI(block, TOG, SEQ_MAKE_PREMUL,
|
||||
B_SEQ_BUT_RELOAD, "Convert to Premul",
|
||||
10,110,150,19, &last_seq->flag,
|
||||
B_SEQ_BUT_RELOAD, "Premul",
|
||||
10,110,80,19, &last_seq->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"Converts RGB values to become premultiplied with Alpha");
|
||||
|
||||
uiDefButBitI(block, TOG, SEQ_MAKE_FLOAT,
|
||||
B_SEQ_BUT_RELOAD, "Float",
|
||||
90,110,80,19, &last_seq->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"Convert input to float data");
|
||||
|
||||
uiDefButBitI(block, TOG, SEQ_FILTERY,
|
||||
B_SEQ_BUT_RELOAD, "FilterY",
|
||||
10,90,75,19, &last_seq->flag,
|
||||
170,110,80,19, &last_seq->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"For video movies to remove fields");
|
||||
|
||||
uiDefButBitI(block, TOG, SEQ_MAKE_FLOAT,
|
||||
B_SEQ_BUT_RELOAD, "Make Float",
|
||||
85,90,75,19, &last_seq->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"Convert input to float data");
|
||||
|
||||
uiDefButBitI(block, TOG, SEQ_FLIPX,
|
||||
B_SEQ_BUT_RELOAD, "FlipX",
|
||||
10,70,75,19, &last_seq->flag,
|
||||
10,90,80,19, &last_seq->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"Flip on the X axis");
|
||||
uiDefButBitI(block, TOG, SEQ_FLIPY,
|
||||
B_SEQ_BUT_RELOAD, "FlipY",
|
||||
85,70,75,19, &last_seq->flag,
|
||||
90,90,80,19, &last_seq->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"Flip on the Y axis");
|
||||
|
||||
uiDefButF(block, NUM, B_SEQ_BUT_RELOAD, "Mul:",
|
||||
10,50,150,19, &last_seq->mul,
|
||||
0.001, 5.0, 100, 0,
|
||||
"Multiply colors");
|
||||
|
||||
uiDefButBitI(block, TOG, SEQ_REVERSE_FRAMES,
|
||||
B_SEQ_BUT_RELOAD, "Reverse Frames",
|
||||
10,30,150,19, &last_seq->flag,
|
||||
B_SEQ_BUT_RELOAD, "Flip Time",
|
||||
170,90,80,19, &last_seq->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"Reverse frame order");
|
||||
|
||||
uiDefButF(block, NUM, B_SEQ_BUT_RELOAD, "Mul:",
|
||||
10,70,120,19, &last_seq->mul,
|
||||
0.001, 5.0, 0.1, 0,
|
||||
"Multiply colors");
|
||||
|
||||
uiDefButF(block, NUM, B_SEQ_BUT_RELOAD, "Strobe:",
|
||||
10,10,150,19, &last_seq->strobe,
|
||||
130,70,120,19, &last_seq->strobe,
|
||||
1.0, 30.0, 100, 0,
|
||||
"Only display every nth frame");
|
||||
|
||||
uiDefButBitI(block, TOG, SEQ_USE_COLOR_BALANCE,
|
||||
B_SEQ_BUT_RELOAD, "Use Color Balance",
|
||||
10,50,240,19, &last_seq->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"Activate Color Balance "
|
||||
"(3-Way color correction) on input");
|
||||
|
||||
|
||||
if (last_seq->flag & SEQ_USE_COLOR_BALANCE) {
|
||||
if (!last_seq->strip->color_balance) {
|
||||
int c;
|
||||
StripColorBalance * cb
|
||||
= last_seq->strip->color_balance
|
||||
= MEM_callocN(
|
||||
sizeof(struct StripColorBalance),
|
||||
"StripColorBalance");
|
||||
for (c = 0; c < 3; c++) {
|
||||
cb->lift[c] = 1.0;
|
||||
cb->gamma[c] = 1.0;
|
||||
cb->gain[c] = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
uiDefBut(block, LABEL, 0, "Lift",
|
||||
10,30,80,19, 0, 0, 0, 0, 0, "");
|
||||
uiDefBut(block, LABEL, 0, "Gamma",
|
||||
90,30,80,19, 0, 0, 0, 0, 0, "");
|
||||
uiDefBut(block, LABEL, 0, "Gain",
|
||||
170,30,80,19, 0, 0, 0, 0, 0, "");
|
||||
|
||||
uiDefButF(block, COL, B_SEQ_BUT_RELOAD, "Lift",
|
||||
10,10,80,19, last_seq->strip->color_balance->lift,
|
||||
0, 0, 0, 0, "Lift (shadows)");
|
||||
|
||||
uiDefButF(block, COL, B_SEQ_BUT_RELOAD, "Gamma",
|
||||
90,10,80,19, last_seq->strip->color_balance->gamma,
|
||||
0, 0, 0, 0, "Gamma (midtones)");
|
||||
|
||||
uiDefButF(block, COL, B_SEQ_BUT_RELOAD, "Gain",
|
||||
170,10,80,19, last_seq->strip->color_balance->gain,
|
||||
0, 0, 0, 0, "Gain (highlights)");
|
||||
|
||||
uiDefButBitI(block, TOG, SEQ_COLOR_BALANCE_INVERSE_LIFT,
|
||||
B_SEQ_BUT_RELOAD, "Inv Lift",
|
||||
10,-10,80,19,
|
||||
&last_seq->strip->color_balance->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"Inverse Lift");
|
||||
uiDefButBitI(block, TOG, SEQ_COLOR_BALANCE_INVERSE_GAMMA,
|
||||
B_SEQ_BUT_RELOAD, "Inv Gamma",
|
||||
90,-10,80,19,
|
||||
&last_seq->strip->color_balance->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"Inverse Gamma");
|
||||
uiDefButBitI(block, TOG, SEQ_COLOR_BALANCE_INVERSE_GAIN,
|
||||
B_SEQ_BUT_RELOAD, "Inv Gain",
|
||||
170,-10,80,19,
|
||||
&last_seq->strip->color_balance->flag,
|
||||
0.0, 21.0, 100, 0,
|
||||
"Inverse Gain");
|
||||
}
|
||||
|
||||
|
||||
uiBlockEndAlign(block);
|
||||
|
||||
}
|
||||
|
||||
@@ -2190,6 +2190,11 @@ static Sequence *dupli_seq(Sequence *seq)
|
||||
if (seq->strip->proxy) {
|
||||
seqn->strip->proxy = MEM_dupallocN(seq->strip->proxy);
|
||||
}
|
||||
|
||||
if (seq->strip->color_balance) {
|
||||
seqn->strip->color_balance
|
||||
= MEM_dupallocN(seq->strip->color_balance);
|
||||
}
|
||||
|
||||
if(seq->type==SEQ_META) {
|
||||
seqn->strip->stripdata = 0;
|
||||
|
||||
@@ -323,7 +323,11 @@ static struct ImBuf *make_sep_waveform_view_from_ibuf_float(
|
||||
float * rgb = src + 4 * (ibuf->x * y + x);
|
||||
for (c = 0; c < 3; c++) {
|
||||
unsigned char * p = tgt;
|
||||
p += 4 * (w * ((int) (rgb[c] * (h - 3)) + 1)
|
||||
float v = rgb[c];
|
||||
|
||||
CLAMP(v, 0.0, 1.0);
|
||||
|
||||
p += 4 * (w * ((int) (v * (h - 3)) + 1)
|
||||
+ c * sw + x/3 + 1);
|
||||
|
||||
scope_put_pixel_single(wtable, p, c);
|
||||
|
||||
@@ -127,6 +127,9 @@ void free_strip(Strip *strip)
|
||||
if (strip->proxy) {
|
||||
seq_proxy_free(strip->proxy);
|
||||
}
|
||||
if (strip->color_balance) {
|
||||
MEM_freeN(strip->color_balance);
|
||||
}
|
||||
|
||||
free_tstripdata(strip->len, strip->tstripdata);
|
||||
free_tstripdata(strip->endstill, strip->tstripdata_endstill);
|
||||
@@ -1010,6 +1013,164 @@ void set_meta_stripdata(Sequence *seqm)
|
||||
}
|
||||
}
|
||||
|
||||
static StripColorBalance calc_cb(StripColorBalance * cb_)
|
||||
{
|
||||
StripColorBalance cb = *cb_;
|
||||
int c;
|
||||
|
||||
if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_LIFT) {
|
||||
for (c = 0; c < 3; c++) {
|
||||
cb.lift[c] = 1.0 - cb.lift[c];
|
||||
}
|
||||
} else {
|
||||
for (c = 0; c < 3; c++) {
|
||||
cb.lift[c] = -(1.0 - cb.lift[c]);
|
||||
}
|
||||
}
|
||||
if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAIN) {
|
||||
for (c = 0; c < 3; c++) {
|
||||
if (cb.gain[c] != 0.0) {
|
||||
cb.gain[c] = 1.0/cb.gain[c];
|
||||
} else {
|
||||
cb.gain[c] = 1000000; /* should be enough :) */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAMMA)) {
|
||||
for (c = 0; c < 3; c++) {
|
||||
if (cb.gain[c] != 0.0) {
|
||||
cb.gamma[c] = 1.0/cb.gamma[c];
|
||||
} else {
|
||||
cb.gamma[c] = 1000000; /* should be enough :) */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
static void make_cb_table_byte(float lift, float gain, float gamma,
|
||||
unsigned char * table, float mul)
|
||||
{
|
||||
int y;
|
||||
|
||||
for (y = 0; y < 256; y++) {
|
||||
float v = 1.0 * y / 255;
|
||||
v += lift;
|
||||
v *= gain;
|
||||
v = pow(v, gamma);
|
||||
v *= mul;
|
||||
if ( v > 1.0) {
|
||||
v = 1.0;
|
||||
} else if (v < 0.0) {
|
||||
v = 0.0;
|
||||
}
|
||||
table[y] = v * 255;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void make_cb_table_float(float lift, float gain, float gamma,
|
||||
float * table, float mul)
|
||||
{
|
||||
int y;
|
||||
|
||||
for (y = 0; y < 256; y++) {
|
||||
float v = (float) y * 1.0 / 255.0;
|
||||
v += lift;
|
||||
v *= gain;
|
||||
v = pow(v, gamma);
|
||||
v *= mul;
|
||||
table[y] = v;
|
||||
}
|
||||
}
|
||||
|
||||
static void color_balance_byte_byte(Sequence * seq, TStripElem* se,
|
||||
float mul)
|
||||
{
|
||||
unsigned char cb_tab[3][256];
|
||||
int c;
|
||||
unsigned char * p = (unsigned char*) se->ibuf->rect;
|
||||
unsigned char * e = p + se->ibuf->x * 4 * se->ibuf->y;
|
||||
|
||||
StripColorBalance cb = calc_cb(seq->strip->color_balance);
|
||||
|
||||
for (c = 0; c < 3; c++) {
|
||||
make_cb_table_byte(cb.lift[c], cb.gain[c], cb.gamma[c],
|
||||
cb_tab[c], mul);
|
||||
}
|
||||
|
||||
while (p < e) {
|
||||
p[0] = cb_tab[0][p[0]];
|
||||
p[1] = cb_tab[1][p[1]];
|
||||
p[2] = cb_tab[2][p[2]];
|
||||
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void color_balance_byte_float(Sequence * seq, TStripElem* se,
|
||||
float mul)
|
||||
{
|
||||
float cb_tab[4][256];
|
||||
int c,i;
|
||||
unsigned char * p = (unsigned char*) se->ibuf->rect;
|
||||
unsigned char * e = p + se->ibuf->x * 4 * se->ibuf->y;
|
||||
float * o;
|
||||
|
||||
imb_addrectfloatImBuf(se->ibuf);
|
||||
|
||||
o = se->ibuf->rect_float;
|
||||
|
||||
StripColorBalance cb = calc_cb(seq->strip->color_balance);
|
||||
|
||||
for (c = 0; c < 3; c++) {
|
||||
make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c],
|
||||
cb_tab[c], mul);
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
cb_tab[3][i] = ((float)i)*(1.0f/255.0f);
|
||||
}
|
||||
|
||||
while (p < e) {
|
||||
o[0] = cb_tab[0][p[0]];
|
||||
o[1] = cb_tab[1][p[1]];
|
||||
o[2] = cb_tab[2][p[2]];
|
||||
o[3] = cb_tab[3][p[3]];
|
||||
|
||||
p += 4; o += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void color_balance_float_float(Sequence * seq, TStripElem* se,
|
||||
float mul)
|
||||
{
|
||||
float * p = se->ibuf->rect_float;
|
||||
float * e = se->ibuf->rect_float + se->ibuf->x * 4* se->ibuf->y;
|
||||
StripColorBalance cb = calc_cb(seq->strip->color_balance);
|
||||
|
||||
while (p < e) {
|
||||
int c;
|
||||
for (c = 0; c < 3; c++) {
|
||||
p[c] = pow((p[c] + cb.lift[c]) * cb.gain[c],
|
||||
cb.gamma[c]) * mul;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void color_balance(Sequence * seq, TStripElem* se, float mul)
|
||||
{
|
||||
if (se->ibuf->rect_float) {
|
||||
color_balance_float_float(seq, se, mul);
|
||||
} else if(seq->flag & SEQ_MAKE_FLOAT) {
|
||||
color_balance_byte_float(seq, se, mul);
|
||||
} else {
|
||||
color_balance_byte_byte(seq, se, mul);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
input preprocessing for SEQ_IMAGE, SEQ_MOVIE and SEQ_SCENE
|
||||
|
||||
@@ -1022,6 +1183,9 @@ void set_meta_stripdata(Sequence *seqm)
|
||||
- Crop and transform in image source coordinate space
|
||||
- Flip X + Flip Y (could be done afterwards, backward compatibility)
|
||||
- Promote image to float data (affects pipeline operations afterwards)
|
||||
- Color balance (is most efficient in the byte -> float
|
||||
(future: half -> float should also work fine!)
|
||||
case, if done on load, since we can use lookup tables)
|
||||
- Premultiply
|
||||
|
||||
*/
|
||||
@@ -1092,13 +1256,6 @@ static void input_preprocess(Sequence * seq, TStripElem* se, int cfra)
|
||||
IMB_flipy(se->ibuf);
|
||||
}
|
||||
|
||||
if(seq->flag & SEQ_MAKE_FLOAT) {
|
||||
if (!se->ibuf->rect_float) {
|
||||
IMB_float_from_rect(se->ibuf);
|
||||
imb_freerectImBuf(se->ibuf);
|
||||
}
|
||||
}
|
||||
|
||||
if(seq->mul == 0.0) {
|
||||
seq->mul = 1.0;
|
||||
}
|
||||
@@ -1113,6 +1270,20 @@ static void input_preprocess(Sequence * seq, TStripElem* se, int cfra)
|
||||
mul *= seq->blend_opacity / 100.0;
|
||||
}
|
||||
|
||||
if(seq->flag & SEQ_USE_COLOR_BALANCE && seq->strip->color_balance) {
|
||||
color_balance(seq, se, mul);
|
||||
mul = 1.0;
|
||||
}
|
||||
|
||||
if(seq->flag & SEQ_MAKE_FLOAT) {
|
||||
if (!se->ibuf->rect_float) {
|
||||
IMB_float_from_rect(se->ibuf);
|
||||
}
|
||||
if (se->ibuf->rect) {
|
||||
imb_freerectImBuf(se->ibuf);
|
||||
}
|
||||
}
|
||||
|
||||
if(mul != 1.0) {
|
||||
multibuf(se->ibuf, mul);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user