Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Usage

Reply
 
Thread Tools Search this Thread Display Modes
Old 11th September 2018, 13:32   #1  |  Link
Frank62
Registered User
 
Join Date: Mar 2017
Posts: 29
U-V-Swap issue

Hi,

I got copies from older tape recordings (1'') of a series. About ten to 30 times in more than one episode a problem with the colours occurs: Obviously U and V are swapped.

I first thought I could build a detector for this, seemed not too hard because the right black margin expands a few pixels each time the swapping occurs. So far so good, BUT:

The channels are not swapped in the whole frame. Only rectangular parts of the picture, the rest keeps correct.

Has anyone an idea how to build a mask that is transparent only where UV swapping occurs and opaque on the rest of the picture?

Thanks for any idea.

Last edited by Frank62; 11th September 2018 at 13:37.
Frank62 is offline   Reply With Quote
Old 11th September 2018, 13:51   #2  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
I'm sure that somebody would like to take a gander at your peculiar clip [if only for the 'wierd clip collection'], maybe post a sample,
no idea how to do as you require, sorry.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???
StainlessS is offline   Reply With Quote
Old 11th September 2018, 14:05   #3  |  Link
Frank62
Registered User
 
Join Date: Mar 2017
Posts: 29




As you can see the areas also change, that's the problem.
Frank62 is offline   Reply With Quote
Old 11th September 2018, 14:19   #4  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
Is the block 'mirrored' on one of the preceding/postceding frames ? (are you getting chroma from the wrong frame, is it at scene change).

Post a bit of the clip if you can (not just an image).

EDIT: Also try another source filter, and try load into eg VDub2, same ?
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???
StainlessS is offline   Reply With Quote
Old 11th September 2018, 14:35   #5  |  Link
Frank62
Registered User
 
Join Date: Mar 2017
Posts: 29
No scenechange. The chroma is really the swapped chroma from the exact frame. Funny is that the left border of the swapping is fluent, no exact border. If I only could detect the area, I had the rest of the solution in mind already.
This is already from the restored clip, will post a original short clip later.

Yes, I also thought of decoding problems, but from 26 episodes the most do not have this error. Anyway I tried to open the mxf (containing mpeg2) after lwlibavvideosource also by first demuxing with ffmpeg and then indexing with the most reliable DGIndex, as I did earlier, before LSMASH times. Same problem.
Frank62 is offline   Reply With Quote
Old 11th September 2018, 16:10   #6  |  Link
Frank62
Registered User
 
