Log in

View Full Version : Correct Levels, Make Black, Black


zerowalker
18th January 2014, 07:26
Is it possible to correct the black level, as the Black isn't Black.

http://i39.tinypic.com/296ko6h.png

vampiredom
18th January 2014, 10:53
Well, there is Levels() (http://avisynth.nl/index.php/Levels), of course. You can also use Histogram() (http://avisynth.nl/index.php/Histogram) if you want to see how black the blacks are.

StainlessS
18th January 2014, 14:55
You could try this


# Requires RoboCrop, RT_Stats
ORG=ImageReader("1.bmp",end=0) # Or whatever source

STRENGTH=1.0 # Auto level strength 0.0 -> 1.0 (0.0==off)
CROPPED=false # false return with letterbox, true without letterbox
PC=false # Output PC Levels if YUV

ORG.RoboCrop() # Chop off letterbox
Eval(RT_QueryLumaMinMax()) # Get QLMMin and QLMMax
CSMin=(IsRGB()||PC) ? 0 : 16
CSMax=(IsRGB()||PC) ? 255 : 235
ALMin = Int(CSMin - ((CSMin - QLMMMin) * STRENGTH) + 0.5) # Round Up
ALMax = Int(CSMax - ((CSMax - QLMMMax) * STRENGTH)) # Round down

(CROPPED)
\ ? Levels(ALMin,1.0,ALMax,CSMin,CSMax,Coring=False)
\ : ORG.Levels(ALMin,1.0,ALMax,CSMin,CSMax,Coring=False).RoboCrop(Blank=true,BlankPC=PC)


EDITED:
RoboCrop(Blank=true) blanks out letterbox area, to black.

as above script:
https://s20.postimg.org/danggpf25/2_zps90234a70.png (https://postimg.org/image/555eijqt5/)

EDIT: We also corrected for white

zerowalker
18th January 2014, 19:51
Tried your script Stainless, seems to work pretty well.
How can i make sure the White/Dark doesn't crush the colors?
except, perhaps noise, as this is Component Capture and not a Digital one.

StainlessS
19th January 2014, 00:24
# Requires RoboCrop, RT_Stats
ORG=ImageReader("1.bmp",end=0) # Or whatever source

STRENGTH=1.0 # Auto level strength 0.0 -> 1.0 (0.0==off)
CROPPED=false # false return with letterbox, true without letterbox
PC=false # Output PC Levels if YUV
QLMM_SAMPLES=ORG.FrameCount # Number of samples to query for RT_QueryLumaMinMax, default 32
# 0 converted to FrameCount, ie EVERY FRAME(slow), Samples=0 requires RT_Stats v1.30

QLMM_IGNORE=0.0 # Percent of extreme pixels to ignore (noise), default 0.2
# 0.0 = ignore nothing
DEBUG=True # For RT_QueryLumaMinMax

ORG.RoboCrop() # Chop off letterbox
Eval(RT_QueryLumaMinMax(samples=QLMM_SAMPLES,Ignore=QLMM_IGNORE,debug=DEBUG)) # Get QLMMin and QLMMax
CSMin=(IsRGB()||PC) ? 0 : 16
CSMax=(IsRGB()||PC) ? 255 : 235
ALMin = Int(CSMin - ((CSMin - QLMMMin) * STRENGTH) + 0.5) # Round Up
ALMax = Int(CSMax - ((CSMax - QLMMMax) * STRENGTH)) # Round down

(CROPPED)
\ ? Levels(ALMin,1.0,ALMax,CSMin,CSMax,Coring=False)
\ : ORG.Levels(ALMin,1.0,ALMax,CSMin,CSMax,Coring=False).RoboCrop(Blank=true,BlankPC=PC)


above examines every frame and sets Ignore (noise) OFF, default 0.2 should be pretty good

EDIT: Use DebugView to see output from RT_QueryLumaMinMax (google)
EDIT: QLMM_SAMPLES=ORG.FrameCount / 25 would examine 1 in every 25 frames.

Doc for RT_QueryLumaMinMax RT_Stats v1.30

RT_QueryLumaMinMax(clip c,int "Samples"=32,float "Ignore"=0.2,String "Prefix"="QLMM",bool "DEBUG"=false,int "X"=0,int "Y"=0,int "W"=0,int "H"=0, \
int "Matrix"=(Width>1100||Height>600?3:2),int "Start"=Undefined,int "End"=Undefined)
Prescan function to get Luma Min,Max for clip scanning Samples frames area x,y,w,h.
Returns luma min/max as string Default eg "QLMMMin=25 QLMMMax=244", use eg "Eval(RT_QueryLumaMinMax())" to set variables for use in script.

Samples:=32=frames to sample from clip, limited to Framecount.
Samples = 0 converted to FrameCount and Auto Credits skipping disabled.

Ignore:=0.2=Percentage of extreme pixels to ignore (noise) when getting luma min/max (As Threshold arg for YPlaneMin/Max).

Prefix:="QLMM"=Prefix for return string values.

DEBUG:=false= dont show. True=debug info. Need DebugView: http://technet.microsoft.com/en-gb/sysinternals/bb545027

X=Y=W=H=0=Full frame, as crop, area to examine.

Matrix:, For conversion of RGB to YUV-Y, 0 = Rec601, 1 = Rec709, 2 = PC601, 3 = PC709
Default for RGB is 3(PC709) if Width > 1100 || Height > 600 Else 2(PC601) : YUV not used
For RGB, it probably does not make sense to use anything other than PC levels.

Start: Default Undefined. Start frame of scan area. The Start arg overrides Auto Intro credits skipping.

End: Default Undefined. End frame for scan area. Overrides Auto End credits skipping. 0 (or less) will be converted to Framecount - 1.


If user supplied Start and End frame numbers given then that marks the range of frames from which to select the Samples frames.
If neither Start nor End given, the function tries to avoid sampling artificial black/white in Intro and End Credits sequences,
for Auto Intro and End Credits Skipping to be set to 5% (of FrameCount for Intro Skipping) and 90% (for End Skipping), the number of
frames between them must be greater or equal to 250 frames, and MUST also be greater than Samples, otherwise Auto skipping ignored and
the Start and End frame numbers are set to 0 and Framecount - 1.
If a user supplies eg a Start frame number ONLY, then End Skipping has to comply with the same above conditions, range between End Skip
frame and user supplied Start has to be at least 250 frames and greater than Samples, otherwise End frame set to FrameCount - 1. The
same conditions apply if only a user supplied End frame only.
After either user supplied Start/End, or via Auto Credits skipping, or defaulted to 0 & FrameCount -1, we have a sample scan range.
Setting Debug=True, will send debug info including resulting sample frame range to DebugView window.

zerowalker
19th January 2014, 08:36
Will it do a total scan when i add it?
As it totally freeze the script (The file is pretty long though, some hours).

But if i understand right, i only need it to get enough data to make the approximate "blackest black" and "whitest white"?

lansing
19th January 2014, 21:06
a generic way is to use a graphical level filter with histogram display, like the levels filter in virtualdub. Then reference a sample frame off the video that has the darkest part, and then simply drag the input low to match the low cut off in the histogram. After that just copy the numbers and plug them into the levels filter in avisynth. (see attachment)


A more advance way is to reference a point(a pixel or a group of pixels) in a frame where you think should be black, jog down its rgb value, and then adjust the input low in a levels filter or curve in reference to that point, until the rgb value hits (0,0,0). However I don't think neither avisynth or virtualdub has something like this, you'll need a more advanced image manipulating program.

zerowalker
20th January 2014, 08:03
Ah, well it should be fairly simple to do what i want then, as it's a game, and i know what should be white, and what should be black.
I tried to do it manually with Avisynth through levels, but it didn't work however, it just got darker, but never Black.

lansing
20th January 2014, 08:14
deleted: because I misunderstood op's last reply.

StainlessS
21st January 2014, 10:36
How can i make sure the White/Dark doesn't crush the colors?

To 'make sure' you would have to examine every pixel of every frame, us non perfections would be quite happy
with original script as given (although see end of post).

except, perhaps noise, as this is Component Capture and not a Digital one.
That is the purpose of the 'Ignore' setting, default 0.2% ignores 1 in every 500, extra bright/dark pixels,
true white/black is likely to have more than that % of pixels, you could also set STRENGTH to eg 0.90
to only apply 90% correction.

Will it do a total scan when i add it?
As it totally freeze the script (The file is pretty long though, some hours).
Yep, perfectionists do have such a hard time of it. :)

