Log in

View Full Version : TDeint and TIVTC


Pages : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 [33] 34

StainlessS
24th October 2022, 16:58
eg.

.
.
.
a = last
b = a.bwdif(some settings)

Subtract(a,b)

#Levels(127, 1, 129, 0, 255) # for 8bit
#Levels(511, 1, 513, 0, 1023) # for 10bit



I think that the levels are not quite there, are centered around 128 instead of TV levels center ie 126, (16+235)/2.0=125.5 rounded to 126. Subtract centers on 126 whereas the MT_tools subtract thingy centers on 128.

So something like

.
.
.
a = last
b = a.bwdif(some settings)

Subtract(a,b)

#Levels(125, 1, 127, 0, 255) # for 8bit
#Levels(503, 1, 505, 0, 1023) # for 10bit : (126*4)-1=503 : (126*4)+1 = 505


EDIT: Also, if a is original and b is filtered, then maybe should use Subtract(b,a) rather than Subtract(a,b), so result will be above mid grey
if filtered is lighter than original, and below mid grey if darker than original (Subtract(a,b) will be opposite).

None of above tested.

flossy_cake
24th October 2022, 17:57
Thank you for all the help, I'm learning a lot here.

On another note...


There's a ChromaShift plugin, but for YV12 it's 2 pixel increments, or 4 if it's interlaced, or if you're really keen and know the exact shift you can use a resizer to compensate. To shift the chroma of a 1080p video 7.3 pixels to the left (it'd be -7.3 to shift it right).

A = last
MergeChroma(A, A.Spline36Resize(1920,1080, 7.3,0,1920,1080))


Regarding the numbers in bold, according to ChromaShiftSP plugin (http://avisynth.nl/images/ChromaShiftSP.avsi) the values 7.3 and 0 need to be added to them -- is this correct?

I've spent hours trying to understand how the resize crop params work but I can't get my head around whether it's shifting the chroma or if it's actually stretching the chroma out from a fixed point (and if so, which point -- center or a corner?).

edit: just realised I can set the offset to a high value and measure the pixels in photoshop. In this case it seem hello_hello's code is correct: good 50px offset (https://ibb.co/BCSjwwM), bad chromashiftSP code (https://ibb.co/fdM395p)

A separate problem I'm dealing with is how to crop n lines off the top and bottom, and then zoom in to hide the black bars while preserving aspect.

For a 720x576 16:9 video (which Avisynth sees as square pixels 720x576 with aspect 1.25:1) I've got this code for cropping 50 off the top and bottom:

Resize(Round(576*(16.0/9.0)), 576, 50*(720.0/576.0), 50, -50*(720.0/576.0), -50)

In other words, if I'm cropping 50 off the top and bottom, then I need to crop 1.25 times more pixels of the left and right in order to main aspect (I have no idea if this is right, it's just my thinking) and then finally stretch to 1024 wide to compensate for anamorphic pixels.

flossy_cake
24th October 2022, 19:13
subtract, or overlay with difference mode . You can use levels to amplify the differences


Hmm which one is correct:

Subtract(ChangeFPS(last,50),BWDIF(field=-2))
https://i.ibb.co/61NxCtQ/8.png

Subtract(ChangeFPS(last,50),BWDIF(field=-2))
Levels(127, 1, 129, 0, 255)
https://i.ibb.co/SxRnC72/9.png

clip: https://drive.google.com/file/d/1WfW3yXmGhIvUCiexQGYD18gSiXRe2bze/view?usp=sharing

edit: perhaps need a threshold so it wont amplify pixels that barely changed at all?

StainlessS
25th October 2022, 10:55
perhaps need a threshold so it wont amplify pixels that barely changed at all?
Maybe try

Th =16 # or whatever
center = 126 # TV else 128 PC levels
Levels(center-Th, 1, center+Th, 0, 255)

StainlessS
25th October 2022, 16:09
I think that the levels are not quite there,
No, they were right, @PDR, you could've pointed out that I was the one that was wrong :(
(Levels defaulted to Coring=True, so was correct).

Anyways, I've done this before I twigged that I was the wrong'un.


BlankClip(pixel_type="YV12")
#ConvertBits(10)

#

TV = true # Use True if Subtract TV levels.
Th8 = 16 # Threshold, 1 = Max AMP, > 1 reduce AMP.

###
bpc = Last.BitsPerComponent()
shift = bpc - 8
mul = BitLShift(1,shift)
center = (TV) ? 126 : 128 # 126 TV else 128 PC levels
center = center * mul # center at current bit depth
Th = Th8 * mul # Th at current bit depth
oMax = BitLShift(1,bpc)-1 # 255 @ 8bit, 1023 @ 10 bit
RT_DebugF("bpc=%d Shift=%d mul=%d Center=%d Th=%d oMax=%d",bpc,shift,mul,center,Th,oMax,Name="LEVELS: ") # Write to DebugView (google it)
Levels(center-Th, 1.0, center+Th, 0, oMax, coring = FALSE)


Sorry PDR :(

flossy_cake
26th October 2022, 19:26
Should TFM() be capable of correctly deinterlacing the cheese slices (https://drive.google.com/file/d/1xdV5_me-pbafnPo6yXhaZKIhe8IP4Ipq/view?usp=sharing) clip?

Apparently (https://www.avsforum.com/threads/hd-1080i-test-pattern-to-determine-vector-adaptive-deinterlacing-others-icl-ticker.1157287/post-22862294) all it needs for perfect progressive reproduction is to weave frame A field 1 with frame B field 2, but I can't get TFM to do that (tried all the modes and setting different cthresh & MI values).

I suspect what's happening is it's just detecting all frames as combed.

I can confirm that MadVR can correctly deinterlace it with its "film" mode deinterlacing which I'm told is madshi's own custom CPU code for detecting cadences aka "field matching" like TFM.

poisondeathray
26th October 2022, 19:43
Should TFM() be capable of correctly deinterlacing the cheese slices (https://drive.google.com/file/d/1xdV5_me-pbafnPo6yXhaZKIhe8IP4Ipq/view?usp=sharing) clip?

Apparently (https://www.avsforum.com/threads/hd-1080i-test-pattern-to-determine-vector-adaptive-deinterlacing-others-icl-ticker.1157287/post-22862294) all it needs for perfect progressive reproduction is to weave frame A field 1 with frame B field 2, but I can't get TFM to do that (tried all the modes and setting different cthresh & MI values).

I suspect what's happening is it's just detecting all frames as combed.

I can confirm that MadVR can correctly deinterlace it with its "film" mode deinterlacing which I'm told is madshi's own custom CPU code for detecting cadences aka "field matching" like TFM.

Yes, false positive

When you have patterns such as thin horizontal lines, that situation is always going to be detected as false positive and be deinterlaced. You can disable post processing globally with TFM(pp=0) . Or you can use are overrides or exclusion bands (eg. moving text, lower thirds)

In real life, you're typically not going to encounter thin lines such as test patterns, and in real life, you're going to have to use overrides to get it perfect for non standard content

flossy_cake
26th October 2022, 20:44
Ok cool. I always thought that test pattern was kind of ridiculous.

Regarding TDeint though, do you reckon it would work better if it used per-block combing detection? i.e if 16x16 block is combed, then treat only that 16x16 block as combed. Currently it seems to think that means the whole frame should be treated as combed:


blockx:
Sets the x-axis size of the window used during combed frame detection. This has to do with the size of the area in which MI number of pixels are required to be detected as combed for a frame to be declared combed.
http://avisynth.nl/index.php/TDeint


The way I'm imagining it, a lower cthresh/MI could be used and false positives could be confined to that 16x16 block instead of writing off the whole frame.

flossy_cake
29th October 2022, 03:11
I can't seem to detect any difference between:

TDeint(tryWeave=true, full=true)
TDeint(tryWeave=true, full=false)

In both cases it seems to perform combed frame detection according to cthresh,MI,blockx,blocky etc., and returns the full frame if it wasn't detected as combed.

Is my understanding correct, or should there be some difference between the two?

flossy_cake
5th November 2022, 03:58
I've been getting into NTSC DVDs a bit lately, but was disappointed to find a few of them appear to be using "soft telecine" where the actual frames seem to be stored in the MPEG2 stream as 23.976p. This sounds great in theory as it wouldn't need any deinterlacing, but I'm finding a few of them have these split-second combing artefacts on scene changes. Annoyingly just enough to produce a visual annoyance that can't be ignored.

What's the best way to deal with this kind of content -- TFM? Decimate? Can it handle these split-second combing artefacts or are they too short to be detected? Keeping in mind this is "soft telecine" not "hard telecine" (the latter being 23.976p living inside a 29.97i stream using the 3:2 pattern -- this is not that).

Also does anyone know what is actually happening with these artefacts -- are they "baked into" the 23.976p image, or is the MPEG2 stream actually changing to 29.97i mid-stream (i.e variable framerate, which MediaInfo reports is true for all of these DVDs).

Of course I could just throw BWDIF at it, but then I'd be wasting half res on anything that moves.

And sadly DXVA deint chokes on "soft telecine" -- produces constant bob artefacts. I don't think it knows the stream is 23.976p and is trying to treat is as hard telecine 29.97i or something.

And MadVRs own "film" deint also cannot detect and repair these split-second combing artefacts either, so it looks like I'll need an Avisynth solution.

Emulgator
5th November 2022, 13:12
Use DGIndex and watch what pulldown results it throws: 100%film, 98,57%film, etc.
Inspect the .d2v index file with Editor.
If the content stems from film there shouldn't be any pulldown transitions.
If you find them these places got to be repaired and left as 23,976p.
Video (credits, VFX) on top of film: there are lots of suggestions, I would go dgmpgdec, QTGMC to 59,94p
If content is animation any valid MPEG-2 pulldown pattern could have been used to match intended animation flow:
The same, dgmpgdec, QTGMC to 59,94p.

I have still a Sponge Bob sample floating around, and it has been discussed here in doom9

flossy_cake
6th November 2022, 01:33
Here is a clip of soft telecine 24p containing 2 problematic scene cuts: https://drive.google.com/file/d/1dwa7gB3HHuSPXroA2ifm4LtLX0fSs2bM/view?usp=share_link

For some reason DirectShowSource won't open the file on my system, but FFmpegSource2 and LWLibavVideoSource will. Their parameters rffmode and repeat seem to affect whether they will output it natively as 24p or convert to 60i using the repeat flags stored in the stream. LAV Video Decoder seems to use repeat flags to convert it to 60p and doesn't seem to offer a choice.

edit: actually after more testing, MadVR's film mode deint seems to be handling those combed frame transitions perfectly. DXVA almost gets it right but interpolates those ones and jumps back a field for some reason. Not sure why I was having trouble with it before.

edit: it seems LWLibavVideoSource documentation is wrong: the repeat param seems to default to true or perhaps some auto setting, since not setting it results in repeat fields mode. Setting it to false actually causes the video to play back way too fast at 30fps.

A separate issue is that because Avisynth outputs square pixels I have to scale it to 720x540 but that offsets the field lines which makes it impossible to do MadVR or DXVA deint which happen after Avisynth.

flossy_cake
6th November 2022, 02:37
So this seems to work perfectly for handling the problematic combed transitions:


LWLibavVideoSource(clip)
TFM()
TDecimate()
LanczosResize(720,540)


But as I feared TFM() is having issues with combed frame detection (note the aliasing on the table edges -- the sequence is 24p soft telecine and contains no combing artefacts)

https://i.ibb.co/jRQWQwq/avs2-avs-snapshot-00-06-000.png

I'll have to play around with the thresholds to see if it can be improved, but my experience with TDeint seems to imply it's going to be difficult and/or need per-scene thresholding.

edit: PP=0 seems to help with that.

kedautinh12
6th November 2022, 03:55
So this seems to work perfectly for handling the problematic combed transitions:


LWLibavVideoSource(clip)
TFM()
TDecimate()
LanczosResize(720,540)


But as I feared TFM() is having issues with combed frame detection (note the aliasing on the table edges)


I'll have to play around with the thresholds to see if it can be improved, but my experience with TDeint seems to imply it's going to be difficult and/or need per-scene thresholding.

edit: PP=0 seems to help with that.

you can try:
ex_bob(nnedi3=true).SelectEven()
https://github.com/Dogway/Avisynth-Scripts/blob/b4ad8bc47aaef8052f370864f984116217881850/MIX%20mods/QTGMC%2B.avsi#L1486

or:
QTGMC(Preset="Very Slow", Sharpness=0).SelectEven()

Emulgator
6th November 2022, 19:18
How has the .mkv been obtained ?
Throwing it at VirtualDub2 gets repeated frames and the mentioned combs.
MPEG2Source sees FINISHED 95.69% FILM
Flagging borked or DVD borked ?
I would suggest to go back to the .vob and work from there.

StainlessS
6th November 2022, 20:02
go back to the .vob and work from there.
+1

If its DVD VOB, then better use DGIndex [EDIT Mpeg2Source(d2v] and TFM(d2v=d2v_Filename), DGSource dont work with d2v arg. [EDIT: or rather, TFM, dont work with d2v=dgi_Filename]
(you sometimes get mid frame edits (edits split on 2nd field) and Perverse Telecine where progressive fields split across frames.)

TFM on VOB will also announce presence of illegal field transitions with d2v arg. [throw error]

poisondeathray
6th November 2022, 21:17
So this seems to work perfectly for handling the problematic combed transitions:


LWLibavVideoSource(clip)
TFM()
TDecimate()
LanczosResize(720,540)


But as I feared TFM() is having issues with combed frame detection (note the aliasing on the table edges -- the sequence is 24p soft telecine and contains no combing artefacts)

<snip>

I'll have to play around with the thresholds to see if it can be improved, but my experience with TDeint seems to imply it's going to be difficult and/or need per-scene thresholding.

edit: PP=0 seems to help with that.

Yes, you just have to tweak the parameters for your source

Leaving PP=0 will leave combed frames (scene transitions, orphan fields - fields 220, 490 that have unique full content , but missing their "partner" field pair) , because this is not a 100% soft pulldown source (decimated frame numbers 88, 196 will be combed -ie. the frame before the next scene)

You can use display=true to debug MI , cthresh values. eg. The grid pattern of yellow laundry basket might elicit false positive comb detection because it "looks" like combing. (or any scene that looks like combing, maybe some types of horizontal venetian window blinds).

e.g you can see MI values going as high as 166 in the laundry scene. But the true combed frames have mic of 246 and 228. So if you set mi>166 but <228 eg. mi=170, you should catch everything in this clip (you'd have to check the rest of the DVD to see if those settings are ok), and the orphaned fields will be deinterlaced properly, while not deinterlacing the progressive content frames

DGSource("soft telecine.dgi")
TFM(mi=170, clip2=QTGMC().SelectEven(), display=true)
TDecimate()

hello_hello
7th November 2022, 02:16
But as I feared TFM() is having issues with combed frame detection (note the aliasing on the table edges -- the sequence is 24p soft telecine and contains no combing artefacts)

That doesn't quite make sense because as you said, if it's soft telecine there should be no combing to detect. That looks like some sort of production mess.

It's been mentioned already but after remuxing the MKV as a TS file and opening it with DGIndex:

Frame Rate: 29.970030 fps
Video Type: Film 95.90%
Frame Type: Progressive
Coding Type: B
Colorimetry: BT.470-2 B,G*
Frame Structure: Frame
Field Order:
Coded Number: 256
Playback Number: 2
Frame Repeats: 0
Field Repeats: 0

According to DGIndex (and MediaInfo) it's been encoded as progressive, but given the hard telecine, I assume it should have been encoded as interlaced?

Even without using QTGMC to de-interlace, this fixes 90% of it, but it creates a blended frame on at least one scene change (I only checked one).

TFM(pp=5)
TDecimate()

flossy_cake
7th November 2022, 05:01
That doesn't quite make sense because as you said, if it's soft telecine there should be no combing to detect. That looks like some sort of production mess.

Indeed there shouldn't be, but TFM incorrectly detects there are because of the stippled patterns on various objects in the scene. Disabling TFM and stepping through each frame at a time shows no combing artefacts on that motion sequence. But what I learned recently was that this is only happening because the source filter is disobeying the repeat field flags -- if they are obeyed then I see the expect pattern of 2 combed frames followed by 3 progressive frames.

How has the .mkv been obtained ?

I bought the DVD discs the other day and used MakeMKV (https://www.videohelp.com/software/MakeMKV) to remux it to mkv. So there hasn't been any transcoding (I expect it to be just the original MPEG2 stream living inside mkv file) but I'm not sure if the mkv container uses timecodes as well which could be interfering with it somehow. The snippet was then extracted using XMediaRecode in "copy" mode -- again avoiding any transcoding, but still possible that it could be altering metadata or timecodes in the original mkv file. In theory it shouldn't.

In any case that clip is definitely soft telecine 24p, not 30i or 30p. The earlier seasons of that same show seem to be using hard telecine.

StainlessS
7th November 2022, 05:29
DGIndex Mpeg2Source(d2v) on a DVD VOB d2v would do it better, gives TFM more to work with.

flossy_cake
7th November 2022, 08:46
DGIndex on a DVD VOB d2v would do it better, gives TFM more to work with.

Sounds complicated and difficult :scared:

Isn't it interesting though how human vision can tell immediately if there are combed pixels in the frame, but coming up with an algorithm for it is very difficult. Just thinking about it gives me a headache, I mean how are we going to tell if the pixels are real image data or combing artefacts? The difference in colour between neighbouring pixels could be virtually anything and that could still be a real texture in the image.

It seems Tritical and D.G have created their own algorithms for dealing with it (metric=0/1) but both of them still seem to need per-scene or per-video thresholding.

The only suggestion I could come up with was to perhaps apply the combing detection on a per-block basis, but I'm guessing Tritical and D.G had thought of that already.

NVidia's DXVA deinterlacing has combing detection (controlled by the "use inverse telecine" checkbox in NVCP) and it seems to avoid the issue by playing it safe with a very low threshold so it needs only a small amount of combing before it reverts to interpolation. Similar thing with my PVR's deinterlacer (chipset HiSilicon 3790mv200).

Still, TFM seems to do a pretty good job with PP=0 -- I'd rather have the rare 1-2 frame combing artefact on scene splices than tens of frames dropping to 240p.

StainlessS
7th November 2022, 09:26
Sounds complicated and difficult
Really.

d2v="...Whatever.d2v"
Mpeg2Source(d2v) # OOoops, was DGIndex(d2v). I use templates, so never have to type it in myself.
TFM(d2v=d2v, ... additional args you use)

Allows TFM to see the source d2v and detect illegal field transitions etc, instead of hoping that the source filter (eg LWLibavVideoSource or whatever) did everything correctly.
(allows it to see how the source was actually encoded, and DGIndex settings eg "Honour Pulldown Flags" etc)

TFM() on an decoded clip, cannot see any illegal field transitions or exactly how it is encoded, eg soft telecine, only has access to the decoded video provided by the source filter.
DGSource file type dgi, cannot be used by TFM, never implemented.

EDIT:
DGIndex settings eg "Honour Pulldown Flags" etc
Well, this lot from d2v

Stream_Type=1
MPEG_Type=2
iDCT_Algorithm=6
YUVRGB_Scale=1
Luminance_Filter=0,0
Clipping=0,0,0,0
Aspect_Ratio=4:3
Picture_Size=720x576
Field_Operation=0 Honour/Ignore Pulldown Flags/Forced Film
Frame_Rate=25000 (25/1)
Location=0,0,3,4757c

900 5 0 2048 0 1 1 92 b2 b2 a2 b2 b2 a2 b2 b2 a2 b2 b2 a2
900 5 0 319488 0 1 1 92 b2 b2 a2 b2 b2 a2 b2 b2 a2 b2 b2 a2
900 5 0 710656 0 1 1 92 b2 b2 a2 b2 b2 a2 b2 b2 a2 b2 b2 a2
900 5 0 1075200 0 1 1 92 b2 b2 a2 b2 b2 a2 b2 b2 a2 b2 b2 a2
900 5 0 1474560 0 1 1 92 b2 b2 a2 b2 b2 a2 b2 b2 a2 b2 b2 a2
900 5 0 1847296 0 1 1 92 b2 b2 a2 b2 b2 a2 b2 b2 a2 b2 b2 a2
900 5 0 2228224 0 1 1 92 b2 b2 a2 b2 b2 a2 b2 b2 a2 b2 b2 a2

# ...

900 5 3 598341632 0 1 8 92 b2 b2 a2 a2
900 5 3 598458368 0 2 1 d2 ff

FINISHED 100.00% VIDEO

If TFM(d2v=d2v) detects illegal field transition, it will create a OriginalName_fixed.d2v (or something like that) file, and throw error telling you to change to the fixed d2v.
TFM() without d2v cannot tell illegal field transitions, nor create fixed d2v.

d2v for TFM() just makes for less guesswork by TFM.

EDIT:
I'm not sure if DGIndex MPeg2Source(d2v).Tfm(d2v=d2v)
has any advantage over eg SomeOtherVideoSource(d2v).Tfm(d2v=d2v)

But both gotta be better than DGSource(dgi).Tfm()
or SomeOtherVideoSource(dgi [B]OR d2v).Tfm()

EDIT:
I believe that DGIndex Mpeg2Source() is 100% frame accurate, SomeOtherVideoSource() may tend to vary.

hello_hello
7th November 2022, 10:10
Indeed there shouldn't be, but TFM incorrectly detects there are because of the stippled patterns on various objects in the scene. Disabling TFM and stepping through each frame at a time shows no combing artefacts on that motion sequence. But what I learned recently was that this is only happening because the source filter is disobeying the repeat field flags -- if they are obeyed then I see the expect pattern of 2 combed frames followed by 3 progressive frames.

You'll probably also be decoding at the wrong frame rate. If you're using ffms2 or lasmash and they're not obeying the repeat flags, they output the average frame rate. I thought one of them was changed to make obeying repeat flags the default recently. I could be wrong. I'm using the old lsmash that plays with XP and possibly not the latest ffms2.

Decoding with lsmash or ffms2 it looks progressive, except for around the scene changes, and Info() says:

LWLibavVideoSource("D:\soft telecine.lwi", repeat=true)
29.97fps, 317 frames, 10.577 sec

LWLibavVideoSource("D:\soft telecine.lwi")
29.97fps, 256 frames, 8.541 sec

FFVideoSource("E:\soft telecine.mkv", cachefile="D:\soft telecine.ffindex", threads=1, RFFMode=1)
29.97fps, 318 frames, 10.610 sec

FFVideoSource("E:\soft telecine.mkv", cachefile="D:\soft telecine.ffindex", threads=1)
24.3789fps, 256 frames, 10.5 sec

The frame rate for the second ffms2 example is usually the indicator there's repeat flags being ignored, because there's hard telecined or video sections too, making the average frame rate non standard. It'll also mess with the audio sync. I don't know why lsmash didn't output the same frame rate.

I don't know why the repeat flags are resulting in such horrible telecined fields, or why
Field Repeats: 0
from the log file I posted earlier appears to be wrong.

FYI, you can split MKVs into sections with MKVToolNixGUI.
Even if I rip a DVD with MakeMKV (which I rarely do) I always remux the MKV as a TS file with TSMuxer so I can index it with the old DGIndex as it obeys the repeat flags by default. I never use "force film" mode.

Edit: I tried showing the d2v (index) file to TFM after indexing with DGIndex (decoding with DGDecode) but it didn't seem to help.

DGDecode_mpeg2source("D:\soft telecine.d2v")
TFM(d2v="D:\soft telecine.d2v")

flossy_cake
7th November 2022, 11:58
I don't know why the repeat flags are resulting in such horrible telecined fields, or why

I suspect it's where the video editing equipment back in the 90's/00's didn't make sure to maintain field order when the next scene was spliced in. It just spliced it on whatever field happened to be the last at that point when it should have gone 1 more to make sure the next scene started at top field or whatever the order was. It's so annoying cause it damages the video in a way that makes it really difficult to undo. If previewed on interlaced CRT the viewer probably wouldn't be able to tell anything was wrong as it just scans field after field anyway kind of like how if simple bob deinterlacing was used that would also avoid it.

The back of the DVD case says "Every possible effort has been made to produce the highest quality DVD release. Due to the quality of some of the original elements, some visual imperfections may be experienced". Maybe this is what they are referring to but then again maybe they're just covering themselves against refunds.

edit: actually now that I re-read your comment, I think you are referring to why the repeat flags don't match whatever muckup the 90's scene splicer did. In other words, if splicer cut the end of the scene 1 field too early then the repeat flag should reflect that. The answer is of course: I don't know :)

Emulgator
7th November 2022, 15:24
I wanted to say MPEG2Source of course, just correcting that.
Yes, framecuts go right through the wrong place, leaving an orphaned field.
I remember CCE accepting a .i32 pulldown file to avoid that.
Means extra work that might have been neglected.

flossy_cake
11th November 2022, 15:54
Is it possible to have TFM or TDeint set frame property _Combed like eg.

hints = TFM(hint=true, PP=1)
ConditionalFilter(last, deint, last, """propGetAny(hints, "_Combed")""", "=", "true", show=true)


Trying to make it output clip "deint" when _Combed=true

edit: I should probably use

IsCombedTIVTC(clip, int "cthresh", int "MI", bool "chroma", int "blockx", int "blocky")
but it would be nice to know how the hints work as well.

flossy_cake
12th November 2022, 10:19
Kind of stuck with the conditional filters. Trying to evaluate luma diff since prev frame in a 25fps clip and then based on that value conditionally select one of two 50fps output clips.

Problem is this doesn't seem possible due to the way Avisynth evaluates things in real time -- the evaluation of the 25fps clip slows down the 50fps clip to half speed as the evaluation is always performed in the same "code block".

I can kind of get around it by doubling the fps of the 25fps stream but then this breaks things like luma comparisons with the previous frame since it's comparing it to a repeat of itself so it often evaluates to 0 change in luma when it shouldn't. Then tried to work around this with some bodge code but can't get it to do what I want. It seems the only way to get what I want is to perform the evaluations on the original 25fps clip.


LWLibavVideoSource("576i25 mixed cadences 1-1 and 2-2.mkv")
orig25 = last
orig50 = ChangeFPS(orig25, 50)
bwdif50 = ChangeFPS(BWDIF(last, field=-2, thr=3), 50)

ConditionalFilter(orig50, bwdif50, orig50,
\"IsCombedTIVTC(cthresh=9, MI=64) || (YDifferenceFromPrevious() < 2.0)",
\ "=", "true", show=true)


I need to swap the blue orig50 for orig25 to get the correct evaluations, but that causes the playback of the conditionally selected clip (bwdif50/orig50) to become slow. Seems the Avisynth thread that performs the conditional evaluation is somehow tied to the timing of the input clip which it's evaluating.

Tried using FrameEvaluate on orig25 prior to the conditional like this:


FrameEvaluate(orig25, "global isCombed = IsCombedTIVTC(cthresh=9, MI=64)")
FrameEvaluate(orig25, "global yDiff = YDifferenceFromPrevious())


but couldn't access the vars isCombed and yDiff inside the conditional.

edit: in case it's not obvious what I'm trying to do here. Basically I want to use Tritical's IsCombedTIVTC() with one modification: if IsCombedTIVTC says the frame is NOT combed, then I will only obey that if the luma diff since the last frame was suitably small. This is my attempt at trying to mitigate combing artefacts from scenes where there is just a tiny bit of motion and IsCombedTIVTC is erroneously reporting "not combed".

hello_hello
12th November 2022, 11:47
Edit: I haven't read your latest post yet. Got to visit the real world for a bit. Hopefully someone else will come along in the mean time.

TFM's hints have been around for a long time (I can't remember how they work exactly). They're not the same thing as frame properties which are relatively new. Not many plugins support them yet (nor do Avisynth's internal filters).
I can't imagine it could work the way you're doing it.

TIVTC has ShowCombedTIVTC & IsCombedTIVTC functions you can use to check for combed frames. The help file says they use TFM's comb detection.

Here's some functions you may want to play with. They might give you some ideas. I put them together for a discussion in a thread a long time ago, but I'm hopeless with conditional filters too. I remember a lot of frustrated messing around to get them to work and I've never used them myself so I only vaguely remember them. The script has to exist. That is, they probably won't work in AvsPmod until the script is saved.

FindCombing1() writes a log file (run an analysis pass) with the frame number of any combed frame and a running count of combed frames.

12 - Combing 1
13 - Combing 2
14 - Combing 3
15 - Combing 4
16 - Combing 5
17 - Combing 6
18 - Combing 7
19 - Combing 8

FindCombing2() as three MI thresholds and writes a log file of the threshold levels with a running count for each.

91 - Thresh Hi 75
92 - Thresh Hi 76
93 - Thresh Low 1
94 - Thresh Low 2
95 - Thresh Hi 77
96 - Thresh Hi 78
97 - Thresh Hi 79
98 - Thresh Hi 80
99 - Thresh Hi 81
100 - Thresh Med 1
101 - Thresh Low 3
102 - Thresh Med 2

FindCombingRed() - I'm not 100% sure. It was a while ago.
It looks like it creates a B/W version of the clip, runs TFM without de-interlacing followed by TDecimate, makes the combed pixels red, runs IsCombedTIVTC on the B/W clip and also checks the second clip for the amount of red, or something....
It displays the clip with the combed pixels red and the log file looks like this:

76 - Combing 62 - 12.74
77 - Combing 63 - 112.00
78 - Combing 64 - 112.00
79 - Combing 65 - 112.00
80 - Combing 66 - 14.88
82 - Combing 67 - 13.51
83 - Combing 68 - 112.00

I think the idea of that one was to field match and decimate without repairing combing and then checking for it. Or something....

# -------------------------------------------------------------------------------
# FindCombing1
# -------------------------------------------------------------------------------

function FindCombing1(clip Vid, bool "Append", string "FileName", bool "All") {

Append = default(Append, false)
FileName = default(FileName, "")
All = default(All, false)

global Count = 0
ScriptName = ScriptFile()
EndLength = FindStr(LCase(ScriptName), ".avs") - 1
Dir = (StrLen(ScriptDir()) < 2) ? "D:" : ""
File = ((FileName != "") ? FileName : \
Dir + ((EndLength > 0) ? LeftStr(ScriptName, EndLength) : ScriptName)) + "_Combing.txt"

Vid = FrameEvaluate(Vid, """

A = IsCombedTIVTC()
Count = A ? Count + 1 : Count
TheCombing = A ? string(Count, " - Combing % 6.0f") : ""

""")

Vid = !All ? WriteFileIf(Vid, File, "A", "current_frame", "TheCombing", Append=Append) : \
WriteFile(Vid, File, "current_frame", "TheCombing", Append=Append)

return Vid }

# -------------------------------------------------------------------------------
# FindCombing2
# -------------------------------------------------------------------------------

function FindCombing2(clip Vid, bool "Append", string "FileName", bool "All") {

Append = default(Append, false)
FileName = default(FileName, "")
All = default(All, false)

ScriptName = ScriptFile()
EndLength = FindStr(LCase(ScriptName), ".avs") - 1
Dir = (StrLen(ScriptDir()) < 2) ? "D:" : ""
File = ((FileName != "") ? FileName : \
Dir + ((EndLength > 0) ? LeftStr(ScriptName, EndLength) : ScriptName)) + "_Combing.txt"

global FCA = 0
global FCB = 0
global FCC = 0
Vid=Vid

Vid = FrameEvaluate(Vid, """

A = IsCombedTIVTC(MI=30)
B = IsCombedTIVTC(MI=80)
C = IsCombedTIVTC(MI=130)

FCA = A && !B && !C ? FCA + 1 : FCA
FCB = B && !C ? FCB + 1 : FCB
FCC = C ? FCC + 1 : FCC

TheCombing = " - " + \
(A && !B && !C ? string(FCA, "Thresh Low % 6.0f") : \
B && !C ? string(FCB, "Thresh Med % 6.0f") : \
C ? string(FCC, "Thresh Hi % 6.0f") : "")

""")

Vid = !All ? WriteFileIf(Vid, File, "A || B || C", "current_frame", "TheCombing", Append=Append) : \
WriteFile(Vid, File, "current_frame", "TheCombing", Append=Append)

return Vid }

# -------------------------------------------------------------------------------
# FindCombingRed
# -------------------------------------------------------------------------------

function FindCombingRed(clip Vid, bool "Append", string "FileName", bool "All", bool "Write") {

Append = default(Append, false)
FileName = default(FileName, "")
All = default(All, false)
Write = default(Write, true)

ScriptName = ScriptFile()
EndLength = FindStr(LCase(ScriptName), ".avs") - 1
Dir = (StrLen(ScriptDir()) < 2) ? "D:" : ""
File = ((FileName != "") ? FileName : \
Dir + ((EndLength > 0) ? LeftStr(ScriptName, EndLength) : ScriptName)) + "_Combing.txt"

global Count = 0
Vid = Vid.GreyScale()
global Vid1 = Vid.TFM(pp=1).TDecimate()
CombTest = BlankClip(Vid, Color=color_red)
Vid2 = Vid.TFM(Clip2=CombTest).TDecimate()
global Everything = All

Out = FrameEvaluate(Vid2, """

IsComb = IsCombedTIVTC(Vid1)
IsRed = (AverageChromaV() > 128)
IsEnd = (FrameCount() == (current_frame + 1))
Count = IsComb ? Count + 1 : Count

WriteThis = \
(!IsComb && !IsRed && !Everything ? "" : string(current_frame)) + \
(!IsComb && !IsRed ? "" : \
IsComb && IsRed ? (string(Count, " - Combing %.0f") + string(AverageChromaV()-128, " - %.2f")) : \
IsComb ? string(Count, " - Combing %.0f") : \
(" - No Combing" + string(AverageChromaV()-128, " - %.2f"))) + \
(!IsEnd ? "" : \
(!IsComb && !IsRed && !Everything ? "" : chr(10)) + string(FrameCount(), "%.0f - Frame Count"))

""")

Out = !Write ? Vid2 : \
!All ? WriteFileIf(Out, File, "IsComb || IsRed || IsEnd", "WriteThis", Append=Append) : \
WriteFile(Out, File, "WriteThis", Append=Append)

return Out }

flossy_cake
12th November 2022, 13:34
Thanks hello_hello, I'll get stuck in again tomorrow as I already spent the day working on this without luck.

The Avisynth wiki (http://avisynth.nl/index.php/FrameEvaluate#Advanced_conditional_filtering:_part_I) gives this code example which seems to indicate that I should be able to use FrameEvaluate to perform the IsCombedTIVTC test on the 25fps clip and then reference the results of it from elsewhere in the script:


function g(clip c)
{
global w = c
c2 = ScriptClip(c, "subtitle(t)")
c3 = FrameEvaluate(c2, "me()")
c4 = FrameEvaluate(c3, "global text = YDifferenceFromPrevious(w)")
return c4
}

function me()
{
global t = String(text)
}


But I had no such luck, every time I try to reference it I get the error "I don't know what <varname> means".

On another note...

You can disable post processing globally with TFM(pp=0)

Somehow I missed this and indeed TFM can weave cheese slices silly weird cadence just fine with pp=0. In fact pp=0 seems to do well on actual content as well, even dodgy stuff like my Caroline in the City NTSC DVDs which has all these weird 1-field edits on scene splices, while MadVR's [deint=film] chokes badly with lots of stutter (tfm's mode=0 helps with that too, and then tdecimate's hybrid=1 to blend over single-field splices:


TFM(mode=0, PP=1)
TDecimate(mode=1, hybrid=1, hint=true, cycle=5, cycleR=1,
\ viddetect=2, vidthresh=2.2, display=false)


So in fact I am very grateful and pleased that we have TFM as it's doing a significantly better job than Nvidia's DXVA and MadVR's film mode!

So a big :thanks: to Tritical

StainlessS
12th November 2022, 16:38
That Advanced Scripting on Wiki is way headbanging stuff, and I personally think the necessity is questionable.
Everything that can be done in the weird back-to-front and upside down order can more easily be done with scriptclip.
(and in sane order)

but anyways, for anybody wants to play with this [equivalent of flossy prev given script from Wiki]


#v = AviSource("E:\Temp\Test3\atomic_kitten.avi").ConvertToYV12
KCLIP=BlankClip(Pixel_Type="YV12",color=$000000)
WCLIP=KCLIP.BlankClip(color=$FFFFFF)
MCLIP=KCLIP.BlankClip(color=$808080)

V = Interleave(KCLIP,WCLIP,MCLIP)

function g(clip c)
{
global w = c
c2 = ScriptClip(c, """RT_DebugF("%d] Subtitle(t)='%s'",current_frame,t) subtitle(t)""")
c3 = FrameEvaluate(c2, """RT_DebugF("%d] Calling me()",current_frame) me()""")
c4 = FrameEvaluate(c3, """RT_debugF("\n%d] Setting Global text with YDifferenceFromPrevious(w)",current_frame) global text = YDifferenceFromPrevious(w)""")
return c4
}

function me()
{
# RT_DebugF("%d] me(): Setting Global t to %s",current_frame,string(text)) # DONT WORK. current_frame not available here
RT_DebugF("me(): Setting Global t to %s",string(text))
global t = String(text)
}

g(v)


shows this


00004140 15:29:36.029 RT_DebugF:
00004141 15:29:36.029 RT_DebugF: 0] Setting Global text with YDifferenceFromPrevious(w)
00004142 15:29:36.029 RT_DebugF: 0] Calling me()
00004143 15:29:36.029 RT_DebugF: me(): Setting Global t to 0.000000
00004144 15:29:36.029 RT_DebugF: 0] Subtitle(t)='0.000000'
00004145 15:29:37.761 RT_DebugF:
00004146 15:29:37.761 RT_DebugF: 1] Setting Global text with YDifferenceFromPrevious(w)
00004147 15:29:37.761 RT_DebugF: 1] Calling me()
00004148 15:29:37.777 RT_DebugF: me(): Setting Global t to 219.000000
00004149 15:29:37.777 RT_DebugF: 1] Subtitle(t)='219.000000'
00004150 15:29:38.662 RT_DebugF:
00004151 15:29:38.662 RT_DebugF: 2] Setting Global text with YDifferenceFromPrevious(w)
00004152 15:29:38.662 RT_DebugF: 2] Calling me()
00004153 15:29:38.662 RT_DebugF: me(): Setting Global t to 109.000000
00004154 15:29:38.662 RT_DebugF: 2] Subtitle(t)='109.000000'
00004155 15:29:39.548 RT_DebugF:
00004156 15:29:39.548 RT_DebugF: 3] Setting Global text with YDifferenceFromPrevious(w)
00004157 15:29:39.548 RT_DebugF: 3] Calling me()
00004158 15:29:39.548 RT_DebugF: me(): Setting Global t to 110.000000
00004159 15:29:39.548 RT_DebugF: 3] Subtitle(t)='110.000000'
00004160 15:29:41.511 RT_DebugF:
00004161 15:29:41.511 RT_DebugF: 4] Setting Global text with YDifferenceFromPrevious(w)
00004162 15:29:41.511 RT_DebugF: 4] Calling me()
00004163 15:29:41.511 RT_DebugF: me(): Setting Global t to 219.000000
00004164 15:29:41.511 RT_DebugF: 4] Subtitle(t)='219.000000'