Join Date: Mar 2017
Posts: 29
A short sample:
https://we.tl/t-zBuudR6KqL
Frank62 is offline   Reply With Quote
Old 11th September 2018, 20:05   #7  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
Strange.
As well as black rhs border swelling on problem, also significant reduction in chroma saturation for both U and V channels when problem occurs.
(Histogram(mode="levels")
When color comes back, seems to jump up from the bottom, (squares your mention), like I/Q (color burst or whatever it is in TV signal), aint quite in sync,
maybe some TV engineer could give better insight.

EDIT:
Code:
AVISource("D:\UVSwap.mp4.AVI")
ORG=LAst
A=Trim(0,20)
B=Trim(21,33)
C=Trim(34,0)
B=B.SwapUV.Subtitle("***",Align=5)
Fx=A++B++C
ORG=ORG.Histogram(Mode="Levels")
Fx=FX.Histogram(Mode="Levels")
StackVertical(ORG,Fx)
EDIT: What is approx max duration of the probs ? (in sample about 13 frames)

EDIT: Added separate histograms to each clip in code block.

EDIT: "Aint quite in sync",
I'm sure that you've seen tumbling picture on old analogue TV, disappears off top of screen only to reappear up from the bottom,
is kinda like that, TV / capture card could not lock to the signal.
[EDIT: Lost both horizontal and vertical sync, but just for chroma]
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 13th September 2018 at 16:11.
StainlessS is offline   Reply With Quote
Old 11th September 2018, 21:26   #8  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
This does detect, to some extent.

Code:
AVISource("D:\UVSwap.mp4.AVI").ConvertToYV24
### Prep
Crop_L=10 CROP_T=36 CROP_R=-20 CROP_B=-4
x0=701 x1=702 x2=703 x3=704
MID = Crop(Crop_L,CROP_T,CROP_R,CROP_B) # Crop off all border crap
YC  = MID.ConvertToY8 # available if needed
UC  = MID.UToY8
VC  = MID.VToY8
### Config ###
GAP=0
Y0_TH=24.0  # AveLuma of RHS vertical column of pixels @ x0, ie border. [Border creeps in on damage]
U_TH =17.0  # 17.0, Percent population in range 128-GAP -> 128+GAP      [On damage, gets less saturated, more chroma at 128, less outside of 128]
V_TH =23.5  # 23.5, Percent population in range 128-GAP -> 128+GAP      [Ditto]
ClipClopName=  "ClipClopCmd.txt"
FrameSelName=  "FrameSelFrames.txt"
RangeName =    "Ranges.txt"
WRITE_ENDS=True # If RangeName != "" then Also write RangeName+"_PRE.TXT" and RangeName+"_POST.TXT" frame before 1st & frame after last BAD frames.
                # Can use FrameSel to 'pull out' bad frame plus up to 5 frames either side of bad frame (total 11 frames incl bad frame).
SHOW = True # True Show Metrics
FLAGS= True # True Show Frame Number and Flags (Also Shown if SHOW=False)
###########################
PREV_BINGO=False
PREV_START=-1
PREV_FRAME=-1
ClipClopName=(ClipClopName!="") ? RT_GetFullPathName(ClipClopName): ""
FrameSelName=(FrameSelName!="") ? RT_GetFullPathName(FrameSelName): ""
RangeName=   (RangeName!="")    ? RT_GetFullPathName(RangeName)   : ""
DORANGES=RangeName!=""
Pre_Name=(DORANGES)?RangeName+"_PRE.TXT":""
Post_Name=(DORANGES)?RangeName+"_POST.TXT":""
(ClipClopName!="") ? RT_FileDelete(ClipClopName)     : NOP
(FrameSelName!="") ? RT_FileDelete(FrameSelName)     : NOP
(RangeName!="")    ? RT_FileDelete(RangeName)        : NOP
(Pre_Name!="")    ? RT_FileDelete(Pre_Name)        : NOP
(Post_Name!="")      ? RT_FileDelete(Post_Name)          : NOP
HILITE=RT_Ord("!")    # RT_Subtitle Hilite control code
NORM  =RT_Ord("-")    # RT_Subtitle Normal white text control code
LOLITE=RT_Ord("L")    # RT_Subtitle LoLite/DIM control code

SSS="""
    n=current_frame
    y0=RT_AverageLuma(x=x0,y=CROP_T,h=CROP_B,w=1)
    y1=RT_AverageLuma(x=x1,y=CROP_T,h=CROP_B,w=1)
    y2=RT_AverageLuma(x=x2,y=CROP_T,h=CROP_B,w=1)
    y3=RT_AverageLuma(x=x3,y=CROP_T,h=CROP_B,w=1)
    #
    Y=YC.RT_AverageLuma
    U=UC.RT_YInRange(lo=128-GAP,hi=128+GAP) * 100.0 # %
    V=VC.RT_YInRange(lo=128-GAP,hi=128+GAP) * 100.0 # %
    T1 = (Y0<Y0_TH)  T2 = (U>U_TH)  T3 = (V>V_TH)
    BINGO=(T1 && T2 && T3)
    T1_C=(T1)?HILITE:NORM   T2_C=(T2)?HILITE:NORM   T3_C=(T3)?HILITE:NORM   # Hilite control codes for Metrics
    F1_C=(T1)?NORM:LOLITE   F2_C=(T2)?NORM:LOLITE   F3_C=(T3)?NORM:LOLITE F_BINGO=(BINGO)?HILITE:LOLITE # Ctrl codes for FLAGS
    (FLAGS)?RT_Subtitle("%d] \a%cB\a%cU\a%cV \a%c*",n,F1_C,F2_C,F3_C,F_BINGO):NOP
    (SHOW)?RT_Subtitle("Y at RHS:  \a%cx0=%.2f\a- x1=%.2f x2=%.2f x3=%.2f",T1_C,y0,y1,y2,y3,align=5,Y=5*20):NOP
    (SHOW)?RT_Subtitle("YAve=%.2f : \a%cU=%.2f%%\a- : \a%cV=%.2f%%\a-",Y,T2_C,U,T3_C,V,align=5,Y=8*20):NOP
    (SHOW&&BINGO)?SUBTITLE("!!!BINGO!!!",Align=5,size=48):NOP
    (BINGO&&ClipClopName!="") ? RT_WriteFile(ClipClopName,"1 %d",n,Append=True) : NOP # Use ClipClop to replace frame with same from clip Index 1.
    (BINGO&&FrameSelName!="") ? RT_WriteFile(FrameSelName,"%d",n,Append=True)   : NOP # Use FrameSel Frame number only file.
    if(DORANGES) {
        If(PREV_FRAME!=n-1) { DORANGES = False } # User jumped about so all bets are OFF
        Else {
            if(BINGO) {
                 if(!PREV_BINGO) { # New Start
                    PREV_START=n
                }
            } Else {
                 if(PREV_BINGO) {  # New End
                    RT_WriteFile(RangeName,"%d,%d",PREV_START,n-1,Append=True)     # Write Range
                    if(WRITE_ENDS) {
                        RT_WriteFile(Pre_Name,"%d",PREV_START-1,Append=True)        # Write pre BAD frame
                        RT_WriteFile(Post_Name,"%d",n,Append=True)                  # Write post BAD frame
                    }
                    PREV_START=-1
                 }
            }
            PREV_BINGO=BINGO
        }
        PREV_FRAME=n
    }
    Return last
"""
Return Scriptclip(SSS)
The triple detector numbers shown in Orange in metrics, for x0, U, and V.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 12th September 2018 at 15:32.
StainlessS is offline   Reply With Quote
Old 12th September 2018, 11:28   #9  |  Link
Frank62
Registered User
 
Join Date: Mar 2017
Posts: 29
Wow! That looks interesting! I also detected meanwhile beginning, ends and single frame swaps, but this seems a way to detect everything between also without need for programming some logic outside Avisynth.
Thanks a lot!
No time to test this the whole day but I will report how it works earliest tomorrow evening.

Frank62 is offline   Reply With Quote
Old 12th September 2018, 13:57   #10  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
Have updated above script, writes Pre bad range and post bad range frames (ie frame before bad range and also frame after).

Can use FrameSel to pull out eg pre-bad + some extra frames, and simple fix might be to repair using frame before pre-bad,
same type thing for frame after bad range.

From FrameSel
Code:
FrameSel(Clip, int F1, ... , int Fn, string 'scmd',string 'cmd', bool 'show', bool 'ver',bool "reject",bool "ordered",
            \ bool "debug", int "Extract"=1)
Code:
        Extract Int, Default 1, MUST be ODD, 1 to 11. Error if not default 1 AND neither Ordered nor Reject == True.
                Let us call the UNIQUE resultant frames after Ordered and/or Reject Processing 'Target' frames.
                The number of frames pulled out on either side of Target frame is Extract / 2 (integer divide), so when Extract=3, it will
                extract 1 frame before target, the Target frame, and 1 frame after target, for each and every Target frame.
                This arg allows you to select eg 3 frames for each Target frame, the previous frame, Target frame and next frame.
                May be of use to extract bad frames together with eg 1 frame either side for saving as bitmaps and editing
                in some kind of RotoScope editor to repair bad frames using image from adjacent frames. The edited frames could
                then be re-loaded, middle one selected via SelectEvery(3,1), and then put back into original source clip via FrameRep().
                Another simple use could be when you have a clip where each frame before a scene change is bad, with Ordered=True
                and Extract=3, you pull out 3 frames, a SelectEvery(3,0) would select the frames previous to the bad frames and
                then use Framerep() to replace the bad frames with those previous to them. A SelectEvery(3,2) would select the frames
                after Target frames.
                The total number of frames pulled out of the source clip will be (Extract * number of Target frames).
                Reject is less likely to be of use with Extract, unless frame select commands specify good frames rather than bad,
                where Reject in FrameRep should also be true (same as in FrameSel, as always).
                See FrameRep() for example uses of Extract.
Code:
    C=Colorbars().Trim(0,-50).ShowFrameNumber()                     # 50 frames (0 -> 49)
    BADFRAMES = "10;20;30;40"                                       # 4 bad frames in source clip
    EXTRACT=FrameSel(C,scmd=BADFRAMES,ordered=True,extract=3)       # Extract Previous, Target and Next frames for each Target frame
    REPAIR=EXTRACT.SelectEvery(3,0)                                 # Select each frame previous to Target bad frames, 1st of each triplet
    #REPAIR=REPAIR.Invert()                                         # So we can easily see repaired frames
    Return FrameRep(C,REPAIR,scmd=BADFRAMES)                        # Fix bad frames with REPAIR clip using exact same BADFRAMES spec.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???
StainlessS is offline   Reply With Quote
Old 12th September 2018, 15:51   #11  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
Added Flags shown top LHS,
Here last bad frame of range, and the following half bad frame where only two of detector metrics satified.
(Border metric fails detect but chroma metric still detecting)
[In such case might just be able to use chroma from following frame].
Might be best to do a prescan, to establish scene cuts, and process each separately after establishing some average chroma metric
for the scene (how do we do that, considering some of scene may be bad ???).

Script updated.
Code:
A=trim(33,-1)
B=trim(34,-1)
StackVertical(A,B)
Spline36Resize(640,960)


Frame after half bad frame, ie 2 frames after last bad detect.
Code:
X=trim(35,-1)
return X.Spline36Resize(640,480)
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 12th September 2018 at 15:58.
StainlessS is offline   Reply With Quote
Old 12th September 2018, 17:42   #12  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
Modified to detect both bad range and last bad + 1 half bad frame, writing clipclop file to fix both
(assumes that detector works for complete clip, maybe does, maybe does not,
Who can tell the secret of the Black Magic Box.
Is the box of chocolates alive, or is the box of chocolates dead, you can only know when you open the box ).

Code:
#_FIX_UVSWAP_MOD.avs
AVISource("D:\UVSwap.mp4.AVI").ConvertToYV24
### Prep
Crop_L=10 CROP_T=36 CROP_R=-20 CROP_B=-4
x0=701 x1=702 x2=703 x3=704
MID = Crop(Crop_L,CROP_T,CROP_R,CROP_B) # Crop off all border crap
YC  = MID.ConvertToY8 # available if needed
UC  = MID.UToY8
VC  = MID.VToY8
### Config ###
GAP=0
Y0_TH=24.0  # AveLuma of RHS vertical column of pixels @ x0, ie border. [Border creeps in on damage]
U_TH =17.0  # 17.0, Percent population in range 128-GAP -> 128+GAP      [On damage, gets less saturated, more chroma at 128, less outside of 128]
V_TH =23.5  # 23.5, Percent population in range 128-GAP -> 128+GAP      [Ditto]
ClipClopName=  "ClipClopCmd.txt"
SHOW = True # True Show Metrics
FLAGS= True # True Show Frame Number and Flags (Also Shown if SHOW=False)
###########################
PREV_BINGO=False
PREV_START=-1
PREV_FRAME=-1
ClipClopName=(ClipClopName!="") ? RT_GetFullPathName(ClipClopName): ""
DORANGES=ClipClopName!=""
(ClipClopName!="") ? RT_FileDelete(ClipClopName)     : NOP
HILITE=RT_Ord("!")    # RT_Subtitle Hilite control code
NORM  =RT_Ord("-")    # RT_Subtitle Normal white text control code
LOLITE=RT_Ord("L")    # RT_Subtitle LoLite/DIM control code

SSS="""
    n=current_frame
    y0=RT_AverageLuma(x=x0,y=CROP_T,h=CROP_B,w=1)
    y1=RT_AverageLuma(x=x1,y=CROP_T,h=CROP_B,w=1)
    y2=RT_AverageLuma(x=x2,y=CROP_T,h=CROP_B,w=1)
    y3=RT_AverageLuma(x=x3,y=CROP_T,h=CROP_B,w=1)
    #
    Y=YC.RT_AverageLuma
    U=UC.RT_YInRange(lo=128-GAP,hi=128+GAP) * 100.0 # %
    V=VC.RT_YInRange(lo=128-GAP,hi=128+GAP) * 100.0 # %
    T1 = (Y0<Y0_TH)  T2 = (U>U_TH)  T3 = (V>V_TH)
    BINGO=(T1 && T2 && T3)
    T1_C=(T1)?HILITE:NORM   T2_C=(T2)?HILITE:NORM   T3_C=(T3)?HILITE:NORM   # Hilite control codes for Metrics
    F1_C=(T1)?NORM:LOLITE   F2_C=(T2)?NORM:LOLITE   F3_C=(T3)?NORM:LOLITE F_BINGO=(BINGO)?HILITE:LOLITE # Ctrl codes for FLAGS
    (FLAGS)?RT_Subtitle("%d] \a%cB\a%cU\a%cV \a%c*",n,F1_C,F2_C,F3_C,F_BINGO):NOP
    (SHOW)?RT_Subtitle("Y at RHS:  \a%cx0=%.2f\a- x1=%.2f x2=%.2f x3=%.2f",T1_C,y0,y1,y2,y3,align=5,Y=5*20):NOP
    (SHOW)?RT_Subtitle("YAve=%.2f : \a%cU=%.2f%%\a- : \a%cV=%.2f%%\a-",Y,T2_C,U,T3_C,V,align=5,Y=8*20):NOP
    (SHOW&&BINGO)?SUBTITLE("!!!BINGO!!!",Align=5,size=48):NOP
    if(DORANGES) {
        If(PREV_FRAME!=n-1) { DORANGES = False } # User jumped about so all bets are OFF
        Else {
            if(BINGO) {
                 if(!PREV_BINGO) { # New Start
                    PREV_START=n
                }
            } Else {
                 if(PREV_BINGO) {  # New End
                    RT_WriteFile(ClipClopName,"1 %d,%d",PREV_START,n-1,Append=True) # Write ClipClop Range to replace with clip index 1
                    if(T2 && T3) {  # Border Detect Fail
                        RT_WriteFile(ClipClopName,"2 %d",n,Append=True)             # replace End Bad + 1 frame with clip index 2 frame
                    }
                    PREV_START=-1
                 }
            }
            PREV_BINGO=BINGO
        }
        PREV_FRAME=n
    }
    Return last
"""
Scriptclip(SSS)
ClipClop repair script
Code:
# _FIX_UVSwap_MOD_ClipClop.avs
AVISource("D:\UVSwap.mp4.AVI")
ClipClopName=  "D:\ClipClopCmd.txt"
ORG=Last

CONT_U = 0  # ColorYUV U Sat adjust for bad range (0=no adjust)
CONT_V = 0  # ColorYUV V Sat adjust for bad range (0=no adjust)

Nxt=SelectEvery(1,1)              # Shift next frame to current
CN_Chroma = ORG.MergeChroma(Nxt)  # Copy Next Chroma into current, Fix End Bad + 1 half bad frame


V1 = SwapUV().ColorYUV(cont_u=CONT_U,cont_v=CONT_V)
V2 = CN_Chroma

NickNames ="""  # Psuedonyms for clips (clip index number)
    SwapUV    = 1 # Fixed Bad range clip (SwapUV with optional Chroma Sat adjustment)
    CN_Chroma = 2 # Fixed half bad end bad + 1 frame (Copy Chroma from next)
"""

SHOW=True

ClipClop(ORG,V1,V2,Cmd=ClipClopName,nickname=NickNames,show=SHOW)
StackVertical(Last,ORG)
Last bad range frame fixed by ClipClop, (Src on bottom)


Last bad range + 1 frame (half bad frame, copy chroma from next frame) fixed (src on bottom)



EDIT:
ClipClopCmd.txt to fix range Plus End Bad + 1 (Half bad) frame
Code:
1 21,33
2 34
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 12th September 2018 at 18:23.
StainlessS is offline   Reply With Quote
Old 12th September 2018, 21:23   #13  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
I might not be able to do anything else before about Saturday, here a tool to perhaps enable you to continue with detector,
eg detect scenes, get some kind of average metrics for Chroma, and mod chroma detect thresholds for current scene.

Just wrote the DBase_DetectScenes thing for this pupose.

EDIT: Below DB_FindTrim() mentions clips, rather than scenes, function was written for different purpose.

Library funcs
Code:
# ############
# DB_FindTrim.avs [Replaced with RT_DBaseFindSeq() plugin function in RT_Stats v2.0]
# DB_FindTrim Returns clip (or record number) containing movie frame Frame.
#   Search DBase for the record (clip) that contains the arg Frame, using Binary Search.
#   S_Field is the DB field that contains the first frame of the record clip.
#   E_Field is the DB field that contains the Last frame of the record clip.
#   Return of -1 = NOT FOUND.
# ############

Function DB_FindTrim(String DB,Int S_Field,Int E_Field,Int Frame) {
    IsAvsPlus=(FindStr(UCase(versionString),"AVISYNTH+")!=0) HasGScript=RT_FunctionExist("GScript")
    Assert(IsAvsPlus || HasGScript,RT_String("DB_FindTrim: Need either GScript or AVS+"))
    result = -1                                                     # Init NOT FOUND
    low     = 0
    high    = RT_DBaseRecords(DB) - 1
    GS="""
        while(low <= high) {
            mid = (low + high) / 2
            if(RT_DBaseGetField(DB,mid,E_Field) < Frame) {
                low = mid + 1
            } Else If (RT_DBaseGetField(DB,mid,S_Field) > Frame) {
                high = mid - 1
            } Else {
                low = high + 1                                      # Force exit
                Result = mid
            }
        }
    """
    HasGScript ? GScript(GS) : Eval(GS)   # Use GSCript if installed (loaded plugs override builtin)
    return result
}


Function DBase_DetectScenes(clip c,String DB,Int "SOS_Field",Int "EOS_Field",Int "OffSet",Int "thSCD1",Int "thSCD2") {
/*
    Requires RT_Stats, MVTools2, MaskTools2. (and either Avs+ or GSCript)
    Given a pre-allocated DBase (can have 0 records), with at least two int fields for SOS and EOS (Start and End Of Scene),
    will APPEND records with SOS and EOS frame numbers inserted into SOS_Field and EOS_Field fields, remaining fields of record
    will be initialized to nul, ie int=0, Float=0.0, Bool=False, Bin=0,String="".
    Will Scan clip using MvTools2 MSCDetection, and when established SOS and EOS, will write new record
    filling in SOS_Field field with (StartOfSceneFrame + Offset) and EOS_Field field with (EndOfSceneFrame + Offset).
    SOS_Field, Default 0.
    EOS_Field, Default SOS_Field+1.
    Offset,    Default 0.
    thSCD1,    Default 400, See MvTools
    thSCD2,    Default 130, See MvTools
    Returns Number of Records (ie Scenes found in clip) added to DBase.
*/
    c  myName="DBase_DetectScenes: "
    IsAvsPlus=(FindStr(UCase(versionString),"AVISYNTH+")!=0) HasGScript=RT_FunctionExist("GScript")
    HasMvTools=RT_FunctionExist("MSuper")                    HasMaskTools=RT_FunctionExist("MT_Lutxy")
    Assert(IsAvsPlus || HasGScript,RT_String("DB_FindTrim: Need either GScript or AVS+"))
    Assert(HasMVTools,RT_String("%sNeed MvTools2:-http://forum.doom9.org/showthread.php?t=131033",myName))
    Assert(HasMaskTools,RT_String("%sNeed MaskTools",myName))
    SOS_Field=Default(SOS_Field,0)
    EOS_Field=Default(EOS_Field,SOS_Field+1)
    OffSet=Default(OffSet,0)
    thSCD1=Default(thSCD1,400)  thSCD2=Default(thSCD2,130)
    FC=FrameCount
    Records=RT_DBaseRecords(DB) Fields=RT_DBaseFields(DB)    Rec=Records
    Assert(SOS_Field>=0 && SOS_Field<fields,RT_String("%sSOS_Field(%d) Does Not exist in DBase(0->%d)",myName,SOS_Field,Fields-1))
    Assert(EOS_Field>=0 && EOS_Field<fields,RT_String("%sEOS_Field(%d) Does Not exist in DBase(0->%d)",myName,EOS_Field,Fields-1))
    Assert(EOS_Field != SOS_Field,RT_String("%sEOS_Field(%d) Cannot be same as SOS_Field",myName,EOS_Field))
    Sup  = c.MSuper(pel=1,sharp=0,rfilter=2,hpad=16, vpad=16)
    BvEos= Sup.MAnalyse(isb=True,  delta=1,blksize=16)
    FvSos= Sup.MAnalyse(isb=False, delta=1,blksize=16)
    Eos  = c.MSCDetection(BvEos,thSCD1=thSCD1,thSCD2=thSCD2)
    Sos  = c.MSCDetection(FvSos,thSCD1=thSCD1,thSCD2=thSCD2)
    SC_Clip = MT_Lutxy(Eos,Sos,yexpr="y 0 == x 0 == 0 1 ? x 0 == 2 3 ? ?",u=-128,v=-128)
    LastWrE=-1
    GS="""
        For(n=0,FC-1) {
            eosos = SC_Clip.RT_AverageLuma(n,w=1,h=1).Int   # All Luma pixel = 0 =Norm, 1=EOS, 2=SOS, 3=EOS & SOS
            eosos = (n==FC-1) ? RT_BitSet(eosos,0) : eosos  # Force EOS at Last frame, fix some bugged
            if(eosos>=2 && LastWrE<n-1 && n!=0) {           # Is flagged SOS, so force any earlier non written range
                Rec=RT_DBaseExtend(DB,1)                    # Add 1 Record, nullified fields, Rec = current number of records
                RT_DBaseSetField(DB,Rec-1,SOS_Field,LastWrE+1+OFfset)
                LastWrE=n-1
                RT_DBaseSetField(DB,Rec-1,EOS_Field,LastWrE+OFfset)
            }
            if(eosos==1 || eosos==3) {                      # Flagged EOS, Write to current
                Rec=RT_DBaseExtend(DB,1)                    # Add 1 Record, nullified fields, Rec = current number of records
                RT_DBaseSetField(DB,Rec-1,SOS_Field,LastWrE+1+OFfset)
                LastWrE=n
                RT_DBaseSetField(DB,Rec-1,EOS_Field,LastWrE+OFfset)
            }
        }
    """
    HasGScript ? GScript(GS) : Eval(GS)   # Use GSCript if installed (loaded plugs override builtin)
    Return Rec-Records
}
DB_FindTrim.avs [Replaced with RT_DBaseFindSeq() plugin function in RT_Stats v2.0], so can use RT_DBaseFindSeq if you use RT_Stats v2.0, Beta.

Create DBase with scene change range data (can add some fields for other stuff, eg stored chroma thresh to use in each detector stage
(generated by some kind of chroma average script).

DBase Generator (after generated, can fill in your additional empty fields via some eg chroma thresh based on average)
Code:
# Create DBase
AVISource("D:\Parade.AVI")
DB="D:\Parade.DB"
RT_DBaseAlloc(DB,0,"ii")            # Alloc minimum of two int fields, 0=SOS, 1=EOS. (add others if required)
Records = DBase_DetectScenes(DB)    # Use Defaults for fields, Offset, and thSCD1 and thSCD2
Return MessageClip("DBase_DetectScenes: Records="+String(records))
Demo showing scenes only
Code:
# Show Scenes
AVISource("D:\Parade.AVI")
DB="D:\Parade.DB"
SSS="""
    n=current_frame
    Record=DB_FindTrim(DB,0,1,n)                                    # Record or scene number (relative 0) # -1 NOT FOUND
    SceneStart = (Record>=0) ? RT_DBaseGetField(DB,Record,0) : -1   # Get scene start from field 0 (SOS)
    SceneEnd   = (Record>=0) ? RT_DBaseGetField(DB,Record,1) : -1   # Get scene end from field 1 (EOS)
    RT_Subtitle("%d] #%d Start=%d End=%d",n,Record,SceneStart,SceneEnd)

"""
Scriptclip(SSS)
return Last
EDIT: Scene detectors dont seem to always generate a Start Of Scene following an End Of Scene, or an End Of Scene before
a Start Of Scene, above detector should be devoid of such behaviour.
NOTE, Some scenes may be single frame, especially at blended transition. [ie both SOS and EOS]

EDIT: You can use Offset, to concatenate multiple clip scene change data into a single DBase for spliced final clip.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 12th September 2018 at 22:01.
StainlessS is offline   Reply With Quote
Old 13th September 2018, 01:11   #14  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
Additional Demo.

All done in one script, init DBase with scene change data, scan each scene getting min and max aveluma of scene, update DBase with min/max stuff
then play clip showing result scene numbers, and scene min/max aveluma for each frame in scene.

Code:
######
# Demo, Add something to DBase for each scene/record, in this case just min and max average luma as 2 Floats @ Field 2=min, 3=max
######
AVISource("D:\Parade.AVI")
DB="D:\Parade.DB"
######
# 1st Create DBase with 2 additional fields
######
RT_DBaseAlloc(DB,0,"iiff")          # Alloc two int fields for SOS & EOS, also add Field 2 Float for MinAveLuma, and Field 3 for MaxAveLuma
Records = DBase_DetectScenes(DB)    # Use Defaults for fields, Offset, and thSCD1 and thSCD2
RT_DebugF("DEMO: Detected %d Scenes, added to DBase",Records) # See output in DebugView (Google)
#return MessageClip("DONE")

######
### 2nd, Scan scenes in clip, establish Min/max luma for each scene, and update DBase
### Using AVS+ here, mod if using GSCript
######
Records=RT_DBaseRecords(DB)
For(scene=0,Records-1) {
    SFrm = RT_DBaseGetField(DB,scene,0)   # Get scene start from field 0 (SOS)
    EFrm = RT_DBaseGetField(DB,scene,1)   # Get scene end from field 1 (EOS)
    MinLum=256.0    MaxLum=-1.0           # Prep for scene
    for(frm=SFrm,EFrm) {                  # Scan all Frames in Scene
        AveLum=RT_AverageLuma(n=frm)      # could specify eg area to measure eg x=32,y=32,w=-32,h=-32 # as for crop(32,32,-32,-32)
        MinLum=Min(MinLum,AveLum)
        MaxLum=Max(MaxLum,AveLum)
    }
    RT_DbaseSetField(DB,scene,2,MinLum)     # Set Minimum encountered luma in this scene to 3rd field, field 2
    RT_DbaseSetField(DB,scene,3,MaxLum)     # Set Maximum encountered luma in this scene to 4th field, field 3
    RT_DebugF("DEMO: Scene#%d[%d,%d] MinLuma=%.3f MaxLuma=%.3f",scene,SFrm,EFrm,MinLum,MaxLum) # See output in DebugView (Google)
}
#return MessageClip("DONE")

######
# 3rd, NOW PLAY Clip
######

SSS="""
    n=current_frame
    Record=DB_FindTrim(DB,0,1,n)                            # Record or scene number (relative 0) # -1 NOT FOUND
    if(Record>=0) {
        Records    = RT_DBaseREcords(DB)                    # Show number of records ie scenes
        SceneStart = RT_DBaseGetField(DB,Record,0)          # Get scene start from field 0 (SOS)
        SceneEnd   = RT_DBaseGetField(DB,Record,1)          # Get scene end from field 1 (EOS)
        MinLum     = RT_DBaseGetField(DB,Record,2)          # Get MinLuma for entire scene (same for each frame in scene)
        MaxLum     = RT_DBaseGetField(DB,Record,3)          # Get MaxLuma for entire scene (same for each frame in scene)
        SceneFMax  = SceneEnd-SceneStart                    # For show scene relative frame number n/nmax, 0 rel
        RT_Subtitle("%d/%d] #%d/%d:%d/%d[%d,%d,Len=%d]\nMinLuma=%.3f\nMaxLuma=%.3f",
            \ n,FrameCount-1,Record,Records-1,n-scenestart,SceneFMax,SceneStart,SceneEnd,SceneFMax+1,MinLum,MaxLum)
    } Else { Subtitle("ERROR: RECORD NOT FOUND !",align=5,size=48)}
"""
Scriptclip(SSS)
It will take some time before playing with long clip (scan for scene change/ scan for minmax avluma, then play).

Can view some stuff via DebugView while Scanning (Google)
EDIT: You also need prev posted library funcs.

EDIT: In above ScriptClip Play section, could if required only update scene constant stuff from DBase, when a new scene
is encountered, eg MinLuma is set for entire scene, and would only need be gotten once per scene, but
is no real problem to get it every time, when it would be a good idea, would be when getting some string
from DBase, where strings take up quite a bit of memory as new string required for every iteration, (waste of mem).
However, if updating only on new record/scene, then would require a Global variable to remember the previous record/scene,
and also the previous string.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 13th September 2018 at 16:57.
StainlessS is offline   Reply With Quote
Old 13th September 2018, 18:39   #15  |  Link
Frank62
Registered User
 
Join Date: Mar 2017
Posts: 29
You're great, a big thank you again!
I tried this with the whole episode: Unfortunately:

-At some swapped ranges U and V population/saturation get a lot higher compared to the frames before and after, on other ranges it is as you assumed, they get smaller.
At those ranges I observed, the differences between pop before/after and pop inside are quite significant - but this gives me again only the direct possibility to detect the beginnings and ends of the ranges - if you don't have another idea for this. And it's not safe, because with some ranges significantly higher, some ranges significantly lower, I bet that there are some where there will be no difference...

-The other method with testing the right margin works most times well, but fails if the near content is also very dark - and I already found some scenes where exactly this happens...

-My first method with this:

Code:
v=avisource("26.avi")
vminus1=trim(v,1,0)
global sep=";"
x=WriteFileIf(v,"F:\Scripts\26UV.log","(UDifferenceFromPrevious(v)-UDifferenceFromPrevious(vminus1)>1.7) && (YDifferenceFromPrevious(v)-YDifferenceFromPrevious(vminus1)<10)","current_frame-1")
works quite well for beginning and ends of the ranges, and also detects the one-frame-swaps.

So I fear I will save the beginnings and ends with my/your mixed detector (works for this purpose quite at 100%) and write something meta that will output a final repair-script.

To work myself into all that great stuff with database and all I haven't got the time, which I regret - all episodes have to be done next week.

Again for your big efforts! Great people in this forum!

Last edited by Frank62; 13th September 2018 at 18:50.
Frank62 is offline   Reply With Quote
Old 14th September 2018, 09:48   #16  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
Quote:
works quite well for beginning and ends of the ranges, and also detects the one-frame-swaps.

So I fear I will save the beginnings and ends with my/your mixed detector (works for this purpose quite at 100%) and write something meta that will output a final repair-script.
Yeh but how do you tell if beginning, end, or single frame, what magic do you have for that ?

If you can up a longer (~500MB max, no audio), I'll try D/L today.

I was thinking of compare with next frame, and also compare with eg SwapUV for detector.
[I'm also still sticking with DBase, too much potential for error crossing scene boundaries].

EDIT:
Quote:
Originally Posted by Frank62 View Post
[CODE]
v=avisource("26.avi")
vminus1=trim(v,1,0)
global sep=";"
x=WriteFileIf(v,"F:\Scripts\26UV.log","(UDifferenceFromPrevious(v)-UDifferenceFromPrevious(vminus1)>1.7) &&" +
\ "(YDifferenceFromPrevious(v)-YDifferenceFromPrevious(vminus1)<10)","current_frame-1")
Also note that UDifferenceFromPrevious(vminus1) same as UDifferenceToNext(v), no need for additional next vminus clip.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 14th September 2018 at 10:16.
StainlessS is offline   Reply With Quote
Old 14th September 2018, 11:46   #17  |  Link
Frank62
Registered User
 
Join Date: Mar 2017
Posts: 29
Quote:
Originally Posted by StainlessS View Post
Yeh but how do you tell if beginning, end, or single frame, what magic do you have for that ?
Walking through from the beginning.
First hit is either single or beginning.
If between this and next hit more than let's say 30 frames (maximum length I saw was 20 frames) then it was a single swap, if not, then next one is end.
a. s. o.
Only if two single swaps are nearer than 30 frames I will become problems. But can fix this by hand, maybe once an episode, if it ever happens.

I can't do this in avisynth, but extern no problem, I am doing similar things all the time, so one or two hours of work should do.

Quote:
I was thinking of compare with next frame, and also compare with eg SwapUV for detector.
Big thanks again, but it's no more necessary, because the detector works 99% - only some work to do.

Quote:
Also note that UDifferenceFromPrevious(vminus1) same as UDifferenceToNext(v), no need for additional next vminus clip.
Due to my inclination to maximum simplicity, readability, through-thinkability I wrote so. But sometimes very simple is more complicated, so I overlooked this.
Frank62 is offline   Reply With Quote
Old 14th September 2018, 17:13   #18  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
When I get home, I shall try complete my version detector as in your 2nd last quote, seemed to be working before I had to leave.
Maybe yours works fine, but gonna try my altrnative, just the same.

be good.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???
StainlessS is offline   Reply With Quote
Old 14th September 2018, 19:12   #19  |  Link
Frank62
Registered User
 
Join Date: Mar 2017
Posts: 29
Sorry, I didn't want to thwart. Just avoid work for you.
Frank62 is offline   Reply With Quote
Old 14th September 2018, 19:58   #20  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 5,863
Quote:
Originally Posted by Frank62 View Post
Sorry, I didn't want to thwart. Just avoid work for you.
Yeh, I know, just found it an interesting prob.
In the words of some UK TV program (that I cant quite remember the name of, EDIT: MasterMind with Magnus Magnusson), 'I've started, so I'll finish', if your detector works, then great, if not then there might be a viable alternative, I'll post mine anyways, whether you successfully complete or not.

But not right now, think I shall succumb to this booze induced coma that I'm about to fall into .
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 15th September 2018 at 00:37.
StainlessS is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 17:21.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2018, vBulletin Solutions Inc.