Log in

View Full Version : de-fade: possible?


spoRv
27th December 2016, 13:15
I would like to know if it's possible to recover somehow a faded part of the clip (faded in or out) - at least for the first (last) frames.

EDIT: Yes, it's possible, thanks to Gavino!
http://forum.doom9.org/showthread.php?p=1791309#post1791309

feisty2
27th December 2016, 14:12
possible if your clip was encoded with floating point precision samples (which is almost impossible)

feisty2
27th December 2016, 14:17
if you ever try to reverse fades on low bit depth clips, eg. anything less than 16bpc, you will end up with "binarized" results.

ChaosKing
27th December 2016, 15:24
Just an idea: If you need only the first frames. Maybe photoshops dehaze filter can help?

feisty2
27th December 2016, 17:08
Just an idea: If you need only the first frames. Maybe photoshops dehaze filter can help?

it can't, for the same reason you can't restore "16777216 shades of color" from a gif image.

spoRv
27th December 2016, 17:50
feisty2, may you post an example script, so I can make some tests? Thanks!

feisty2
27th December 2016, 17:56
feisty2, may you post an example script, so I can make some tests? Thanks!

go ahead and waste your time

//10.12345 could be any other amplifying factor
y = converttoy8().mt_lut("x 10.12345 *")
u = utoy8().mt_lut("x 128 - 10.12345 * 128 +")
v = vtoy8().mt_lut("x 128 - 10.12345 * 128 +")
ytouv(u,v,y)

spoRv
27th December 2016, 19:48
This is the comparison (top original, bottom output):

https://s27.postimg.org/gpxvihxsj/defaded.jpg

feisty2
27th December 2016, 19:52
//10.12345 could be any other amplifying factor
apparently reading an English sentence is a challenge.

spoRv
27th December 2016, 20:55
Sorry, but I didn't understand that "could be any other amplifying factor" implies that I should find out the right one... my fault, forgive me, I'm just an Italian, after all! :D

Motenai Yoda
28th December 2016, 00:13
Uncle, post a full res png, maybe it's barely recoverable
and this can work too, w/o all feisty2's wacky stuff
mx=6 #6 is just an example
mt_lut(expr="x 128 - "+string(mx)+" * 128 +", yexpr="x "+string(mx)+" *",u=3,v=3)
#note: it will throw an error if input isn't yuv

spoRv
28th December 2016, 10:31
Motenai Yoda, thanks for the help!

I tried your script, and it works somehow for one or two faded frames; I noted that, if I overlay a black clip, using different opacity values for each frame, it helps.

Another path I thought that is possible to follow is to change gamma, contrast, brightness and saturation taking in account how much dark the faded frame is; I "think" that it's possible to restore quite well the great part of frames near the first one near fade, while I have few hopes for the darker ones. Now someone skilled may try to find the right values for each faded frame, and write a function, something like this (just an idea):

function defadeout (clip clip, int frames) {

# frames are the faded one, from the least dark to the almost black
# variables will be calculated according to how many frames the fade includes
sx=?
cx=?
bx=?
gx=?
# don't know how to write a loop... :/

frame1.tweak(sat=sx*1,cont=cx*1,bright=bx*1).levels(0,gx*1,255,0,255)
frame2.tweak(sat=sx*2,cont=cx*2,bright=bx*2).levels(0,gx*2,255,0,255)
etc.
# defadein will just do the contrary, from almost black to near normal
}

Sorry for my poor explanation, hope it is understandable!

feisty2
28th December 2016, 13:03
like what I said earlier, the precision also fades into nada as the clip fades into pure blackness with integer samples.. just do the simple math you guys
it won't even work theoretically, just don't bother trying
it is indeed possible to reverse fades on clips with floating point samples, cuz you got a fixed precision of 24 binary digits(IEEE single) or 53 binary digits(IEEE double) regardless of the scale(exponent bits) of the value.
a floating point sequence won't lose precision as it converges to 0(or any other constant value) but an integer sequence will.
now I don't really wanna be a math nerd here but y'all gotta realize it's never gonna work, as you cannot get the lost precision back from ..???

StainlessS
28th December 2016, 17:00
One cannot fault anything that the oracle feisty2 has said above, dont waste your time trying to prove otherwise :)

Groucho2004
28th December 2016, 17:43
like what I said earlier, the precision also fades into nada as the clip fades into pure blackness with integer samples.. just do the simple math you guys
it won't even work theoretically, just don't bother trying
it is indeed possible to reverse fades on clips with floating point samples, cuz you got a fixed precision of 24 binary digits(IEEE single) or 53 binary digits(IEEE double) regardless of the scale(exponent bits) of the value.
a floating point sequence won't lose precision as it converges to 0(or any other constant value) but an integer sequence will.
now I don't really wanna be a math nerd here but y'all gotta realize it's never gonna work, as you cannot get the lost precision back from ..???
It doesn't matter if you're using floating point or integer data types. The precision is dictated by the width of that data type (32 bit, 64 bit, ...) and how many discrete values it can represent.

