1 2
6 7 8 9
Joined: 11/4/2007
Posts: 1772
Location: Australia, Victoria
I came up with this idea earlier. My idea involved dumping 32-bit PNG image strips of every layer and then blending the ones when appropriate manually. It isn't perfect, but it's better than doing the whole frame. This, of course, requires cooperation with emulator authors, but none will be interested.
Site Admin, Skilled player (1236)
Joined: 4/17/2010
Posts: 11274
Location: RU
This is too labour-intensive, though I wanted to suggest something like that a week ago. But let's remember all these talks about sprite RAM. Can this sprite data be hacked on console basis, not game one? Lua may be able to kill sprites that blink (which may be detected using logging info at the first pass, say, running a movie) & draw them pixel by pixel transparently (if not, don't shoot me for n00bity).
Warning: When making decisions, I try to collect as much data as possible before actually deciding. I try to abstract away and see the principles behind real world events and people's opinions. I try to generalize them and turn into something clear and reusable. I hate depending on unpredictable and having to make lottery guesses. Any problem can be solved by systems thinking and acting.
Player (136)
Joined: 9/18/2007
Posts: 389
I have already tried to draw additional sprites on SNES. The result was quite horrible. Something was drawn, but definitely not the same sprite (and it introduced desyncs...) And drawing the sprite pixel-by-pixel would introduce another problem: The sprites must be drawn in the right order... I will give this a try though, but it will definitely take a lot more time. It might be difficult to guess which sprites are of the same "type" (for example being part of one character, part of his movement animation, part of his damage animation...) -- this is required for motion interpolation. If we can find an absolutely reliable way for detecting such, it would be game-independent, and remain "only" console-dependant... (Well -- as long as no effects are applied after drawing the layers. Example: water levels in Donkey Kong Country.)
creaothceann
He/Him
Editor
Joined: 4/7/2005
Posts: 1874
Location: Germany
Flygon wrote:
I came up with this idea earlier. My idea involved dumping 32-bit PNG image strips of every layer and then blending the ones when appropriate manually. It isn't perfect, but it's better than doing the whole frame.
There are some problems due to how some consoles render the screen. Here's the table for the SNES:
BGMode  front -> back  condition
-----------------------------------
0        3AB2ab1CD0cd
1        3AB2ab1C 0c   BG3_Top == 0
1       C3AB2ab1  0c   BG3_Top == 1
2        3A 2B 1a 0b
3        3A 2B 1a 0b
4        3A 2B 1a 0b
5        3A 2B 1a 0b
6        3A 2  1a 0
7        3  2  1a 0    EXTBG == 0
7        3  2B 1a 0b   EXTBG == 1


0..3    = sprites with that priority
ABCD    = BG1..BG4 tiles with priority bit == 1
abcd    = BG1..BG4 tiles with priority bit == 0

BGMode  = register $2105 bits 0..2
BG3_Top = register $2105 bit 3
EXTBG   = register $2133 bit 6
Note how layer "B" is drawn in front of layer "2" in BG modes 0 and 1, but not in the others. And games can change the BG mode after each scanline. Also, for some reason sprites with a lower index are always in front of sprites with a higher index, regardless of their priority. So you could have sprite #1 (priority set to 3) on top of BG1, but where sprite #0 (priority set to 0) overlaps sprite #1, only BG1 is visible.
Joined: 11/4/2007
Posts: 1772
Location: Australia, Victoria
Yes, this is why it'd require cooperation from emulator authors. To cut out the parts of the sprites that are suppose to be hidden. The method runs into problems regardless, though, for games that use sprites as background objects (Such as Sonic 3 and Knuckles). I knew pretty much immediately that blending only certain sprites is completely game dependent. This encoding stuff is what I think of while I'm at TAFE and browsing either Cracked or TVTropes.
Site Admin, Skilled player (1236)
Joined: 4/17/2010
Posts: 11274
Location: RU
partyboy1a wrote:
And drawing the sprite pixel-by-pixel would introduce another problem: The sprites must be drawn in the right order
No, if you redraw them transparent. The real issue is sprite/backgroung order I think.
Warning: When making decisions, I try to collect as much data as possible before actually deciding. I try to abstract away and see the principles behind real world events and people's opinions. I try to generalize them and turn into something clear and reusable. I hate depending on unpredictable and having to make lottery guesses. Any problem can be solved by systems thinking and acting.
Player (65)
Joined: 4/21/2011
Posts: 232
http://www.youtube.com/watch?v=7dvTKkQaa0o http://www.mediafire.com/?yh13m7fhh3wxayj
start = FFVideoSource("sm.avi").assumefps(60).converttoyuy2

