View Full Version : [Solved] Colour mark detection for frames remouval in 8mm/S8 transfer
chmars
3rd May 2021, 10:50
Hello dear users,
BACKGROUND
I am achieving the construction of a film-transfer system for 8mm and Super8 films.
It is based on the method of capturing the frames directly into the projector's gate with a running video camera (versus frame by frame capture).
My first goal coming here was to enjoy the huge Fred's script and John's version generously shared here and perfected with the help of many users in this thread. (https://forum.doom9.org/showthread.php?t=144271&highlight=power+avisynth)
As I needed to have a frame accurate capture (one video frame for one footage frame) to use these scripts, i built a system and posted my setup description and question there (https://forum.doom9.org/showthread.php?p=1941818#post1941818). But that became off topic. I began this thread.
SETUP Detailed setup + pictures here (https://forum.doom9.org/showthread.php?t=182868)
As is not possible to synchronize the camera I am using with the projector, I had to find a way to peseudo-sync them.
The idea I had was to place an LED on the side of the gate. The LED is turned on each time the projector is changing from one frame to the next one, then turned off when the frame is steady. The projector runs at 18 fps while the camera shoots at 50 fps.
This way, the capture contains the information about which frames are usable and which are not.
THE SITUATION
Sample here (https://we.tl/t-2Aejg9KjXJ), md5:0820A24F2D0AB47483FA5E3BF5DADB69 File is directly out of the camera, hence inverted.
As you can see in the sample, I now have captured sequences containing one or more "bad frames" followed by one or more "good frames":
Here is a screenshot to give you an idea:
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/TpZy6VqmiU3YVLh/download
B = Bad frame (blue light presence)
G = good frame (no blue light)
Example starting from frame 314 included, to 335:
G B GG B GG B G BB G BB G B GG B GG B
We sometimes have GG, sometimes BB.
But we always have at least one G between one or some B.
I think we could say:
"keep only one G between each B/each group of B", it should work, don't You think?
Step by step, more or less human spoken, it would give:
If B, throw away and flag "last was B"
else if G, and flag is "last was B", keep and flag "last was G"
else if G, and flag is "last was G", throw away
and so on...
THE QUESTION
How do we ask this to Avisynth?
I'll share my attempts into the next post.
chmars
3rd May 2021, 10:56
Being very noob, I needed half of last night to find a start of partly working solution.
It may be very naive and inappropriate but here it is, at least to prove my effort :--)
This code is removing all B frames except when two are directly in a row.
LoadPlugin("C:\Program Files (x86)\AviSynth+\plugins/ffms2.dll") # Load the plugin able to read MXF files
initial_video = FFmpegSource2("C:\some_path\my_sample.MXF", atrack=-2) # How to read and which is the file
video = Crop(initial_video, 474, 190, -166, -170) # Crop my video frame
ScriptClip(video, \ #Will be done on each frame of clip "video"
"frame_chromaU = AverageChromaU(Crop(video,0, 0, -1000, 0))" + chr(13) + \ #Store the chroma U average of a cropped part of the immage in a variable
"frame_chromaV = AverageChromaV(Crop(video,0, 0, -1000, 0))" + chr(13) + \ #Store the chroma V average of a cropped part of the immage in a variable
"frame_luma = AverageLuma(Crop(video,0, 0, -1000, 0))" + chr(13) + \ #Store the luma average of a cropped part of the immage in a variable
"black_ref_luma = AverageLuma(Crop(video,150, 560, -1000, 0))" + chr(13) + \#Same for black part as reference
"round(frame_chromaU) > 520 && \ # If chroma U average is bigger than 520 AND
round(frame_chromaV) < 503 && \ # if chroma V average is smaller than 503 AND
round(frame_luma) > 200 && \ # if luma average is bigger than 200 AND
round(black_ref_luma) < 200 \ # if the black part of the image is not lit by something else
? DeleteFrame(current_frame) : subtitle(string()) ") # then we can hope the led is ON and delete the frame. Else, do nothing
This code works but has to be adapted (crop values) and run a second time on the resulting avi file as it appeared to me that it seems not possible to delete two frames in a row.
And then? It'll result in a file with lots of duplicated frames. I could then use someting like a duplicated frame detector (http://avisynth.nl/index.php/External_filters#Duplicate_Frame_Detectors).
But this is no good solution as it adds an interpretation of the images, introducing a cause of errors (Am I right on this point?).
What would be needed is to store the B frame-number into a variable outside of the run-time environment to be able to keep only one of the next G frames.
Or write a list into a text file?
I'll make some tries but if you have suggestions, they are very welcome.
StainlessS
3rd May 2021, 16:24
Script moved here from this post:- https://forum.doom9.org/showthread.php?p=1941999#post1941999
Blue_LED_Detect.avs [detector, frames.txt maker]
# Blue_LED_Detect.avs
/*
Requires, AVS+, RT_Stats, MaskTools
Detects Blue LED's, selects mid frame of those frames between blue LEDs,
when SEL2ND==True and frame count between Blue LEDs are even, then selects the later middle frame rather than default earlier middle frame.
Writes only single middle frame between BLUE frames.
May need to adjust AREA Coords where BLUE expected
*/
FN = "MBGV0403.MXF"
############
VFLIP = True # Vertical Flip if upside down
SETUP_BLUE = False # Setup BLUE Detect Vars MODE ONLY. DOES NOT Detect non BLUE nor write Frames
BAFFLE = 4 # Blue Detect Vars (RT_YInRangeLocate, Probably should leave this one alone)
THRESH = 10.0 # Ditto, Maybe bout 5.0 -> 20.0
LUMA_MIN = 60 # Ditto, blue luma min
LUMA_MAX = 255 # Ditto (Leave alone)
AREA_X = 240 # BLUE Coords test area
AREA_Y = 300 # Ditto
AREA_W = 530 # Ditto
AREA_H = 572 # Ditto
SEL2ND = False # When NonBlue count is EVEN, false selects earlier middle frame, True select later middle frame.
SHOW = true # Metrics + BLUE MARKER [FALSE for final, quicker]
############
FN = FN.RT_GetFullPathName
LWLibavVideoSource(FN)
############
ConvertBits(8).ConvertToYV12 # Just for Detect
ORG = Last
(VFLIP) ? FlipVertical : NOP
# Un-comment BELOW to SHOW BLUE TEST AREA COORDS
#return Overlay(Last.BlankClip(Length=1,Width=AREA_W,Height=AREA_H,color=$FFFF00),x=AREA_X,y=AREA_Y,Opacity=0.3)
##########################
DB = ".\MyDBase.DB".RT_GetFullPathName
FRAMES = ".\Frames.txt".RT_GetFullPathName
TypeStr = "iiiiiiii"
RT_FileDelete(FRAMES)
RT_DBaseAlloc(DB,FrameCount,TypeStr)
############ DBase Field Index's
STAT_FLD = 0 # 0=Unknown, 1=BLUE, 2=Non Blue Frame(Not chosen), 3=Non Blue chosen Frame.
# Valid only When STAT==2 OR STAT==3 (NOT BLUE_LED Stat==1)
FRM_S_FLD = 1 # Ditto, 1st frame of non BLUE
FRM_M_FLD = 2 # Ditto Chosen Non Blue (writen to Frames file)
FRM_E_FLD = 3 # Ditto Last frame of non BLUE
BLUE_X_FLD = 4 # Blue Detect Coords, Valid ONLY when STAT==1 (BLUE_LED)
BLUE_Y_FLD = 5 # Ditto
BLUE_W_FLD = 6 # Ditto
BLUE_H_FLD = 7 # Ditto
# Setup Detect Vars Script
SCRIPT_0 = """
n=current_frame
if(RT_YInRangeLocate(Last,n=n,x=AREA_X,y=AREA_Y,w=AREA_W,h=AREA_H,Baffle=BAFFLE,Thresh=THRESH,Lo=LUMA_MIN,Hi=LUMA_MAX)) {
Blue_x = YIRL_X /2 * 2 Blue_y = YIRL_Y / 2 * 2
Blue_w = (YIRL_W + 1) / 2 * 2 Blue_h = (YIRL_H + 1) / 2 * 2
Mrk = Last.BlankClip(Length=1,Width=Blue_w,Height=Blue_h,Color=$FFFF00)
Msk = Hit_Marker(Blue_w,Blue_h,False)
Overlay(Mrk,x=Blue_x,y=Blue_y,Mask=Msk,Mode="Blend")
}
Subtitle("Setup BLUE Detect Vars",Size=48)
Return Last
"""
# Write FRAMES File Script
SCRIPT_1="""
n=current_frame
Stat = RT_DBaseGetField(DB,n,STAT_FLD)
if(Stat == 0) { # Unknown
Stat = RT_YInRangeLocate(Last,n=n,x=AREA_X,y=AREA_Y,w=AREA_W,h=AREA_H,Baffle=BAFFLE,Thresh=THRESH,Lo=LUMA_MIN,Hi=LUMA_MAX) ? 1 : 2
if(Stat==1) { # BLUE
Blue_x = YIRL_X / 2 * 2 Blue_y = YIRL_Y / 2 * 2
Blue_w = (YIRL_W + 1) / 2 * 2 Blue_h = (YIRL_H + 1) / 2 * 2
RT_DBaseSet(DB,n,Stat, -1,-1,-1, Blue_X,Blue_Y,Blue_W,Blue_H)
} Else { # NOT BLUE
Frame_S = n
For(i=n-1,0,-1) { # Step Backwards looking for previous BLUE
# i is Always either KNOWN BLUE or Unknown
Stat = RT_DBaseGetField(DB,i,STAT_FLD)
if(Stat == 0) { # Unknown
if(RT_YInRangeLocate(Last,n=i,x=AREA_X,y=AREA_Y,w=AREA_W,h=AREA_H,Baffle=BAFFLE,Thresh=THRESH,Lo=LUMA_MIN,Hi=LUMA_MAX)) {
Blue_x = YIRL_X / 2 * 2 Blue_y = YIRL_Y / 2 * 2
Blue_w = (YIRL_W + 1) / 2 * 2 Blue_h = (YIRL_H + 1) / 2 * 2
RT_DBaseSet(DB,i,1, -1,-1,-1, Blue_X,Blue_Y,Blue_W,Blue_H) # set BLUE stuff
Frame_S = i + 1 # Start frame = BLUE + 1
i = 0 # Break
} Else { Frame_S = i } # Non BLUE
} else { # KNOWN BLUE
Assert(Stat==1,"Internal Error #1 Stat="+String(Stat))
Frame_S = i + 1 # Start frame = BLUE + 1
i = 0 # Break
}
}
Frame_E = n
For(i=n+1,FrameCount-1) { # Step Forwards looking for next BLUE
# i is Always either KNOWN BLUE or Unknown
Stat = RT_DBaseGetField(DB,i,STAT_FLD)
if(Stat == 0) { # Unknown
if(RT_YInRangeLocate(Last,n=i,x=AREA_X,y=AREA_Y,w=AREA_W,h=AREA_H,Baffle=BAFFLE,Thresh=THRESH,Lo=LUMA_MIN,Hi=LUMA_MAX)) {
Blue_x = YIRL_X / 2 * 2 Blue_y = YIRL_Y / 2 * 2
Blue_w = (YIRL_W + 1) / 2 * 2 Blue_h = (YIRL_H + 1) / 2 * 2
RT_DBaseSet(DB,i,1, -1,-1,-1, Blue_X,Blue_Y,Blue_W,Blue_H) # set BLUE stuff
Frame_E = i - 1 # End frame = BLUE - 1
i = FrameCount-1 # Break
} Else { Frame_E = i } # Non BLUE
} else { # KNOWN BLUE
Assert(Stat==1,"Internal Error #2 Stat="+String(Stat))
Frame_E = i - 1 # End frame = BLUE - 1
i = FrameCount-1 # Break
}
}
SelIx = (Frame_E - Frame_S) / 2
Frame_M = (SEL2ND) ? Frame_E-SelIx : Frame_S + SelIx
for(i=Frame_S,Frame_E) {
Stat = (i==Frame_M)?3:2
RT_DBaseSet(DB,i,Stat, Frame_S,Frame_M,Frame_E, -1,-1,-1,-1)
}
Stat = (n==Frame_M)?3:2
}
} # End, if(Stat == 0)
# Here, Stat=1=BLUE, =2 non-blue Frame - not chosen, 3=Chosen Frame
if(Stat==1) { # BLUE
if(SHOW) {
Blue_x = RT_DBaseGetField(DB,n,BLUE_X_FLD) Blue_y = RT_DBaseGetField(DB,n,BLUE_Y_FLD)
Blue_w = RT_DBaseGetField(DB,n,BLUE_W_FLD) Blue_h = RT_DBaseGetField(DB,n,BLUE_H_FLD)
Mrk = Last.BlankClip(Length=1,Width=Blue_w,Height=Blue_h,Color=$FFFF00)
Msk = Hit_Marker(Blue_w,Blue_h,False)
Overlay(Mrk,x=Blue_x,y=Blue_y,Mask=Msk,Mode="Blend",Opacity=0.3)
Subtitle(RT_String("%d ] BLUE LED, detect x=%d y=%d w=%d h=%d",n,Blue_x,Blue_y,Blue_w,Blue_h),Size=48,Align=1)
}
} else if(Stat==3 || SHOW) {
Frame_S = RT_DBaseGetField(DB,n,FRM_S_FLD)
Frame_E = RT_DBaseGetField(DB,n,FRM_E_FLD)
(SHOW) ? Subtitle(RT_String("%d ] S=%d E=%d Len=%d",n,Frame_S,Frame_E,Frame_E-Frame_S+1),Size=48) : NOP
if(Stat==3) { # Write To Frames File
if(!SEL2ND || n == Frame_S + ((Frame_E - Frame_S) / 2)) {
RT_WriteFile(FRAMES,"%d",n,Append=n!=0)
(SHOW) ? Subtitle(RT_String("Writing"),Size=48,y=48) : NOP
} else {
RT_WriteFile(FRAMES,"%d # 2nd of middle pair",n,Append=n!=0)
(SHOW) ? Subtitle(RT_String("Writing, 2nd of middle pair"),Size=48,y=48) : NOP
}
}
}
Return Last
"""
SSS = (SETUP_BLUE) ? SCRIPT_0 : SCRIPT_1
ScriptClip(SSS)
Return Last
Function Hit_Marker(int W, Int H, Bool "Hit", Int "BW", Int "BH",Int "PW",Int "PH",Bool "YV12",Bool "Mod2") {
/*
Req RT_Stats & mt_tools v2. http://forum.doom9.org/showthread.php?t=174527
Creates a marker mask WxH, for use with Overlay as Mask arg.
Intended for use via some kind of detector to show detection Hit, or Miss.
Returns Single frame clip with null audio, the marker top left hand side is aligned to 0,0.
Default return clip colorspace is Y8 for Avisynth v2.6 and above, or YV12 if defunct version.
Args:-
W,H, Size of marker mask (can be odd), return clip dimensions are rounded up to next multiple of 2 if YV12 return clip.
Bare minimum usable size is 4x4 with defaulted BW, BH, PW, PH.
HIT, Default False, returns marker as angled corners (Thickness set by BW and BH).
True, returns marker as angled corners + outer perimeter where perimeter thickness set by PW and PH.
BW, Default Max(W/8,1). Horizontal thickness of the marker corners.
BH, Default Max(H/8,1). Vertical thickness of the marker corners.
PW, Default Max(BW/8,1). Horizontal thickness of the vertical perimeter.
PH, Default Max(BH/8,1). Vertical thickness of the horizontal perimeter.
YV12, Default False if Avisynth version 2.6 or greater(Y8), else true(YV12). Selects return clip colorspace.
Mod2, Default True. If Y8 then round odd dimensions up modulo 2 (the mask is still WxH).
Example:-
Import("Hit_Marker.avs")
WW=128 HH=WW HIT=True
BlankClip
Yell=Last.BlankClip(Width=WW,Height=HH,Length=1,Color=$FFFF00)
Return OverLay(Yell,x=(Width-WW)/2,y=(Height-HH)/2,mask=Hit_Marker(WW,HH,HIT))
*/
Hit=Default(hit,False) BW=Max(Default(BW,W/8),1) BH=Max(Default(BH,H/8),1)
BW2=(W>4)?BW*2:BW BH2=(H>4)?BH*2:BH
PW=Max(Default(PW,BW/8),1) PH=Max(Default(PH,BH/8),1) is26 = VersionNumber>=2.6
YV12=(!is26) ? True : Default(YV12,False) Mod2=Default(Mod2,True) Mod = (YV12||Mod2) ? 2 : 1
CanvasW=(W+Mod-1)/Mod*Mod CanvasH=(H+Mod-1)/Mod*Mod
Rpn= RT_String("x %d < x %d >= | y %d < | y %d >= | x %d < x %d >= | & y %d < y %d >= | & ",BW,W-BW,BH,H-BH,BW2,W-BW2,BH2,H-BH2)
Rpn= (Hit) ? Rpn + RT_String("x %d < x %d >= | y %d < | y %d >= | | ",PW,W-PW,PH,H-PH) : Rpn
Rpn= Rpn + RT_String("x %d < y %d < & & 255 0 ?",W,H)
Blankclip(width=CanvasW,height=CanvasH,Length=1,pixel_type=YV12?"YV12":"Y8").Killaudio
return mt_lutspa(relative = false,yExpr=Rpn, chroma = "-128")
}
Blue_LED_FrameSel.avs
# Blue_LED_FrameSel.avs
# Requires FrameSel plugin. (OK for HBD so long as dont use FrameSel SHOW arg).
# Requires Frames.txt as generated by Blue_LED_Detect.avs
FN = "MBGV0403.MXF".RT_GetFullPathName
FRAMES = "Frames.txt".RT_GetFullPathName
############
VFLIP = True # Vertical Flip if upside down
REJECT = False # If True then show all rejected frames instead of selected frames
LWLibavVideoSource(FN)
(VFLIP) ? FlipVertical : NOP
# FrameSel, DONT USE SHOW ARG if NOT 8 bit.
Return FrameSel(Last,Cmd=FRAMES,Ordered=True,REJECT=REJECT)
EDIT: click to enlarge
Blue Detect Frame [SHOW=true]
https://i.postimg.cc/PLZg32GT/det.jpg (https://postimg.cc/PLZg32GT)
Non Blue selected frame [SHOW=true]
https://i.postimg.cc/7f6p8xvB/sel.jpg (https://postimg.cc/7f6p8xvB)
EDIT: I can possibly mod current script, (I'll leave above in-situ), to auto scan [will seem to pause for some time],
and then do equivalent to calling the FrameSel script, and be ready to output final clip in eg VDub2 Save AVI or whatever.
All in single script, and auto deleting the DBase file on clip closure.
ScriptClip MUST have same number of output frames as input, and also same size/colorspace etc, that is why you are ending up
with many dupes at end of clip. [The framecount, size, colorspace, is fixed as soon as frameserving begins]
EDIT: Is the BLUE_LED detection working as per requirement ?
Also, is it required that you can execute two or more separate instances of the script simultaneously ?
johnmeyer
3rd May 2021, 19:23
My guess is that you can use one or two lines of code, simply using the YDDifference function built into AVISynth. I do this all the time to find "flash frames," my term for the grossly overexposed frame that you get in a movie camera at the first frame when the camera is still coming up to speed, and the shutter blade is rotating too slowly, resulting in overexposure.
All you need to do is compare the current frame to each adjacent frame, and when this bidirectional metric blows up, you have found your LED frame.
StainlessS
3rd May 2021, 20:13
YDifference just tells absolute difference, could be going lighter, or darker, if different to prev, then could be black to blue or blue to black,
if same then could be both black or both blue.
Something additional is needed [ie Averageluma or similar on current frame].
If just picking 1st non blue frame after blue, then dont think you need bother about next frame at all, only previous.
You still got lots of dupes at end to remove.
EDIT: Also, there is maybe need to specifiy what exactly a blue frame is, ie how much blue, is any blue at all
considered blue. My detector looks for a 'chunk of blue of a minimum size [avoid any noise] and possibly moving
[as Blue LED does].
6] With current settings, this is considered [2nd of 2] Not Blue [but could be tweaked to consider as blue]
https://i.postimg.cc/3y2Dg719/Not-Blue.jpg (https://postimg.cc/3y2Dg719)
7] Blue
https://i.postimg.cc/fkVDF5nQ/Isblue.jpg (https://postimg.cc/fkVDF5nQ)
8] Not blue [1 of 1]
https://i.postimg.cc/dkzXg2rJ/8.jpg (https://postimg.cc/dkzXg2rJ)
9] Blue
https://i.postimg.cc/Pvjym21v/9.jpg (https://postimg.cc/Pvjym21v)
The detector is looking for a chunk of blue of a certain size & 'density'.
And the fact that its a blue LED dont really make a whole helluva lot of difference, brightness will quite suffice to detect.
johnmeyer
3rd May 2021, 20:21
I use the ratio of YDifferenceToNext and YDifferenceToPrevious. This gets rid of the problem of how these metrics vary over time as the nature of the video changes. I posted such a detection script several years ago and, with StainlessS' help, turned it into a pretty useful detection script for finding individual "bad" frames. The LED flash is a classic bad frame, and my detection script should therefore work perfectly. Here is the link:
Finding individual "bad" frames in video; save frame number; or repair (https://forum.doom9.org/showthread.php?t=174104&highlight=ydifferencetonext)
My finished script appears in post #6.
StainlessS
3rd May 2021, 20:55
With current clip cap speeds, there can be single or multiple [2] of either blue or non blue frames,
any single would appear as a flash in a YDifferenceToNext and YDifferenceToPrevious ratio thingy,
whether it be black flash or blue flash. You still need to be able to tell one from other.
I've deliberately made my detector be able to cope with (single or) many blue and/or (single or) many black frames,
if cap speeds were to be changed.
EDIT:
Simple-ish detector would test luma [AverageLuma, or maybe YPlaneMax] and if BELOW some threshold, then
also test if sufficiently different to prev frame, if so then is first non blue.
[ie current frame TEST AREA is BLACK, prev frame TEST AREA is NOT BLACK]
EDIT: Fixed, I originally wrote "Above".
EDIT: Yep, Maybe YPlaneMax(threshold=100/256.0) # where threshold = 0.4% Percent of extreme [possible noise] pixels to ignore.
chmars
3rd May 2021, 21:30
Hi,
I was very excited to find your script, it's great to have such a tool for my setup! Thanks again very much for the work.
ScriptClip MUST have ... many dupes at end of clip.
Ok, thanks. But...you know, I think i'll leave my "script" on the side for the moment and focus on yours. ;)
Your functional proposals are interesting. The more is automated, the best it is. But I am far from asking any more, as it is already time spent for you and so great compared to what I can write!
Also, is it required that you can execute two or more separate instances of the script simultaneously ?
Ideally? Put all the clips into a directory, go drink a coffee (or shoot some more) and have finished deduped+deblued clips in another dir when I come back. :-)
Is the BLUE_LED detection working as per requirement ?
EDIT: Works perfectly in AvsPmod 2.6.7.5.
On my side, half way: It behaves as if one part of it would be too fast for another part. It ends with only some frames numbers into the txt file. Same with/without showing metrics+marker.
Text file:
0
11
52
68
121
140
302
321
371
495
701
718
743
766
782
816
844
849
Error Window:
Error parsing plugin string at position 0:
Error parsing Func plugin parameters: unknown character 'n'
Error parsing ConditionalSelect plugin parameters: unknown character 'n'
Error parsing ConditionalSelect plugin parameters: unknown character 'n'
Error parsing ConditionalFilter plugin parameters: unknown character 'n'
Error parsing ConditionalFilter plugin parameters: unknown character 'n'
Error parsing ConditionalFilter plugin parameters: unknown character 'n'
Error parsing ScriptClip plugin parameters: unknown character 'n'
Error parsing ScriptClip plugin parameters: unknown character 'n'
Error parsing WriteFile plugin parameters: unknown character 'n'
Error parsing WriteFile plugin parameters: + without preceeding argument
Error parsing WriteFileIf plugin parameters: unknown character 'n'
Error parsing WriteFileIf plugin parameters: + without preceeding argument
Error parsing WriteFileStart plugin parameters: unknown character 'n'
Error parsing WriteFileStart plugin parameters: + without preceeding argument
Error parsing WriteFileEnd plugin parameters: unknown character 'n'
Error parsing WriteFileEnd plugin parameters: + without preceeding argument
Error parsing WriteFile plugin parameters: unknown character 'n'
Error parsing WriteFile plugin parameters: + without preceeding argument
Error parsing WriteFileIf plugin parameters: unknown character 'n'
Error parsing WriteFileIf plugin parameters: + without preceeding argument
Error parsing WriteFileStart plugin parameters: unknown character 'n'
Error parsing WriteFileStart plugin parameters: + without preceeding argument
Error parsing WriteFileEnd plugin parameters: unknown character 'n'
Error parsing WriteFileEnd plugin parameters: + without preceeding argument
Error parsing propSet plugin parameters: unknown character 'a'
Error parsing propSetInt plugin parameters: unknown character 'n'
Error parsing propSetFloat plugin parameters: unknown character 'n'
Error parsing propSetString plugin parameters: unknown character 'n'
Error parsing propSetArray plugin parameters: unknown character 'n'
Error parsing propSet plugin parameters: unknown character 'a'
Error parsing propSet plugin parameters: unknown character 'a'
Error parsing propSet plugin parameters: unknown character 'a'
Error parsing propSet plugin parameters: unknown character 'a'
Error parsing OnCPU plugin parameters: unknown character 'n'
Error parsing OnCPU plugin parameters: unknown character 'n'
But when I run it manually (arrow key), it works correctly.
I use AVS+ 3.7.0 on a win10 PC.
and going to search the way to determine the version of the DLLs
EDIT: I tried many times, to be sure. Deleting the db, lwi and text file between attempts. The source file (...403.mxf) is in the same directory.
chmars
3rd May 2021, 22:03
Wow, works absolutely fluently in AvsPmod 2.6.7.5 !
StainlessS
3rd May 2021, 22:35
I cannot make my ver$ fully automatic.
TWriteAVI(), could have made possible but cannot write files > 2GB, nor supports HBD. [I cannot mod for > 2GB, I dont speak x86 assy nor
do I know how to mod for DML AVI spec supporting > 2GB files.]
If TWriteAVI suppored both HBD and > 2GB files, would be a [near] walk in the park.
[EDIT: Only small amount of x86 assy in TWriteAVI, main prob is the DML AVI spec >2GB stuff]
This stuff
Error Window:
Error parsing plugin string at position 0:
Error parsing Func plugin parameters: unknown character 'n'
Error parsing ConditionalSelect plugin parameters: unknown character 'n'
Error parsing ConditionalSelect plugin parameters: unknown character 'n'
Error parsing ConditionalFilter plugin parameters: unknown character 'n'
Error parsing ConditionalFilter plugin parameters: unknown character 'n'
Error parsing ConditionalFilter plugin parameters: unknown character '
Was that output from my script, or yours ? [definitely should not have come out of my script, I dont even use WriteFileIf, nor other stuff],
but referring to deleting the DB has me puzzled.
Wow, works absolutely fluently in AvsPmod 2.6.7.5 !
And what is that referring to, what works in AvsPMod.
doctorkhv
3rd May 2021, 23:26
I don’t understand why to do this?
The cost of high-quality digitizing of 8 mm film 60 min ~ $ 100
StainlessS
4th May 2021, 01:08
The cost of high-quality digitizing of 8 mm film 60 min ~ $ 100
Well if he has 1000 hours of the stuff, then that would be $100,000.00, that would be a more than good enough reason for me.
chmars,
Metrics viewer, for adjusting test area coords and thresholds.
Using same method should work pretty well. Choose Detection_Threshold midway between displayed metrics for
minimum Blue_LED frame, and maximum Non_blue_LED frame. Also can choose metrics as for 8 bit or native bit depth
eg 10 bit for your posted clip. [8 Bit will be easily more than sufficient (and more familiar values)].
# Requires Grunt() plugin
LWLibavVideoSource(".\MBGV0403.MXF")
############
TEST_X = 374
TEST_Y = 210
TEST_W = 372
TEST_H = 700
BITS8 = True # Metrics are as 8 bit
MMDIFTH = 0.4 # YPlaneMinMaxDifference Threshold (100.0/256.0) about 0.4 % [Percentage of extreme (noise) pixels to ignore].
VFLIP = True # Vertical Flip if upside down
############
(VFLIP) ? FlipVertical : NOP
Show_TestArea(TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,MMDIFTH)
Return Last
Function Show_TestArea(clip c,int x,int y,int w,int h,Bool "Bits8",Float "MMDifTh") {
Bits8 = Default(Bits8,False) # If True, then metrics are for 8 bit
Th = Default(MMDifTh,0.4) # YPlaneMinMaxDifference Threshold (%)
tc = c.Crop(x,y,w,h)
tc = Bits8 ? tc.ConvertBits(8).ConvertToYV12 : tc
SSS="""Return Subtitle(String(current_frame)+String(tc.YPlaneMinMaxDifference(threshold=Th),"] %.1f"),Size=48)"""
c.ScriptClip(SSS, Args="tc,Th")
Return Last.OverLay(c.BlankClip(Length=1,Width=w,Height=h,Color=$FFFF00),x=x,y=y,Opacity=0.1)
}
The Yellow Overlayed Block shows the Test area.
23] Blue_LED [frame number, then Metric ie YPlaneMinMaxDifference(threshold=0.4) in 8 Bit]
https://i.postimg.cc/HVfFkcWr/23-Blue.jpg (https://postimg.cc/HVfFkcWr)
24] Black
https://i.postimg.cc/tZSMQ7mC/24-Black.jpg (https://postimg.cc/tZSMQ7mC)
doctorkhv
4th May 2021, 01:25
Well if he has 1000 hours of the stuff, then that would be $100,000.00, that would be a more than good enough reason for me.
If the job is big, then you can just buy a scanner :)
https://www.ebay.com/b/Film-Scanner-Movie-Editing-Equipment/4790/bn_108187128
StainlessS
4th May 2021, 01:42
Not as much 'fun' as DIY, then Fred/Johns scripts for the ultimate results.
Maybe :)
StainlessS
4th May 2021, 05:31
Here is simpler detect [or will be when slimmed down] script, test version to see if the YPlaneMinMaxDifference thingy works OK.
LWLibavVideoSource(".\MBGV0403.MXF")
############
TEST_X = 374 # Test AREA COORDS (Even only)
TEST_Y = 210 # Ditto
TEST_W = 372 # Ditto
TEST_H = 700 # Ditto
BITS8 = True # Metrics are as 8 bit
DETTH = 50.0 # Detection Threshold (50 is 8 bit thresh)
MMDIFTH = 0.4 # YPlaneMinMaxDifference Threshold (100.0/256.0) about 0.4 % [Percentage of extreme (noise) pixels to ignore].
VFLIP = True # Vertical Flip if upside down
FRAMES = ".\Frames.txt"
############
(VFLIP) ? FlipVertical : NOP
############
FRAMES=FRAMES.RT_getFullPathName
RT_FileDelete(FRAMES)
tc = Crop(TEST_X,TEST_Y,TEST_W,TEST_H)
tc = Bits8 ? tc.ConvertBits(8).ConvertToYV12 : tc
SSS = """
DetCur = tc.YPlaneMinMaxDifference(threshold=MMDifTh)
DetPrv = tc.YPlaneMinMaxDifference(threshold=MMDifTh,offset=-1)
T1= DetCur < DetTh
T2= DetPrv >= DetTh
T3 = (T1 && (current_frame==0 || T2))
(T3) ? RT_WriteFile(FRAMES,"%d",current_frame,Append=true) : NOP
s= RT_string("%d] DetCur=%d(%.1s) DetPev = %d(%.1s) T=%s",current_frame,DetCur,T1,DetPrv,T2,T3)
Subtitle(s,size=48)
Return Last
"""
ScriptClip(SSS)
I will mod to use WriteFileIf whotsit [tomorrow, I'm off to bed].
Output identical frame numbers to original script except this one outputs 91 and original 90.
Output of this will extract good frames using the same Framsel script.
chmars
4th May 2021, 06:00
I cannot make my ver$ fully automatic.
I made you spend enough time already. I was not asking seriously. Your script is infinitely better than wha I could do and works perfectly. Fits perfectly my needs.
You are right, the errors output are present even with Version().
Nothing to do with your script.
And what is that referring to, what works in AvsPMod.
Your script. It misses lots of good frames when I run it in Avspmod 2.5.1, but everything is ok in Avspmod 2.6.7.5.
Deleting the DB and all that was generated by your script was just a way to restart from zero with no elements in the directory that could (remember, i am a total noob) have perturbed the results and made me report wrongly.
chmars,
Metrics viewer, for adjusting test area coords and thresholds.
Great, perfect, luxury, lots of thanks!
I don’t understand why to do this?
The cost of high-quality digitizing of 8 mm film 60 min ~ $ 100
Yes, not as much fun at all.
Also, the price/quality from certain "professional" services I could see is alas far from what you describe.
I also ha e seen some regrets in this direction while reading the The power of Avisynth: restoring old 8mm films (https://forum.doom9.org/showthread.php?t=144271).
StainlessS
4th May 2021, 12:45
You are right, the errors output are present even with Version().
Nothing to do with your script.
At a guess, I'de say you may have a script in plugins that should not be there.
AVSI's should really only contain eg constants [like the colors_rgb.avsi thing], OR,
script function definitions [there might be a few additional exceptions].
It should not contain script to eg try to load some clip, and process it.
[This is my suspected problem - if it fails with "Version()" then is failing in erroneous script before it even gets to Version() whosit].
[Remove them all, then add then back, maybe one at a time until problem script is revealed with "Version()" script.]
[It is possible that there is an *.AVS script in plugins, with code not intended for AVSI script, AVS+ also loads AVS from plugins,
assuming that you forgot to rename to AVSI (pre-AVS+ did not auto load AVS)].
You did not have to delete the DB, RT_DBaseAlloc() initializes a new DBase, whether existing or not.
The Chosen YPlaneMinMaxDifference(threshold=0.4) builtin runtime filter whotsit,
counts all pixels values into an array [each element a population count for the pixel value that is same as element array index].
For YMax, It scans array elements from topmost downwards [one at a time] until sum of population is greater or equal to 0.4%,
and ignores any extreme values in array ABOVE that element. If there are a few extreme pixels [less than 0.4%] at top end, then these
are ignored, if the highest pop count in array has population of 0.4% or more, then nothing is ignored.
Same sort of thing happens at the bottom of array for the YMin thingy.
Final result of YPlaneMinMaxDifference(0.4) is the difference between these top and bottom chosen array index's.
Above roughly correct, hope that it made some sense.
EDIT:
YPlaneMinMaxDifference seems to work at least as well as the original detection method with yellow marker, and could be
substituted in the original DBase detector [probably also faster]. [I will likely do that].
chmars
4th May 2021, 16:18
I tried to empty the plugins dirs. Error window says the same.
But this happens only when I use Avspmod 2.5.1, not 2.6.7.5.
As long scripts are working, is it really a "must solve"?
I didn't see your new detect version. much faster! and so shorter.
Thank you for your explanations. I feel like a cat in an astrophysics conference: I get the very basic principles but not much more. My knowledge is not rich enough and my English neither is. :o
I tried the detector as it is in your post #15, without the DB part. It creates the text list of frames to keep. Then, I can generate the clip with FrameSel.avs.
So... I am sorry to ask, it is certainly obvious for most people but what is the DB part for?
Or, by saying
... and could be
substituted in the original DBase detector ...
must I understand the detector from post #15 must replace the whole first version?
If you have time, would you agree to write some comments into the detector lines so I could understand easier how it works?
Thank you,
BR
StainlessS
4th May 2021, 16:53
The DB thing was a detector, the one in post #15 is another detector with a different detection device/method,
both create a frames file.
The 2nd [#15] one writes the first frame after BLUE_LED, no matter how many consecutive BLUES or BLACKS there are,
the original DB one selects the middle BLACK frame, so if your timings differed, and/or LED or equivalent was not so precise,
it would give a better chance of selecting good frame.
I was just making a script that might be usable [hackable] in other circumstances, if with a different 'BLUE_LED' indicator, so more flexible, maybe.
I'll add comments to final versions.
chmars
4th May 2021, 17:12
Beautyfull!
In my case, I can adjust the LED start and stop times at the 1/1000 of second scale. So there is no need of possibility choosing the kept frame. But that could be useful for a more analogic system.
I made some tries with higher resolutions also. It works perfect after ajusting the size + pos of the detection zone.
It's a detail but I also made a modification to name the txt file with a part of the name of the clip to avoid mixing by error.
While testing it with several clips, I thought back to your idea of making both scripts into one. This would be very handy as with lots of clips to treat, it represents many manipulations:
I can possibly mod current script, (I'll leave above in-situ), to auto scan [will seem to pause for some time],
and then do equivalent to calling the FrameSel script, and be ready to output final clip in eg VDub2 Save AVI or whatever.
All in single script, and auto deleting the DBase file on clip closure.
But I feel just like having received a Rolls Royce and complaining about the tint! Understand me: Any tint fits perfectly to me and I am very happy with what I have.
StainlessS
4th May 2021, 17:33
Making auto two pass thing is not so difficult, but will be added at the end.
I'm a bit busy doing other stuff, and slotting bits of this in between. Might be a day or two before I complete.
EDIT: I'll continue until I'm happy with the tint.
chmars
4th May 2021, 18:29
EDIT: I'll continue until I'm happy with the tint.
:)
Wow! Are you an AI cluster, an entire group of humans at yourself, ET..?
:)
StainlessS
5th May 2021, 08:11
Auto 2 Pass. [made simpler/bit faster, using YPlaneMax only, single script]
BLUELED_SingleInstance.avs
# BLUELED_SingleInstance.avs
############
# Requires Avs+, RT_Stats, Grunt(), FrameSel, plugins.
############
FN = "MBGV0403.MXF" # Video FileName
##### Freq Changed Config #####
OP = 1 # 0,1,2,3 ONLY. ::: 0=Tweak Test Area, 1=Create Frames file, 2=Extract Frames, 3=Auto Two pass, pass1 then pass2.
SHOW = True # True, shows metrics on OP==1 [False is quicker]
# Less Often changed
TEST_X = 374 # Test AREA COORDS (Best Even only)
TEST_Y = 210 # Ditto
TEST_W = 372 # Ditto
TEST_H = 700 # Ditto
BITS8 = True # (True) Metrics and DetTh are as 8 bit range [If change BITS8 then MUST also CHANGE DETTH, ie DETTH*4]
DETTH = 50 # (50) Detection Threshold [ 50 is 8 bit thresh, for 10 bit use eg (50*4) ]
YMAXTH = 0.4 # (0.4) YPlaneMax Threshold (100.0/256.0) about 0.4 % [Percentage of extreme (noise) pixels to ignore].
VFLIP = True # Vertical Flip if upside down
REJECT = False # Arg to Pass 2 Extract Frames. [Extract BLUE LED frames instead of good frames if TRUE]
############
Assert(0 <= OP <= 3,"BlueLED: 1 <= OP <= 3") # Check Valid
FN = FN.RT_GetFullPathName # Ensure full path if not already got one
Frames = FN.RT_FilenameSplit(7) + "_Frames.txt" # If eg FN="...\MBGV0403.MXF" then Frames = "...\MBGV0403_Frames.txt"
LWLibavVideoSource(FN) # Video Source
############
(VFLIP) ? FlipVertical : NOP
SHOW = (OP==3) ? False : SHOW # Auto Switch OFF SHOW for pass 1 if two pass
if(OP==0) { BlueLED_Tweak(TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,YMaxTh) } # Tweak Coords
else if(OP==1) { BlueLED_Detect(Frames,TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,DetTh,YMaxTh,Show=SHOW) } # Detect
else if(OP==2) { BlueLED_FrameSel(Frames,REJECT) } # Extract Frames
else { # Auto 2 Pass
BlueLED_Detect(Frames,TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,DetTh,YMaxTh,Show=SHOW).RT_ForceProcess()
BlueLED_FrameSel(Frames,REJECT)
}
Return Last
############
# OP=0
Function BlueLED_Tweak(clip c,int x,int y,int w,int h,Bool "Bits8",Float "YMaxTh") {
# Shows YPlaneMax(YMaxTh) of Test Area (x,y,w,h, marked in yellow)
# If Bits8, then Test Area is converted to 8 bit Y8, and metrics shown in range 0->255
Bits8 = Default(Bits8,False) # If True, then metrics are for 8 bit
YMaxTh = Default(YMaxTh,0.4) # YPlaneMax Threshold (%)
tc = c.Crop(x,y,w,h) # Test Area
tc = Bits8 ? tc.ConvertBits(8).ConvertToY8 : tc # 8 Bit if requested
SSS="""
Subtitle(String(current_frame) + "] YMax=" + String(tc.YPlaneMax(threshold=YMaxTh)) , Size=48)
"""
c.ScriptClip(SSS, Args="tc,YMaxTh",Local = true)
OverLay(c.BlankClip(Length=1,Width=w,Height=h,Color=$FFFF00),x=x,y=y,Opacity=0.1) # Mark Test Area in yellow
Return Last
}
# OP=1
Function BlueLED_Detect(clip c,String Fn, int x,int y,int w,int h,Bool "Bits8",int "DetTh",Float "YMaxTh", Bool "Show") {
bpc = c.BitsPerComponent() # Bit Depth of c clip
Bits8 = Default(Bits8,False) # If True, then DetTh and metrics are for 8 bit
DetTh = Default(DetTh,Bits8?50:50*BitLShift(1,bpc-8)) # Detect Threshold. Compliant with Bits8 arg.
YMaxTh = Default(YMaxTh,0.4) # YPlaneMax Threshold (%)
Show = Default(Show,False)
Assert(fn!="","BlueLED_Detect: Fn Cannot be ''")
Fn = Fn.RT_GetFullPathName
RT_FileDelete(Fn)
tc = c.Crop(x,y,w,h)
tc = Bits8 ? tc.ConvertBits(8).ConvertToY8 : tc
SSS="""
YMaxCur = tc.YPlaneMax(YMAXTH) # YMax for current frame
YMaxPrv = tc.YPlaneMax(YMAXTH,offset=-1) # YMax for previous frame
T = (YMaxCur < DetTh && (YMaxPrv >= DetTh || current_frame==0))
(T) ? RT_WriteFile(Fn,"%d # %d",current_frame,YMaxCur,Append=current_frame>0) : NOP
if(Show) {
s = RT_String("%d] %s\\nYMaxCur=%d\\nYMaxPrv=%d\\n(DetTh=%d)",current_frame,T?"Bingo":"",YMaxCur,YMaxPrv,DetTh)
Subtitle(s,Size=48,lsp=0)
}
Return Last
"""
c.ScriptClip(SSS, Args="tc,DetTh,YMaxTh,Fn,Show",Local = true)
Return Last
}
# OP=2
Function BlueLED_FrameSel(clip c,String Frames,Bool "Reject") { # Extract Frames from clip c
Reject = Default(Reject,False)
Assert(Frames!="","BlueLED_FrameSel: Frames Cannot be ''")
Frames = Frames.RT_GetFullPathName # Add full path if not already got one
Return FrameSel(c,Cmd=Frames,Ordered=True,reject=Reject)
}
Updated
chmars
5th May 2021, 17:17
Gorgeous! Fast, Fluid, Clean, A Masterpiece!
I'd like to say something, a remark, demand....
But I don't find anything!
Only huge thanks!
chmars
5th May 2021, 17:40
Oh yes,
-automatic bitdepth
-detection zone always at the same place, relatively to the resolution.
But this is just to be maniac. We can also very easily comment/uncomment prepared lines.
The 403 sample file is 10 bit. Did you try the script while set on 8bit as it appears above? Seems to work too.
Cheers,
Edit:
I'd like to share the LED system, present the capture setup and so on, if it might interest someone.
But where?
"Avs usage", as it wouldn't work without AVS
or
"hardware players"? A super8 projector is a hardware player isn't it? :D
StainlessS
5th May 2021, 18:19
I'm gonna go feed ducks now, but before I do,
If you would like to be able to group select a bunch of your video files and auto batch create scripts with names already inserted [using a template].
See here [Avisynthesizer_Mod]:- https://forum.doom9.org/showthread.php?t=166820
Install it, and run the "Install_SendTo.Cmd" command.
Then,
Config your working script as desired [probably auto mode],
then on very top of script change to [ony the "#ASYNTHER" line required first, and ,also the FN = "___FILE___" required somewhere]
#ASYNTHER BLUELED_MAGIC_STUFF
# Requires Avs+, RT_Stats, Grunt(), FrameSel, plugins.
############
FN = "___FILE___"
Then save in the Avisynthesizer_Mod TEMPLATE directory as "BlueLED_Magic.avst" # Some name ending with ".avst"
BLUELED_MAGIC_STUFF can be any valid name [no spaces, as for an avs variable name]
As above, the BLUELED_MAGIC_STUFF name will be presented in a dialog box as a script selection option,
where multiple script templates are in the template directory. [you get to pick which script template is wanted]
chmars
6th May 2021, 22:07
Ok, thank you, instructions saved for later.
At the moment, too exited using your script which is the key to Fred's + variants (John's, MT...). Finally trying them after days of reading about them!
AND:
Your script confirmed the LED system is absolutely worth it: no frames loss, fast, no blended/duplicated frames, 100% frame accurate.
This is huge. Thanks again.
chmars
11th May 2021, 20:53
Changed from
Frames = FN.RT_FilenameSplit(14) + "_Frames.txt" # If eg FN="...\MBGV0403.MXF" then Frames = "...\MBGV0403_Frames.txt"
to
Frames = FN.RT_FilenameSplit(15) + "_Frames.txt" # If eg FN="...\MBGV0403.MXF" then Frames = "...\MBGV0403_Frames.txt"
(15) instead of (14) to have the whole path, including drive, in case the source is located in another drive than the script.
Can't say how much I 'm happy with this script!
StainlessS
11th May 2021, 21:37
Oh Shit!, it should have been
Frames = FN.RT_FilenameSplit(7) + "_Frames.txt" # If eg FN="...\MBGV0403.MXF" then Frames = "...\MBGV0403_Frames.txt"
sorry,
RT_FilenameSplit(string filename,int "get"=15)
Splits the un-named filename string into component parts selected by 'get' bit flags arg and returns the
parts joined together.
'Get' (default 15, 1 -> 15), If set, Bit 0=DRIVE, 1=Dir, 2=Name, 4=Extension.
Add 1 for Drive (bit 0), add 2 for Dir (bit 1), add 4 for Name (bit 2), add 8 for Extension (bit 3).
Some combinations do not make sense, eg Drive + Extension (1+8=9). Below sensible options.
1 = Drive (includes trailing ':')
2 = Dir (includes trailing '\')
3 = Drive + Dir
4 = Name
6 = Dir + Name
7 = Drive + Dir + Name
8 = Extension (includes leading '.')
12 = Name + Extension
14 = Dir + Name + Extension
15 = Drive + Dir + Name + Extension
Assuming a current working directory of eg "D:\avs\avi\", 'filename'="test.avi" and 'get'=15, returns "D:\avs\avi\test.avi",
so given a relative filename and default 'get'=15, is equivalent to RT_GetFullPathName(filename).
ie without extension, not without drive.
But 15 OK if you dont mind the ".MXF_Frames.txt"" part.
chmars
11th May 2021, 21:47
Nono, you're right, I read too fast.
Now using with AVSPLUS370_x64: I don't know if it is correct but I also added in the beginning:
SetMemoryMax(6000)
threads = 5
SetFilterMTMode("DEFAULT_MT_MODE", 2)
and at the end (before functions):
Prefetch(threads)
Have to tweak the values though.
StainlessS
11th May 2021, 22:09
It probably dont matter a damn with that script, assuming that you're writing result to disk.
EDIT:
Pass1, does little more than pull in frames from source (which needs to be sequential) filter,
only samples YMax for each frame via Scriptclip.
Pass2, does nothing but read frames flagged in frames file from the source filter.
SetMemoryMax(6000), just reserves loads of RAM that will not be needed, and
reduces RAM available to other processes.
Suggest skip all of that pre-script and post-script.
EDIT: OK, it also resizes and colorspace converts detect clip [which I forgot about] but maybe still not
a great deal of difference, you could test and see if any advantage at all.
chmars
11th May 2021, 22:18
:o Ok Sir, thanks for explaining.
First think, then do...
chmars
12th May 2021, 23:25
Made some tests to tax the LED system with StainleSSS script.
6 takes, same footage, same fstop, same focus, same everything except obturation speeds: from 1/100 to 1/6000.
Shot at 50 fps while projected at 19.2fps
6 H-Stacked together to compare.
Text in the middle to offer a stable reference when looking at the video frame by frame.
Autolevels, autowhite (no satisfaction/better than nothing), slight sharpening.
Low res screenshot:
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/mng1BAneqqBrQSR/download
Video here (https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/aLLbby7mcxcdC1L/download)
The system works with all these speeds. At 1/50th of second, the led becomes to be present on too many pictures, of course, as shot at 50fps.
Two interesting phenomena:
.Disapointing: lot of gate-wave. The image is dancing more than I thought.
-Sharpness difference not so big.
IIRC, Johnmeyer said, he is shooting his footages at 1/1000, I thought slower speeds would be more unsharp because of vibrations or film instability. There is a difference however (frame 106).
Concerning the gate-wave, there might be a vibration maybe introduced by the truncated blade disk.
I saw the LED moving too on the full images, not only the film and the gate.
There is a part of the disk left to trigger the speed calculation by the microcontroler into the projector. Disk is complicated to remove on this model but a must do.
StainlessS
13th May 2021, 21:13
Here is another version of the original DBase script, converted to act like the Auto 2 Pass script.
DB_BLUELED_SingleInstance.avs
# DB_BLUELED_SingleInstance.avs
/*
Requires, AVS+, RT_Stats, Grunt(), FrameSel, CallCmd, plugins
[CallCmd Optional, will auto delete DBase on clip closure if installed]
Detects Blue LED's, selects mid frame of those frames between blue LEDs,
when SEL2ND==True and frame count between Blue LEDs are even, then selects the later middle frame rather than default earlier middle frame.
Writes only single middle frame between BLUE frames.
Intent, with greater number of RAW I/P frames captured [greater than necessary], selects middle frame from all the good frames, so that
more chance of selected frame being stationary [un-wobbly].
May need to adjust AREA Coords where BLUE expected
DBase Single Instance Version.
*/
############
FN = "MBGV0403.MXF" # Video FileName
##### Freq Changed Config #####
OP = 3 # 0,1,2,3 ONLY. ::: 0=Tweak Test Area, 1=Create Frames file, 2=Extract Frames, 3=Auto Two pass, OP=1 then OP=2.
SHOW = True # True, shows metrics on OP==1 [False is quicker, Will auto switch OFF SHOW when OP==3]
# Less Often changed
TEST_X = 374 # Test AREA COORDS (Best Even only)
TEST_Y = 210 # Ditto
TEST_W = 372 # Ditto
TEST_H = 700 # Ditto
BITS8 = True # (True) Metrics and DetTh are as 8 bit range [If change BITS8 then MUST also CHANGE DETTH, ie DETTH*4]
DETTH = 50 # (50) Detection Threshold [ 50 is 8 bit thresh, for 10 bit use eg (50*4) ]
YMAXTH = 0.4 # (0.4) YPlaneMax Threshold (100.0/256.0) about 0.4 % [Percentage of extreme (noise) pixels to ignore].
VFLIP = True # Vertical Flip if upside down
REJECT = False # Arg to Pass 2, Extract Frames. [Extract BLUE LED frames instead of good frames if TRUE]
###
SEL2ND = False # When NonBlue count is EVEN, false selects earlier middle frame, True select later middle frame.
############
Assert(0 <= OP <= 3,"DB_BLUELED_SingleInstance: 1 <= OP <= 3") # Check Valid
FN = FN.RT_GetFullPathName # Ensure full path if not already got one
Frames = FN.RT_FilenameSplit(7) + "_Frames.txt" # If eg FN="...\MBGV0403.MXF" then Frames = "...\MBGV0403_Frames.txt"
LWLibavVideoSource(FN) # Video Source
############
(VFLIP) ? FlipVertical : NOP
SHOW = (OP==3) ? False : SHOW # Auto Switch OFF SHOW for pass 1 if two pass
if(OP==0) { BlueLED_Tweak(TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,YMaxTh) } # Tweak Coords
else if(OP==1) { DB_BlueLED_Detect(Frames,TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,DetTh,YMaxTh,SEL2ND,Show=SHOW) } # Detect
else if(OP==2) { BlueLED_FrameSel(Frames,REJECT) } # Extract Frames
else { # Auto 2 Pass
DB_BlueLED_Detect(Frames,TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,DetTh,YMaxTh,SEL2ND,Show=SHOW).RT_ForceProcess()
BlueLED_FrameSel(Frames,REJECT)
}
Return Last
############
# OP=0
Function BlueLED_Tweak(clip c,int x,int y,int w,int h,Bool "Bits8",Float "YMaxTh") {
# Shows YPlaneMax(YMaxTh) of Test Area (x,y,w,h, marked in yellow)
# If Bits8, then Test Area is converted to 8 bit Y8, and metrics shown in range 0->255
Bits8 = Default(Bits8,False) # If True, then metrics are for 8 bit
YMaxTh = Default(YMaxTh,0.4) # YPlaneMax Threshold (%)
tc = c.Crop(x,y,w,h) # Test Area
tc = Bits8 ? tc.ConvertBits(8).ConvertToY8 : tc # 8 Bit if requested
SSS="""
Subtitle(String(current_frame) + "] YMax=" + String(tc.YPlaneMax(threshold=YMaxTh)) , Size=48)
"""
c.ScriptClip(SSS, Args="tc,YMaxTh",Local = true)
OverLay(c.BlankClip(Length=1,Width=w,Height=h,Color=$FFFF00),x=x,y=y,Opacity=0.1) # Mark Test Area in yellow
Return Last
}
# OP=1
Function DB_BlueLED_Detect(clip c,String Fn, int x,int y,int w,int h,Bool "Bits8",int "DetTh",Float "YMaxTh",Bool "SEL2ND", Bool "Show") {
# Fn = Frames file.
bpc = c.BitsPerComponent() # Bit Depth of c clip
Bits8 = Default(Bits8,False) # If True, then DetTh and metrics are for 8 bit
DetTh = Default(DetTh,Bits8?50:50*BitLShift(1,bpc-8)) # Detect Threshold. Compliant with Bits8 arg.
YMaxTh = Default(YMaxTh,0.4) # YPlaneMax Threshold (%)
SEL2ND = Default(SEL2ND,False)
Show = Default(Show,False)
Assert(fn!="","DB_BlueLED_Detect: Fn Cannot be ''")
Fn = Fn.RT_GetFullPathName
fn.RT_FileDelete
tc = c.Crop(x,y,w,h)
tc = Bits8 ? tc.ConvertBits(8).ConvertToY8 : tc
DB = FN.RT_FilenameSplit(7) + ".DB" # If eg FN="...\MBGV0403.MXF" then DB = "...\MBGV0403.DB"
TypeStr = "iiiii"
RT_DBaseAlloc(DB,c.FrameCount,TypeStr)
HasCallCmd =RT_FunctionExist("CallCmd")
############ DBase Field Index's, Use Glbal Vars rather than numeric constants, easier during Development.
Global STAT_FLD = 0 # 0=Unknown, 1=BLUE, 2=Non Blue Frame(Not chosen), 3=Non Blue chosen Frame.
Global YMAX_FLD = 1 # YMax for current frame
# Below, Valid only When STAT==2 OR STAT==3 (NOT BLUE_LED Stat==1)
Global FRM_S_FLD = 2 # Ditto, 1st frame of current non BLUE sequence
Global FRM_M_FLD = 3 # Ditto Chosen frame from current Non Blue sequence (writen to Frames file)
Global FRM_E_FLD = 4 # Ditto Last frame of current non BLUE sequence
SSS="""
n=current_frame
Stat = RT_DBaseGetField(DB,n,STAT_FLD)
if(Stat == 0) { # Unknown
YMaxCurr = tc.YPlaneMax(YMAXTH)
if(YMaxCurr >= DetTh) { # BLUE
Stat=1
RT_DBaseSet(DB,n,Stat,YMaxCurr, -1,-1,-1) # set BLUE, + invalid fields
} Else { # NOT BLUE
RT_DBaseSetField(DB,n,YMAX_FLD,YMaxCurr) # set non-BLUE YMax [set only single field]
Frame_S = n
For(i=n-1,0,-1) { # Step Backwards looking for previous BLUE
# i is Always either KNOWN BLUE or Unknown
Stat = RT_DBaseGetField(DB,i,STAT_FLD)
if(Stat == 0) { # Unknown
current_frame = i # The Frame we will test for YMax
YMaxI = tc.YPlaneMax(YMAXTH)
if(YMaxI >= DetTh) { # Is BLUE
RT_DBaseSet(DB,i,1,YMaxI, -1,-1,-1) # set BLUE, YMax, + invalid fields
Frame_S = i + 1 # Start frame = BLUE + 1
i = 0 # Break
} Else { # Non BLUE
RT_DBaseSetField(DB,i,YMAX_FLD,YMaxI) # set non-BLUE YMax [set only single field]
Frame_S = i
}
} else { # KNOWN BLUE
Assert(Stat==1,"Internal Error #1 Stat="+String(Stat))
Frame_S = i + 1 # Start frame = BLUE + 1
i = 0 # Break
}
}
Frame_E = n
For(i=n+1,FrameCount-1) { # Step Forwards looking for next BLUE
# i is Always either KNOWN BLUE or Unknown
Stat = RT_DBaseGetField(DB,i,STAT_FLD)
if(Stat == 0) { # Unknown
current_frame = i # The Frame we will test for YMax
YMaxI = tc.YPlaneMax(YMAXTH)
if(YMaxI >= DetTh) {
RT_DBaseSet(DB,i,1,YMaxI, -1,-1,-1) # set BLUE, YMax, + invalid fields
Frame_E = i - 1 # End frame = BLUE - 1
i = FrameCount-1 # Break
} Else { # Non BLUE
RT_DBaseSetField(DB,i,YMAX_FLD,YMaxI) # set non-BLUE YMax [set only single field]
Frame_E = i
}
} else { # KNOWN BLUE
Assert(Stat==1,"Internal Error #2 Stat="+String(Stat))
Frame_E = i - 1 # End frame = BLUE - 1
i = FrameCount-1 # Break
}
}
SelIx = (Frame_E - Frame_S) / 2
Frame_M = (SEL2ND) ? Frame_E-SelIx : Frame_S + SelIx # Earlier OR Later middle frame to pick
for(i=Frame_S,Frame_E) { # Scan and set, all NON-BLUE sequence, using DB pre-written YMax
YMaxI = RT_DBaseGetField(DB,i,YMAX_FLD) # Get pre-stored YMax for i frame
Stat = (i==Frame_M)?3:2 # Chosen frame mid frame ?
RT_DBaseSet(DB,i,Stat,YMaxI, Frame_S,Frame_M,Frame_E) # Set all data for frame i, in current NON-BLUE sequence.
}
current_frame = n # Restore current_frame
Stat = (n==Frame_M)?3:2 # Status of current frame [Non Blue, 2=not chosen or 3=chosen]
}
} # End, if(Stat == 0)
# Here, Stat=1=BLUE, =2=non-blue Frame - not chosen, =3=Chosen Frame
if(Stat==1) { # BLUE
if(SHOW) {
YMax = RT_DBaseGetField(DB,n,YMAX_FLD)
Subtitle(RT_String("%d] %d",n,YMax),Size=48)
}
} else if(Stat==3 || SHOW) {
YMax = RT_DBaseGetField(DB,n,YMAX_FLD)
Frame_S = RT_DBaseGetField(DB,n,FRM_S_FLD)
Frame_E = RT_DBaseGetField(DB,n,FRM_E_FLD)
if(Stat == 2) { # SHOW=true
Subtitle(RT_String("%d] %d : S=%d : E=%d : Len=%d",n,YMax,Frame_S,Frame_E,Frame_E-Frame_S+1),Size=48,lsp=0)
} else { # Stat=3, # Write To Frames File
if(SEL2ND && n != Frame_S + ((Frame_E - Frame_S) / 2)) {
RT_WriteFile(fn,"%d # %d : S=%d : E=%d : Len=%d # 2nd of middle pair",n,YMax,Frame_S,Frame_E,Frame_E-Frame_S+1,Append=n!=0)
if(SHOW) {
Subtitle(RT_String("%d] %d : S=%d : E=%d : Len=%d\\nWriting, 2nd of middle pair",
\ n,YMax,Frame_S,Frame_E,Frame_E-Frame_S+1),Size=48,lsp=0)
}
} else {
RT_WriteFile(fn,"%d # %d : S=%d : E=%d : Len=%d",n,YMax,Frame_S,Frame_E,Frame_E-Frame_S+1,Append=n!=0)
if(SHOW) {
Subtitle(RT_String("%d] %d : S=%d : E=%d : Len=%d\\nWriting",
\ n,YMax,Frame_S,Frame_E,Frame_E-Frame_S+1),Size=48,lsp=0)
}
}
}
}
Return Last
"""
c.ScriptClip(SSS, Args="tc,DetTh,YMaxTh,Fn,Show,DB,SEL2ND",Local = true)
HasCallCmd?CallCmd(close=RT_String("""CMD /C chcp 1252 && del "%s" """,DB), hide=true, Synchronous=7):NOP # Auto Delete DBase if CallCmd available
Return Last
}
# OP=2
Function BlueLED_FrameSel(clip c,String Frames,Bool "Reject") { # Extract Frames from clip c
Reject = Default(Reject,False)
Assert(Frames!="","BlueLED_FrameSel: Frames Cannot be ''")
Frames = Frames.RT_GetFullPathName # Add full path if not already got one
Return FrameSel(c,Cmd=Frames,Ordered=True,reject=Reject)
}
Maybe I've misunderstood how the capture machine works [and I aint re-read description].
ie
Writes only single middle frame between BLUE frames.
Intent, with greater number of RAW I/P frames captured [greater than necessary], selects middle frame from all the good frames, so that
more chance of selected frame being stationary [un-wobbly].
Maybe is never stationary. [but for any machine that works as I maybe mistakenly thought, this script should work fine]
Also, the SEL2ND arg (when true) shows that when 2 frames between BLUE LED frames, the earlier one is probably always the better one.
[ie set SEL2ND=true, shows bluish tinge on some frames, where LED not fully extinguished, whereas SEL2ND=False, ALL GOOD Black LED section of frame.]
EDIT: Fragment of Frames file, [Selected_Frame # In-Comments: YMax, then NonBLUE sequence info]
0 # 32 : S=0 : E=0 : Len=1
2 # 32 : S=2 : E=3 : Len=2
5 # 32 : S=5 : E=6 : Len=2
8 # 32 : S=8 : E=8 : Len=1
11 # 32 : S=11 : E=11 : Len=1
13 # 32 : S=13 : E=14 : Len=2
16 # 32 : S=16 : E=17 : Len=2
19 # 32 : S=19 : E=19 : Len=1
22 # 31 : S=22 : E=22 : Len=1
24 # 31 : S=24 : E=25 : Len=2
27 # 31 : S=27 : E=28 : Len=2
30 # 31 : S=30 : E=30 : Len=1
32 # 32 : S=32 : E=33 : Len=2
35 # 32 : S=35 : E=36 : Len=2
38 # 32 : S=38 : E=39 : Len=2
41 # 32 : S=41 : E=41 : Len=1
44 # 31 : S=44 : E=44 : Len=1
46 # 31 : S=46 : E=47 : Len=2
49 # 31 : S=49 : E=49 : Len=1
chmars
13th May 2021, 21:40
I think you understood correctly how it works. (At least your script did perfectly ;) )
The footage moves normally, as in any projector. Only the blades are removed (in exception of a small part of one).
Excuse my question: What is the advantage of the DB version over the other one?
StainlessS
13th May 2021, 21:51
If each frame exposed [ie BLUE LED NOT Lit up] for longer time, and so more nonBLUE frames between BLUE's, then pick middle of the
nonBLUE's, more chance of selected frame being still, maybe.
Maybe could arrage it so that you got eg 4 or 5 NonBLUE frames between BLUE frames, it picks the middle nonBLUE.
Where 4 NonBLUE [ie even number], SEL2ND=FALSE would pick 2nd frame, and TRUE would pick 3rd.
If eg 5 [Odd number of] NonBLUE frames, then would pick the middle 3RD one. [SEL2ND ignored, only used where EVEN]
EDIT: 4 or 5, are just numbers picked out of hat.
EDIT: Number of consecutive BLUE's dont matter.
Frames file fragment when SEL2ND=True [where YMAX > 32 then LED is a bit blueish]
0 # 32 : S=0 : E=0 : Len=1
3 # 32 : S=2 : E=3 : Len=2 # 2nd of middle pair
6 # 46 : S=5 : E=6 : Len=2 # 2nd of middle pair ### A Bit Blu-ish
8 # 32 : S=8 : E=8 : Len=1
11 # 32 : S=11 : E=11 : Len=1
14 # 32 : S=13 : E=14 : Len=2 # 2nd of middle pair
17 # 37 : S=16 : E=17 : Len=2 # 2nd of middle pair ### A Bit Blu-ish
19 # 32 : S=19 : E=19 : Len=1
22 # 31 : S=22 : E=22 : Len=1
25 # 35 : S=24 : E=25 : Len=2 # 2nd of middle pair ### A Bit Blu-ish
28 # 38 : S=27 : E=28 : Len=2 # 2nd of middle pair ### A Bit Blu-ish
30 # 31 : S=30 : E=30 : Len=1
33 # 31 : S=32 : E=33 : Len=2 # 2nd of middle pair
36 # 32 : S=35 : E=36 : Len=2 # 2nd of middle pair
39 # 44 : S=38 : E=39 : Len=2 # 2nd of middle pair ### A Bit Blu-ish
41 # 32 : S=41 : E=41 : Len=1
44 # 31 : S=44 : E=44 : Len=1
47 # 31 : S=46 : E=47 : Len=2 # 2nd of middle pair
49 # 31 : S=49 : E=49 : Len=1
Above in BLUE is comment for D9 post, not in frames file.
EDIT: Above and comparison with SEL2ND=False in earleir post shows that where there are 2 detected
NonBLUE frames, the earlier one is the better choice. [SEL2ND=False]
It also looks like anything above 32 is probably BLUE LED, although a bit of a margin is probably a good idea.
(Based only on those first few frames)
chmars
13th May 2021, 22:32
I don't want you to loose your time. Perfect as it is!
If each frame exposed for longer time, and so more nonBLUE frames between BLUE's, then pick middle of the nonBLUE's, more chance of selected frame being still, maybe.
Maybe a good solution to get more stability.
But time consuming if projecting slower.
In this case, I'd more reconsider a solution like Fred's (frame by frame, machine vision cam) but would have to abandon my idea. First, I'll try to stabilize the projector better.
But... about the DB/noDB versions of your script, what is the advantage of using a DB?
EDIT: Oh, I see. The DB contains more precise informations to know what happens, debug or adjust better.
StainlessS
13th May 2021, 22:53
EDIT: Oh, I see. The DB contains more precise informations to know what happens, debug or adjust better.
Yes there is that too. With non DB version, we have no idea how long any BLUE or NONBLUE sequence is, although we could add YMax output to Frames File. [FrameSel() ignores '#' comments in Frames File]
You could use the DB ver$ if cap contraption changed, to see numbers,
and if you still always want first NONBLUE frame after any BLUE frame, then use the other script.
StainlessS
14th May 2021, 01:38
Post #23, BLUELED_SingleInstance.avs [Non-DB] updated. Added YMax in comments to frames file.
0 # 32
2 # 32
5 # 32
8 # 32
11 # 32
13 # 32
16 # 32
19 # 32
22 # 31
24 # 31
27 # 31
30 # 31
32 # 32
35 # 32
38 # 32
41 # 32
44 # 31
46 # 31
49 # 31
EDIT: I wonder if the YMAX numbers from DB ver$ with SEL2ND=False/True, would indicate that the
LED is quicker at switching OFF, than it is at switching ON [LED brightness change speed].
(or maybe it just happens to be the timing of mechanical switching as implemented your LED cap contraption).
Ie, the 1st nonBLUE YMAX is pretty consistant about 31 or 32, whereas when SEL2ND=True and nonBLUE length==2,
2nd nonBLUE is sometimes a bit Blue-ish, somewhat greater than 32 [46 on frame 6, and 44 on frame 39, in post #36].
EDIT: You can see the blue-ish stuff [DB VER$, OP=3], by setting SEL2ND=False and viewing[not blue-ish],
then set SEL2ND=true, and view again[blue-ish].
StainlessS
14th May 2021, 16:17
Mod non DB version, not so much for chmars BLUE_LED gizmo, but flexible detector for maybe some other cap contraption.
DB mod version will follow at some point.
# BLUELED_SingleInstance_Mod.avs # https://forum.doom9.org/showthread.php?p=1942862#post1942862
############
# Requires Avs+, RT_Stats, Grunt(), FrameSel, plugins.
# Mod version:
# Can use YMODE:= 0=YPlaneMin, 1=YPlaneMax, 2=YPlaneMinMaxDifference, 3=YPlaneMedian, 4=AverageLuma, detection modes on YPlane, result in YDet.
# Also, DETMODE:= 0="YDet<DetTh", 1="YDet>DetTh", 2="YDet<=DetTh", 3="YDet>=DetTh", 4="YDet==DetTh", 5="YDet!=DetTh", detect logic comparitor.
# Whether above mods are of any other use, depends upon how your cap contraption indicates "A Moving Frame", or a "Still Frame".
# Where YMODE=1 [YPlaneMax], and DETMODE=0 [YDet < DetTh], is same as original script version.
# (eg, where White LED flags Good frame rather than bad moving frame, then could use YMODE=0 [YPlaneMin] and DEETMODE=1 [YDet > DetTh])
# Intent, that the script can be of use with other cap contraption devices other than chmars BLUE_LED gizmo.
############
FN = "MBGV0403.MXF" # Video FileName
##### Freq Changed Config #####
OP = 0 # 0,1,2,3 ONLY. ::: 0=Tweak Test Area, 1=Create Frames file, 2=Extract Frames, 3=Auto Two pass, pass1 then pass2.
SHOW = True # True, shows metrics on OP==1 [False is quicker]
# Less Often changed
TEST_X = 374 # Test AREA COORDS (Best Even only)
TEST_Y = 210 # Ditto
TEST_W = 372 # Ditto
TEST_H = 700 # Ditto
BITS8 = True # (True) Metrics and DetTh are as 8 bit range [If change BITS8 then MUST also CHANGE DETTH, ie DETTH*4]
YMODE = 1 # (1) 0=YPlaneMin, 1=YPlaneMax, 2=YPlaneMinMaxDifference, 3=YPlaneMedian, 4=AverageLuma.
# For BLUELED we use YMODE=1 ie YDet=YPlaneMax on Area TEXT_X,TEST_Y,TEST_W,TEST_H.
# YTh only used for YPlaneMin, YPlaneMax, YPlaneMinMaxDifference, others dont have a threshold arg.
YTH = 0.4 # (0.4) YPlaneMax Threshold (100.0/256.0) about 0.4 % [Percentage of extreme (noise) pixels to ignore].
DETMODE = 0 # (0) Comparison mode for Detect of BLACK(non BLueLED) frames. Is BlueLED where NOT BLACK.
# 0="YDet<DetTh", 1="YDet>DetTh", 2="YDet<=DetTh", 3="YDet>=DetTh", 4="YDet==DetTh", 5="YDet!=DetTh"
DETTH = 50 # (50) Detection Threshold [ 50 is 8 bit thresh, for 10 bit use eg (50*4) ]
#
VFLIP = True # Vertical Flip if upside down
REJECT = False # Arg to Pass 2 Extract Frames. [Extract BLUE LED frames instead of good frames if TRUE]
############
Assert(0 <= OP <= 3,"BlueLED: 1 <= OP <= 3") # Check Valid
Assert(0 <= YMODE <= 4,"BlueLED: 0 <= YMODE <= 4") # Check Valid
Assert(0 <= DETMODE <= 5,"BlueLED: 0 <= DETMODE <= 5") # Check Valid
FN = FN.RT_GetFullPathName # Ensure full path if not already got one
Frames = FN.RT_FilenameSplit(7) + "_Frames.txt" # If eg FN="...\MBGV0403.MXF" then Frames = "...\MBGV0403_Frames.txt"
LWLibavVideoSource(FN) # Video Source
############
(VFLIP) ? FlipVertical : NOP
SHOW = (OP==3) ? False : SHOW # Auto Switch OFF SHOW for pass 1 if two pass
if(OP==0) { BlueLED_Tweak(TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,YMODE,YTH) } # Tweak Coords
else if(OP==1) { BlueLED_Detect(Frames,TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,YMODE,YTH,DETMODE,DetTh,Show=SHOW) } # Detect
else if(OP==2) { BlueLED_FrameSel(Frames,REJECT) } # Extract Frames
else { # Auto 2 Pass
BlueLED_Detect(Frames,TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,YMODE,YTH,DETMODE,DetTh,Show=SHOW).RT_ForceProcess()
BlueLED_FrameSel(Frames,REJECT)
}
Return Last
############
# OP=0
Function BlueLED_Tweak(clip c,int x,int y,int w,int h,Bool "Bits8",Int "YMODE",Float "YTh") {
# Shows YPlane value (YPlane Mode selected by YMODE) of Test Area (x,y,w,h, marked in yellow)
# If Bits8, then Test Area is converted to 8 bit Y8, and metrics shown in range 0->255
Bits8 = Default(Bits8,False) # If True, then metrics are for 8 bit
YMODE = Default(YMODE,1) # Default 1=YPLaneMax
YTh = Default(YTh,0.4) # YPlaneMax Threshold (%)
Assert(0 <= YMODE <= 4,"BlueLED_Tweak: 0 <= YMODE <= 4")
tc = c.Crop(x,y,w,h) # Test Area
tc = Bits8 ? tc.ConvertBits(8).ConvertToY8 : tc # 8 Bit if requested
SSS="""
YDet=
\ (YMODE==0) ? tc.YPlaneMin(YTh) :
\ (YMODE==1) ? tc.YPlaneMax(YTh) :
\ (YMODE==2) ? tc.YPlaneMinMaxDifference(YTh) :
\ (YMODE==3) ? tc.YPlaneMedian :
\ tc.AverageLuma.Round
Subtitle(String(current_frame) + "] YDet=" + String(YDet) , Size=48)
"""
c.ScriptClip(SSS, Args="tc,YMODE,YTh",Local = true)
OverLay(c.BlankClip(Length=1,Width=w,Height=h,Color=$FFFF00),x=x,y=y,Opacity=0.15) # Mark Test Area in yellow
Return Last
}
# OP=1
Function BlueLED_Detect(clip c,String Fn, int x,int y,int w,int h,Bool "Bits8",Int "YMODE",Float "YTh",Int "DETMODE",int "DetTh", Bool "Show") {
bpc = c.BitsPerComponent() # Bit Depth of c clip
Bits8 = Default(Bits8,False) # If True, then DetTh and metrics are for 8 bit
YMODE = Default(YMODE,1) # Default 1=YPLaneMax
YTh = Default(YTh,0.4) # YPlane Threshold (%) for YMODE=0,1,2, YPlaneMin, YPlaneMax, and YPLaneMinMaxDifference.
DETMODE= Default(DETMODE,0) # Default 0="YDet<DetTh" for detect NOT BlueLED
DetTh = Default(DetTh,Bits8?50:50*BitLShift(1,bpc-8)) # Detect Threshold. Compliant with Bits8 arg.
Show = Default(Show,False)
Assert(fn!="","BlueLED_Detect: Frames file Fn Cannot be ''")
Fn = Fn.RT_GetFullPathName
RT_FileDelete(Fn)
tc = c.Crop(x,y,w,h)
tc = Bits8 ? tc.ConvertBits(8).ConvertToY8 : tc
SSS="""
YDetCur=
\ (YMODE==0) ? tc.YPlaneMin(YTh) :
\ (YMODE==1) ? tc.YPlaneMax(YTh) :
\ (YMODE==2) ? tc.YPlaneMinMaxDifference(YTh) :
\ (YMODE==3) ? tc.YPlaneMedian :
\ tc.AverageLuma.Round
YDetPrv=
\ (YMODE==0) ? tc.YPlaneMin(YTh,-1) :
\ (YMODE==1) ? tc.YPlaneMax(YTh,-1) :
\ (YMODE==2) ? tc.YPlaneMinMaxDifference(YTh,-1) :
\ (YMODE==3) ? tc.YPlaneMedian(-1) :
\ tc.AverageLuma(-1).Round
T1 =
\ (DETMODE==0) ? (YDetCur <DetTh) :
\ (DETMODE==1) ? (YDetCur >DetTh) :
\ (DETMODE==2) ? (YDetCur<=DetTh) :
\ (DETMODE==3) ? (YDetCur>=DetTh) :
\ (DETMODE==4) ? (YDetCur==DetTh) :
\ (YDetCur!=DetTh)
T2 =
\ (DETMODE==0) ? (YDetPrv <DetTh) :
\ (DETMODE==1) ? (YDetPrv >DetTh) :
\ (DETMODE==2) ? (YDetPrv<=DetTh) :
\ (DETMODE==3) ? (YDetPrv>=DetTh) :
\ (DETMODE==4) ? (YDetPrv==DetTh) :
\ (YDetPrv!=DetTh)
T = (T1 && (!T2 || current_frame==0)) # True if current frame is detected non moving,and previous detected as moving.
(T) ? RT_WriteFile(Fn,"%d # %d",current_frame,YDetCur,Append=current_frame>0) : NOP
if(Show) {
s = RT_String("%d] %s\\nYDetCur=%d\\nYDetPrv=%d\\n(DetTh=%d)",current_frame,T?"Bingo":"",YDetCur,YDetPrv,DetTh)
Subtitle(s,Size=48,lsp=0)
}
Return Last
"""
c.ScriptClip(SSS, Args="tc,YMODE,YTh,DETMODE,DetTh,Fn,Show",Local=true)
Return Last
}
# OP=2
Function BlueLED_FrameSel(clip c,String Frames,Bool "Reject") { # Extract Frames from clip c
Reject = Default(Reject,False)
Assert(Frames!="","BlueLED_FrameSel: Frames Cannot be ''")
Frames = Frames.RT_GetFullPathName # Add full path if not already got one
Return FrameSel(c,Cmd=Frames,Ordered=True,reject=Reject)
}
EDIT: Another user a couple of years back required detect and extract depending upon artificial border color,
another used arifical pure black to indicate frames to delete. The DB version similar to this could
achieve both those goals.
chmars
14th May 2021, 23:28
Thanks StainlessS.
Stability problem solved.
Projector physically stabilized + found the correct speed where vibrations don't amplify by making resonances.
Projector at max speed (>20fps), camera @ 100fps.
Lots of frames to eject! Will surely go lower than 100fps.
EDIT: It appears that depending on the position on the reel, vibrations can appear at 20 fps. Specially in the beginning of the reel.
Tried to free the footage form both in and out reels, no changes.
Safe projection speed: more around 10fps.
Very stable, no deformations. Sample if interested (https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/8gjMK1rUd5wJ6qe/download)
Please watch it frame by frame, looking at the borders and footage hole. Also, no more sqweeze-stretch phenomenon inside the image.
Next thing to study: workflow.
The camera is delivering XAVC-L:
ID : 2
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High 4:2:2@L4.2
Format settings : CABAC / 2 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference frames : 2 frames
Format settings, GOP : M=3, N=12
Format settings, wrapping mode : Frame
Codec ID : 0D01030102106001-0401020201316001
Duration : 22 s 560 ms
Bit rate mode : Variable
Bit rate : 52.5 Mb/s
Maximum bit rate : 50.0 Mb/s
Width : 1 920 pixels
Height : 1 080 pixels
Display aspect ratio : 16:9
Frame rate : 50.000 FPS
Color space : YUV
Chroma subsampling : 4:2:2
Bit depth : 10 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.507
Stream size : 141 MiB (92%)
Color range : Limited
Color primaries : BT.709
Transfer characteristics : BT.709
Matrix coefficients : BT.709
I have to:
-pass it through StainlessS script,
-grade it into Resolve,
-eventually remove dirt and deshake with Avisynth and VirtualDub.
Knowing Resolve is the free wersion which do accept 10 bit only in prores (It should not. Bug?).
Until now, I did:
-Remove the BLUE (StainlessS script) and save to uncompressed avi with VirtualDub.
-Convert it like:
ffmpeg -i D:\myFileIn -c:v prores_ks -profile:v [0-3] -vendor apl0 -bits_per_mb 8000 -pix_fmt yuv422p10le -an D:\myFileOut
-Grade in Resolve
-Export to grass Valey AVI
-Use Fred's script or versions
-Vdub to mp4 H265 or 264.
No idea if this is correct!
What do you folks think?
And, should/dare I ask in a new thread?
StainlessS
16th May 2021, 17:33
Very stable, no deformations. Sample if interested
For me, source is more interesting.
I'm busy [at times] doing DB version of the previous script, [well, it will I think combine prev script functionality and DB in single script],
will be an Avsi with example client script.
chmars
16th May 2021, 23:07
For me, source is more interesting.
Well, here (https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/R0EN4VYFyWQUFev/download) is one.
100 fps, this time.
StainlessS
19th May 2021, 12:22
chmars,
I note that your attachment image has yet to be approved.
Mods dont wander around as much as they used to, might be a good idea to post on somewhere like PostImages.org
https://postimages.org/ [for some reason, changed its name from postimage.org/, added the 's' at the end].
You can upload an image, with or without an account. [account is handy though].
You can use the Image for forum or thumbnail for forum options.
chmars
19th May 2021, 12:32
Thanks. Yes, noticed this. Changed recent pictures and movies to a private space.
Links updated.
StainlessS
21st May 2021, 01:45
Post #1 of 3.
OK, bit of a mod, in multiple parts. [limit in Usage is 16KB].
Gizmo_Extractor.avsi Part 1 [glue them together]
# Gizmo_Extractor.avsi
/*
Gizmo_Extractor, By StainlessS @ Doom9 : https://forum.doom9.org/showthread.php?p=1943231#post1943231
Requires, AVS+, RT_Stats, Grunt(), FrameSel, CallCmd, plugins
[CallCmd Optional, will auto delete DBase on clip closure if installed]
Original Post prompting script:- https://forum.doom9.org/showthread.php?p=1941818#post1941818
Gizmod_Detect(), Selects first non BLUE LED frame following a BLUE_LED frame.
Gizmod_Detect_DB()
Detects Blue LED's, selects mid frame of those frames between blue LEDs,
when SEL2ND==True and frame count between Blue LEDs are even, then selects the later middle frame rather than default earlier middle frame.
Writes only single middle frame between BLUE frames.
Intent, with greater number of RAW I/P frames captured [greater than necessary], selects middle frame from all the good frames, so that
more chance of selected frame being stationary [un-wobbly].
Mod version:
Can use YMODE:= 0=YPlaneMin, 1=YPlaneMax, 2=YPlaneMinMaxDifference, 3=YPlaneMedian, 4=AverageLuma, detection modes on YPlane, result in YDet.
Also, DETMODE:= 0="YDet<DetTh", 1="YDet>DetTh", 2="YDet<=DetTh", 3="YDet>=DetTh", 4="YDet==DetTh", 5="YDet!=DetTh", detect logic comparitor.
Whether above mods are of any other use, depends upon how your cap contraption indicates "A Moving Frame", or a "Still Frame".
Where YMODE=1 [YPlaneMax], and DETMODE=0 [YDet < DetTh], is same as original script version.
(eg, where White LED flags Good frame rather than bad moving frame, then could use YMODE=0 [YPlaneMin] and DETMODE=1 [YDet > DetTh])
Intent, that the script can be of use with some other cap contraption devices other than user Chmars BLUE_LED gizmo.
*/
# OP=0 : Setup Coords
Function Gizmo_Tweak(clip c,int x,int y,int w,int h,Bool "Bits8",Int "YMODE",Float "YTh") {
# Shows YPlane value (YPlane Mode selected by YMODE) of Test Area (x,y,w,h, marked in yellow)
# If Bits8, then Test Area is converted to 8 bit Y8, and metrics shown in range 0->255
Bits8 = Default(Bits8,False) # If True, then metrics are for 8 bit
YMODE = Default(YMODE,1) # Default 1=YPLaneMax
YTh = Default(YTh,0.4) # YPlaneMax Threshold (%)
Assert(0 <= YMODE <= 4,"Gizmo_Tweak: 0 <= YMODE <= 4")
tc = c.Crop(x,y,w,h) # Test Area
tc = Bits8 ? tc.ConvertBits(8).ConvertToY8 : tc # 8 Bit if requested
SSS="""
YDet=
\ (YMODE==0) ? tc.YPlaneMin(YTh) :
\ (YMODE==1) ? tc.YPlaneMax(YTh) :
\ (YMODE==2) ? tc.YPlaneMinMaxDifference(YTh) :
\ (YMODE==3) ? tc.YPlaneMedian :
\ tc.AverageLuma.Round
Subtitle(String(current_frame) + "] YDet=" + String(YDet) , Size=48)
"""
c.ScriptClip(SSS, Args="tc,YMODE,YTh",Local = true)
OverLay(c.BlankClip(Length=1,Width=w,Height=h,Color=$FFFF00),x=x,y=y,Opacity=0.15) # Mark Test Area in yellow
Return Last
}
# OP=2, Select/extract frames using Frames file.
Function Gizmo_FrameSel(clip c,String Frames,Bool "Reject") { # Extract Frames from clip c
Reject = Default(Reject,False)
Assert(Frames!="","Gizmo_FrameSel: Frames Cannot be ''")
Frames = Frames.RT_GetFullPathName # Add full path if not already got one
Return FrameSel(c,Cmd=Frames,Ordered=True,reject=Reject)
}
# OP=1 USEDB=False : Selects first non BLUE LED frame following a BLUE_LED frame.
Function Gizmo_Detect(clip c,int x,int y,int w,int h,String "Frames", Bool "Bits8",Int "YMODE",Float "YTh",Int "DETMODE",int "DetTh", Bool "Show",
\ Bool "TwoPass", Bool "Reject") {
bpc = c.BitsPerComponent() # Bit Depth of c clip
Bits8 = Default(Bits8,False) # If True, then DetTh and metrics are for 8 bit
YMODE = Default(YMODE,1) # Default 1=YPLaneMax
YTh = Default(YTh,0.4) # YPlane Threshold (%) for YMODE=0,1,2, YPlaneMin, YPlaneMax, and YPLaneMinMaxDifference.
DETMODE= Default(DETMODE,0) # Default 0="YDet<DetTh" for detect NOT BlueLED
DetTh = Default(DetTh,Bits8?50:50*BitLShift(1,bpc-8)) # Detect Threshold. Compliant with Bits8 arg.
TwoPass= Default(TwoPass,False)
Show = (!TwoPass) ? Default(Show,False) : False
Reject = Default(Reject,False)
Frames = Default(Frames,"")
Assert(TwoPass || Frames!="","Gizmo_Detect: Frames file Cannot be '' when TwoPass==False")
IsTmpfn= (Frames=="")
Frames = (IsTmpfn) ? "~" + RT_LocalTimeString(true) + "_Frames.txt" : Frames
Frames = Frames.RT_GetFullPathName
RT_FileDelete(Frames)
tc = c.Crop(x,y,w,h)
tc = Bits8 ? tc.ConvertBits(8).ConvertToY8 : tc
HasCallCmd = RT_FunctionExist("CallCmd")
SSS="""
YDetCur=
\ (YMODE==0) ? tc.YPlaneMin(YTh) :
\ (YMODE==1) ? tc.YPlaneMax(YTh) :
\ (YMODE==2) ? tc.YPlaneMinMaxDifference(YTh) :
\ (YMODE==3) ? tc.YPlaneMedian :
\ tc.AverageLuma.Round
YDetPrv=
\ (YMODE==0) ? tc.YPlaneMin(YTh,-1) :
\ (YMODE==1) ? tc.YPlaneMax(YTh,-1) :
\ (YMODE==2) ? tc.YPlaneMinMaxDifference(YTh,-1) :
\ (YMODE==3) ? tc.YPlaneMedian(-1) :
\ tc.AverageLuma(-1).Round
T1 =
\ (DETMODE==0) ? (YDetCur <DetTh) :
\ (DETMODE==1) ? (YDetCur >DetTh) :
\ (DETMODE==2) ? (YDetCur<=DetTh) :
\ (DETMODE==3) ? (YDetCur>=DetTh) :
\ (DETMODE==4) ? (YDetCur==DetTh) :
\ (YDetCur!=DetTh)
T2 =
\ (DETMODE==0) ? (YDetPrv <DetTh) :
\ (DETMODE==1) ? (YDetPrv >DetTh) :
\ (DETMODE==2) ? (YDetPrv<=DetTh) :
\ (DETMODE==3) ? (YDetPrv>=DetTh) :
\ (DETMODE==4) ? (YDetPrv==DetTh) :
\ (YDetPrv!=DetTh)
T = (T1 && (!T2 || current_frame==0)) # True if current frame is detected non moving,and previous detected as moving.
(T) ? RT_WriteFile(Frames,"%d # %d",current_frame,YDetCur,Append=current_frame>0) : NOP
if(Show) {
s = RT_String("%d] %s\\nYDetCur=%d\\nYDetPrv=%d\\n(DetTh=%d)",current_frame,T?"Writing":"",YDetCur,YDetPrv,DetTh)
Subtitle(s,Size=48,lsp=0)
}
Return Last
"""
c.ScriptClip(SSS, Args="tc,YMODE,YTh,DETMODE,DetTh,Frames,Show",Local=true)
if(TwoPass) {
RT_ForceProcess()
c.Gizmo_FrameSel(Frames,REJECT)
# Auto Delete temp frames if CallCmd available
(IsTmpfn&&HasCallCmd)
\ ? CallCmd(close=RT_String("""CMD /C chcp 1252 && del "%s" """,Frames), hide=true, Synchronous=7)
\ : NOP
}
Return Last
}
StainlessS
21st May 2021, 01:46
Post #2 of 3.
Gizmo_Extractor.avsi Part 2
# OP=1 USEDB=True : Select middle frame from non BLUE_LED frames.
Function Gizmo_Detect_DB(clip c,int x,int y,int w,int h,String "Frames", Bool "Bits8",Int "YMODE",Float "YTh",Int "DETMODE",int "DetTh",Bool "SEL2ND",Bool "Show",
\ Bool "TwoPass", Bool "Reject") {
bpc = c.BitsPerComponent() # Bit Depth of c clip
Bits8 = Default(Bits8,False) # If True, then DetTh and metrics are for 8 bit
YMODE = Default(YMODE,1) # Default 1=YPLaneMax
YTh = Default(YTh,0.4) # YPlane Threshold (%) for YMODE=0,1,2, YPlaneMin, YPlaneMax, and YPLaneMinMaxDifference.
DETMODE= Default(DETMODE,0) # Default 0="YDet<DetTh" for detect NOT BlueLED
DetTh = Default(DetTh,Bits8?50:50*BitLShift(1,bpc-8)) # Detect Threshold. Compliant with Bits8 arg.
TwoPass= Default(TwoPass,False)
Show = (!TwoPass) ? Default(Show,False) : False
Reject = Default(Reject,False)
Frames = Default(Frames,"")
Assert(TwoPass || Frames!="","Gizmo_Detect_DB: Frames file Cannot be '' when TwoPass==False")
IsTmpfn= (Frames=="")
Frames = (IsTmpfn) ? "~" + RT_LocalTimeString(true) + "_Frames.txt" : Frames
Frames = Frames.RT_GetFullPathName
RT_FileDelete(Frames)
tc = c.Crop(x,y,w,h)
tc = Bits8 ? tc.ConvertBits(8).ConvertToY8 : tc
DB = Frames.RT_FilenameSplit(7) + ".DB" # If eg FN="...\MBGV0403.MXF" then DB = "...\MBGV0403.DB"
TypeStr = "iiii"
RT_DBaseAlloc(DB,c.FrameCount,TypeStr)
HasCallCmd = RT_FunctionExist("CallCmd")
############ DBase Field Index's
# Field 0 = STATUS, 0=Unknown, 1=BLUE, 2=Non Blue Frame(Not chosen), 3=Non Blue chosen Frame.
# Field 1 = YDet for current frame
# Below, Valid only When STAT==2 OR STAT==3 (NOT BLUE_LED Status==1)
# Field 2, First frame of current non BLUE sequence
# Field 3, Last frame of current non BLUE sequence
SSS="""
n=current_frame
Stat = RT_DBaseGetField(DB,n,0)
if(Stat == 0) { # Unknown
YDet=
\ (YMODE==0) ? tc.YPlaneMin(YTh) :
\ (YMODE==1) ? tc.YPlaneMax(YTh) :
\ (YMODE==2) ? tc.YPlaneMinMaxDifference(YTh) :
\ (YMODE==3) ? tc.YPlaneMedian :
\ tc.AverageLuma.Round
T =
\ (DETMODE==0) ? (YDet <DetTh) :
\ (DETMODE==1) ? (YDet >DetTh) :
\ (DETMODE==2) ? (YDet<=DetTh) :
\ (DETMODE==3) ? (YDet>=DetTh) :
\ (DETMODE==4) ? (YDet==DetTh) :
\ (YDet!=DetTh)
if(!T) { # BLUE, ie moving frame
Stat=1
RT_DBaseSet(DB,n,Stat,YDet, -1,-1) # set BLUE, + invalid fields
} Else { # NOT BLUE (ie not moving)
RT_DBaseSetField(DB,n,1,YDet) # set non-BLUE YDet [set only single field]
Frame_S = n
For(i=n-1,0,-1) { # Step Backwards looking for previous BLUE/Moving
# i is Always either KNOWN BLUE(moving) or Unknown
Stat = RT_DBaseGetField(DB,i,0)
if(Stat == 0) { # Unknown
current_frame = i # The Frame we will test for YDet
YDetI=
\ (YMODE==0) ? tc.YPlaneMin(YTh) :
\ (YMODE==1) ? tc.YPlaneMax(YTh) :
\ (YMODE==2) ? tc.YPlaneMinMaxDifference(YTh) :
\ (YMODE==3) ? tc.YPlaneMedian :
\ tc.AverageLuma.Round
T =
\ (DETMODE==0) ? (YDetI <DetTh) :
\ (DETMODE==1) ? (YDetI >DetTh) :
\ (DETMODE==2) ? (YDetI<=DetTh) :
\ (DETMODE==3) ? (YDetI>=DetTh) :
\ (DETMODE==4) ? (YDetI==DetTh) :
\ (YDetI!=DetTh)
if(!T) { # Is BLUE(moving)
RT_DBaseSet(DB,i,1,YDetI, -1,-1) # set BLUE, YDet, + invalid fields
Frame_S = i + 1 # Start frame = BLUE + 1
i = 0 # Break
} Else { # Non BLUE(non moving)
RT_DBaseSetField(DB,i,1,YDetI) # set non-BLUE YDet [set only single field]
Frame_S = i
}
} else { # should be KNOWN BLUE(moving)
Assert(Stat==1,"Should be BLUE, Internal Error #1 Stat="+String(Stat))
Frame_S = i + 1 # Start frame = BLUE + 1
i = 0 # Break
}
}
Frame_E = n
For(i=n+1,FrameCount-1) { # Step Forwards looking for next BLUE
# i is Always either KNOWN BLUE(moving) or Unknown
Stat = RT_DBaseGetField(DB,i,0)
if(Stat == 0) { # Unknown
current_frame = i # The Frame we will test for YDet
YDetI=
\ (YMODE==0) ? tc.YPlaneMin(YTh) :
\ (YMODE==1) ? tc.YPlaneMax(YTh) :
\ (YMODE==2) ? tc.YPlaneMinMaxDifference(YTh) :
\ (YMODE==3) ? tc.YPlaneMedian :
\ tc.AverageLuma.Round
T =
\ (DETMODE==0) ? (YDetI <DetTh) :
\ (DETMODE==1) ? (YDetI >DetTh) :
\ (DETMODE==2) ? (YDetI<=DetTh) :
\ (DETMODE==3) ? (YDetI>=DetTh) :
\ (DETMODE==4) ? (YDetI==DetTh) :
\ (YDetI!=DetTh)
if(!T) { # BLUE, ie moving frame
RT_DBaseSet(DB,i,1,YDetI, -1,-1) # set BLUE, YDet, + invalid fields
Frame_E = i - 1 # End frame = BLUE - 1
i = FrameCount-1 # Break
} Else { # Non BLUE (ie not moving)
RT_DBaseSetField(DB,i,1,YDetI) # set non-BLUE YDet [set only single field]
Frame_E = i
}
} else { # should be KNOWN BLUE(moving)
Assert(Stat==1,"Should be BLUE, Internal Error #2 Stat="+String(Stat))
Frame_E = i - 1 # End frame = BLUE - 1
i = FrameCount-1 # Break
}
}
SelIx = (Frame_E - Frame_S) / 2
Frame_M = (SEL2ND) ? Frame_E-SelIx : Frame_S + SelIx # Earlier OR Later middle frame to pick
for(i=Frame_S,Frame_E) { # Scan and set, all NON-BLUE sequence, using DB pre-written YDet
YDetI = RT_DBaseGetField(DB,i,1) # Get pre-stored YDet for i frame
Stat = (i==Frame_M)?3:2 # Chosen frame mid frame ?
RT_DBaseSet(DB,i,Stat,YDetI, Frame_S,Frame_E) # Set all data for frame i, in current NON-BLUE sequence.
}
current_frame = n # Restore current_frame
Stat = (n==Frame_M)?3:2 # Status of current frame [Non Blue, 2=not chosen or 3=chosen]
}
} # End, if(Stat == 0)
# Here, Stat=1=BLUE, =2=non-blue Frame - not chosen, =3=Chosen Frame
if(Stat==1) { # BLUE (moving)
if(SHOW) {
YDet = RT_DBaseGetField(DB,n,1)
Subtitle(RT_String("%d] %d",n,YDet),Size=48)
}
} else if(Stat==3 || SHOW) { # Chosen non-BLUE (not moving) or SHOW
YDet = RT_DBaseGetField(DB,n,1)
Frame_S = RT_DBaseGetField(DB,n,2)
Frame_E = RT_DBaseGetField(DB,n,3)
if(Stat == 2) { # Not Chosen, SHOW=true
Subtitle(RT_String("%d] %d : S=%d : E=%d : Len=%d",n,YDet,Frame_S,Frame_E,Frame_E-Frame_S+1),Size=48,lsp=0)
} else { # Stat=3, Chosen, # Write To Frames File
if(SEL2ND && n != Frame_S + ((Frame_E - Frame_S) / 2)) {
RT_WriteFile(Frames,"%d # %d : S=%d : E=%d : Len=%d # 2nd of middle pair",n,YDet,Frame_S,Frame_E,Frame_E-Frame_S+1,Append=n!=0)
if(SHOW) {
Subtitle(RT_String("%d] %d : S=%d : E=%d : Len=%d\\nWriting, 2nd of middle pair",
\ n,YDet,Frame_S,Frame_E,Frame_E-Frame_S+1),Size=48,lsp=0)
}
} else {
RT_WriteFile(Frames,"%d # %d : S=%d : E=%d : Len=%d",n,YDet,Frame_S,Frame_E,Frame_E-Frame_S+1,Append=n!=0)
if(SHOW) {
Subtitle(RT_String("%d] %d : S=%d : E=%d : Len=%d\\nWriting",
\ n,YDet,Frame_S,Frame_E,Frame_E-Frame_S+1),Size=48,lsp=0)
}
}
}
}
Return Last
"""
c.ScriptClip(SSS, Args="tc,Frames,DB,YMode,YTh,DetMode,DetTh,SEL2ND,Show",Local = true)
if(TwoPass) {
RT_ForceProcess()
c.Gizmo_FrameSel(Frames,REJECT)
# Auto Delete temp Frames if CallCmd available
(IsTmpfn && HasCallCmd)
\ ? CallCmd(close=RT_String("""CMD /C chcp 1252 && del "%s" """,Frames), hide=true, Synchronous=7)
\ : NOP
}
HasCallCmd?CallCmd(close=RT_String("""CMD /C chcp 1252 && del "%s" """,DB), hide=true, Synchronous=7):NOP # Auto Delete DBase if CallCmd available
Return Last
}
StainlessS
21st May 2021, 01:48
Post #3 of 3.
Gizmo_Extractor_Client.avs [Can be converted into a batch mode Avisynthesizer_Mod Template.
Avisynthesizer_Template requirements in BLUE
#ASYNTHER BATCH_GISMO_EXTRACTOR
# Above, name "BATCH_GISMO_EXTRACTOR" Presented in Avisynthesizer_Mod dialog box to select this as a template.
FN = "MBGV0403.MXF" # Video FileName : if using as Avisynthesizer_Mod template, use eg:- FN = "___FILE___"
#Import(".\Gizmo_Extractor.avsi") # Or In Plugins
## Gizmo_Extractor_Client.avs
#
# Requires, AVS+, RT_Stats, Grunt(), FrameSel, CallCmd, plugins
# (CallCmd Optional, will auto delete DBase on clip closure if installed)
##
##### Freq Changed Config #####
OP = 1 # 0,1,2 ONLY. ::: 0=Tweak Test Area, 1=Create Frames file (Also extracts when TWOPASS=true), 2=Extract Frames.
TWOPASS = True # If True and OP==1, then do two pass, create Frames file then extract.
USEDB = True # False, uses NON-DB mode : True uses DB Mode (NonDB selects 1st frame good frame after BLUE, DB selects Middle Good frame)
SHOW = True # True, shows metrics on OP==1 (auto switched OFF if TWOPASS==True)
AUTONAME = True # If true and TWOPASS, then will generate temp frames file name and delete it on close (if CallCmd available).
# Permits use of Frames="" when calling Detect funcs, when TWOPASS=True. (TWOPASS=False, and Frames="" is an Error)
# AUTONAME, permits two or more instances of Frames file with same source, without Frames names conflict, + auto delete frames.
# Additionally, when using Avisynthesizer_Mod template generated client file, can run multiple instances of the script
# loaded into eg VDub2, and on TWOPASS frames extraction, save file and will auto delete both DB and Frames files
# for each instance (on source clip closure).
# Less Often changed
TEST_X = 374 # Test AREA COORDS (Best Even only)
TEST_Y = 210 # Ditto
TEST_W = 372 # Ditto
TEST_H = 700 # Ditto
BITS8 = True # (True) Metrics and DetTh are as 8 bit range (If change BITS8 then MUST also CHANGE DETTH, ie DETTH*4)
YMODE = 1 # (1) 0=YPlaneMin, 1=YPlaneMax, 2=YPlaneMinMaxDifference, 3=YPlaneMedian, 4=AverageLuma.
# For BLUELED we use YMODE=1 ie YDet=YPlaneMax on Area TEXT_X,TEST_Y,TEST_W,TEST_H.
# YTh only used for YPlaneMin, YPlaneMax, YPlaneMinMaxDifference, others dont have a threshold arg.
YTH = 0.4 # (0.4) YPlaneMax Threshold (100.0/256.0) about 0.4 % (Percentage of extreme (noise) pixels to ignore).
DETMODE = 0 # (0) Comparison mode for Detect of BLACK(non BLueLED) frames. Is BlueLED where NOT BLACK.
# 0="YDet<DetTh", 1="YDet>DetTh", 2="YDet<=DetTh", 3="YDet>=DetTh", 4="YDet==DetTh", 5="YDet!=DetTh"
DETTH = 50 # (50) Detection Threshold ( 50 is 8 bit thresh, for 10 bit use eg (50*4) )
SEL2ND = False # (False) DB Mode only. When NonBlue count is EVEN, false selects earlier middle frame, True select later middle frame.
#
VFLIP = True # (True) Vertical Flip if upside down
REJECT = False # (False) Arg to Pass 2 Extract Frames. (Extract BLUE LED frames instead of good frames if TRUE)
############
Assert(0 <= OP <= 2,"Gizmo_Extractor_Client: 1 <= OP <= 2") # Check Valid
Assert(0 <= YMODE <= 4,"Gizmo_Extractor_Client: 0 <= YMODE <= 4") # Check Valid
Assert(0 <= DETMODE <= 5,"Gizmo_Extractor_Client: 0 <= DETMODE <= 5") # Check Valid
FN = FN.RT_GetFullPathName # Ensure full path if not already got one
Frames = (TWOPASS && AUTONAME) ? "" : FN.RT_FilenameSplit(7) + "_Frames.txt" # If eg FN="...\MBGV0403.MXF" then Frames = "...\MBGV0403_Frames.txt"
LWLibavVideoSource(FN) # Video Source filter
############
(VFLIP) ? FlipVertical : NOP
if(OP==0) { # Tweak coords
Gizmo_Tweak(TEST_X,TEST_Y,TEST_W,TEST_H,BITS8,YMODE,YTH)
} else if (OP==2) { # Extract frames only
Gizmo_FrameSel(Frames,REJECT)
} else { # Create Frames file, and if TWOPASS, then also extract frames. USEDB select mode, DB mode if True.
(!USEDB) ? Gizmo_Detect(TEST_X,TEST_Y,TEST_W,TEST_H,Frames,BITS8,YMODE,YTH,DETMODE,DetTh, Show=SHOW,twopass=TWOPASS,reject=REJECT)
\ : Gizmo_Detect_DB(TEST_X,TEST_Y,TEST_W,TEST_H,Frames,BITS8,YMODE,YTH,DETMODE,DetTh,SEL2ND,Show=SHOW,twopass=TWOPASS,reject=REJECT)
}
Return Last
Fixed.
chmars
21st May 2021, 12:12
Excellent.
How does it have to be cooked?
Same way you explained in your post #26 (https://forum.doom9.org/showthread.php?p=1942338#post1942338)?
(Workflow soon ok, almost ready to explore this)
StainlessS
21st May 2021, 12:57
Yes, same way.
Just need to make sure the coords are set, and are happy with the DetTh, [make sure it works ok with your settings]
and then set
OP=1
TWOPASS=True
USEDB = Whatever
AUTONAME=True
Make as Template ie set the FN = "___FILE___" in the client, and copy to Avisynthesizer Template directory as
eg "BATCH_GISMO_EXTRACTOR.avst" (note the 't' on the end, ie avst).
Then can use Avisynthesizer_Mod, group select video files, right click SendTo -> Avisynthesizer, and select the BATCH_GISMO_EXTRACTOR from dialog box. [will then create an avs file for each selected source clip file]
Can then (if you like) start a separate instance of VDub2 on each generated AVS file, and save result when each instance completed its work.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.