spoRv
28th December 2016, 17:49
I know Feisty is a math guru, so I'm sure he is absolutely right.

But I still wonder if it's possible to restore some of the faded frames; let's say, more than half ones (the least darkened) to be similararound 90% of the frame before the fade; if so, I'll be more than happy with that result!

Otherwise, sorry if I annoyed everyone here... with impossible to solve problems... again! ;)

StainlessS
28th December 2016, 19:01
It doesn't matter if you're using floating point or integer data types. The precision is dictated by the width of that data type (32 bit, 64 bit, ...) and how many discrete values it can represent.

Surely, float division by a power of 2, would just shift the binary point position so eg dec 255 / 256 would be binary 11111111.0 -> 0.11111111 and dec 1.0 /256 would be 1.0 -> 0.00000001,
so totally recoverable ??? (division by non power of 2 recoverable to lesser degree).
I've never touched floating point colorspace and know nothing of it, are you saying that there are only 256 [or maybe 65536 or whatever] valid values in floating point colorspace ?
(although I believe it may be in range 0.0 -> 1.0 rather than 0.0 -> 255.0).

Integer division would of course lose precision in the lowest bit, even with a single division of 2 (assuming originally odd).

EDIT: Of course any file storage of faded clip would also have to be done in Float and not eg converted to/from integer [unlikely to be the case].

poisondeathray
28th December 2016, 19:20
You can have float code values that go below zero, and above 1.0 . Raw images, log film scans, HDRI formats, CG exports (EXR).

But chances are, the OP wasn't referring to or doesn't have one of these formats.

Groucho2004
28th December 2016, 19:23
Surely, float division by a power of 2, would just shift the binary point position so eg dec 255 / 256 would be binary 11111111.0 -> 0.11111111 and dec 1.0 /256 would be 1.0 -> 0.00000001,
so totally recoverable ??? (division by non power of 2 recoverable to lesser degree).
I've never touched floating point colorspace and know nothing of it, are you saying that there are only 256 [or maybe 65536 or whatever] valid values in floating point colorspace ?
(although I believe it may be in range 0.0 -> 1.0 rather than 0.0 -> 255.0).

Integer division would of course lose precision in the lowest bit, even with a single division of 2 (assuming originally odd).

EDIT: Of course any file storage of faded clip would also have to be done in Float and not eg converted to/from integer.
I was simply pointing out that a data type, no matter what type, cannot have more precision than the total number of discrete values it can represent. I don't deny that float can be more convenient in some cases.

feisty2
28th December 2016, 21:01
It doesn't matter if you're using floating point or integer data types. The precision is dictated by the width of that data type (32 bit, 64 bit, ...) and how many discrete values it can represent.

The total available precision(defined by data type) != the actual precision on each frame(what we were talking about) for integer samples since precision is directly related to the range in use.

Say the input clip has the precision of 8 bits(0-255), a halfway faded frame would only have an actual precision of 7 bits(0-127, 128-255 are wasted due to the fade)

Now the total available precision = the actual precision on each frame for floating point samples cuz range(scale, exponent part) is no longer relevant to precision(fraction part) and that's the point

jmac698
28th December 2016, 22:35
I have a lot of ideas for this. You don't literally defade the image as you'll run into the problems as described; what you do is take a good frame and then use motion detect on the faded frames to move the good pixels into the places they should be.
You can also use background subtraction and keep the static parts of the background, then do something with the changed parts.
Another idea is to do some type of smoothing on the lower bit-depth image. Similar to umm.. what's that filter called? Anyhow you can take the idea further, train a neural net just on the good image so it can interpolate bit-depth on the degraded image.

Depending on the type of image, say it's a cartoon, just use edge detect and recolour the faded frames. The edges will only be a guide to recreate the image. So many ways to do this. Even on real footage, using the edges as a guide you could do some kind of cloning operation to fill them in.

Post a sample and I can play with it. Some of these ideas could take a while, I'll just start with the simple approaches first. How much quality do you need?