start
e=selecteven.dbz.selectevery(4,0)
o=selectodd.dbz.selectevery(4,1)

#stackhorizontal(e,o)
interleave(e,o)

stackhorizontal(start,last.changefps(60))

#b b b b b
# u u u u u

#BibiBibiB
# uIuiuIuiu

#http://avisynth.org.ru/mvtools/mvtools2.html
#
#AVISource("c:\test.avi") # or MPEG2Source, DirectShowSource, some previous filter, etc
## assume progressive PAL 25 fps source
#super = MSuper(pel=2)
#backward_vec = MAnalyse(super, isb = true)
#forward_vec = MAnalyse(super, isb = false)
#MFlowFps(super, backward_vec, forward_vec, num=50, den=1, ml=100) # get 50 fps

function dbz(clip c)
{
    c
    super = MSuper(pel=2)
    backward_vec = MAnalyse(super, isb = true)
    forward_vec = MAnalyse(super, isb = false)
    MFlowFps(super, backward_vec, forward_vec, num=60, den=1, ml=100)
}
#e e e e e e # o o o o o o The 60Hz clip can be thought of as two separate clips (one with the blink object, one without) that have been interleaved to produce the blinking. Decimating by just taking the even frames doesn't work. So take every other even frame and try to interpolate the missing frame from the odd clip. #E e E e E e # oIoioIoioI Ideally the motion compensation works well and a nice sharp frame is produced. When the interpolation doesn't work it defaults to blending, which shouldn't be any worse than the other methods. Here is a highlight of the difference of interpolation versus blend. http://www.mediafire.com/?6py0sazeip6oiw5
start
e=selectevery(4)
o=selectodd.convertfps(60).selectevery(4,1)
o2=selectodd.dbz.selectevery(4,1)

#stackhorizontal(start,interleave(e,o).changefps(60),interleave(e,o2).changefps(60))
stackhorizontal(o.subtitle("blend"),o2.subtitle("interpolate"))
Banned User, Former player
Joined: 3/10/2004
Posts: 7698
Location: Finland
The video is private.
creaothceann
He/Him
Editor
Joined: 4/7/2005
Posts: 1874
Location: Germany
Why not detect flickering pixels and apply TASBlend only to those pixels? -Vit- posted this code:
function TASBlend(clip c, float "ratio")  { 
        # reduces framerate to 1/2 but leaves flicker effects partly visible 
        # blends frame pairs with alternating opacity (default is 2/3 + 1/3;1/3 + 2/3) 
        # optional "ratio" is the opacity of the first frame out of the four 
        ratio   = default(ratio, 2.0/3) 
        opacity = round(ratio * 257) 
        # blend flicker to half-rate
        c.SelectEvery(4, 1, 0, 2, 3)
        blend = Layer(SelectEven, SelectOdd, level=opacity)
        # determine flicker is a simplistic way - compare each pixel with the previous and next two frames
        similar2   = 1  # how similar current pixel must be to the same pixel 2 frames forwards and backwards
        different1 = 8  # how different current pixel must be from the same pixel 1 frame forwards and backwards
        mask_f2 = Overlay(c, c.SelectEvery(1, 2), mode="difference", pc_range=true).Greyscale.Levels(128 + similar2  , 1.0, 129 + similar2  , 0, 255, false).Invert
        mask_f1 = Overlay(c, c.SelectEvery(1, 1), mode="difference", pc_range=true).Greyscale.Levels(128 + different1, 1.0, 129 + different1, 0, 255, false)
        mask_b1 = Overlay(c, c.SelectEvery(1,-1), mode="difference", pc_range=true).Greyscale.Levels(128 + different1, 1.0, 129 + different1, 0, 255, false)
        mask_b2 = Overlay(c, c.SelectEvery(1,-2), mode="difference", pc_range=true).Greyscale.Levels(128 + similar2  , 1.0, 129 + similar2  , 0, 255, false).Invert
        mask_f  = Overlay(mask_f1, mask_f2, mode="multiply", pc_range=true)
        mask_b  = Overlay(mask_b1, mask_b2, mode="multiply", pc_range=true)
        mask    = Overlay(mask_f,  mask_b,  mode="multiply", pc_range=true).SelectEven
        # only use blend where detected flicker
        Layer(c.SelectEven, blend.mask(mask))
}
Player (65)
Joined: 4/21/2011
Posts: 232
Warp wrote:
The video is private.
Sorry, misclicked unlisted, should work now.
creaothceann
He/Him
Editor
Joined: 4/7/2005
Posts: 1874
Location: Germany
Resizing it to 2x would help a bit with the colors...
AVISource(...)
PointResize(Width * 2, Height * 2)
ConvertToYUY2
Test


