Log in

View Full Version : How to diff "arbitrary" frames?


MrPete
30th December 2014, 14:21
OK, time to jump in with both feet. (Thanks to some great wiki examples, I now understand that avisynth really is NOT a procedural language... yet has procedural bits here and there, like inside ScriptClip...)

Here's my current challenge. I am writing a state machine for selecting frames from captured 8mm film... where typically either odd or even frames are "correct" but every once in a while this shifts. The "best" frames aren't necessarily combed; in my current captures the better frames are sharper, darker.

But to do it properly, particularly in sequences where the overall luminance is in a monotonically increasing or decreasing trend, one can't simply compare luminance between neighboring frames. (Think of a fading scene: every frames is going to be a bit darker than the previous frame.)

So what I want to do is discover the most-similar frame pairs, eg if current frame is 0, I want to decide if 0/1, 2/3, 4/5 are pairs or 1/2, 3/4, 5/6 are pairs.

I noticed from another example that AverageLuma() supports a format of AverageLuma(clip,relN) where relN is 0 for current frame, -1 for previous, 1 for next, 2 for next+1.

My Questions:
1) What is the equivalent thing for YDifferenceFromPrevious or YDifferenceFromNext? What I need is to compare:
- current vs next
- current vs next+1
- next vs next+1
- next vs next+3
- next+1 vs next+2
- next+2 vs next+3
etc
2) Where can I go to learn such things? I've not seen documentation (yet) on this (clip, relN) format.
3) (If necessary I can reduce my expectations and run the state machine from a "middle" frame, looking at current-prev and current-next... but that seems both logically painful and also quite limiting. I am hoping to track sync-lock based on more than just three frames...


Thanks muchly!
Pete

Wilbert
30th December 2014, 15:36
I noticed from another example that AverageLuma() supports a format of AverageLuma(clip,relN) where relN is 0 for current frame, -1 for previous, 1 for next, 2 for next+1.
Just curious. Where did you see this? Looking at the code i see it doesn't support a reIN. Looking at the other functions, they do actually support a current vs current+/-j, but that's not implemented fully.

MrPete
30th December 2014, 15:58
Just curious. Where did you see this? Looking at the code i see it doesn't support a reIN. Looking at the other functions, they do actually support a current vs current+/-j, but that's not implemented fully.
Gavino wrote it (http://forum.doom9.org/showthread.php?p=1410922#post1410922) back in 2010.

johnmeyer
30th December 2014, 16:17
The code you linked to was an attempt to remove the worst of the "extra" fields that are captured when you point a 30 fps video camera at a film projector operating at 18 fps (or less). The video camera captures some fields when the shutter is closed during film pulldown, and these fields are the top candidates for removal. Next in line are the fields that are duplicates because of the speed differences between the cameras. The goal is to produce a "frame accurate" film transfer using a film-to-video capture system that is not frame accurate (e.g., simply pointing the camera at a movie projector screen).

There were at least two more thread that tackled this same problem. If what I describe is what you now want to do (it certainly is what Gavino's code was designed to do), there was another long thread about this which came several years later. The OP was so happy with the result that he started a new thread just to discuss the subject. You can find that by clicking here: The power of Avisynth: salvaging "botched" transfers of old 8mm films to DVD. (http://forum.doom9.org/showthread.php?t=161493)

Gavino
30th December 2014, 17:34
I noticed from another example that AverageLuma() supports a format of AverageLuma(clip,relN) where relN is 0 for current frame, -1 for previous, 1 for next, 2 for next+1.

My Questions:
1) What is the equivalent thing for YDifferenceFromPrevious or YDifferenceFromNext? What I need is to compare:
- current vs next
- current vs next+1
...
The standard versions of the run-time functions do not have that parameter, but it is available if you use the extended versions of the functions in my GRunT plugin.

When used with YDifferenceFromPrevious or YDifferenceFromNext, these functions will take current_frame+offset (instead of just current_frame) as the frame to be compared with its previous or next frame. Thus, they still compare adjacent frames and cannot be used directly to compare completely arbitrary frames like current vs next+1.

One way to do that is to use LumaDifference(), adjusting the starting point of the second comparison clip via Trim().
Alternatively, I believe one of StainlessS' many functions (I've lost track now :)) can probably do the job.

While I'm here, I'll take this opportunity to send my best festive wishes to all.

StainlessS
30th December 2014, 17:52
The 'n' arg is an optional frame number and defaults to 'current_frame' if not specified.
The x,y,w,h, coords specify the source rectangle under scrutiny and are specified as for Crop(), the default 0,0,0,0 is full frame.
If 'interlaced' is true, then every other line is ommited from the scan, so if eg y=1, then scanlines 1,3,5,7 etc are scanned,
if eg y=4 then scanlines 4,6,8,10 etc are scanned. The 'h' coord specifies the full height scan ie same whether interlaced is true
or false, although it will not matter if the 'h' coord is specified as eg odd or even, internally the height 'h' is reduced by 1
when interlaced=true and 'h' is even.