Current_Frame is not available in me() func, but can use this and supply current_frame as arg to new me2() func

#v = AviSource("E:\Temp\Test3\atomic_kitten.avi").ConvertToYV12
KCLIP=BlankClip(Pixel_Type="YV12",color=$000000)
WCLIP=KCLIP.BlankClip(color=$FFFFFF)
MCLIP=KCLIP.BlankClip(color=$808080)

V = Interleave(KCLIP,WCLIP,MCLIP)

function g(clip c)
{
global w = c
c2 = ScriptClip(c, """RT_DebugF("%d] Subtitle(t)='%s'",current_frame,t) subtitle(t)""")
c3 = FrameEvaluate(c2, """RT_DebugF("%d] Calling me2()",current_frame) me2(current_frame)""")
c4 = FrameEvaluate(c3, """RT_debugF("\n%d] Setting Global text with YDifferenceFromPrevious(w)",current_frame) global text = YDifferenceFromPrevious(w)""")
return c4
}

function me2(int n)
{
# current_frame = n # Cheat if current_frame required for something
RT_DebugF("%d] me2(%d): Setting Global t to %s",n,n,string(text)) # current_frame provided as arg n
global t = String(text)
}

g(v)


result

00000246 15:43:25.380 RT_DebugF:
00000247 15:43:25.380 RT_DebugF: 0] Setting Global text with YDifferenceFromPrevious(w)
00000248 15:43:25.380 RT_DebugF: 0] Calling me2()
00000249 15:43:25.380 RT_DebugF: 0] me2(0): Setting Global t to 0.000000
00000250 15:43:25.380 RT_DebugF: 0] Subtitle(t)='0.000000'
00000251 15:43:27.315 RT_DebugF:
00000252 15:43:27.315 RT_DebugF: 1] Setting Global text with YDifferenceFromPrevious(w)
00000253 15:43:27.315 RT_DebugF: 1] Calling me2()
00000254 15:43:27.315 RT_DebugF: 1] me2(1): Setting Global t to 219.000000
00000255 15:43:27.315 RT_DebugF: 1] Subtitle(t)='219.000000'
00000256 15:43:28.523 RT_DebugF:
00000257 15:43:28.523 RT_DebugF: 2] Setting Global text with YDifferenceFromPrevious(w)
00000258 15:43:28.523 RT_DebugF: 2] Calling me2()
00000259 15:43:28.523 RT_DebugF: 2] me2(2): Setting Global t to 109.000000
00000260 15:43:28.523 RT_DebugF: 2] Subtitle(t)='109.000000'
00000261 15:43:29.360 RT_DebugF:
00000262 15:43:29.360 RT_DebugF: 3] Setting Global text with YDifferenceFromPrevious(w)
00000263 15:43:29.360 RT_DebugF: 3] Calling me2()
00000264 15:43:29.360 RT_DebugF: 3] me2(3): Setting Global t to 110.000000
00000265 15:43:29.360 RT_DebugF: 3] Subtitle(t)='110.000000'
00000266 15:43:30.346 RT_DebugF:
00000267 15:43:30.346 RT_DebugF: 4] Setting Global text with YDifferenceFromPrevious(w)
00000268 15:43:30.346 RT_DebugF: 4] Calling me2()
00000269 15:43:30.346 RT_DebugF: 4] me2(4): Setting Global t to 219.000000
00000270 15:43:30.346 RT_DebugF: 4] Subtitle(t)='219.000000'
00000271 15:43:31.295 RT_DebugF:
00000272 15:43:31.295 RT_DebugF: 5] Setting Global text with YDifferenceFromPrevious(w)
00000273 15:43:31.295 RT_DebugF: 5] Calling me2()
00000274 15:43:31.295 RT_DebugF: 5] me2(5): Setting Global t to 109.000000
00000275 15:43:31.295 RT_DebugF: 5] Subtitle(t)='109.000000'