Gavino
29th December 2016, 00:08
Another path I thought that is possible to follow is to change gamma, contrast, brightness and saturation taking in account how much dark the faded frame is; I "think" that it's possible to restore quite well the great part of frames near the first one near fade, while I have few hopes for the darker ones. Now someone skilled may try to find the right values for each faded frame, and write a function, something like this (just an idea):
The way to vary filter parameters over a range of frames is to use Animate() (http://avisynth.nl/index.php/Animate).

If the fade is a linear one (such as produced by Avisyth itself), it can be (approximately) undone by using a multiplier whose inverse decreases linearly from 1 to almost 0 over the course of the fade.
Try this:
function Defade(clip c, int frames) {
c
Animate(framecount-frames-1, framecount, "Defade2", 1.0, 0.0)
}

# Helper function to be animated by Defade()
function Defade2(clip c, float div) {
mx = 1.0/div
c.mt_lut(expr="x 128 - "+string(mx)+" * 128 +", yexpr="x 16 - "+string(mx)+" * 16 +",u=3,v=3)
}
This uses Motenai Yoda's method (but corrected for the Y black point being 16, not zero).

The parameter 'frames' is the number of frames in the fade - the last input frame should be almost (but not quite) black.
For example,
ColorBars(pixel_type="YV12").Trim(0, 49)
FadeOut0(10)
Defade(10)

works almost perfectly.

Of course, feisty2 and others are correct to point out that you cannot regain the precision lost by the original fade.
However, this loss is gradual and not as drastic as one might think.
It takes until half-way through the fade before you are down to 7 bits of precision, and even 7/8 of the way through the fade, you still have 5 bits of precision.

The ColorBars example is artificially good, as the picture is made up of totally flat areas of colour.
On a real video source, banding will gradually be introduced as the 'defade' proceeds.
Nevertheless, it will work well enough if you just want to see a bit more of what was faded out.

spoRv
29th December 2016, 13:25
Gavino, you are my hero!!! You are one of the avisynth guru I follow since many years ago... THANKS!!!

Of course, thanks also to Motenai Yoda for the input given.

jmac698: maybe your idea could be used to recover somehow the most faded frame(s), which suffers of banding.

But the Gavino function really does a great job!!!

If you permit, I slightly modified your function - I know there are more elegant way to do, but it works, so... :D

###########################################################################################
### DeFade: recovers the faded part of a clip ###
### ###
### Usage: DeFadeIn(clip,frames) and DeFadeOut(clip,frames) ###
### ###
### The frames number includes the most near to the unfaded, and the nearest to black ###
### Nearest black frame(s) suffers of banding ###
### ###
### AviSynth script made by Gavino, using Motenai Yoda's method - Created: 2016-12-29 ###
### Original idea: spoRv - reference: http://forum.doom9.org/showthread.php?t=174140 ###
### ###
### Creative Commons 4,0 - Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) ###
### Link to the licence page: https://creativecommons.org/licenses/by-sa/4.0/ ###
###########################################################################################

function DefadeOut(clip c, int frames) {
c
Animate(framecount-frames-1, framecount, "Defade2", 1.0, 0.0)
}

function DefadeIn(clip c, int frames) {
c.reverse
Animate(framecount-frames-1, framecount, "Defade2", 1.0, 0.0)
reverse
}

# Helper function to be animated by Defade()
function Defade2(clip c, float div) {
mx = 1.0/div
c.mt_lut(expr="x 128 - "+string(mx)+" * 128 +", yexpr="x 16 - "+string(mx)+" * 16 +",u=3,v=3)
}

Yes, I like "pompose" functions... ;)

Because the solution is found, I edited the first post and added a link to this function.

spoRv
29th December 2016, 16:23
OK, I played with the function, with both real and test clips; here you are my conclusion.

As pointed out, the functions is not able to reconstruct perfect image for the faded frames near black; I used this script to make my own test:

# I used this image: http://sipi.usc.edu/database/database.php?volume=misc&image=40#top (House)
# but of course you can use "any other image" ;)

# number of faded frames
x=99

clp=imagesource("house.tiff").converttoyv12.ColorYUV(levels="PC->TV").trim(0,x)
blk=blankclip(clp).trim(1,1)

fdi=clp.fadein0(x)
dfi=fdi.defadein(x)

fdo=clp.fadeout0(x)
dfo=fdo.defadeout(x)

# for fadein test
return stackhorizontal(blk+clp,blk+dfi,blk+fdi)

# for fadeout test
return stackhorizontal(clp+blk,dfo+blk,fdo+blk)

(Exagerated, I know, because there will never be IMHO a 100 frames fade, but it helps for test purposes.)

So, let's take the fadein; frame 0 is all black, frame 100 is the untouched image; in between there are all the faded frames.

1 is of course the worse; just white and gray
2 is slightly better, with white, gray and one or two color shades
from around 10 it starts to have some resemblance of the original frame
from around 20 it is decent enough
from 40-50 it is really close to the original image