Matrix: Conversion matrix for conversion of RGB to YUV-Y Luma. 0=REC601 : 1=REC709 : 2 = PC601 : 3 = PC709,
Default = (Width > 1100 OR Height>600) then 3(PC709) else 2(PC601). YUV not used

The optional mask clip, governs which pixels are processed by the functions. Where a luma pixel in selected area of the the mask clip is
in range "MaskMin" to "MaskMax" inclusive, then those pixels will be processed. The Mask must also be Planar but not
necessarily the same colorspace as clip c, also must be same dimensions and have at least the same number of frames as clip c.
Calling without mask clip OR with MaskMin=0,MaskMax=255 will effectively ignore the mask and scan full x,y,w,h area.

RT_AverageLuma(clip c,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,bool "interlaced"=false,
int "Matrix"=(Width>1100||Height>600?3:2),clip "mask"=NOT_USED,int "MaskMin"=128,"MaskMax"=255)
Return int -1, if no valid pixels in Mask clip.
Returns FLOAT value average luma (0.0 -> 255.0) in frame(n+delta) for area x,y,w,h.


Full Frame Only

RT_FrameDifference(clip c,clip c2,int "n"=current_frame,int "n2"=current_frame,Float "ChromaWeight"=1.0/3.0)
Returns difference between clip c frame n and clip c2 frame n2 (0.0 -> 255.0).
ChromaWeight range 0.0 -> 1.0.
For RGB, returns same as RGBDifference.
For Y8 returns same as LumaDifference.
For non Y8 Planar returns Lumadif + Chromadif with chroma weighted by ChromaWeight arg.
Returns:- (1.0 - ChromaWeight) * Lumadif + ChromaWeight * ((Udif + Vdif)/2.0).



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


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

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

***
***
***

RT_LumaDifference(clip,clip2,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,
int "n2"=current_frame,int "delta2"=0,int "x2"=x,int "y2"=y,bool "interlaced"=false,int "Matrix"=(Width>1100||Height>600?3:2))
Returns FLOAT value luma difference (0.0 -> 255.0) between clip frame (n+delta) area x,y,w,h, and clip2 frame (n2+delta2) area x2,y2,w,h.
Note, 'x2' and 'y2' default to 'x' and 'y' respectively.



RT_LumaCorrelation(clip,clip2,int "n"=current_frame,int "delta"=0,int "x"=0,int "y"=0,int "w"=0,int "h"=0,int "n2"=current_frame,
int "delta2"=0,int "x2"=x,int "y2"=y,bool "interlaced"=false,int "Matrix"=(Width>1100||Height>600?3:2))
Returns FLOAT value luma correlation (-1.0 -> 1.0) between clip frame (n+delta) area x,y,w,h, and clip2 frame (n2+delta2) area x2,y2,w,h.
Note, 'x2' and 'y2' default to 'x' and 'y' respectively.
Pearson's Sample Correlation Coefficient.
http://en.wikipedia.org/wiki/Correlation_and_dependence
http://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient
Uses equivalent routine to the JMac698's JCorr plugin here:
http://forum.doom9.org/showthread.php?t=165386
and here:
http://forum.doom9.org/showthread.php?p=1495098#post1495098



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

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


And a Happy New Years to one and all :)

MrPete
30th December 2014, 18:37
The code you linked to was an attempt to remove the worst of the "extra" fields that are captured when you point a 30 fps video camera at a film projector operating at 18 fps (or less)....If what I describe is what you now want to do (it certainly is what Gavino's code was designed to do), there was another long thread about this which came several years later. The OP was so happy with the result that he started a new thread just to discuss the subject. You can find that by clicking here: The power of Avisynth: salvaging "botched" transfers of old 8mm films to DVD. (http://forum.doom9.org/showthread.php?t=161493)
Yup, I'm aware of the more recent thread; thanks for the reminder though. I intend to go back to that for inspiration once I'm past my first steps.
My situation is a bit different. My Sniper unit synchronizes camera and projector--almost. It takes a live Y signal from the camera and feeds it back to the projector to adjust the projector motor so they are in sync. Or it would, if I were still using the original Canon HV20 camcorder :) ... I get mostly-sync'd captures, with the occasional hiccups every few seconds. (I have examined the circuitry... there are at least four trim pots and some other switches, all completely undocumented as this is Roger's proprietary invention. I guess it wouldn't hurt to ask if he's willing to share some sync-tuning secrets since he doesn't sell it any more :) :) )