function Test(clip c)  {
	Interleave(c.SelectEven.dbz.SelectEvery(4, 0),
	\          c.SelectOdd .dbz.SelectEvery(4, 1))
}
function dbz(clip c)  {
	super        = c.MSuper(pel=2)
	backward_vec = MAnalyse(super, isb=true)
	forward_vec  = MAnalyse(super, isb=false)
	MFlowFps(c, super, backward_vec, forward_vec, num=60, den=1, ml=100)
}
Player (136)
Joined: 9/18/2007
Posts: 389
creaothceann wrote:
Why not detect flickering pixels and apply TASBlend only to those pixels? -Vit- posted this code:
function TASBlend(clip c, float "ratio")  { 
        # reduces framerate to 1/2 but leaves flicker effects partly visible
 ...
}
If only the mask was better, or if the motion estimation nanogyth posted didn't produce these bad artifacts... Then we would have a better solution than global TASblend or 20fps videos right now.
Player (65)
Joined: 4/21/2011
Posts: 232
partyboy1a wrote:
or if the motion estimation nanogyth posted didn't produce these bad artifacts...
You could just do blending for the odd frames.
Interleave(c.SelectEvery(4, 0),
\          c.SelectOdd.convertfps(60).SelectEvery(4, 1))
Less aggressive motion estimation settings should reduce artifacts while still showing some improvements. http://www.youtube.com/watch?v=EjDRm0CbILU
Senior Moderator
Joined: 8/4/2005
Posts: 5770
Location: Away
Please include sections with 30 Hz arm-pumping and more complex background scrolling (ideally emergency countdown Ceres or some Norfair segment with heat haze) in your demonstrations. The current ones show way too little.
Warp wrote:
Edit: I think I understand now: It's my avatar, isn't it? It makes me look angry.
Player (136)
Joined: 9/18/2007
Posts: 389
The least would be one reference for all. For example this one which is even more evil, as it has animations with a length of 4 frames... I originally found it at Combovid.
creaothceann
He/Him
Editor
Joined: 4/7/2005
Posts: 1874
Location: Germany
Here's a recording of cpadolf's SNES Super Metroid "any%, glitched", with some edits to keep the file size below 200 MB. Encoded with ZMBV (included with DOSBox & ffdshow), no audio: http://www.mediafire.com/?n4q7bs4nd3d1spw I think nanogyth's algorithm shows the best results:
AVISource("#2223 - cpadolf's SNES Super Metroid ''any%, glitched''.avi").ConvertToRGB32

v1 = TASBlend    .PointResize(512, 448)
v2 =              PointResize(512, 448).ConvertToYUY2.TASBlend_nanogyth.ConvertToRGB32
v3 = TASBlend_Vit.PointResize(512, 448)

StackHorizontal(v1.Subtitle("TASBlend"         ),
\               v2.Subtitle("TASBlend_nanogyth"),
\               v3.Subtitle("TASBlend_Vit"     ))