When used in real life situations, the function works pretty well, because actual fades durations are around 5-10 frames; of course, the first one frame nearest black is the worst, but it usually last for few dozen milliseconds, and often unnoticeable; so, the function works well to recover around 80/90% of faded frames, as I supposed.

So, one could live with an inferior quality frame or two, trim it (them), or try to improve the quality of it (them).

I'm not the function genius like many of you - more a theory maker, so I can give just suggestions... back on example:
fadein, 0=black, 10=untouched
I have frame 1 (as usual) but also 2 with noticeable banding; the function will be something like DeFadeIn(clip,first faded frame number, total faded frames,bad frames at the beginning) and it must predict frame 1 and 2 based to frame sequence of frames 3-9 (and also 10 and following, if needed); of course they will be interpolated, and may be quite different from actual frames, but I think it's a good thing to have watchable frames (albeit "invented") instead of bad ones, or none.
Also, frames from 3 to 9 could be debanded as well in other ways, leaving the frames intact, using other methods.
(same thing, reversed, for DeFadeOut, of course!)

Thanks to everyone for your time and help!!!

spoRv
5th January 2017, 11:23
I noted that often (if not always) the fade found in the real video is not linear, so the defade doesn't work well - what it does is a partial defade, so it brighten the faded frames, but not as much as the non faded level.

To (try to) address this, I made a mod; added the bad and start variables, where bad is the last (first) bad frames of the fade to be replaced with the last (first) good frame, and start is the first faded frame (near to black, or near to unfaded).

The DeFadeIn and DeFadeOut is the linear defade, as the original script; the DeFadeInX and DeFadeOutX is my attempt to solve the problem of unlinear fade. The last (first) defaded frame is ALWAYS very bad, and the one before (after) is often quite bad; that's why I added an option to replace these bad frames.

As you can see, my code is a mess, as well as the solution I found. But it works (somehow).

# DeFade 1.1

function DeFadeIn(clip clip, int frames, int "cut", int "start") {
start=default(start,2)
cut=default(cut,0)
clip.trim(start,start+frames).reverse
Animate(framecount-frames-1, framecount, "DeFade2", 1.0, 0.0)
def=reverse.loop(cut+1,cut,cut).trim(cut,frames+1)
clip.trim(0,start-1)+def+clip.trim(start+frames,0)
}

function DeFadeOut(clip clip, int frames, int "cut", int "start") {
start=default(start,2)
cut=default(cut,0)
clip.trim(start,start+frames)
tmp=Animate(framecount-frames-1, framecount, "DeFade2", 1.0, 0.0)
def=tmp.trim(0,frames-cut-1)+tmp.trim(frames-cut-1,frames-cut-1).loop(cut)
clip.trim(0,start-1)+def+clip.trim(start+frames,0)
}

function DeFadeInX(clip clip, int frames, int "cut", int "start") {
start=default(start,2)
cut=default(cut,1)
clip.trim(start,start+frames).reverse
a=Animate(framecount-frames-1, framecount, "DeFade2", 1.0, 0.0)
b=Animate(framecount-frames-1, framecount, "DeFade2X", 1.0, 0.0)
def=merge(a,b).reverse.loop(cut+1,cut,cut).trim(cut,frames+1)
clip.trim(0,start-1)+def+clip.trim(start+frames,0)
}

function DeFadeOutX(clip clip, int frames, int "cut", int "start") {
start=default(start,2)
cut=default(cut,1)
clip.trim(start,start+frames)
a=Animate(framecount-frames-2, framecount-1, "DeFade2", 1.0, 0.0)
b=Animate(framecount-frames-2, framecount-1, "DeFade2X", 1.0, 0.0)
tmp=merge(a,b)
def=tmp.trim(0,frames-cut-1)+tmp.trim(frames-cut-1,frames-cut-1).loop(cut)
clip.trim(0,start-1)+def+clip.trim(start+frames,0)
}

# Helper functions to be animated by DeFade()
function DeFade2 (clip c, float div) {
mx = 1.0/div
c.mt_lut(expr="x 128 - "+string(mx)+" * 128 +", yexpr="x 16 - "+string(mx)+" * 16 +",u=3,v=3)
}

function DeFade2X(clip c, float div) {
mx = 1.0/div/div
c.mt_lut(expr="x 128 - "+string(mx)+" * 128 +", yexpr="x 16 - "+string(mx)+" * 16 +",u=3,v=3)
}

Things to do:
1) Clear the code
2) Replace the bad frames with interpolated ones (and not a mere copy of a good defade frame), based on the good defaded ones
3) Find a proper (or better) way to handle non linear fades

Thanks to everyone who would like to spend some time to test the function, and eventually solve the problems.