EDIT: I guess that you could Ultra Cheat and use

Function me3(int current_frame) { ... }


But I had no such luck, every time I try to reference it I get the error "I don't know what <varname> means".
You did not post what it was that you were trying to do, but whatever it was, it could only be used within runtime environment eg ScriptClip.
(and maybe only with After_Frame=true)

ScriptClip(clip clip, string filter [, bool show, bool after_frame, AVS+ bool local]
AVS+ ScriptClip(clip clip, function func [, bool show, bool after_frame, bool local] )

If after_frame=true, the script should be evaluated after the frame has been fetched from the filters above. Default is false.

ScriptClip on Wiki:- http://avisynth.nl/index.php/ConditionalFilter#ScriptClip

Note,

SSS """
# ...
Y = AverageLuma() # After any kind of fetching/sampling of current_frame frame in ScriptClip,
# code following will act as if After_frame=True
# ie, all upstream filters would have been called to provide the frame for AverageLuma()
# ...
"""
ScriptClip(SSS,After_Frame=FALSE) # FALSE is default

If using eg Scriptclip(...,After_frame=False), and some FrameEvaluate() style function is supposed to set a global var,
on FIRST FRAME, that global var may not have been set EVER unless upstream filters have been processed ie FrameEvaluate() not yet called,
and on subsequent frames, the global var set by FrameEvaluate would be as when set on the FrameEvaluate of previous frame.
So may need the After_frame=true thingy.
(if that makes any sense)

flossy_cake
13th November 2022, 10:31
Thanks, got it working with ScriptClip and after_frame=true.

I still need to keep the input and output clips at the same frame rate (in this case 50fps since bwdif will be outputting 50fps) otherwise I encountered other sync issues, but managed to work around it by making the luma check ignored if the diff is < 0.1, i.e if it was a duplicate frame, i.e 25fps. But it still seems to need denoising otherwise a static shot can have luma diff of 0.3 ish.

edit: neither of those ended up being reliable solutions. Should be able to workaround it tho with YDifferenceToNext(-2) which should always look at the real previous frame instead of the duplicate. Actually I'm impressed with what is possible with these realtime functions. It's giving me an explosion of ideas and possibilities like detecting 4 combed frames in a row could be used to infer 1:1 cadence and then if that was untrue it may even be possible to dynamically switch to TFM(). The problem is with handling of edge cases. So many edge cases it seems :scared:

flossy_cake
14th November 2022, 09:23
Presume this is some kind of diff overflow bug in FieldDiff(),


#WhateverSource(...)
OPT=4 # (default) Auto
#OPT=0 # Use C routines
FieldDiff(debug=true,display=true,opt=OPT)
return last

Similar to both display and DebugView, thoughout video clip.


OPT=4 (Default)

00007315 3.68521953 FieldDiff: Frame = 14233 Diff = -207589436161 (sad)



Were you able to resolve this?

I'm asking as I need to use more metrics as I'm finding that IsCombedTIVTC still results in a lot of false negatives compared to the one used by TDeint, and I can't compensate with YUV diffing as there are still edge cases, so I'm looking at using CFieldDiff as well to somehow mitigate that but...yeah :rolleyes:

Maybe it's possible to workaround by subtracting/multiplying/bitshifting it by something and still get a meaningful value out of it? What is the range of the value supposed to be?

StainlessS
14th November 2022, 11:23
Were you able to resolve this?
Nope.

There is this lot for 8 bit only.

****************************************************
********** RUNTIME CLIP COMPARISON FUNCTIONS ********
*****************************************************

The compiletime/runtime clip functions share some common characteristics.
The 'n' and (where used) 'n2' args are the optional frame numbers and default to 'current_frame' if not specified.
The x,y,w,h, coords specify the source rectangle under scrutiny and are specified as for Crop(), the default 0,0,0,0 is full frame.
If 'interlaced' is true (sometimes use Altscan arg name instead), then every other line is ommited from the scan, so if eg x=0,y=1, then
scanlines 1,3,5,7 etc are scanned, if eg x=0,y=4 then scanlines 4,6,8,10 etc are scanned. The 'h' coord specifies the full height scan ie
same whether interlaced is true or false, although it will not matter if the 'h' coord is specified as eg odd or even, internally the
height 'h' is reduced by 1 when interlaced=true and 'h' is even.
Some of the functions have 'x2' and 'y2' args for a second frame (which could be the same frame).
Note, 'x2' and 'y2' default to 'x' and 'y' respectively.
v2.0, Where two clip comparison, c and c2 need not be same dimensions but BEWARE, x2 and y2 default to x and y also w and h default to
0 which is converted to c.width-x and c.height-y, may be best to provide x2, y2, w and h where c2 not same dimensions
as c.


RT_YDifference(clip c,int "n"=current_frame,int "delta"=1,int "x"=0,int "y"=0,int "w"=0,int "h"=0,int "x2"=x,int "y2"=y,
bool "interlaced"=false,int "Matrix"=(Width>1100||Height>600?3:2))
Returns FLOAT value luma difference (0.0 -> 255.0) between frame n area x,y,w,h, and frame (n+delta) area x2,y2,w,h.
Note, by default it will be equivalent to YDifferenceToNext as delta defaults to 1 and x,y,w,h defaults full frame.
BEWARE, x2 and y2 default to x and y.

Eg, RT_YDifference(clip,delta=0,y2=1,interlaced=true)
Would difference the even and odd lines of the same frame,

***
***
***

RT_LumaDifference(clip c,clip c2,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,
int "n2"=current_frame,int "delta2"=0,int "x2"=x,int "y2"=y,bool "interlaced"=false,int "Matrix"=(Width>1100||Height>600?3:2))
Returns FLOAT value luma difference (0.0 -> 255.0) between clip c frame (n+delta) area x,y,w,h, and clip c2 frame (n2+delta2) area x2,y2,w,h.
Note, 'x2' and 'y2' default to 'x' and 'y' respectively.
v2.0, c and c2 need not be same dimensions but BEWARE, x2 and y2 default to x and y also w and h default to 0
which is converted to c.width-x and c.height-y, may be best to provide x2, y2, w and h where c2 not same dimensions as c.

***
***
***

RT_LumaCorrelation(clip c,clip c2,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,int "n2"=current_frame,
int "delta2"=0,int "x2"=x,int "y2"=y,bool "interlaced"=false,int "Matrix"=(Width>1100||Height>600||clip2.Width>1100||clip2.Height>600?3:2))
Returns FLOAT value luma correlation (-1.0 -> 1.0) between clip c frame (n+delta) area x,y,w,h, and clip c2 frame (n2+delta2) area x2,y2,w,h.
Note, 'x2' and 'y2' default to 'x' and 'y' respectively.
v2.0, c and c2 need not be same dimensions but BEWARE, x2 and y2 default to x and y also w and h default to 0
which is converted to c.width-x and c.height-y, may be best to provide x2, y2, w and h where c2 not same dimensions as c.

Pearson's Sample Correlation Coefficient.
http://en.wikipedia.org/wiki/Correlation_and_dependence
http://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient
Uses equivalent routine to the JMac698's JCorr plugin here:
http://forum.doom9.org/showthread.php?t=165386
and here:
http://forum.doom9.org/showthread.php?p=1495098#post1495098


***
***
***

RT_LumaPixelsDifferent(clip c,clip c2,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0, \
int "n2"=current_frame,int "delta2"=0,int "x2"=x,int"y2"=y,bool "interlaced"=false, \
int "matrix"=(Width>1100||Height>600?3:2),int "Thresh"=0)

Compares clip c frame (n+delta) at x,y,w,h, and clip c2 frame (n2+delta2) at x2,y2,w,h, and returns amount of pixels
whose pixel luma difference is greater than Thresh (RGB converted to Luma-Y using Matrix).
Matrix 0=Rec601, 1=Rec709, 2=PC601, 3=PC709.
If Interlaced=True, then skips every other raster line, eg process only y, y+2, y+4 etc.
Thresh Default 0, returns number of pixels that are not exactly the same.
Return value is in range 0.0 (meaning none) to 255.0 meaning 100% of pixels.
v2.0, c and c2 need not be same dimensions but BEWARE, x2 and y2 default to x and y also w and h default to 0
which is converted to c.width-x and c.height-y, may be best to provide x2, y2, w and h where c2 not same dimensions as c.

***
***
***

RT_LumaPixelsDifferentCount(clip c,clip c2,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0, \
int "n2"=current_frame,int "delta2"=0,int "x2"=x,int"y2"=y,bool "interlaced"=false, \
int "matrix"=(Width>1100||Height>600?3:2),int "Thresh"=0)

Compares clip c frame (n+delta) at x,y,w,h, and clip c2 frame (n2+delta2) at x2,y2,w,h, and returns number of pixels
whose pixel luma difference is greater than Thresh (RGB converted to Luma-Y using Matrix).
Matrix 0=Rec601, 1=Rec709, 2=PC601, 3=PC709.
If Interlaced=True, then skips every other raster line, eg process only y, y+2, y+4 etc.
Thresh Default 0, returns number of pixels that are not exactly the same.
Note, returns the number of pixels whose difference is greater than Thresh, so ranges 0 -> (Width*Height).
v2.0, c and c2 need not be same dimensions but BEWARE, x2 and y2 default to x and y also w and h default to 0
which is converted to c.width-x and c.height-y, may be best to provide x2, y2, w and h where c2 not same dimensions as c.

***
***
***

RT_FrameDifference(clip c,clip c2,int "n"=current_frame,int "n2"=current_frame,Float "ChromaWeight"=1.0/3.0,
int "x"=0,int "y"=0,int "w"=0,int "h"=0,int "x2"=x,int "y2"=y,bool "Altscan"=false,bool "ChromaI"=false,
Int "Matrix"=(Width>1100||Height>600)?3:2)
Returns difference between clip c frame n area x,y,w,h and clip c2 frame n2 area x2,y2,w,h. (range 0.0 -> 255.0).

Args:-
c, c2, clips to difference.
n, default = current_Frame. Frame from clip c.
n2, default = current_Frame. Frame from clip c2.
ChromaWeight, default 1.0/3.0. Range 0.0 -> 1.0.
Y8, returns same as LumaDifference. ChromaWeight ignored.
YUV,
Weighting applied YUV chroma:- (1.0 - ChromaWeight) * Lumadif + ChromaWeight * ((Udif + Vdif)/2.0).
RGB,
If ChromaWeight > 0.0, then returns same as RT_RGBDifference() [ie average RGB pixel channel difference].
If ChromaWeight == 0.0, then returns same as RT_LumaDifference() using Matrix arg to convert RGB to YUV-Y Luma.
x,y,w,h. All Default 0 (full frame), for clip c.
x2,y2. x2 defaults x, y2 defaults y, for clip c2.
Altscan, default false. If true then scan only every other scanline starting at clip c y coord, and clip c2 y2 coord.
ChromaI, default false. If YV12 and ChromaI, then do YV12 interlaced chroma scanning.
Ignored if not YV12. Both YV12 clips must be same, cannot difference one that is progressive and one that has interlaced chroma.
Matrix, default (c.Width>1100||c.Height>600||c2.Width>1100||c2.Height>600)?3:2
Conversion matrix for conversion of RGB to YUV-Y Luma. 0=REC601 : 1=REC709 : 2 = PC601 : 3 = PC709.
Default = (c.Width > 1100 OR c.Height>600 OR c2.Width > 1100 OR c2.Height>600) then 3(PC709) else 2(PC601). YUV not used
Matrix only Used if RGB and ChromaWeight == 0.0, where returns same as RT_LumaDifference().
Note, 'x2' and 'y2' default to 'x' and 'y' respectively.
v2.0, c and c2 need not be same dimensions but BEWARE, x2 and y2 default to x and y also w and h default to 0
which is converted to c.width-x and c.height-y, may be best to provide x2, y2, w and h where c2 not same dimensions as c.


Using Delta, Interlaced (later renamed to AltScan for some functions), and Y args to compare pretty much any fields.

EDIT: From the RT_YDifference example given,

diff = RT_YDifference(clip,delta=0,y2=1,interlaced=true)
# Would difference the even and odd lines of the same frame,


and

diff = RT_YDifference(clip,delta=1,y2=1,interlaced=true)
# Would difference the current_frame even and Next_frame odd lines, etc

flossy_cake
14th November 2022, 11:30
I guess there is also something like


LumaDifference(SeparateFields().SelectEven(), SeparateFields().SelectOdd())


But I don't know how meaningful it is.

edit: yep, not very meaningful it seems. I'm getting more meaningful numbers out of CFieldDiff / 1000000 + 207590 -- a value of about 0.25 on noncombed pans and 7 on combed pans. If it's less than about 0.125 then it seems safe to believe the result of IsCombedIVTC.

I'll have to try your RT_ funcs to see how they compare -- thanks.

StainlessS
14th November 2022, 11:39
LumaDifference takes two clips (where could be same clip).

similar is

RT_LumaDifference(clip c,clip c2,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,
int "n2"=current_frame,int "delta2"=0,int "x2"=x,int "y2"=y,bool "interlaced"=false,int "Matrix"=(Width>1100||Height>600?3:2))
Returns FLOAT value luma difference (0.0 -> 255.0) between clip c frame (n+delta) area x,y,w,h, and clip c2 frame (n2+delta2) area x2,y2,w,h.
Note, 'x2' and 'y2' default to 'x' and 'y' respectively.
v2.0, c and c2 need not be same dimensions but BEWARE, x2 and y2 default to x and y also w and h default to 0
which is converted to c.width-x and c.height-y, may be best to provide x2, y2, w and h where c2 not same dimensions as c.

StainlessS
14th November 2022, 11:44
Maybe of interest,
mod of snippit posted by TheCoreyBurton, [cant find his post, TheCoreyBurton account deleted]
https://forum.doom9.org/showthread.php?p=1785099#post1785099


Function DoubleRate(clip c,Bool "Blend") {
c
Blend=Default(Blend,False) # Avoid blends at scene change (copy previous frame)
prefilt = DeGrainMedian() # some smoothing
superfilt = MSuper(prefilt, hpad=16, vpad=16, rfilter = 4) # all levels for MAnalyse
super = MSuper(pel=2, hpad=16, vpad=16,rfilter=4,levels=1) # one level is enough for MRecalculate
bw_1 = MAnalyse(superfilt, chroma = false, isb = true, blksize = 16, OverLap=2, searchparam = 3, plevel = 0, search = 3, badrange = (-24))
fw_1 = MAnalyse(superfilt, chroma = false, isb = false, blksize = 16, OverLap=2, searchparam = 3, plevel = 0, search = 3, badrange = (-24))
bw_2 = MRecalculate(super, chroma = false, bw_1, blksize = 8, searchparam = 1, search = 3) # No Overlap (currently broken for final vectors)
fw_2 = MRecalculate(super, chroma = false, fw_1, blksize = 8, searchparam = 1, search = 3) # No Overlap
MBlockFps(super, bw_2, fw_2, num=FramerateNumerator(c) * 2, den=FramerateDenominator(c), mode=0, Blend=Blend)
Return Last
}

Function HybridDoubleRate_QTGMC(clip c,String "Preset",Bool "Blend",Bool "Show") {
c
Preset=Default(Preset,"Very Slow")
Blend=Default(Blend,False) # for DoubleRate. False dont blend scene change, copy previous frame, true blend.
Show=Default(Show,False)
DeInt=QTGMC(preset=Preset) Deint=(Show) ? Deint.AddBorders(0,0,0,20,$FF0000).Subtitle("QTGMC "+Preset+" Deinterlaced",Align=1) : Deint
Dbl=DoubleRate(c,Blend) Dbl =(Show) ? Dbl.AddBorders(0,0,0,20,$000000).Subtitle("DoubleRate",Align=1) : Dbl
A=ConditionalFilter(last,DeInt.SelectEven,Dbl.SelectEven,"IsCombedTIVTC","=","true")
B=ConditionalFilter(last,DeInt.SelectOdd, Dbl.SelectOdd, "IsCombedTIVTC","=","true")
Interleave(A,B)
Return Last
}

Function HybridDoubleRate_NedYad(clip c,Bool "Blend",Bool "Show") {
c
Blend=Default(Blend,False) # for DoubleRate. False dont blend scene change, copy previous frame, true blend.
Show=Default(Show,False)
NED = NNedi3(Field=-2, nns=2) # Field -2 = double rate, internal parity value to start (set by AssumeT/BFF)
DeInt= YadifMod(Order=-1,Mode=1,edeint=NED) # Order -1 = Internal Parity. Mode 1=double rate do spactial
Deint=(Show) ? Deint.AddBorders(0,0,0,20,$FF0000).Subtitle("Ned/Yad Deinterlaced",Align=1) : Deint
Dbl=DoubleRate(c,Blend) Dbl =(Show) ? Dbl.AddBorders(0,0,0,20,$000000).Subtitle("DoubleRate",Align=1) : Dbl
A=ConditionalFilter(last,DeInt.SelectEven,Dbl.SelectEven,"IsCombedTIVTC","=","true")
B=ConditionalFilter(last,DeInt.SelectOdd, Dbl.SelectOdd, "IsCombedTIVTC","=","true")
Interleave(A,B)
Return Last
}


VideoFileName ="D:\BAB-59\VIDEO_TS\bab59.d2v"
MPEG2Source(VideoFileName)
AssumeTFF

#HybridDoubleRate_QTGMC(Preset="Slow",Show=True)
HybridDoubleRate_NedYad(Show=True)


Is really pretty good.
Deinterlace interlaced sections, and MC doubled framerate for progressive sections.
Perhaps change YdifMod to YadifMod2


EDIT: something I was playing with (Work in Progress - not sure if in working condition or not)


vExt = GetFilenameExtension(VideoFileName)

If(vExt == ".dgi") { DGSource(VideoFileName) }
Else { Mpeg2Source(VideoFileName)}


AudioExt=RT_GetFileExtension(AudioFileName)

Audio= (AudioExt==".ac3") ? NICAC3Source(AudioFileName,channels=2,DRC=0)
\ : (AudioExt==".mpa"||AudioExt=="mp1"||AudioExt==".mp2"||AudioExt==".mp3") ? NicMPG123Source(AudioFileName,Normalize=False)
\ : (AudioExt==".wav") ? RaWavSource(AudioFileName)
\ : (AudioExt==".dts") ? NicDTSSource(AudioFileName)
\ : (AudioExt==".w64") ? RaWavSource(AudioFileName,samplerate=6)
\ : 0

Assert(!isInt(Audio),"NO AUDIO")


(!isInt(Audio)) ? AudioDub(Audio).DelayAudio(AudioDelay).Trim(0,0) : NOP # Trim, chop/add audio to length

(!isInt(Audio) && AudioRate() <> 44100) ? ResampleAudio(44100) : NOP

####### CONFIG ##########

/*
PalHybridToProgressive().

Optional:
Calls TFM() to match fields for Phase Shifted. [When showing Stacked result, shows original pre-TFM clip as Src]
Calls Spotless() on Separated Fields and re-weaves. [more temporally stable than separate calls for interlaced/progressive]

IsCombedTIVTC() Interlaced de-interlaced via YadifMod2, Progressive double rated via JohnFPS() [even fields Lossless].

Optional:
McDegrainSharp() on now fully progressive result. [also helps smooth and migrate detail into even result frames when returning singlerate (well thats the idea anyway)].

*/



If(vExt == ".d2v") {
TFM(d2v=VideoFileName) # field match, fix Perverse Telecine + other crap
} Else {
TFM()
}


return last

DBLRATE = True # Double Rate result.
DOTFM = false # Basic fix phase shifted
TFM_Mode = 0
DS_RADT = 2 # Spotless Radius
DS_THSAD = 128*(8/2*8/2) # noise + small spots on interlaced [255*(8/2*8/2) / 2 : /2 for interlaced field despot]
DS_PEL = 1 #
CMB_CTHRESH = 9 # 9)
CMB_MI = 80 # 80)
CMB_Chroma = False # False)
CMB_BlockX = 16 # 16)
CMB_BlockY = 16 # 16)
CMB_Metric = 1 # 0)
MCD_FRAMES = 1 #
MCD_CSHARP = 0.3 #
Show = True # True to switch on subs etc
Stack = True # True to Show Source as well as result (If Show)

# Requires setting Field Order before calling.
PalHybridToProgressive(DBLRATE, DoTfm=DOTFM,TFM_mode=TFM_Mode, DS_RadT=1, DS_ThSAD=DS_THSAD,DS_Pel=DS_PEL,CMB_CThresh=CMB_CTHRESH,CMB_Mi=CMB_MI,CMB_Chroma=CMB_CHROMA,CMB_Metric=CMB_Metric,Mcd_Frames=MCD_FRAMES,Mcd_Csharp=MCD_CSHARP,Show=SHOW,Stack=STACK)

Return Last

Prefetch(4)
Return Last

Function PalHybridToProgressive(clip c, Bool "DblRate",bool "Chroma",
\ Bool "DoTfm", Int "TFM_Mode",
\ Int "DS_RadT", Int "DS_ThSAD", Int "DS_ThSAD2", Int "DS_Pel", Int "DS_BlkSz", Int "DS_TM", String "DS_Dc", [* Spotless Args *]
\ Int "CMB_CThresh",Int "CMB_MI",Bool "CMB_Chroma", Int "CMB_BlockX",Int "CMB_BlockY",int "CMB_Metric", [* IsCombedTIVTC *]
\ Int "MCD_Frames", Float "MCD_CSharp", [* McDegrainSharp *]
\ Bool "Show", Bool "Stack" [* Debug *]
\ )
{
DblRate = Default(DblRate, True)
Chroma = Default(Chroma, True) # Make False for Greyscale.
#
DoTfm = Default(DoTfm,False) # False) True=Field matching. Basic fix for Phase Shifted (AKA Perverse) Telecine
TFM_Mode = Default(TFM_Mode,1) # 0) If DoTfm then TFM(Mode=TFM_Mode). If more exotic TFM() required, then set DoTfm=False & call Your Tfm() before this function.
# SpotLess, Set frame radius DS_RADT 1 or more to switch on.
DS_RadT = Default(DS_RadT, 0) # 0) SpotLess temporal radius (spots on RadT consecutive frames)
DS_ThSAD = Default(DS_ThSAD, 255 * (8/2 * 8/2)) # 255 * (8/2 * 8/2) = 4080 = 1/4 of 8x8 block @ 255 or Maybe eg 24 * (8*8) = 1536 for general noise. ::: Spotless/MvTools default = 10,000, about 156*(8*8)
DS_ThSAD2 = Default(DS_ThSAD2, DS_ThSAD - ((DS_RadT-1)*(8*8))) # A bit less.
DS_Pel = Default(DS_Pel, 2) # 2), or max = 4
DS_BlkSz = Default(DS_BlkSz, 8) # 8) Maybe dont change
DS_Tm = Default(DS_Tm, False) # False). TrueMotion, some like true, some like False.
DS_Dc = Default(DS_Dc,"RemoveGrain(22).Blur(0.3)")

# CombedTIVTC args, Defaults, 1st after comment hash.
CMB_CThresh = Default(CMB_CThresh, 8) # 8), Area combing threshold [ ~ 8 -> 12].
# Valid settings are from -1 (every pixel will be detected as combed) to 255 (no pixel will be detected as combed).
# This is basically a pixel difference value. A good range is between 8 to 12.
CMB_Mi = Default(CMB_Mi, 80) # 80), Number of combed pixels inside any of the BlockX by BlockY size blocks on the frame, for the frame to be detected as combed.
CMB_Chroma = Default(CMB_Chroma,False) #
CMB_BlockX = Default(CMB_BlockX, 16) # 16), X-axis size of the window used during combed frame detection.
CMB_BlockY = Default(CMB_BlockY, 16) # 16), Y-axis size of the window used during combed frame detection.
CMB_Metric = Default(CMB_Metric,1) #
# So in any single block, if 85[MI] out of 256[BlockX x BlockY] pixels pass CThresh as combed, then is Interlaced.
#
MCD_Frames = Default(MCD_Frames, 0) # 0) Acts on both Deinterlaced and JohnFPS doubled Progressive frames. McDegrainSharp(frames=MCD_Frames), (0=Dont McDegrainSharp)
MCD_CSharp = Default(MCD_CSharp, 0.3) # 0.3) McDegrainSharp() , defaults to 0.6 in McdegrainSharp.

#
Show = Default(Show,False) # Show Titlebar and Deinterlaced Sub.
Stack = Default(Stack,True) # Shows Src as well as result [Ignored if Show=False]
###
c
Stack = (Show&&Stack)
Src = Last
myName = "PalHybridToProgressive: "
Assert(!c.Is420 || Height % 4 == 0,myName+"Interlaced Height MUST be mod 4")

COMBDET = "IsCombedTIVTC(cthresh="+string(CMB_cthresh)+",MI="+String(CMB_MI)+",chroma="+String(CMB_Chroma)+",blockx="+String(CMB_blockx)+",blocky="+String(CMB_blocky)+",metric="+String(CMB_metric)+")"

MatchedSrc = (DoTfm) ? Src.TFM(Mode=TFM_Mode,PP=0,Slow=1,mchroma=false,micMatching=0) : Src

# Field based despotting, for both interlace and progressive [avoid inconstancy between interlaced and progressive]
if(DS_RadT>0) {
DeSpot_E = MatchedSrc.SeparateFields.SelectEven.SpotLess(Radt=DS_RadT,thsad=DS_ThSAD,thsad2=DS_ThSAD2,Pel=DS_Pel,chroma=Chroma,blksz=DS_BlkSz,tm=DS_Tm,glob=True,dc=MatchedSrc.SeparateFields.SelectEven.Eval(DS_Dc))
DeSpot_O = MatchedSrc.SeparateFields.SelectOdd.SpotLess( Radt=DS_RadT,thsad=DS_ThSAD,thsad2=DS_ThSAD2,Pel=DS_Pel,chroma=Chroma,blksz=DS_BlkSz,tm=DS_Tm,glob=True,dc=MatchedSrc.SeparateFields.SelectOdd.Eval (DS_Dc))
DeSpot = Interleave(DeSpot_E,DeSpot_O).Weave
} Else { DeSpot = MatchedSrc }

# Deinterlaced = DeSpot.YadifMod2(Order=-1,Mode=1,edeint=DeSpot.NNedi3(Field=-2, nns=2)) # Order -1 = Internal Parity. Mode 1=double rate do spatial : Field-2=double rate internal parity,
Deinterlaced = DeSpot.BWDif(Field=-2,edeint=DeSpot.NNedi3(Field=-2, nns=2)) # field -2=Double rate internal parity.
# Deinterlaced = DeSpot.QTGMC(Preset="fast",NoisePreset="Fast",SourceMatch=2,Lossless=2,EZKeepGrain=0.4,Sharpness=0.1, tr2=0)

Progressive = Despot.JohnFPS()

DoubleRateE = GConditionalFilter(MatchedSrc, Deinterlaced.SelectEven, Progressive.SelectEven, COMBDET,"=","true")
DoubleRateO = GConditionalFilter(MatchedSrc, Deinterlaced.SelectOdd, Progressive.SelectOdd, COMBDET,"=","true")
DoubleRate = Interleave(DoubleRateE,DoubleRateO)
Last = (MCD_Frames>0) ? DoubleRate.McDeGrainSharp(frames=MCD_Frames,csharp=MCD_CSharp,chroma=Chroma) : DoubleRate # McDegrainSharp on resultant doublerate Progressive

if(SHOW) {
Tit = (!DblRate) ? "SingleRate" : "DoubleRate"
SrcD = Interleave(Src,Src)
MatchedSrcD = Interleave(MatchedSrc,MatchedSrc)
ResultBar_K = Last.BlankClip(height=20,Color=$000000).ScriptClip("""Subtitle(""""+"(P)"+Tit+"""")""")
ResultBar_R = Last.BlankClip(height=20,Color=$FF0000).ScriptClip("""Subtitle(""""+"(I)"+Tit+"""")""")
ResultBar = GConditionalFilter(MatchedSrcD, ResultBar_R, ResultBar_K, COMBDET,"=","true")
Last = StackVertical(ResultBar,Last)
if(Stack) {
Tit = (!DblRate) ? "Src" : "Src (DblRate:Dupes)"
if(DoTfm) {
bpc = Src.BitsPerComponent()
Src8D = (bpc==8) ? SrcD : SrcD.ConvertBits(8)
MSrc8D = (bpc==8) ? MatchedSrcD : MatchedSrcD.ConvertBits(8)
LftWin_A = StackVertical(Last.BlankClip(height=20).ScriptClip("""Subtitle(""""+Tit+"""")"""),Src8D)
WW_L = (LftWin_A.Width / 4) * 2
WW_R = LftWin_A.Width - WW_L
LftWin_BL = LftWin_A.Crop(0,0,WW_L,0)
LftWin_BR = StackVertical(MSrc8D.BlankClip(Width=WW_R,height=20,Color=$0000FF).Subtitle("TFM"),MSrc8D.Crop(WW_R,0,0,0))
LftWin_B = StackHorizontal(LftWin_BL,LftWin_BR)
LftWin = LftWin_A.GConditionalFilter(LftWin_A,LftWin_B,"LumaDifference(Src8D,MSrc8D)","=","0.0",Args="LftWin_B,Src8D,MSrc8D",Local=True)
#SSS="return (LumaDifference(Src8D,MSrc8D) == 0.0) ? Last : LftWin_B"
#LftWin = LftWin_A.GScriptClip(SSS ,Args="LftWin_B,Src8D,MSrc8D",Local=True)
} Else {
LftBar = Last.BlankClip(height=20,Color=$000000).ScriptClip("""Subtitle(""""+Tit+"""")""")
LftWin=StackVertical(LftBar,SrcD)
}
StackHorizontal(LftWin,Last)
}
}
Return ((DblRate) ? Last : Last.SelectEven).AudioDubEx(Src)
}






Function GetFilenameExtension(String fn) {
fn=fn.RevStr i1=fn.FindStr("\") i2=fn.FindStr("/")
i=(i1==0) ? i2 : (i2==0) ? i1 : min(i1,i2)
fn=(i>0) ? Fn.LeftStr(i-1) : fn
i=fn.FindStr(".")
Return (i>0)?fn.LeftStr(i).RevStr:""
}

# Stack Overhead Subtitle Text, with optional FrameNumber shown.
Function TSub(clip c,string Tit,Bool "ShowFrameNo",Int "Col"){
c.BlankClip(height=20,Color=Default(Col,0))
(Default(ShowFrameNo,False))?ScriptClip("""Subtitle(String(current_frame,"%.f] """+Tit+""""))"""):Trim(0,-1).Subtitle(Tit)
Return StackVertical(c).AudioDubEx(c)
}


EDIT: Above EDITED

EDIT: qCombed() v1.03, mod of IsCombed (c)Donald Graft.:- https://forum.doom9.org/showthread.php?p=1776495#post1776495

flossy_cake
15th November 2022, 06:49
I couldn't get DG's IsCombed() working on my system, it always returns false regardless of threshold param. But your qCombed mod works -- cheers. I'll have to play around with it for a few hours to see what it thinks of various content. Preliminary results are that it is similar to IsCombedTIVTC but with a lower threshold.

Honestly though I'm a bit frustrated as I can't seem to get a grip on how NTSC soft telecine actually works. For instance, do the repeat flags mean repeat FIELD or repeat FRAME? Is the stream really 24p with repeat flags, or is it the same 30i stream but with duplicate fields simply containing no picture data and just a "repeat me" flag. One source filter behaves different to another even with the same "repeat" param, so I can't even do experiments to get enough data to make a reliable inference.

Anyway, I decided to dig out my old Sony DVD player to see how it handles it. The test video was S03E01 of NTSC Caroline in the City (from which that laundry scene was taken). The rest of that season is hard telecined, so I can easily compare how the DVD player handles both types.

The hard telecined episodes are motion compensated deinterlaced (same as bwdif with threshold set to a value of around 2-3). So static stuff gets weave, anything that moves drops to 240p. Therefore on hard telecine content, TFM is producing superior results compared to my DVD player, and this is highly satisfying. The only issue with TFM is that because some scenes begin on a combed frame, the first field of the scene is only a half image without any other field to match it to, so it gets dropped, resulting in a repeated frame at the beginning of some scene changes. This is actually noticeable and kind of annoying, but I think still preferable to 240p on motion. I've tried to get TDecimate to produce a blend on such frames but couldn't get it to work reliably. Played around with the scene threshold params too but couldn't find the magic setting.

As for the soft telecined episodes, those seem to be handled better by the DVD player: progressive frames are presented unaltered, while any combing on scene changes is interpolated. And it seems to get this perfect -- never interpolates when it shouldnt, never weaves when it shouldn't. The final output format of the DVD player is p60 though, so 3:2 judder. But all frames are progressive and contain maximum resolution available at all times. I'm not able to achieve this with TFM or TDecimate unfortunately, so far.

Seems to be an issue with the source filter. I think the source filter needs to signal repeat FIELDS correctly so that downstream knows which exact fields need to be interpolated. I can't seem to get this happening, so for now I'm just forcing the soft telecined episodes to hard telecined by setting "obey repeat flag" to true in the source filter, and letting TFM and TDecimate convert it back to 24p again.

I'm not keen on adding a lot of extra post processing like additional decombing or deint passes and such, as those can degrade the image and I'm yet to find a combing detection filter that is reliable enough to avoid false positives and therefore cause unnecessary drops to 240p (or conversely, failing to detect combing).

So I keep coming back to this idea that the source filter needs to flag FIELDS as needing interpolation, and the downstream processor/renderer needs to use that to decide when to interpolate FIELDS. And, I need this to be done in realtime, just like with a DVD player. This seems possible in theory, but in practice?

StainlessS
15th November 2022, 10:10
do the repeat flags mean repeat FIELD or repeat FRAME?
I believe only fields are repeated (but I live in pal land and rarely have NTSC 'stuff'.)

So I keep coming back to this idea that the source filter needs to flag FIELDS as needing interpolation, and the downstream processor/renderer needs to use that to decide when to interpolate FIELDS.
I think that is why its best to use

d2v = "..."
Mpeg2Source(d2v)
TFM(d2v=d2v,...) # maybe PP = 0 for no post processing

tormento
15th November 2022, 11:01
As I am getting mad at Cowboy Bebop, I need your help as expert "defielders". :p

There have been different attempts in the past but nowadays we have a lot more of powerful plugins, so I decided to give it a personal run.

The video is an "intentional" mix of 23.976p (animations, the 80% of the video), 29.97p (pannings) and 60i (CGI), all soft tagged as 29.97p. The author tells us that that was the best way to preserve the "feeling" and "crispness" of the anime.

I'd like to have a uniform fps, possibly a standard one, such as 23.976p being the most used there, without sacrificing quality too much (CGI has different images at every 60i frame).

Can you, please, help me with a proper script to deal with it?

Here (https://krakenfiles.com/view/ZCTElUsXUN/file.html) is a sample.

PoeBear
16th November 2022, 07:38
LWLibavVideoSource("Bebop.m2ts")
TFM().TDecimate()

Unless you're going to VFR or comb through them by hand and do something special with the 29.97/59.94 scenes, that's all you really can do. Your output would match how the US Blu-ray was done

tormento
16th November 2022, 17:52
Your output would match how the US Blu-ray was done
That has terrible rendering of the 60i frames. :(

flossy_cake
17th November 2022, 05:54
I'm working on a realtime solution for such "mixed cadence" content, where it will output all sequences at 60p, such that the 24p sequences become 3:2, 30p sections become 2:2, and 60i sections are 1:1. All in a 60p "container". hello_hello managed to solve this already by making it into a VFR file using timecode file, but it wasn't ideal for me as I wanted a realtime solution that didn't require transcoding (generation loss).

The logic of it is actually simpler than I was expecting: just choose either TFM.TDecimate.ChangeFPS(60000,1001) or TFM.BWDIF(field=-2, thr=3) depending on whether the last 5 consecutive frames of the output of TFM are unique, i.e if the YDiff or CFrameDiff are all above a certain value for the last 5 frames. The hard part is trying to get Avisynth to do what I want it to do on a per-frame basis given the quirks and limitations of its runtime functions, but, I think I've finally got it doing what I want using a combination of ScriptClip and FrameEvaluate. But I'm not optimistic as I really need to "look ahead" 5 frames otherwise the transition between 24p and 30p/60i sections could have a stutter. And the per-frame evaluations need to be done in a controlled order, which is difficult given how Avisynth handles multithreading (the docs warn that messaging through global variables is "unsafe" inside a runtime function due to this).

What would really help though is if Tritical's CFrameDiff had a parameter to calculate the diff between current frame and n frames ahead, just like the internal YDiffToNext does. Because I have a feeling YDiffToNext is not going to be sufficient & Tritical is using more robust metrics with CFrameDiff (and even that gets some false positives eg. if there's composite video dotcrawl that changes every field -- coincidentally that's why sometimes the duplicate frame in the TFM stream looks ever so slightly different -- because it's matching it with a field that although correctly matched in the sense it comes from the same frame, it comes from a different "copy" of that field, i.e the third of the "3" in "3:2" sequence instead of the first).

PoeBear
17th November 2022, 07:50
That has terrible rendering of the 60i frames. :(

Then you can edit out all the 60i parts by hand, and use that Dogway script on them. It's always going to look rough unless you interpolate more frames before bringing back down to 23.976

Dogway
17th November 2022, 10:09
The video is an "intentional" mix of 23.976p (animations, the 80% of the video), 29.97p (pannings) and 60i (CGI), all soft tagged as 29.97p. The author tells us that that was the best way to preserve the "feeling" and "crispness" of the anime.

I'd like to have a uniform fps, possibly a standard one, such as 23.976p being the most used there, without sacrificing quality too much (CGI has different images at every 60i frame).

Can you, please, help me with a proper script to deal with it?

Here (https://krakenfiles.com/view/ZCTElUsXUN/file.html) is a sample.

Now your explanation made it more clear and with the source I could have a look.
Interesting practice as it has been a very long time since I had to deal with fields...

The script below treats each mode separately, augmenting them to 60fps progressive with duplicates.

DGSource("Bebop.dgi",cl=236,ct=0,cr=236,cb=0)
src=last


### NTSC ###
N=Interleave(src,src)

### FILM ###
DGTelecide()
TDecimate(mode=1) # anime
Interleave(last,last,last)
TDecimate(1,1,6) # Decimate on longest strike so the pace shift ratio is minimal
F=last

### INTERLACED ###
src
QTGMCp(tr2=1,preset="very slow",sourcematch=2,sharpness=0.2,MatchEnhance=0.0,MatchPreset="Slow", MatchPreset2="Slow",border=false)
I=last


ClipClop(F,N,I,sCMD="N(0,5125); F(5126,5455); N(5456,9180); I(9181,9349);")

# VFR in 60fps CFR progressive

In the end you run the fabolous ClipClop to stitch them back together.
The way to look for frame numbers in this 60fps mashup is to take the source and simply:
src
Interleave(last,last)

in another tab in AvsPmod, then go through it and mark with bookmarks the frames where each mode starts.
A script for detection could be possible I think. Simply look for combed frames, if all progressive it's 29.97, if all combed it's 60i, otherwise it's telecine. It's not that easy since you have to keep into account long streaks of no movement, and also scene changes.
As I said yesterday I'm a bit busy finishing my scripts but many people can help on this regard.


A remark on augmenting FILM to 60fps, this works only because it's anime. As I observed the animation pattern goes mostly 3x3, sometimes 3x2, and rarely 2x2. The framerate augment is not linear so the animation pace can be altered but on the good side the shift is minimal 1/60 = 0.017 seconds at most every 10 frames. Or for a 3x3 pattern, multiplied by 2.5 gives 7.5x7.5 or 8x7 after 1 out of 6 decimation.
The only problematic area is when there's 30fps content going on through the windows (the asteroids), there you'll see 3 dups followed by 2 dups, and this can cause some stutter, but it would be the same if played on TV.

In my opinion this is better than interpolation, which doesn't work nice for anime.
It would involve interpolating 24p to 120p, then selectevery(4,0).Interleave(last,last)

timecode VFR I don't recommend as the TV will be jumping through refresh rates.

tormento
17th November 2022, 13:08
I'm working on a realtime solution
That would be really nice! Please keep us informed about progress.

tormento
17th November 2022, 13:24
The script below treats each mode separately, augmenting them to 60fps progressive with duplicates.
Great! Does it keep the original duration? I don't want to mess with audio or subs.
in another tab in AvsPmod, then go through it and mark with bookmarks the frames where each mode starts.
This point is obscure to me. Using interleave(last,last) outputs a 59.97 video, how is possible to find the exact places where fps changes?
A script for detection could be possible I think.
It would be much better, please ;) That script could be really usefulm even in ExTools, to have a swiss knife to deal with "variable" fps sources.

Reel.Deel
17th November 2022, 18:11
@tormento

There's NTSCanalyze (https://forum.doom9.org/showthread.php?p=1251823#post1251823), from experience it does an OK job, but it's prone to some errors on some frames. There was a discussion on how to improve it here (https://forum.doom9.org/showthread.php?t=173905).

flossy_cake
18th November 2022, 06:54
Yeah the big issue is dealing with false positives and false negatives. And @Dogway mentioned also: "It's not that easy since you have to keep into account long streaks of no movement, and also scene changes". If the content is like 90% 24p and 10% 30p/60i then I suppose you could bias the error in the direction of assuming 24p in such "when in doubt" scenarios. eg. if YDiff or CFrameDiff of last 5 frames are ALL below some threshold, then treat it as 24p. In this case 24p sections should look good, but slight stutter when there is very small amount of motion on 30p sections.

flossy_cake
18th November 2022, 14:38
There seems to be a bug with TFM's motion adaptive deinterlacing, eg. when PP=6 (the default). It seems to drop the entire frame to half vertical resolution when it detects combing, when it should only be doing that for moving parts of the image, as that is the whole "motion adaptive" feature (otherwise I think it would have been called field discarding or drop field or something like that). To reproduce it set cthresh=-1 so that TFM thinks everything is combed.

It seems we can work around this though with eg. clip2=bwdif, which then seems to activate TFM's better internal logic of only using deinterlaced pixels for moving parts of the image, and those pixels then become bwdif's pixels. edit: actually now that I think about it, it's probably just replacing the entire frame with bwdif's pixels when isCombed, but I can't tell for sure. If it were the case, it just means TFM's motion adaptive deinterlacing is extremely primitive... but that doesn't seem likely either given the author's other work with TDeint. Still, I don't know for sure.

Also on the other issue of scene changes having a repeat frame due to orphaned field, that seems workaroundable with scthresh=100, which causes combed frames on scene changes to stay combed, so that they get picked up by PP=6 & therefore clip2=bwdif'd. With this setting, image quality now is on par with my Sony DVD player for such soft telecined content which orphaned fields on scene changes - good.

flossy_cake
18th November 2022, 19:04
I'm working on a realtime solution for such "mixed cadence" content, where it will output all sequences at 60p, such that the 24p sequences become 3:2, 30p sections become 2:2, and 60i sections are 1:1. All in a 60p "container". hello_hello managed to solve this already by making it into a VFR file using timecode file, but it wasn't ideal for me as I wanted a realtime solution that didn't require transcoding (generation loss).

Wow it looks like TFM can do this all on its own!

Test clip: https://drive.google.com/file/d/1KdE0np8016zr7ovRassdbH7OtbKU7e-a/view?usp=sharing


source = "480i 3-2 and 1-1.mkv"

LWLibavVideoSource(source=source, stream_index=-1, repeat=true, cache=false)

TFM(last.ChangeFPS(60000,1001), mode=5, PP=6, cthresh=3, MI=80,
\ scthresh=100, slow=2, ubsco=false, mmsco=false, micmatching=4,
\ clip2=bwdif(last, field=3, thr=3), display=true)

LanczosResize(720,540)


The above assumes you have the latest BWDIF which has the new thr param: https://github.com/Asd-g/AviSynth-BWDIF/releases. Also its negative field param values won't work anymore if the file has _FieldBased=0 (progressive) which soft-telecined content seems to have. That's why I've set it to 3 instead of -2 (this particular clip is hard-telecined though).

Still have the issue with combing detection not being quite good enough on actors mouths when they are sitting perfectly still (eg. the female newsreader in the clip) their mouth will get combed cause there just isn't enough motion. That's why I've lowered cthresh from 9 to 3, and it still fails a little bit there. If your content has a lot of 60i you might want to lower it to 2 and then lower MI as well to 48-64 or something. But then you'll probably get more false positives on 24p sections and have resolution dropping to 240p on motion when it shouldn't.

edit: BWDIF and yadifmod2 seem to have an issue where they can't detect dynamic changes to the field order (git issue (https://github.com/Asd-g/AviSynth-BWDIF/issues/4#issuecomment-1321062436)). TDeint(mode=1) and Bob() seem to be fine and can detect dynamic field order changes. The test clip in this post is not affected as the field order is static.