VideoHelp Forum
+ Reply to Thread
Results 1 to 22 of 22
Thread
  1. Hi, let's see if I am able to explain what I'm try to do in few words.

    I have a series of small static images that I use in a forum signature, one of these images is an APNG of a cat walking.
    I would like this unique image to move from the left to the right, and reappear to the right in a infinite loop.
    I have already asked if it was possible to use some bbcode such as [marqueeleft] and [table],
    but it seems it's quite complicated or not possible to set different table columns sizes.

    So I decided to "cheat" trying to create a banner with this cat
    https://i.postimg.cc/Qtpn2zNk/black-cat-walks-64.png
    moving from the right to the left.

    As I cannot find a simple way to do that, I thought I could maybe use some Avisynth commands in order to:
    given an APNG, create a video banner where the image slowly scrolls, appearing from the right and disappearing on the left,
    so then I can easily convert the video back to an APNG, having the image lenght that I want,
    something like 500*64px or so, with the cat that moves in a loop.

    where do I start from?
    Last edited by maudit; 26th Nov 2022 at 06:01.
    Quote Quote  
  2. Here's a basic example.

    Code:
    function catwalk(clip background, clip cat, int xpos, int ypos)
    {
        xpos = xpos % (background.width + cat.width) - cat.width
        Overlay(background, cat, xpos, ypos, mask=cat.ShowAlpha())
    }
    
    cat = LWlibavVideoSource("black-cat-walks-64.png").FlipHorizontal() # png with alpha channel, 88x64, 322 frames
    cat = cat.RGBADjust(r=0, g=0, b=0)
    cat = cat+cat+cat+cat+cat # make cat animation 5x longer
    
    background = ColorBars(width=640, height=480).Trim(0,1455)
    
    Animate(0, 1455, "catwalk", background,cat,0,259, background,cat,1456,259)
    I made the cat move left to right to make the math a little clearer.
    Image Attached Files
    Quote Quote  
  3. that's pretty nice, I really barely understand how all the commands are working, but thank you very much.
    it's cool that I can decide the cat direction with ".FlipHorizontal()", maybe I could do a moonwalking cat.

    now please, just a few fixes..
    - the background must be white - idk maybe using "BlankClip()" instead of "ColorBars"?
    - the resolution must be "A_NUMBER_THAT_I_CAN_DECIDE x 64"

    - the length of the animation is doubled, I mean the cat passes 2 times, why?
    why the trim is at 1455? can be fixed to exact one pass only? .Trim(0,727) is correct?
    Last edited by maudit; 26th Nov 2022 at 10:01.
    Quote Quote  
  4. Here's a simple mod to move the cat from left to right:


    Code:
    function catwalk(clip background, clip cat, int xpos, int ypos)
    {
        xpos = xpos % (background.width + cat.width) - cat.width
        Overlay(background, cat, xpos, ypos, mask=cat.ShowAlpha())
    }
    
    cat = LWlibavVideoSource("black-cat-walks-64.png").FlipHorizontal() # png with alpha channel, 88x64, 322 frames
    cat = cat.RGBADjust(r=0, g=0, b=0)
    cat = cat+cat+cat+cat+cat # make cat animation 5x longer
    
    background = ColorBars(width=640, height=480).Trim(0,1455)
    
    background = FlipHorizontal(background)
    Animate(0, 1455, "catwalk", background,cat,0,259, background,cat,1456,259)
    FlipHorizontal()
    The background is flipped horizontally before adding the cat, the flipped back after adding the cat.
    Quote Quote  
  5. Originally Posted by maudit View Post
    - the background must be white
    The background of what must be white? The background image? Instead of ColorBars() use BlankClip(color=color_white).

    Originally Posted by maudit View Post
    - the resolution must be "A_NUMBER_THAT_I_CAN_DECIDE x 64"
    The resolution of the background must be N*64? N is the width:height of the overlay? Just some random numbers?

    Code:
    background = BlankClip(width=cat.width*64, cat.height*64, color=color_white)
    Code:
    background = BlankClip(width=10*64, 8*64, color=color_white)
    You'll have to adjust the motion parameters in the Animate() call. Read up on the function:

    http://avisynth.nl/index.php/Animate

    Originally Posted by maudit View Post
    - the length of the animation is doubled, I mean the cat passes 2 times, why?
    why the trim is at 1455? can be fixed to exact one pass only? .Trim(0,727) is correct?
    Yes, you can trim to frame 727 to get only one pass. I wanted to show that the cat would automatically wrap around in longer videos because you asked for that -- "I would like this unique image to move from the left to the right, and reappear to the right in a infinite loop." You must extend the cat animation to be as long or longer than the background video if you want it to cover the entire length of the background video.
    Last edited by jagabo; 26th Nov 2022 at 10:35.
    Quote Quote  
  6. yes the background image, sorry I meant it must be Transparent, but if not possible, I'll remove the white color later.
    white is ok, BlankClip(color=color_white) is ok.

    the final resolution must be N(width)*64(same as the Apng height)

    I don't know how to write the script.
    Quote Quote  
  7. So you're looking to create a new big overlay (where the cat moves around) from the old small overlay? Not just overlay the PNG sequence onto a source video? I was showing how to do the latter.
    Quote Quote  
  8. I think it suppose to be a website banner, image that can loaded as some signature on a website. So just wide transparent PNG of walking cat.
    But then he needs to provide actual width.
    Quote Quote  
  9. Image
    [Attachment 67859 - Click to enlarge]
    This is a banner of a black cat walking with white background, cat appears from the left, just off screen and clip ends when it just walks off screen on the right,
    you can select width of that banner choosing CLIP_MULTIPLE integer:
    PHP Code:
    #python script
    import vapoursynth as vs
    from vapoursynth import core
    import havsfunc
    cat
    alpha core.ffms2.Source(r"C:\....your full path here....\black-cat-walks-64.png"alpha=True)
    CLIP_MULTIPLE 5              #sets aproximate banner width
    START_POS = -cat.width         #to start to walk just from off screen, cannot be less than:-cat.width
    margins 2CLIP_MULTIPLE #cat has 8pixels margin from the frame
    cat cat.std.FlipHorizontal()
    alpha alpha.std.FlipHorizontal()
    canvas cat.std.BlankClip(width=CLIP_MULTIPLE*cat.width-margins,
                               
    color = (255,255,255),
                               
    length=CLIP_MULTIPLE*cat.width-margins-START_POS)
    #making sure, length is longer that canvas length (length in these scripts is number of frames, not clip width)
    cat cat*3
    alpha 
    alpha*3
    banner 
    canvas.std.FrameEval(lambda nhavsfunc.Overlay(canvascatx=max(-cat.width+1n+START_POS), y=0mask=alpha))
    banner.set_output() 
    It is a Vapoursynth script. Not Avisynth. You might download Hybrid and use that script to encode your banner.
    Alpha might be treated differently in ffms2 source plugin, in latest versions and latest vapoursynth versions, putting alpha into properties instead as a clip. If you'd have problem I'd fix that for latest version.
    Last edited by _Al_; 26th Nov 2022 at 21:46.
    Quote Quote  
  10. Image
    [Attachment 67869 - Click to enlarge]

    choosing CLIP_MULTIPLE integer (in this example it is 10) for approximate clip width where script rounds it up to strictly mod 64, multiples of 64,
    and again cat always appears on the left from off screen and just disappears on the right:
    PHP Code:
    #python3
    import vapoursynth as vs
    from vapoursynth import core
    import havsfunc
    import functools
    cat
    alpha core.ffms2.Source(r"C:\... path ...\black-cat-walks-64.png"alpha=True)
    CLIP_MULTIPLE 10              #sets aproximate banner length
    START_POS = -cat.width          #to start to walk just from off screen

    margins 2CLIP_MULTIPLE  #cat has 8pixels margin from the frame
    width CLIP_MULTIPLE*cat.width-margins
    width 
    width + (64-width%64)   #width is mod 64, rounded up
    canvas cat.std.BlankClip(width=widthcolor=(255,255,255), length=width-START_POS)
    #making sure, number of frames for cat is more than canvas
    mul = (canvas.num_frames//cat.num_frames) + 1
    cat   cat.std.FlipHorizontal() * mul
    alpha 
    alpha.std.FlipHorizontal() * mul
    banner 
    canvas.std.FrameEval(lambda nhavsfunc.Overlay(canvascatx=max(-cat.width+1n+START_POS), y=0mask=alpha))
    banner.set_output() 
    Last edited by _Al_; 27th Nov 2022 at 01:04.
    Quote Quote  
  11. yes, thanks, that's what I'm trying to achieve. a cat walking in a forum signature.
    A transparent APNG walking cat as a layer on a transparent background. (if not possible to get transparent background, white is ok too.)
    The background must be 64px height and variable length.

    the 2 previous examples are perfect except for the background color, can be set as transparent?
    and by the way, all those Vapoursynth scripts, can be please converted/translated in a way that they works with Avisynth?
    Last edited by maudit; 27th Nov 2022 at 06:34.
    Quote Quote  
  12. Here is a rough template script modified from jagabo and _Al_ . It can probably be cleaned up a bit

    The variables are up top, you can adjust the width but you have to adjust the framecount for a given width to make the motion more correct (other wise there will be more or less foot sliding) . The trim_ends are to reduce the transparent frames at the start and end of the animation, you might have to adjust it a bit

    Code:
    bg_width = 480
    total_frames = 500
    trim_ends = 9
    
    lwlibavvideoSource("black-cat-walks-64.png")
    fliphorizontal()
    loop(10)
    a=last
    
    a = a.trim(0, total_frames-1)
    
    b=blankclip(a, width=bg_width, color=color_white)
    bb=blankclip(a, width=bg_width)
    
    xpos_final=bg_width
    xpos_start=0-a.width
    
    
    rgb=Animate(0,a.framecount,  "catwalk", b, a, xpos_start, b,a, xpos_final)
    alpha=Animate(0,a.framecount,  "catwalka", bb, a, xpos_start, b,a, xpos_final) #as RGB
    
    CombinePlanes(RGB.extractr,RGB.extractg,RGB.extractb, alpha.extractr, planes="RGBA",  source_planes="YYYY", sample_clip=b.converttoplanarrgba) 
    #showframenumber()
    trim(trim_ends-1, last.framecount-trim_ends-1)
    
    
    function catwalk(clip background, clip fg, int xpos)
    {
        xpos = xpos 
        Overlay(background, fg, xpos, mask=fg.ShowAlpha())
    }
    
    function catwalka(clip background, clip fg, int xpos)
    {
        xpos = xpos 
        Overlay(background, fg.showalpha, xpos)
    }
    If your web forum supports webp, I recommend webp for compression

    It's a cat race
    ffmpeg -i script.avs -plays 0 -c:v apng apng.png
    1.31MB


    ffmpeg -i script.avs -loop 0 -c:v libwebp_anim -lossless 1 webp.webp
    899KB



    Originally Posted by maudit View Post

    As I cannot find a simple way to do that, I thought I could maybe use some Avisynth commands in order to:
    Pretty easy to do in a video editor too. Avisynth would not be most people's first choice to animate images
    Quote Quote  
  13. Here's a simple method to generate the video with alpha channel:

    Code:
    function CatPan(clip cat, int width, int height, int xpos, int ypos)
    {
        AddBorders(cat, width, height, width, height)
        Crop(width-xpos, height-ypos, width, height)
    }
    
    cat = LWlibavVideoSource("black-cat-walks-64.png") # png with alpha channel, 88x64, 322 frames
    cat = cat.RGBADjust(r=0, g=0, b=0)
    cat = cat+cat+cat # make cat animation 3x longer to make sure there is enough to walk entirely across the frame
    cat = cat.FlipHorizontal()
    
    FRAMEWIDTH = 640 # desired frame width
    FRAMEHEIGHT = 64 # desired frame height
    
    Animate(0, FRAMEWIDTH+cat.width, "catpan", \
        cat, FRAMEWIDTH, FRAMEHEIGHT, -cat.width, 0,\
        cat, FRAMEWIDTH, FRAMEHEIGHT, FRAMEWIDTH, 0)
    Trim(0, FRAMEWIDTH+cat.width)
    FlipHorizontal()
    AssumeFPS(24) # set whatever frame rate you want
    
    #
    # the video is all black at this point, but has an alpha channel, ie a black cat will be overlaid where the alpha channel indicates
    #
    # to see the alpha channel as a white cat on a black background:
    # ShowAlpha()
    #
    # or overlay cat onto a background video (all green here):
    # background = BlankClip(width=FRAMEWIDTH, height=FRAMEHEIGHT, color=color_green, length=FRAMEWIDTH+cat.width)
    # Overlay(background, last, mask=ShowAlpha())
    #
    # or export an ARGB video or PNG sequence from an editor
    #
    Change FRAMEWIDTH and FRAMEHEIGHT to the size you want.

    Sample attached with cat overlaid onto a green background.
    Image Attached Files
    Last edited by jagabo; 27th Nov 2022 at 19:11.
    Quote Quote  
  14. thanks all of you guys, much appreciated.
    that's awesome.. I'm gonna try to use them..

    "cat race" lol..
    Quote Quote  

  15. How would I get alpha out of vapoursynth script to ffmpeg? Question perhaps for poisondeathray.
    I have script outputting both:
    Code:
    import vapoursynth as vs
    from vapoursynth import core
    import havsfunc
    
    cat, alpha = core.ffms2.Source(r"D:\downloads\black-cat-walks-64.png", alpha=True)
       
    CLIP_MULTIPLE = 10          #sets aproximate banner length
    START_POS = -cat.width+1    #to start to walk just from off screen
    
    margins = 8 * 2* CLIP_MULTIPLE  #cat has 8pixels margin from the frame
    width = CLIP_MULTIPLE*cat.width-margins
    width = width + (64-width%64)   #width is mod 64, rounded up
    canvas_cat = cat.std.BlankClip(width=width, color=(255,255,255), length=width-START_POS)
    canvas_alpha = canvas_cat.std.BlankClip(color=0, format=vs.GRAY8) #default is all transparent (black)
    #making sure, number of frames is more than canvas
    mul = (canvas_cat.num_frames//cat.num_frames) + 1
    cat   = cat  .std.FlipHorizontal() * mul
    alpha = alpha.std.FlipHorizontal() * mul
    def get_x(n):
        #overlay cannot be fully outside of canvas
        return min(max(-cat.width+1, n+START_POS),canvas_cat.width-1)
    walking_cat   = canvas_cat  .std.FrameEval(lambda n: havsfunc.Overlay(canvas_cat,   cat,   x=get_x(n), y=0, mask=alpha))
    walking_alpha = canvas_alpha.std.FrameEval(lambda n: havsfunc.Overlay(canvas_alpha, alpha, x=get_x(n), y=0, mask=alpha))
    walking_cat.set_output()
    walking_alpha.set_output(1)
    
    if __name__ == '__main__':
        import view
        view.Preview([walking_cat, walking_alpha])
    Last edited by _Al_; 28th Nov 2022 at 13:03.
    Quote Quote  
  16. Just to clarify latest alpha loading for Vapoursynth if anyone tests this, I have old setup for Vapoursynth but latest portable R60 and latest lsmash (HolyWu/Akarin dll) perhaps would load alpha like this:
    Code:
    cat = core.lsmas.LWLibavSource("black-cat-walks-64.png")
    if isinstance(cat, (tuple,list)):
        cat = cat[0]
        alpha= cat[1]
    elif '_Alpha' in cat.get_frame(0).props:
        alpha = cat.std.PropToClip(prop='_Alpha')
    Quote Quote  
  17. Yes, for VPY R57+ versions, you need to use PropToClip . I like the old way better .

    For RGBA and vspipe use rawvideo, and ffmpeg use -pix_fmt gbrap

    Code:
    .
    .
    
    alpha = core.std.PropToClip(clip)
    clip.set_output(alpha=alpha)
    vspipe to ffmpeg for 8bit RGB+A would look something like

    Code:
    vspipe script.vpy - | ffmpeg -f rawvideo -s <width>x<height> -pix_fmt gbrap -r <framerate> -i - ...
    Quote Quote  

  18. thanks!
    walking_cat.py with CLIP_MULTIPLE = 10:
    Code:
    import vapoursynth as vs
    from vapoursynth import core
    import havsfunc
    
    cat, alpha = core.ffms2.Source(r"black-cat-walks-64.png", alpha=True)
       
    CLIP_MULTIPLE = 10          #sets aproximate banner length
    START_POS = -cat.width+1    #to start to walk just from off screen
    
    margins = 8 * 2* CLIP_MULTIPLE  #cat has 8pixels margin from the frame
    width = CLIP_MULTIPLE*cat.width-margins
    width = width + (64-width%64)   #width is mod 64, rounded up
    canvas_cat = cat.std.BlankClip(width=width, color=(255,255,255), length=width-START_POS)
    canvas_alpha = canvas_cat.std.BlankClip(color=0, format=vs.GRAY8) #default is all not transparent (black)
    #making sure, number of frames is more than canvas
    mul = (canvas_cat.num_frames//cat.num_frames) + 1
    cat   = cat  .std.FlipHorizontal() * mul
    alpha = alpha.std.FlipHorizontal() * mul
    def get_x(n):
        #overlay cannot be fully outside of canvas
        return min(max(-cat.width+1, n+START_POS),canvas_cat.width-1)
    walking_cat   = canvas_cat  .std.FrameEval(lambda n: havsfunc.Overlay(canvas_cat,   cat,   x=get_x(n), y=0, mask=alpha))
    walking_alpha = canvas_alpha.std.FrameEval(lambda n: havsfunc.Overlay(canvas_alpha, alpha, x=get_x(n), y=0, mask=alpha))
    walking_cat.set_output(alpha=walking_alpha)
    encode.py, that is run and using walking_cat.py:
    Code:
    import vapoursynth as vs
    from vapoursynth import core
    from subprocess import Popen, PIPE
    
    VSPipe = r'C:\... some path ..\vspipe.exe'
    ffmpeg = r'D:\... some path ..\ffmpeg.exe'
    output = r'D:\... some path ..\walking_cat.webp'
    script_path = r'D:\... same path as encode.py ..\walking_cat.py'
    output_index = 0
    
    vs.clear_outputs
    import walking_cat
    #Getting clip just for properties,  this is for old API3, not 4.
    clip, alpha = vs.get_output(output_index) #output is a tuple in our case 
    
    #encoding script output
    vspipe_cmd = [VSPipe, '--outputindex', f'{output_index}', script_path, '-']
    
    ffmpeg_cmd = [ffmpeg,   '-f',              'rawvideo',
                            '-s',             f'{clip.width}x{clip.height}',
                            '-pix_fmt',        'gbrap',
                            '-r',             f'{clip.fps.numerator/clip.fps.denominator}',
                            '-i',              '-',
                  
                            '-loop',           '0',
                            '-c:v',            'libwebp_anim',
                            '-lossless',       '1',              
                            output
                 ]
    print(vspipe_cmd)
    print(ffmpeg_cmd)
    print('encoding ...')
    p1 = Popen(vspipe_cmd, stdout=PIPE, stderr=PIPE)
    p2 = Popen(ffmpeg_cmd, stdin=p1.stdout, stdout=PIPE, stderr=PIPE)
    p1.stdout.close()
    p2.communicate()
    print('done')
    Last edited by _Al_; 28th Nov 2022 at 21:13.
    Quote Quote  
  19. Where is marcoroccini ?
    Quote Quote  
  20. Originally Posted by _Al_ View Post
    Where is marcoroccini ?
    got chased away? woof!

    Quote Quote  
  21. , someone just have to post this in any of his new threads ...
    Quote Quote  
  22. But, he might show up with this cat!

    Code:
    import vapoursynth as vs
    from vapoursynth import core
    import havsfunc
    
    CANVAS_WIDTH = 768
    SPEED = 13 #speed over canvas, 1 is normal, but movement would be slow
    
    #gif has no alpha, just white background, so alpha is made
    cat = core.ffms2.Source(r"running_lion.gif")
    cat = cat.std.CropAbs(width=956, height=574, left=63, top=89)
    cat = cat.resize.Bicubic(width=int(cat.width*128/cat.height), height=128)
    alpha = cat.std.ShufflePlanes(planes=[0], colorfamily=vs.GRAY)
    alpha = alpha.std.Invert().std.Levels(max_in=235, max_out=255)
    START_POS = -cat.width+1    #to start to walk just from off screen
    canvas_cat = cat.std.BlankClip(width=CANVAS_WIDTH, color=(255,255,255), length=CANVAS_WIDTH-START_POS)
    canvas_alpha = canvas_cat.std.BlankClip(color=0, format=vs.GRAY8) #default is all not transparent (black)
    mul = (canvas_cat.num_frames//cat.num_frames) + 1
    
    def one_run(cat, alpha):
        #making sure, number of frames is more than canvas
        cat   = cat * mul
        alpha = alpha * mul
        def get_x(n):
            #overlay cannot be fully outside of canvas
            return min(max(-cat.width+1, n+START_POS),canvas_cat.width-1)
        walking_cat   = canvas_cat  .std.FrameEval(lambda n: havsfunc.Overlay(canvas_cat,   cat,   x=get_x(n*SPEED), y=0, mask=alpha))
        walking_alpha = canvas_alpha.std.FrameEval(lambda n: havsfunc.Overlay(canvas_alpha, alpha, x=get_x(n*SPEED), y=0, mask=alpha))
        end_trim = int(walking_cat.num_frames/SPEED)
        return walking_cat[0:end_trim], walking_alpha[0:end_trim]
    
    cat1, alpha1 = one_run(cat, alpha)
    cat   = cat.std.FlipHorizontal()
    alpha = alpha.std.FlipHorizontal()
    cat2, alpha2 = one_run(cat, alpha)
    cat = cat1.std.Reverse()+cat2
    alpha = alpha1.std.Reverse()+alpha2
    cat.set_output(alpha=alpha)
    gif image had no alpha so alpha is constructed,
    image downloaded from: xxxxx://static.wixstatic.com/media/df67ef_1bf2d545aa57420398b9471c02fee3e8.gif
    xxxxx=https
    Last edited by _Al_; 29th Nov 2022 at 16:49.
    Quote Quote  



Similar Threads

Visit our sponsor! Try DVDFab and backup Blu-rays!