Log in

View Full Version : ScSelect_HBD v0.01 - 13 Feb 2021


StainlessS
13th February 2021, 16:18
A high bit depth replacement script for ScSelect from Removedirt. Works better.

ScSelect_HBD.avs

# ScSelect_HBD.avs

Function SCSelect_HBD(clip dClip,clip Start,clip End,clip Motion, float "dfactor",Float "MinDif",bool "show",String "S_Frames",String "E_Frames") {
/*
ScSelect_HBD(), v0.01. by StainlessS @ Doom9. : https://forum.doom9.org/showthread.php?t=182392
Requires Grunt (c) Gavino. If S_Frames or E_Frames != "" then also requires RT_Stats.

SCSelect_HBD(clip dClip,clip Start,clip End,clip Motion,
float "dfactor"=3.5,Float "MinDif"=1.0,
bool "show"=False,String "S_Frames"="",String "E_Frames"="")

ScSelect_HBD(), Mod of ScSelect_Like():- https://forum.doom9.org/showthread.php?p=1644023#post1644023
Named with "_HDB" extender as should work ok with HBD in AVS+.
ScSelect_Like() emulated ScSelect() from RemoveDirt.
RemoveDirt's SCSelect(clip input, clip scene_begin, clip scene_end, clip global_motion, float dfactor, bool debug, bool planar)
To emulate original ScSelect results, use ScSelect_HBD(dFactor=4.0,MinDif=0.0).

Args:
dClip, Detection clip. May be different size and colorspace to Start, End and Motion clips. YUV only.
If High Bit Depth (greater than 8 bits per channel) then will be converted to 8 bit for scene change
detection stage. For larger source clips, you may want to downsize the dClip to speed up detection .

Start, Clip of frames that will replace frames from Motion clip when Start-Of-Scene detected.
End, Clip of frames that will replace frames from Motion clip when End-Of-Scene detected.
Motion, Clip the will be used where neither start nor end of scene detected.
Start, End, and Motion, clips can be different colorspace and size compared to dClip (unlike ScSelect),
but must all be same colorspace and size as each other, also can be high-bit-depth or RGB.

dFactor, Default 3.5. (1.0 <= dFactor) Detection factor, a multiplier applied to frame difference
metrics to decide if a scene change.
Mindif, Default 1.0. (0.0 <= Mindif, Supply MinDif as if in 8 bit range, 0.0 -> 255.0)
An additional component part of scene change detection.
Where difference measurements,
pDf = Average per pixel Luma difference, between dClip current frame and previous frame (0.0->255.0).
nDf = Average per pixel Luma difference, between dClip current frame and next frame (0.0->255.0).
pTh = dFactor * nDf + MinDif : If pDf greater than this then is SOS, Start-Of-Scene.
nTh = dFactor * pDf + MinDif : If nDf greater than this then is EOS, End-Of-Scene.
Detect method,
SOS = pDf > pTh : SOS = pDf > dFactor * nDf + MinDif, Also,
EOS = nDf > nTh : EOS = nDf > dFactor * pDf + MinDif.
(If pDf > pTh, then pDf is also greater than nDf as dFactor is at least 1.0 and MinDif at least 0.0)
Original ScSelect, used default dFactor=4.0, and equivalent of MinDif=0.0 (It had no MinDif arg).
Using only dFactor, and no Mindif (ie 0.0), is not too good as a detector, especially where
scene of low motion or near static scene, eg when nDf=0.0 then pDf value of anything above 0.0
would detect a scene change, not exactly as desired for near static scene, additinal component is needed.
In same situation where MinDif=1.0 and nDf=0.0, so SOS = pDf > pTh : SOS = pDf > 4.0 * 0.0 + 1.0
so, to detect Start of scene then pDf has to be greater than 1.0 for a start of scene detect.
In near static scene, we are most reliant upon Mindif being of sufficient magnitude to avoid a false
detection. In scene with plenty of motion, then value of dFactor becomes more important to prevent false
detection. In a very jerky or anime scene, then probably a high dFactor and high Mindif are required.
In this crazy mixed up world, you have to find a good compromise for dFactor and MinDif
so as to detect scene changes without producing false detections.
Our default of dFactor=3.5 and Mindif=1.0, is just one combination, you might prefer bigger Mindif
and smaller dFactor,(whatever you choose, some clips will require an alternative set).
I suggest dFactor usually no less than about 2.5 and no more than 4.0, and Mindif no less than 0.5, and
maybe no more than about 4.0. As you lower dFactor, you might want to raise Mindif, and vise versa.
Anime is likely to have different requirments with bigger MinDif (maybe 4 or more but depends upon the clip).

Show, Default False. In original ScSelect, this arg is called Debug, and output some info to DebugView (google),
we show info on frame and so have changed arg name to Show but of roughly same functionality.

Metrics when Show=True (metrics provided as if in 8 bit range):
>>>>>>>>>>>>>>>>>
20531 ] S {SOS: dFact= 19.7365:MinD=54.6495}
SOS: P{ 66.214} > pTh{ 12.565}<==
EOS: N{ 3.304} > nTh{232.750}
<<<<<<<<<<<<<<<<<

20531, Is current Frame Number
S, Is flagging a detected Start-Of-Scene (Also 'E'=End-Of-Scene, and 'G' = Global motion.
SOS: P{ 66.214} > pTh{ 12.565} <== The arrow "<==" at the end denotes a SOS (Start Of Scene) detection.
'P' (short for pDf, screen space saving) is difference to previous frame.
pTh = dFactor * nDf + MinDif
EOS: N{ 3.304} > nTh{232.750} Much as Above, but no EOS (End Of Scene) detection.
'N' (short for nDf), is difference to next frame.
nTh = dFactor * pDf + MinDif

{SOS: dFact= 19.7365:MinD=54.6495}, NOT ALWAYS SHOWN.
The Scene change Arg, matching estimate info, in this case for SOS estimate.
Shown only if pDf, nDF, and arg limits on dFactor and MinDif could
produce either SOS or EOS. This indicator only makes any sense on frames
that YOU have decided should be a scene change frame, otherwise ignore.
dFact is the dFactor that will produce an EXACT match of the threshold
(SOS pTh or EOS nTh) to the higher difference {SOS pDf or EOS nDf), when
MinDif unchanged.
As this example shows SOS, so the threshold is pTh and higher difference is pDf,
so it balances this line,
P{ 66.214} == pTh{66.214}, or
P{ 66.214} == {dfact * nDf + MinDif)
P{ 66.214} == {19.7365 * nDf + MinDif)
So in this particular instance it shows that the maximum value for dFactor arg
that could produce SOS on this frame with current Mindif is LESS THAN 19.7365.
It shows that lowest value of dFactor that would fail to produce a SOS, so the maxium
value of dFactor that would succeed to detect SOS for current frame is just below this
value. (pDf has to be greater than pTh so when equal will fail SOS detect).
Similar can be deduced when EOS estimator is shown.
MinD is similar estimator (in this case again for SOS) which shows where MinDif
will balance (with current dFactor unchanged)
P{ 66.214} == pTh{66.214}, or
P{ 66.214} == {dfactor * nDf + MinD)
P{ 66.214} == {dfactor * nDf + 54.641195)
Similar can be deduced when EOS estimator is shown.
Hope some of that made at least a little sense, is intended to give you some
idea about how much you can raise (or lower) dFactor or Mindif to get
a successful detection on current frame.

S_Frames, Default "". Name of Start-Of-Scene Frames text file. Req RT_Stats if non "".
E_Frames, Default "". Name of End-Of-Scene Frames text file. Req RT_Stats if non "".

*/
dfactor = Float(Default(dfactor,3.5)) # Suggest 2.5 -> 4.0 ::: Change default to 4.0 to emulate ScSelect
Mindif = Float(Default(MinDif ,1.0)) # Suggest 0.5 -> 4.0 ::: Change default to 0.0 to emulate ScSelect
Show = Default(show,false)
S_Frames= Default(S_Frames,"")
E_Frames= Default(E_Frames,"")
Assert(!DClip.IsRGB,"SCSelect_HBD: DClip YUV Only")
Assert(1.0 <= dFactor,"SCSelect_HBD: 1.0 <= dFactor")
Assert(0.0 <= Mindif ,"SCSelect_HBD: 0.0 <= MinDif")
try { bpc = DClip.BitsPerComponent } catch(err_msg) { bpc = 8 }
DClip = (bpc!=8) ? DClip.ConvertBits(8) : DClip
Sz = Max(Round(Motion.Height*0.05),14)
S_Frames = (S_Frames!="") ? S_Frames.RT_GetFullPathName : ""
E_Frames = (E_Frames!="") ? E_Frames.RT_GetFullPathName : ""
(S_Frames !="") ? RT_FileDelete(S_Frames) : NOP
(E_Frames !="") ? RT_FileDelete(E_Frames) : NOP
Motion.GScriptClip("""
n = current_frame
pDf = Dclip.YDifferenceFromPrevious
nDf = Dclip.YDifferenceToNext
pTh = nDf*dfactor+MinDif
nTh = pDf*dfactor+MinDif
SC = 2 # Default To SC = MOTION (Last is MOTION clip)
if (n==0) { SC = 0 Start S_Frames!=""?RT_WriteFile(S_Frames,"%d",n,Append=true):NOP} # SOS
else if(n==FrameCount-1){ SC = 1 End E_Frames!=""?RT_WriteFile(E_Frames,"%d",n,Append=true):NOP} # EOS, Fixes ScSelect SOS detect on Last frame
else if(pDf>pTh) { SC = 0 Start S_Frames!=""?RT_WriteFile(S_Frames,"%d",n,Append=true):NOP} # SOS
else if(nDf>nTh) { SC = 1 End E_Frames!=""?RT_WriteFile(E_Frames,"%d",n,Append=true):NOP} # EOS
if(show) {
mx = Max(pDf,nDf)
mn = Min(pDf,nDf)
Can_dF = (mx > mn + Mindif) # Can any values of dfactor(1.0 and aove) cause scene detect ?
Can_Md = (mx > dFactor * mn) # Can any values of MinDif(0.0 and above) cause scene detect ?
if(Can_dF || Can_Md) {
E_dF = (Can_dF) ? String(Min((mx - Mindif) / max(mn,0.00001),99.9999),"dFact=%7.4f") : ""
E_Md = (Can_Md) ? String(mx - dFactor * mn,"MinD=%7.4f") : ""
EdfS = E_dF + ((Can_dF && Can_Md) ? ":" : "") + E_Md + "}"
EdfS = ((pDf==mx) ? "{SOS:" :"{EOS:") + EdfS
} else { EdfS = "" }
Subtitle(
\ String(n,"%.0f] ") + MidStr("SEG",SC+1,1) + " " + EdfS + "\n" +
\ String(pDf,"SOS: P{%7.3f} > ") + String(pTh,"pTh{%7.3f}") + (SC==0 ? " <==":"") + "\n" +
\ String(nDf,"EOS: N{%7.3f} > ") + String(nTh,"nTh{%7.3f}") + (SC==1 ? " <==":"")
\ ,Font="Courier New",Size=Sz,lsp=0)
}
Return Last
""",Args="dfactor,Start,End,Dclip,MinDif,show,S_Frames,E_Frames,Sz",Local=true) # Needs Grunt for args
return Last
}


