giftbox2

Back to All Results

Motion Vectorization

Input video: giftbox2

Output SVG motion program code

Output SVG motion program

Motion Program Transformation

Spatial Motion Adjustment

Motion textures

Input SVG motion program

MPTransformer(P, args):
  // Change background image.
  setBgImg(P, args.background)

  // OBJECT SELECTOR: Query for black region.
  selObjs = objSelector(P, propQuery, "color", "red", [0, P.endFrm])
  changeAppearanceObjTransformer(selObjs, args.name)

  // OBJECT SELECTOR: Query for moving shape objects.
  function is_moving(vals, t):
      if np.abs(vals[t] - vals[t - 1]) > 1:
          return True
      return False
  selObjs = objSelector(P, propQuery, "positionY", is_moving, [0, P.endFrm])
  
  newObjs = []
  for obj in selObjs:
      newObjs.append(obj)
      for i in range(2):
          objCopy = copy(obj)
          newObjs.append(objCopy)

  // The random_choice(arr, size) function selects a random subset of size with replacement 
  // from a list of choices.
  balloons = random_choice(args.balloonImgs, len(newObjs))
  changeAppearanceObjTransformer(newObjs, balloons)    

  // OBJECT TRANSFORMER: Make movements of each bubble random.
  for obj in newObjs:
      // Rotate randomly.
      function rotateFn(theta, [t]):
          return 10 * randFloat()
      adjGlobalMotion(obj, rotateFn, [obj.startFrm, obj.endFrm])

      // Vary the scale.
      function scaleFn(t, [x]):
          s = 0.3 * random.random() + 0.2
          return x[t] * s
      adjGlobalMotion(obj, scaleFn, [obj.startFrm, obj.endFrm])

      // Apply motion adjustment to vary the starting position of each bubble.
      function shiftXFn(t, [x]):
          return (2 * random.random() - 0.5) * 10
      adjLocalMotion(obj, shiftXFn, [obj.startFrm, obj.endFrm])

      function shiftYFn(t, [y]):
          return (2 * random.random() - 0.5) * -20
      adjLocalMotion(obj, shiftYFn, [obj.startFrm, obj.endFrm])

      // Apply motion adjustment to vary bubble paths.
      function translateXFn(t, [x, amp]):
          s = 2 * amp * (random.random() - 0.5)
          return [s * (t / len(time))**4 for t in time]
      adjLocalMotion(obj, translateXFn, [obj.startFrm, obj.endFrm], amp=200)

  // OBJECT TRANSFORMER: Retime the entire timeline randomly so the 
  // bubbles move at different speeds.
  linearRetimeObjTransformer(newObjs, randFloat(0.5, 1), [frmA, frmB])

  // OBJECT TRANSFORMER: Release bubbles at different times.
  for each obj in newObjs:
      duration = randomInt(24, 96)
      freezeFrame(obj, 0, duration)
  

Motion program transformer code. We repurpose the input SVG for a birthday card. The shapes in the box are duplicated and changed into different colored balloons. Local and global motion adjustments are made to each balloon so that they all float away in different directions.

Output SVG motion program

Input SVG motion program

MPTransformer(P, args):
  // Change background image.
  setBgImg(P, args.background)

  // OBJECT SELECTOR: Query for black region.
  selObjs = objSelector(P, propQuery, "color", "red", [0, P.endFrm])
  changeAppearanceObjTransformer(selObjs, args.name)

  // OBJECT SELECTOR: Query for moving shape objects.
  function is_moving(vals, t):
      if np.abs(vals[t] - vals[t - 1]) > 1:
          return True
      return False
  selObjs = objSelector(P, propQuery, "positionY", is_moving, [0, P.endFrm])
  
  newObjs = []
  for obj in selObjs:
      newObjs.append(obj)
      for i in range(2):
          objCopy = copy(obj)
          newObjs.append(objCopy)

  // The random_choice(arr, size) function selects a random subset of size with replacement 
  // from a list of choices.
  balloons = random_choice(args.balloonImgs, len(newObjs))
  changeAppearanceObjTransformer(newObjs, balloons)    

  // OBJECT TRANSFORMER: Make movements of each bubble random.
  for obj in newObjs:
      // Rotate randomly.
      function rotateFn(theta, [t]):
          return 10 * randFloat()
      adjGlobalMotion(obj, rotateFn, [obj.startFrm, obj.endFrm])

      // Vary the scale.
      function scaleFn(t, [x]):
          s = 0.3 * random.random() + 0.2
          return x[t] * s
      adjGlobalMotion(obj, scaleFn, [obj.startFrm, obj.endFrm])

      // Apply motion adjustment to vary the starting position of each bubble.
      function shiftXFn(t, [x]):
          return (2 * random.random() - 0.5) * 10
      adjLocalMotion(obj, shiftXFn, [obj.startFrm, obj.endFrm])

      function shiftYFn(t, [y]):
          return (2 * random.random() - 0.5) * -20
      adjLocalMotion(obj, shiftYFn, [obj.startFrm, obj.endFrm])

      // Apply motion adjustment to vary bubble paths.
      function translateXFn(t, [x, amp]):
          s = 2 * amp * (random.random() - 0.5)
          return [s * (t / len(time))**4 for t in time]
      adjLocalMotion(obj, translateXFn, [obj.startFrm, obj.endFrm], amp=200)

  // OBJECT TRANSFORMER: Retime the entire timeline randomly so the 
  // bubbles move at different speeds.
  linearRetimeObjTransformer(newObjs, randFloat(0.5, 1), [frmA, frmB])

  // OBJECT TRANSFORMER: Release bubbles at different times.
  for each obj in newObjs:
      duration = randomInt(24, 96)
      freezeFrame(obj, 0, duration)

Motion program transformer code. We can reuse the same program transformation above to generate a birthday card for a different person. Notice how the balloons have changed as well.

Output SVG motion program