function TASBlend_nanogyth(clip c)  {
        c
        Assert(!IsRGB, "TASBlend_nanogyth: clip cannot be RGB")
        Interleave(SelectEven.dbz.SelectEvery(4, 0),
        \          SelectOdd .dbz.SelectEvery(4, 1))
}
function dbz(clip c)  {
        super        = c.MSuper(pel=2)
        backward_vec = MAnalyse(super, isb=true)
        forward_vec  = MAnalyse(super, isb=false)
        MFlowFps(c, super, backward_vec, forward_vec, num=60, den=1, ml=100)
}



function TASBlend_Vit(clip c, float "ratio")  { 
        # reduces framerate to 1/2 but leaves flicker effects partly visible 
        # blends frame pairs with alternating opacity (default is 2/3 + 1/3;1/3 + 2/3) 
        # optional "ratio" is the opacity of the first frame out of the four 
        ratio   = default(ratio, 2.0/3) 
        opacity = round(ratio * 257) 
        # blend flicker to half-rate
        c.SelectEvery(4, 1, 0, 2, 3)
        blend = Layer(SelectEven, SelectOdd, level=opacity)
        # determine flicker is a simplistic way - compare each pixel with the previous and next two frames
        similar2   = 1  # how similar current pixel must be to the same pixel 2 frames forwards and backwards
        different1 = 8  # how different current pixel must be from the same pixel 1 frame forwards and backwards
        mask_f2 = Overlay(c, c.SelectEvery(1, 2), mode="difference", pc_range=true).Greyscale.Levels(128 + similar2  , 1.0, 129 + similar2  , 0, 255, false).Invert
        mask_f1 = Overlay(c, c.SelectEvery(1, 1), mode="difference", pc_range=true).Greyscale.Levels(128 + different1, 1.0, 129 + different1, 0, 255, false)
        mask_b1 = Overlay(c, c.SelectEvery(1,-1), mode="difference", pc_range=true).Greyscale.Levels(128 + different1, 1.0, 129 + different1, 0, 255, false)
        mask_b2 = Overlay(c, c.SelectEvery(1,-2), mode="difference", pc_range=true).Greyscale.Levels(128 + similar2  , 1.0, 129 + similar2  , 0, 255, false).Invert
        mask_f  = Overlay(mask_f1, mask_f2, mode="multiply", pc_range=true)
        mask_b  = Overlay(mask_b1, mask_b2, mode="multiply", pc_range=true)
        mask    = Overlay(mask_f,  mask_b,  mode="multiply", pc_range=true).SelectEven
        # only use blend where detected flicker
        Layer(c.SelectEven, blend.mask(mask))
}
Player (65)
Joined: 4/21/2011
Posts: 232
moozooh wrote:
Please include sections with 30 Hz arm-pumping and more complex background scrolling (ideally emergency countdown Ceres or some Norfair segment with heat haze) in your demonstrations. The current ones show way too little.
Yes, more samples would be welcome, I only have the one posted at doom9. One of the sonic levels would be nice. I think an important step forward is identifying where the actual blinking is occurring. Most of my gross motion prediction artifacts are in places that aren't blinking. Taking just the even frames causes problems for blinking, but is otherwise the right thing to do. So always take every other even frame (selectevery(4)), and then figure out which parts of the other even frame can be safely used and which parts need to be (and can be) interpolated from the odd frames.
e e e
 o o o

E   e   E

  o I o   o
There are three transitions I want to consider oe, eo, and oo.
  e
 / \