But if i understand right, i only need it to get enough data to make the approximate "blackest black" and "whitest white"?
Yep, that is my view, given enough sample data, and as game source, likely to use identical black all way through clip.
Setting SAMPLES to eg ORG.FrameCount / 100, would be less paranoid than sampling every frame and be about 100 times quicker.

The 2nd script (with whatever ajustments made to config vars) should be a lot easier than messing with eg paint prog or vdub and probably
produce better approximation, also, the RoboCrop thing removes border from clip and so would avoid that influence.

suggest add this to end of script:-

RT_Subtitle("Levels(%d,1.0,%d,%d,%d,Coring=False)",ALMin,AlMax,CSMin,CSMax)


Above produces this for 2nd script on supplied RGB bitmap (IGNORE=0.0), differing results if your source is YUV:

Levels(1,1.0,213,0,255,Coring=False)


Or this when default IGNORE=0.2

Levels(1,1.0,162,0,255,Coring=False)

Looks like IGNORE 0.2 is ignoring all/most of the white text

so suggest setting IGNORE to eg 0.02% which produces this:

Levels(1,1.0,200,0,255,Coring=False)


That is probably about best setting, try scan SAMPLES=ORG.FRameCount / 100 IGNORE=0.02
and then just use subtitled results.

EDIT: Adding this instead