EDIT: Some additional scripts follow.
The other comparison script pairs [EDIT: Posts #3 and #4], are intended to save user work.
They allow you to view only scene change detections, instead of scanning through entire clip looking for them.
And the other one allows to view two arg sets, but only where their results differ, again without having to manually scan entire clip.

Zip at MediaFire and SendSpace(30 days only) below this post.

StainlessS
13th February 2021, 16:19
ScSelect_HBD_Simple_Client.avs

# ScSelect_HBD_Simple_Client.avs
Import(".\ScSelect_HBD.avs")

VideoFileName = "D:\DVD\C\A_01.mp4.d2v"
Mpeg2Source(VideoFileName)

DFACTOR_1 = 3.5 # ScSelect_HDB default = 4.0
MINDIF_1 = 1.0 # ScSelect_HDB default = 0.5

SHOW = True

## HBD test
#ConvertToYV12.ConvertBits(10) # YUV420P10 - 10 bit
#ConvertToYV12.ConvertBits(16) # YUV420P16 - 16 bit
#ConvertToYV12.ConvertBits(32) # YUV420PS - 32 bit Float

SZ = Max(Round(Height*0.10),24)
Start=Subtitle("START OF SCENE",align=5,size=SZ,Y=Height/2-SZ,Text_Color=$FF4040)
End=Subtitle("END OF SCENE", align=5,size=SZ,Y=Height/2+SZ,Text_Color=$4040FF)
Motion=Subtitle("GLOBAL MOTION",align=5,size=SZ)

SCSelect_HBD(Last,Start,End,Motion,dFactor=DFACTOR_1,MinDif=MINDIF_1,show=SHOW)

Return Last.ConvertToRGB32()


ScSelect_HBD_Cmp_Client.avs

# ScSelect_HBD_Cmp_Client.avs

# Test / compare script : Compare SCSelect_HBD against SCSelect equivalent

VideoFileName = "D:\DVD\C\A_01.mp4.d2v"
Mpeg2Source(VideoFileName)

#########
FINAL = False # If true returns only Set 1 result
SHOW = True

# Comparison set 1
DFACTOR_1 = 3.5 # ScSelect_HDB default = 4.0
MINDIF_1 = 1.0 # ScSelect_HDB default = 0.5

# Comparison set 2
DFACTOR_2 = 3.5 # As ScSelect Plugin
MINDIF_2 = 0.5 # ScSelect does not have this setting, acts as if 0.0

## HBD test
#ConvertToYV12.ConvertBits(10) # YUV420P10 - 10 bit
#ConvertToYV12.ConvertBits(16) # YUV420P16 - 16 bit
#ConvertToYV12.ConvertBits(32) # YUV420PS - 32 bit Float

Import(".\ScSelect_HBD.avs")
#########
SHOW = (SHOW && !FINAL)

SZ = Max(Round(Height*0.10),24)
Start=Subtitle("START OF SCENE",align=5,size=SZ,Y=Height/2-SZ,Text_Color=$FF4040)
End=Subtitle("END OF SCENE", align=5,size=SZ,Y=Height/2+SZ,Text_Color=$4040FF)
Motion=Subtitle("GLOBAL MOTION",align=5,size=SZ)


L=SCSelect_HBD(Last,Start,End,Motion,dFactor=DFACTOR_1,MinDif=MINDIF_1,show=SHOW)
R=SCSelect_HBD(Last,Start,End,Motion,dFactor=DFACTOR_2,MinDif=MINDIF_2,show=SHOW) # OR=SCSelect(Last,Start,End,Motion)
Result = L

L=L.TestTit(String(dFACTOR_1,"dFactor=%.3f") + String(MINDIF_1," : MinDif=%.3f"))
R=R.TestTit(String(dFACTOR_2,"dFactor=%.3f") + String(MINDIF_2," : MinDif=%.3f"),$FF0080)

(!FINAL) ? StackHorizontal(L,R) : Result

try { bpc = BitsPerComponent } catch(err_msg) { bpc = 8 }

(!FINAL && bpc!=8) ? ConvertToRGB32 : Last # for View if not 8 bit (comment out if your view can show clip)

Prefetch(4)

Return Last#.Info

################

Function TestTit(clip c,string Tit,int "col") {
Col = Default(col,$C000C0)
SZ = Max(Round(c.Height*0.033)*2,20)
c.BlankClip(height=SZ,Length=1,Color=Col).Subtitle(Tit,Size=SZ-2)
Return StackVertical(c).AudioDubEx(c)
}


https://i.postimg.cc/CxnSfnbJ/Sc-Select-HBD-Cmp-Client-00.jpg (https://postimg.cc/PCHBgx38)

EDIT: To compare original ScSelect, set 2nd arg set to DFACTOR_2=4.0 MINDIF_2 = 0.0 where it will behave the same.

StainlessS
13th February 2021, 16:22
Pair of scripts in folder CompareArgSet
Extract and show ONLY scene change frames mismatches [where 2 different sets of args produced mismatched detections]
and before and after frames, with comparison against another arg set.
EDIT: Saves scan and view of complete clip looking for mismatched results, only produces a few frames to look at.

1_CompareArgSet_SCAN.avs

# 1_CompareArgSet_SCAN.avs

# Req Grunt, RT_Stats, FrameSel, Source filter plugin

/*
Pair of scripts to compare different results using two sets of ScSelect_HBD(dFactor,MinDif) args.
1_CompareArgSet_SCAN.avs : This script, scan and creates a frames file where detections differ. [VDub2 Video Analysis pass]
2_CompareArgSet_SHOW.avs : Display different detections, using data from 1st script.
*/


##### CODE COMMON IN:- 1_CompareArgSet_SCAN.avs ... And ...2_CompareArgSet_SHOW.avs #######
# Edit As Required : This code will being imported into '2_CompareArgSet_SHOW.avs" comparison display script.

INIT_SSS = """

VideoFileName = "D:\DVD\C\A_01.mp4.d2v"
Mpeg2Source(VideoFileName)

# Comparison arg set 1
dFACTOR_1 = 3.5
MINDIF_1 = 1.0

# Comparison arg set 2
dFACTOR_2 = 3.0
MINDIF_2 = 1.5

## HBD test
#ConvertToYV12.ConvertBits(10) # YUV420P10 - 10 bit
#ConvertToYV12.ConvertBits(16) # YUV420P16 - 16 bit
#ConvertToYV12.ConvertBits(32) # YUV420PS - 32 bit Float

# Get ScSelect_HBD.avs from parent directory
ScSelect_HBD_script = "..\ScSelect_HBD.avs".RT_GetFullPathName # Comment out these two lines if ScSelect_HBD.avsi in plugins
Import(ScSelect_HBD_script) #

Frames = "~CompareArgSet_COMMON_Frames.txt".RT_GetFullPathName

SZ = Max(Round(Height*0.10),24)
Start=Subtitle("START OF SCENE",align=5,size=SZ,Y=Height/2-SZ,Text_Color=$FF4040)
End=Subtitle("END OF SCENE", align=5,size=SZ,Y=Height/2+SZ,Text_Color=$4040FF)
Motion=Subtitle("GLOBAL MOTION",align=5,size=SZ)

dClip = Last
AClip = dClip.SCSelect_HBD(Start,End,Motion,dFactor=dFACTOR_1,MinDif=MINDIF_1,show=SHOW)
BClip = dClip.SCSelect_HBD(Start,End,Motion,dFactor=dFACTOR_1,MinDif=MINDIF_2,show=SHOW) # For Comparison

try { bpc = AClip.BitsPerComponent } catch(err_msg) { bpc = 8 }
A8BitClip = (bpc!=8) ? AClip.ConvertBits(8) : AClip
B8BitClip = (bpc!=8) ? BClip.ConvertBits(8) : BClip

"""

# ########################### END COMMON CODE ########################

CommonAvs = RT_GetFullPathName("~CompareArgSet_COMMON_TMP.avs") # COMMON CODE file name

RT_WriteFile(CommonAvs,"%s",INIT_SSS) # Write temp COMMON CODE avs script

SHOW = FALSE # Arg to SCSelect_HBD() via below Import() of Common Code script.
Import(CommonAvs)

RT_Filedelete(Frames)

Subtract(A8BitClip,B8BitClip) # 8 bit subtract.

Sz = Max(Round(Height*0.05),18)

Global DIFCNT=0 # Problematic if Prefetch(), Needs Global [Maybe down to 2 instances of GScriptclip]

LOOP_SSS="""
n=current_frame
Z=AverageLuma
if(Z!=126.0) { # 126.0 = 8 bit TV_Levels center, ie Round((16+235)/2.0), as produced by Subtract().
Global DIFCNT = DIFCNT + 1 # Has to be Global if Prefetch, Prefetch breaks local access to to DifCnt, Frames, and Sz
RT_WriteFile(Frames,"%d",n,Append=true)
}
Subtitle(String(n,"%.0f") + String((n+1)*100.0/FrameCount," : %.2f%%") + String(DifCnt,"] DifCnt=%.0f"),Size=Sz)
"""

GScriptClip(LOOP_SSS,Args="frames,Sz") # Have to use Args here to import Frames, and Sz, if PREFETCH().

Prefetch(4) # !!! Problematic !!!

Return Last



2_CompareArgSet_SHOW.avs

# 2_CompareArgSet_SHOW.avs

# Req Grunt, RT_Stats, FrameSel, Source filter plugin

CommonAvs = RT_GetFullPathName("~CompareArgSet_COMMON_TMP.avs")

SHOW =TRUE

VIEW_RADIUS = 1 # 0, or 1 or 2. Shows mismatched, and VIEW_RADIUS before and after frames.
# 0 Show mismatched frames ONLY.
# 1 Show mismatched, before and after frames.
# 2 Show mismatched, two before and two after frames.
#################################

# Import CommonAvs as created by 1_CompareArgSet_SCAN.avs
Try {
Import(CommonAvs)
} Catch (msg) {
msg = (FindStr(msg,"couldn't open")==0) ? msg : "Run '2_CompareArgSet_SCAN.avs" + Chr(10) + Chr(10) + msg
Assert(False, msg)
}

Assert(0 <= VIEW_RADIUS <= 2,"2_CompareArgSet_SHOW.avs: 0 <= VIEW_RADIUS <= 2")
vFrms = VIEW_RADIUS * 2 + 1


AClip=AClip.FrameSel(Cmd=Frames,Extract=vFrms)
BClip=BClip.FrameSel(Cmd=Frames,Extract=vFrms)

if(VFrms > 1) {
EVAS="Ax=StackHorizontal("
EVBS="Bx=StackHorizontal("
For(i=0,vFrms-1) {
EVAS=RT_String("%sAClip.SelectEvery(vFrms,%d)%s",EVAS,i,i==vFrms-1?")":",")
EVBS=RT_String("%sBClip.SelectEvery(vFrms,%d)%s",EVBS,i,i==vFrms-1?")":",")
}
Eval(EVAS)
Eval(EVBS)
} Else { Ax = AClip Bx = BClip }

ASTR = String(dFACTOR_1,"dFactor=%.3f") + String(MINDIF_1," : MinDif=%.3f")
BSTR = String(dFACTOR_2,"dFactor=%.3f") + String(MINDIF_2," : MinDif=%.3f")

StackVertical(Ax.TestTit(ASTR),Bx.TestTit(BSTR,$FF0080)) # Show groups of 3 frames, before_frame, different_result_frame, after_frame
Return Last

######

Function TestTit(clip c,string Tit,int "col") {
Col = Default(col,$C000C0)
SZ = Max(Round(c.Height*0.033)*2,20)
c.BlankClip(height=SZ,Length=1,Color=Col).Subtitle(Tit,Size=SZ-2)
Return StackVertical(c).AudioDubEx(c)
}

https://i.postimg.cc/ZnZ7L29V/2-Compare-Arg-Set-SHOW-00.jpg (https://postimg.cc/0MW0kt0w)

StainlessS
13th February 2021, 16:23
Pair of scripts in folder ExtractSceneChanges
Extract and show ONLY scene change frames and before and after frames.

1_ExtractSceneChanges_SCAN.avs

# 1_ExtractSceneChanges_SCAN.avs

# Req Grunt, RT_Stats, FrameSel, Source filter plugin

/*
Pair of scripts to view scene change detections using ScSelect_HBD().
1_ExtractSceneChanges_SCAN.avs : This script, scan and creates a frames files. [VDub2 Video Analysis pass]
2_ExtractSceneChanges_SHOW.avs : Display ONLY detected scene changes + before and after frames.
*/

##### CODE COMMON IN:- 1_ExtractSceneChanges_SCAN.avs ... And ...2_ExtractSceneChanges_SHOW.avs #######
# Edit As Required : This code will being imported into '2_ExtractSceneChanges_SHOW.avs" comparison display script.

INIT_SSS = """

VideoFileName = "D:\DVD\C\A_01.mp4.d2v"
Mpeg2Source(VideoFileName)

dFACTOR = 3.5
MINDIF = 1.0

## HBD test
#ConvertToYV12.ConvertBits(10) # YUV420P10 - 10 bit
#ConvertToYV12.ConvertBits(16) # YUV420P16 - 16 bit
#ConvertToYV12.ConvertBits(32) # YUV420PS - 32 bit Float

# Get ScSelect_HBD.avs from parent directory
ScSelect_HBD_script = "..\ScSelect_HBD.avs".RT_GetFullPathName # Comment out these two lines if ScSelect_HBD.avsi in plugins
Import(ScSelect_HBD_script) #

S_Frames = "~ExtractSceneChanges_COMMON_S_FRAMES.txt".RT_GetFullPathName
E_Frames = "~ExtractSceneChanges_COMMON_E_FRAMES.txt".RT_GetFullPathName

SZ = Max(Round(Height*0.10),24)
Start=Subtitle("START OF SCENE",align=5,size=SZ,Y=Height/2-SZ,Text_Color=$FF4040)
End=Subtitle("END OF SCENE", align=5,size=SZ,Y=Height/2+SZ,Text_Color=$4040FF)
Motion=Subtitle("GLOBAL MOTION",align=5,size=SZ)
"""

# ########################### END COMMON CODE ########################

CommonAvs = RT_GetFullPathName("~ExtractSceneChanges_COMMON_TMP.avs") # COMMON CODE file name

RT_WriteFile(CommonAvs,"%s",INIT_SSS) # Write temp COMMON CODE avs script

Import(CommonAvs)

SHOW=False
SCSelect_HBD(Start,End,Motion,dFactor=dFACTOR,MinDif=MINDIF,show=SHOW,s_frames=S_Frames,e_frames=E_Frames)

Prefetch(4)

Return Last#.ComnvertToRGB32 # for View


2_ExtractSceneChanges_SHOW.avs

# 2_ExtractSceneChanges_SHOW.avs

# Req Grunt, RT_Stats 2 Beta 13, FrameSel, Source filter plugin

CommonAvs = RT_GetFullPathName("~ExtractSceneChanges_COMMON_TMP.avs")

VIEW_MODE = 2 # 0 = Scene Start Frames, 1 = Scene End Frames, 2 = Scene Start + Scene End Frames

VIEW_RADIUS = 1


#################################
Assert(0 <= VIEW_RADIUS <= 2,"2_ExtractSceneChanges_SHOW.avs: 0 <= VIEW_RADIUS <= 2")
vFrms = VIEW_RADIUS * 2 + 1

# Import CommonAvs as created by 1_ExtractSceneChanges_SCAN.avs
Try {
Import(CommonAvs)
} Catch (msg) {
msg = (FindStr(msg,"couldn't open")==0) ? msg : "Run '1_ExtractSceneChanges_SCAN.avs" + Chr(10) + Chr(10) + msg
Assert(False, msg)
}

SCSelect_HBD(Start,End,Motion,dFactor=dFACTOR,MinDif=MINDIF,show=TRUE)


If (VIEW_MODE==0) { Frames_OUT = S_Frames }
Else if(VIEW_MODE==1) { Frames_OUT = E_Frames }
Else {
TmpS=RT_ReadTxtFromFile(S_Frames)
Frames_TMP_OUT = "~Frames_TMP_OUT.txt".RT_GetFullPathName
RT_WriteFile(Frames_TMP_OUT,"%s",TmpS)
TmpS=RT_ReadTxtFromFile(E_Frames)
Frames_OUT = "~Frames_OUT.txt".RT_GetFullPathName
RT_WriteFile(Frames_TMP_OUT,"%s",TmpS,Append=True)
FrameSel_CmdReWrite(Frames_OUT,cmd=Frames_TMP_OUT,Ordered=True,Reject=False,Range=False)
RT_FileDelete(Frames_TMP_OUT)
}


AClip=FrameSel(Cmd=Frames_OUT,Extract=vFrms)
(VIEW_MODE==2) ? RT_FileDelete(Frames_OUT) : NOP

if(VFrms > 1) {
EVAS="Ax=StackHorizontal("
For(i=0,vFrms-1) {
EVAS=RT_String("%sAClip.SelectEvery(vFrms,%d)%s",EVAS,i,i==vFrms-1?")":",")
}
Eval(EVAS)
} Else { Ax = AClip }


Ax.TestTit(String(dFACTOR,"dFactor=%.3f") + String(MINDIF," : MinDif=%.3f"))

Return Last

######

Function TestTit(clip c,string Tit,int "col") {
Col = Default(col,$C000C0)
SZ = Max(Round(c.Height*0.033)*2,20)
c.BlankClip(height=SZ,Length=1,Color=Col).Subtitle(Tit,Size=SZ-2)
Return StackVertical(c).AudioDubEx(c)
}

https://i.postimg.cc/8kKM4xrc/2-Extract-Scene-Changes-SHOW-00.jpg (https://postimg.cc/vDn4Hqhw)

real.finder
13th February 2021, 16:44
but in https://github.com/pinterf/RemoveDirt

SCSelect: add support for 10-16 bits and 32 bit float clips

StainlessS
13th February 2021, 16:45
I did not know that, but, Works way better.

EDIT:

Try simulated compare,
Dfactor=4.0, MinDif=0.0 # as ScSelect # Has loads of false detections in near static scenes
Dfactor=4.0, MinDif=1.0 # as ScSelect_HBD default, 2nd script in 2nd post
(but you need to change arg set to dFactor=4.0, MinDif=0.0 for ScSelect original emulation).


# Original ScSelect, detect on Start of scene, eg where Next_diff==0.0 so anything above 0.0 yields SOS.
SOS = Prev_diff > Next_Diff * 4.0
SOS = 0.000001 > 0.0 *4.0 = TRUE # anything above 0.0 is start of scene,

SOS = Prev_diff > Next_Diff * 4.0 + MinDif
SOS = 0.000001 > 0.0 * 4.0 + 1.0 = FALSE # Way better in near static scenes,

In other words, original ScSelect plugin (whether new HBD plugin or original),
detects a near dupe before an exact dupe to be a Start Of Scene, similar for end of scene, near dupe after an exact dupe.

EDIT:
Mindif, Default 1.0. (0.0 <= Mindif, Supply MinDif as if in 8 bit range, 0.0 -> 255.0)
An additional component part of scene change detection.
Where difference measurements,
pDf = Average per pixel Luma difference, between dClip current frame and previous frame (0.0->255.0).
nDf = Average per pixel Luma difference, between dClip current frame and next frame (0.0->255.0).
pTh = dFactor * nDf + MinDif : If pDf greater than this then is SOS, Start-Of-Scene.
nTh = dFactor * pDf + MinDif : If nDf greater than this then is EOS, End-Of-Scene.
Detect method,
SOS = pDf > pTh : SOS = pDf > dFactor * nDf + MinDif, Also,
EOS = nDf > nTh : EOS = nDf > dFactor * pDf + MinDif.
(If pDf > pTh, then pDf is also greater than nDf as dFactor is at least 1.0 and MinDif at least 0.0)
Original ScSelect, used default dFactor=4.0, and equivalent of MinDif=0.0 (It had no MinDif arg).
Using only dFactor, and no Mindif (ie 0.0), is not too good as a detector, especially where
scene of low motion or near static scene, eg when nDf=0.0 then pDf value of anything above 0.0
would detect a scene change, not exactly as desired for near static scene, additinal component is needed.
In same situation where MinDif=1.0 and nDf=0.0, so SOS = pDf > pTh : SOS = pDf > 4.0 * 0.0 + 1.0
so, to detect Start of scene then pDf has to be greater than 1.0 for a start of scene detect.
In near static scene, we are most reliant upon Mindif being of sufficient magnitude to avoid a false
detection. In scene with plenty of motion, then value of dFactor becomes more important to prevent false
detection. In a very jerky or anime scene, then probably a high dFactor and high Mindif are required.
In this crazy mixed up world, you have to find a good compromise for dFactor and MinDif
so as to detect scene changes without producing false detections.

StainlessS
13th February 2021, 19:01
Here test script with ScSelect script version versus ScSelect plugin [not sure if original or updated]
EDIT: does not really matter either way whether update or original version plugin, the fact that scriipt
works with HBD is really incidental, we convert dClip to 8 bit for detection anyway, makes little difference
for scene change detect. We use 8 bit dclip only for 0.0 -> 255.0 range MinDif and metrics shown.


Import(".\ScSelect_HBD.avs")

Colorbars(pixel_type="YV24").killaudio.Trim(0,-1)
A=Last
K=Last.BlankClip(width=1,height=1,Color=$808080) # Single middle grey dot
B=Overlay(K,x=4,Y=4) # Single grey dot @ coords 4,4, YV24 [overlay on grey bar]
A+A+B+A+A # Frame 2 with grey dot
C=LAst

SZ = Max(Round(Height*0.10),24)
Start=Subtitle("START OF SCENE",align=5,size=SZ,Y=Height/2-SZ,Text_Color=$FF4040)
End=Subtitle("END OF SCENE", align=5,size=SZ,Y=Height/2+SZ,Text_Color=$4040FF)
Motion=Subtitle("GLOBAL MOTION",align=5,size=SZ)

X = ScSelect_HBD(C,Start,End,Motion,dFactor=4.0,Mindif=1.0) # ScSelect_HBD() Script
Y = ScSelect (C,Start,End,Motion,dFactor=4.0) # ScSelect, Plugin

StackVertical(X,Y)

R1=Trim(0,-1)
R2=Trim(1,-1)
R3=Trim(2,-1)
R4=Trim(3,-1)
R5=Trim(4,-1)

StackHorizontal(R1,R2,R3,R4,R5) # Stack frames horizontal

Spline36Resize(1200,360) # for forum view


https://i.postimg.cc/PrG3TncR/test-00.jpg (https://postimages.cc/)

top, script version dfactor=4.0, Mindif=1.0
bot, plugin version dfactor=4.0 # Mindif equivalent to 0.0.

Script marks start and end frame correctly.
Also no detect of single dot on middle frame 2, mid grey dot on top of nearly mid grey bar].
(plugin marks frames before it [EDIT: before the dot frame] and after it as scene change frames).
An almost almost almost identical frame should not really produce any scene change detection [above caused 2 detects].

EDIT:
The other comparison script pairs, are intended to save user work.
They allow you to view only scene change detections, instead of scanning through entire clip looking for them.
And the other one allows to view two arg sets results, but only where their results differ, again without having to manually scan entire clip.