o - o
If all three are smooth transitions then the even frame can be used as is. If oe and eo are complex, but oo is smooth, then the interpolation should be used. If all three are complex then use the even frame, because the interpolation will be ugly. ??? THEN partyboy1a posted something with f1 and f2 blinking and it wrinkled my brain. =_=
creaothceann
He/Him
Editor
Joined: 4/7/2005
Posts: 1874
Location: Germany
What I found interesting is that shots get sometimes duplicated. :) EDIT: another fun screenshot
Player (136)
Joined: 9/18/2007
Posts: 389
I created a mask which marks most of the defects caused by MFlowFPS:
#AVISource("#2223 - cpadolf's SNES Super Metroid ''any%, glitched''.avi").ConvertToRGB32 
AVIsource("test-blend.avi").ConvertToRGB32

 v1 = TASBlend    .PointResize(512, 448) 
 v2 =              PointResize(512, 448).ConvertToYUY2.TASBlend_nanogyth.ConvertToRGB32 
 v3 =              PointResize(512, 448).ConvertToYUY2.TASBlend_extendednanogyth2.ConvertToRGB32 
 v4 = TASBlend_Vit.PointResize(512, 448) 

 StackVertical( stackhorizontal(last.PointResize(512, 448).selecteven, last.PointResize(512, 448).selectodd), \
 StackHorizontal(v1.Subtitle("TASBlend"         ), v4.Subtitle("TASBlend_Vit"     )), \
 stackHorizontal(v2.Subtitle("TASBlend_nanogyth"), v3.Subtitle("TASBlend_extendednanogyth")))




 function TASBlend_nanogyth(clip c)  { 
         c 
         Assert(!IsRGB, "TASBlend_nanogyth: clip cannot be RGB") 
         Interleave(SelectEven.dbz.SelectEvery(4, 0), 
         \          SelectOdd .dbz.SelectEvery(4, 1)) 
 }
 
  function TASBlend_nanogyth_custom(clip c,int delta)  { 
         c 
         Assert(!IsRGB, "TASBlend_nanogyth: clip cannot be RGB") 
         Interleave(SelectEven.dbz_custom(delta).SelectEvery(4, 0), 
         \          SelectOdd .dbz_custom(delta).SelectEvery(4, 1)) 
 }
  
  function differenceclip(clip a, clip b)
{
	overlay( \
		a.overlay(b.invert,mode="add",pc_range=true).invert, \
		b.overlay(a.invert,mode="add",pc_range=true),mode="add",pc_range=true \
	).invert.greyscale.levels(2,1,3,0,255)
}

  function differenceclip_weak(clip a, clip b)
{
	overlay( \
		a.overlay(b.invert,mode="add",pc_range=true).invert, \
		b.overlay(a.invert,mode="add",pc_range=true),mode="add",pc_range=true \
	).invert.greyscale.levels(2,1,70,0,255)
}
  
 function TASBlend_Vit(clip c, float "ratio")  { 
         # reduces framerate to 1/2 but leaves flicker effects partly visible 
         # blends frame pairs with alternating opacity (default is 2/3 + 1/3;1/3 + 2/3) 
         # optional "ratio" is the opacity of the first frame out of the four 
         ratio   = default(ratio, 2.0/3) 
         opacity = round(ratio * 257) 
         # blend flicker to half-rate 
         c.SelectEvery(4, 1, 0, 2, 3) 
         blend = Layer(SelectEven, SelectOdd, level=opacity) 
         # determine flicker is a simplistic way - compare each pixel with the previous and next two frames 
         similar2   = 1  # how similar current pixel must be to the same pixel 2 frames forwards and backwards 
         different1 = 8  # how different current pixel must be from the same pixel 1 frame forwards and backwards 
         mask_f2 = Overlay(c, c.SelectEvery(1, 2), mode="difference", pc_range=true).Greyscale.Levels(128 + similar2  , 1.0, 129 + similar2  , 0, 255, false).Invert 
         mask_f1 = Overlay(c, c.SelectEvery(1, 1), mode="difference", pc_range=true).Greyscale.Levels(128 + different1, 1.0, 129 + different1, 0, 255, false) 
         mask_b1 = Overlay(c, c.SelectEvery(1,-1), mode="difference", pc_range=true).Greyscale.Levels(128 + different1, 1.0, 129 + different1, 0, 255, false) 
         mask_b2 = Overlay(c, c.SelectEvery(1,-2), mode="difference", pc_range=true).Greyscale.Levels(128 + similar2  , 1.0, 129 + similar2  , 0, 255, false).Invert 
         mask_f  = Overlay(mask_f1, mask_f2, mode="multiply", pc_range=true) 
         mask_b  = Overlay(mask_b1, mask_b2, mode="multiply", pc_range=true) 
         mask    = Overlay(mask_f,  mask_b,  mode="multiply", pc_range=true).SelectEven 
         # only use blend where detected flicker 
         Layer(c.SelectEven, blend.mask(mask)) 
 }
  
  function TASBlend_extendednanogyth(clip c)  {
		ng = TASBlend_nanogyth(c)
		m=differenceclip(ng,TASBlend_nanogyth_custom(c,1))
		m=overlay(m,differenceclip(ng,c.selecteven).invert,mode="add",pc_range=true)
		m=overlay(m,differenceclip(ng,c.selecteven.deleteframe(0)).invert,mode="add",pc_range=true).converttorgb32.levels(250,1,251,0,255)
		almostfinal = overlay(ng, c.selecteven, mask=m)
		return almostfinal
        return differenceclip(almostfinal, TASBlend_Vit(c.converttorgb32))
 }
 
   function TASBlend_extendednanogyth2(clip c)  {
		ng = TASBlend_nanogyth(c)
		m = differenceclip(ng,TASBlend_nanogyth_custom(c,2))
		m2 = differenceclip(ng,TASBlend_nanogyth_custom(c,3))
		mask0 = overlay(m,m2,mode="add",pc_range=true)
		ng2 = TASBlend_nanogyth(c.deleteframe(0))
		m3 = differenceclip(ng,ng2.duplicateframe(0))
		mask1 = overlay(mask0, m3, mode="add",pc_range=true)
		#return overlay(ng, mask1, mask=mask1, pc_range=true)
		#return overlay(c.selecteven, ng, mask=mask1.invert)
		#return overlay(c.selecteven, mask1, mask=mask1)
		mask2 = overlay(mask1.invert.greyscale.levels(127,1,128,0,255), differenceclip(ng, c.selecteven),mode="add")
		mask3 = overlay(mask2, differenceclip(ng, c.selectodd), mode="subtract").greyscale
		return ng.overlay(mask3.invert,mask=mask3.invert)
		return overlay(mask3,mask4.invert,mode="add")
		return overlay(ng, mask3.invert, mask=mask3.invert)
 }
 
  function dbz(clip c)  { 
         super        = c.MSuper(pel=2) 
		 backward_vec = MAnalyse(super, isb=true) 
         forward_vec  = MAnalyse(super, isb=false) 
         MFlowFps(c, super, backward_vec, forward_vec, num=60, den=1, ml=100) 
 }
 
 function dbz_custom(clip c, int delta)  { 
         super        = c.MSuper(pel=2) 
		 backward_vec = MAnalyse(super, isb=true,delta=delta) 
         forward_vec  = MAnalyse(super, isb=false,delta=delta) 
         MFlowFps(c, super, backward_vec, forward_vec, num=60, den=1, ml=100) 
 }


 function TASBlend(clip c) {
	ratio = 2.0/3
	opacity = round(ratio * 257)
	c.SelectEvery(4, 1, 0, 2, 3) 
    blend = Layer(SelectEven, SelectOdd, level=opacity) 
	Layer(c.SelectEven, blend)
 }
 