RT_Subtitle("Levels(%d,1.0,%d,%d,%d,Coring=False)\nPixMin=%d PixMax=%d",ALMin,AlMax,CSMin,CSMax,QLMMMin,QLMMMax)


also shows the minimum and maximum pixels values sampled (with some IGNORE'd) but before any STRENGTH adjustment.

EDIT: Actually changed my mind again, leaving as default 0.2% might give more accurate results with more sampled frames, I doubt
that all frames will be quite as dark and some will have greater volume of white (not just text) and so will get white level
from those frames rather than from overlayed text. 1 frame to sample is very constricted.

LemMotlow
22nd January 2014, 03:25
In the image you posted, the only objects that should be black are the borders and (perhaps) the figure's boots. The characters in the title are already white; the panel with text inside will never be pure black, but rather semi-transparent darkish gray. The scene as posted is too dark to begin with and has suppressed gamma and brights, which is rather strange for this type of video (to me, anyway). Likely you'll have to make multiple corrections because of many level/chroma changes thru the length of the movie. Properly get into/out of RGB and use histograms and something like gradation curves. It's difficult to eyeball when something that's supposed to be white, gray, or black really is one of those "colors". To do it correctly you should use a pixel sampler. "Black" is RGB 0-0-0. Middle Gray is RGB 128-128-128. Brightest white is RGB 255-255-255. Use controls to get blacks, near-blacks, grays and whitish colors to conform to those proportions, and the other colors will fall into place. Lansing's suggestion with the Levels GUI control is also useful. The image below used it, as well as an "S" curve in a gradation-curve filter.

Starting with a brighter capture would help. Trying to compensate in post-production for the lack of bright data creates gamma problems and causes rather thin-looking objects in the bright end. You can brighten stuff, but you can't create something from nothing without distortion of some kind.