ANYway... while I started with some of what's in the aforementioned thread(s), I've already had to go beyond. Partly because they actually don't work well in all situations, and partly because my source material is quite a bit different.

MrPete
30th December 2014, 19:06
RT_AverageLuma...RT_FrameDifference...RT_LumaCorrelation

And a Happy New Years to one and all :)

These are incredible, StainlessS! Thank you for all your hard work over the years.

I've got a separate interesting question for you as my "Christmas Present" :-D ... a new thread for that one.

May everyone have a wonderful time with whoever is your family as we enter a New Year!

Blessings,
Pete

johnmeyer
30th December 2014, 23:35
My Sniper unit synchronizes camera and projector--almost. It takes a live Y signal from the camera and feeds it back to the projector to adjust the projector motor so they are in sync. Or it would, if I were still using the original Canon HV20 camcorder ... I get mostly-sync'd captures, with the occasional hiccups every few seconds. Actually, I don't think that is how the sync works. I corresponded with Roger when he was in the middle of inventing this. I was also in the middle of inventing my system which uses only software to achieve the same objective. His system is more foolproof, but it requires quite a bit of custom hardware.

I think the way the Sniper works is that it has a sensor switch that closes each time the projector shutter closes. This is identical to the older, slower Workprinter (the unit I have). However, instead of sending that contact closure to the left mouse button in order to take a snapshot of the result, it instead goes to a "beep generator" that emits a very short beep.

Now this is the part that you need to understand if you're going to use another camera.

That beep then gets fed into the video camera, which is operating in regular video mode, so that the camera records a video version of the film, including fields that contain dark or black fields when the film projector's shutter is closed, during pulldown. The resulting video is then fed into some software that "looks" at the beeps and uses those to determine which fields of film should be thrown away. Even if the projector and camera drift (i.e., don't run at constant speed), this approach always gives you a perfect result.

So, if you are having sync problems, you either aren't recording the audio, or it is at the wrong levels, or the software that came with the unit isn't "tuned" properly.

MrPete
31st December 2014, 07:08
John, what you are describing is the original Sniper model, which also depends on a quirk in the older version of the BlackMagic Design capture card -- to sync frames on the beep.

The final (?) version of the Sniper has an AutoSync feature. No beeps. No audio connection at all, in fact. And yes, it works as I described. The projector speeds/slows until it believes it is in sync with the camera:
* The frame-light LED doesn't even turn on unless/until the projector circuitry sees the sync signal.
* The sync signal is a video signal with standard sync -- either composite (from Canon HV40 - I goofed earlier; HV40 not HV20) or Y from a composite cable.***
* AFAIK, the original Sniper had no need to receive a sync from the camera; mine does.

MrPete
31st December 2014, 07:12
Hmmm... now I am curious: the main difference between my new setup and the "standard" AutoSync sniper is in the sync signal:

Standard: the projector receives a composite video signal from the camcorder.
Mine: the projector receives a component Y video signal, converted with least-possible-delay from the camera's HDMI. (I am using an HDMI splitter plus HDFury 3 box, which supposedly has only a fraction of a msec delay.)

I wonder: is there any significant timing difference in the sync signal on composite vs Component-Y? That might explain a lot...

[edit...] Oh my... I have NOT been thinking clearly. Of COURSE there's a difference. Composite is always 480i (NTSC), and the sync is bilevel. Component is HD... and HD sync is completely different, ie tri-level (square wave pulse negative then positive.)

What I actually need is a speedy HD to Composite conversion box. I've been wasting a lot of time doing this wrong... Sigh.

[edit] UPDATE: I think I have my answer...
a) HDFury is the fastest HDMI-to-Component converter out there
b) I need a Component-to-Composite converter. MonoPrice has one that's supposedly very very fast. We shall see! http://www.monoprice.com/Product?c_id=101&cp_id=10114&cs_id=1011407&p_id=7114&seq=1&format=2

johnmeyer
31st December 2014, 18:54
I stand corrected (about how the newer Sniper sync works). I have no idea about what he is doing now. Syncing the projector to the camera sounds dreadfully difficult, and I would think there would be a lag, but if that is how it works, then I guess that's how it works!

MrPete
1st January 2015, 01:12
I have no idea really... but considering that all that matters is the inter-frame timing, they could do the whole thing with a 1 frame lag and it would still work. Or 2 or 3 or whatever...

I wonder what it would take to find a general purpose tunable-lag signal delay... hmmmm I'm sure they exist!

johnmeyer
1st January 2015, 01:32
I wonder what it would take to find a general purpose tunable-lag signal delay... hmmmm I'm sure they exist!I have an EE degree and could easily answer that, but only if I understood exactly how your Sniper model works.