I tested this code with this video which has fast movement and flicker at the same time . edit: seems to be a bit too restrictive in the super metroid video...
Player (65)
Joined: 4/21/2011
Posts: 232
It seems like mvtools would be able to tell when an object popped in from nowhere/disappeared. Having a mask of that would be helpful. PS - what codec is the roadrunner clip in? ffvideosource green screened, directshowsource worked.
creaothceann
He/Him
Editor
Joined: 4/7/2005
Posts: 1874
Location: Germany
It's Lagarith.
Player (65)
Joined: 4/21/2011
Posts: 232
So, here is something. It fixes some of the problems I was having, but causes some other pretty serious ones. http://www.youtube.com/watch?v=SHv53ayuZ-0
assumefps(60)
PointResize(Width * 2, Height * 2)
ConvertToYv12

super=MSuper()
fvec =MAnalyse(super, isb=false, truemotion=false)
bvec =MAnalyse(super, isb=true , truemotion=false)

fmask=Mmask(last,fvec,kind=1,ml=130).mt_binarize
bmask=Mmask(last,bvec,kind=1,ml=130).mt_binarize

mask=mt_logic(fmask,bmask,mode="and").selectevery(4,2).mt_expand

e0=selectevery(4,0)
e2=selectevery(4,2)
i2=selectodd.convertfps(60).selectevery(4,1)

interleave(e0,mt_merge(e2,i2,mask,chroma="copy second"))
Player (65)
Joined: 4/21/2011
Posts: 232
Ok, I think I fixed it up pretty well, disappearing lady near the end, but otherwise pretty smooth. I've given up on motion compensation for the moment. The places it would be used usually look better blended anyway. And this way the pixels can stay in rgb32. The yv12 is only used to make the mask. Might not even need to resize at all now. http://www.youtube.com/watch?v=bU-OnJzjQu8
assumefps(60)
PointResize(Width * 2, Height * 2)
source=last

ConvertToYv12

super=MSuper()
fvec =MAnalyse(super, isb=false, truemotion=false)
bvec =MAnalyse(super, isb=true , truemotion=false)
fmask=Mmask(last,fvec,kind=1,ml=130).mt_binarize
bmask=Mmask(last,bvec,kind=1,ml=130).mt_binarize
mask=mt_logic(fmask,bmask,mode="and").selectevery(4,2).mt_expand.mt_expand

oo=selectodd.mt_motion(thT=255).selectodd
mask2=mt_logic(oo,mask.mt_invert,mode="and").mt_expand.mt_expand

source.converttorgb32

e0=selectevery(4,0)
e2=selectevery(4,2)
i2=selectodd.convertfps(60).selectevery(4,1)

merge=overlay(i2,e2,mask=mask2)
interleave(e0,merge)
creaothceann
He/Him
Editor
Joined: 4/7/2005
Posts: 1874
Location: Germany
New function on doom9: http://forum.doom9.org/showthread.php?p=1524289#post1524289 Unfortunately it seems to not detect much of Samus' arm-pumping, at least with the tweaking as-is.
Player (65)
Joined: 4/21/2011
Posts: 232
creaothceann wrote:
New function on doom9: http://forum.doom9.org/showthread.php?p=1524289#post1524289 Unfortunately it seems to not detect much of Samus' arm-pumping, at least with the tweaking as-is.
We ended up with similar functions. What is the arm-pumping? Part of the running animation?
FFVideoSource("sm.avi")
ConvertToRGB32
HalfWink

function HalfWink(clip c){
    c

    #e e e
    # o o o
    #The clip is made of even/odd frames and the simplest way to reduce
    #framerate would be to just take the even frames. But some clips have
    #blinking that alternates frame to frame. That could make a "transparent"
    #object solid or disappear entirely.

    #E   e   E
    #  o I o   o
    #This function takes every other even frame and a frame interpolated
    #from the odd frames. There are even times when it is appropriate to
    #use some of the skipped even frame.

    e0=selectevery(4,0)
    e2=selectevery(4,2)
    OddBlend=selectodd.convertfps(c).selectevery(4,1)
    interleave(e0,overlay(OddBlend,e2,mask=BlinkMask(c)))
}

function BlinkMask(clip c){
    c.ConvertToYv12

    #oo is the part of the odd frame that is moving.
    #If it isn't moving it doesn't need to be replaced.

    OddMoving=selectodd.mt_motion(thT=255).selectodd

    #Use mvtools to detect motion.
    #If the object is blinking it will show crazy high motion since it doesn't
    #exist frame to frame.

    super=MSuper()
    fvec =MAnalyse(super, isb=false, truemotion=false)
    bvec =MAnalyse(super, isb=true , truemotion=false)
    fmask=Mmask(last,fvec,kind=1,ml=130).mt_binarize
    bmask=Mmask(last,bvec,kind=1,ml=130).mt_binarize

    #mask is the part of the even frame that IS moving in both the forward and
    #backwards direction. If it isn't moving in BOTH directions then it isn't
    #blinking and we CAN!!! use it.

    Blinking=mt_logic(fmask,bmask,mode="and").selectevery(4,2).mt_expand.mt_expand
    NotBlinking=Blinking.mt_invert

    mt_logic(OddMoving,NotBlinking,mode="and").mt_expand.mt_expand
}
RoadRunner StreetFighter
1 2
6 7 8 9