Odd Couple
Tutorials – Kdenlive and ImageMagick
By using two very different tools, Kdenlive and ImageMagick, you can make animation less tedious and create some pretty cool video effects and transitions.
Below is the Custom Transitions video associated with this article.
Back in Linux Magazine issue 209 [1], I used FFmpeg and animation to create a transition from one video clip to another. In that instance, I used a Pacman animation with a transparent area and a blue, chroma area to make Pacman gobble up the first clip and lead in to the second.
Although that was fun, it required some serious and not too intuitive FFmpeg-fu to pull off. Also, placing the transition exactly where I needed it proved tricky, and it wasn't possible to know if I had done it right until I had rendered the final film.
That is why the Free Software gods have purveyed us with things like graphical video editors. Kdenlive [2] is currently my favorite, and, although I did say back in issue 209 that you couldn't use the chroma technique in Kdenlive in one go (you had to use one project to merge the first clip with the animation, render, then start a new project, and merge the rendered clip with the second clip), you can create the custom transition effect in one go using a different technique: masks.
Kdenlive Masks
Masks in Kdenlive are just images that contain transparent and non-transparent pixels that you can combine in different ways with your clips. Fire up your favorite image editor, draw a heart shape on a transparent background, save it as a PNG, and you have a heart mask (Figure 1). That's it.
The trick is in how you apply it in Kdenlive.
Open Kdenlive and load into the project bin (first pane on the left) the two clips you want to merge, as well as the image that will serve as a mask. By default, Kdenlive gives you three video tracks to work with. You can add more, but three is perfect for your purposes. Put your image in the topmost track, the clip you want to use as a mask on the track under that, and the clip you want to show through the hole made by your mask on the bottom-most track.
To turn your image into a mask, right-click on it on the track and choose Add transition | Composite and transform. Pull the ends of the yellow transition bar so that it covers the whole length of your static image clip. With the transition still selected, click on the Properties tab in the Effects and transitions panel (second from left, next to the project bin). You will see the properties of your transition (Figure 2).
One of the last options in the properties panel is the Compositing drop-down. This tells Kdenlive how you want to combine your image with the clip under it. What you want is the Xor option. The XOR operation in this context is very simple: If a pixel in the top layer (the static image that contains opaque and transparent pixels) is colored in (i.e., is opaque), it is considered a 1. The same applies to the pixels on the layer below containing the first clip. Most video clips don't have transparent pixels. If this is the case, all the pixels in all frames will be 1s. As you know from your lessons in binary logic [3], a 1 XORed with another 1 gives 0. In this transition, this means that, when an opaque pixel in the mask is overlaid onto another opaque pixel in the clip on the second track, both are rendered transparent, and the clip on the third layer will show through.
Animating
That was simple enough, but no transitioning is happening. You can make things more dynamic, because masks have keyframeable features (see the "Keyframes" box) that lets you animate them to some degree and turn your mask into a proper transition. For example, to make the second clip gradually appear in your mask and then the mask itself grow until it blots out the first clip, you can do as follows:
Keyframes
You use keyframes in video editing and animation to indicate when something changes and to have your application calculate the intermediate states between the changes. Say, for example, you want a mask to go from completely invisible to completely visible. You place a keyframe on the timeline where you want the mask to be transparent and set the masks opacity to zero percent. Then you place another keyframe further down the timeline, select it, and make the mask's opacity 100 percent. Kdenlive will calculate all of the intermediate levels of opacity so that the mask will gradually fade in between the two keyframes.
1. Click on your Composite and transform transition in the timeline and make your transition about one second long.
2. Look at the properties panel above the tracks (Figure 3), and you will notice the transition has its own timeline. Make sure there's a keyframe at the beginning of the transition – a keyframe looks like a little arrow pointing upward. A keyframe at the beginning is the default, but check just in case. Click on that keyframe (it should turn red, and all the options should become available) and set the Opacity bar to zero percent. This will make your mask completely invisible.
3. Move the transition's timeline cursor (the little triangle under the timeline) about 10 centiseconds in and double-click on the cursor. This will create a new keyframe at the 10-centisecond position. Now make your mask 100 percent opaque. This will make your mask fade in.
If you have trouble placing the new keyframe, that may be because the cursor is not squarely on a frame. Move the cursor a little to the left or a little to the right until you find a spot that will accept a keyframe.
Kdenlive will insert all the intermediate steps, between your two keyframes, making your mask go gradually from completely transparent and invisible, to completely opaque, showing the second clip on the bottom track.
Next, you want to make the mask grow until it completely covers the first clip and, thus, completes the transition to the second clip.
4. Place a third keyframe about five centiseconds from the end, make sure your timeline cursor is on the keyframe (the head of the arrow will be red instead of white), and change the mask's size to cover the whole frame. To do this, you can use the dimension boxes under the timeline. Changing the values in the boxes labeled X (for the width of the mask) and Y (for its height) will change your mask's size.
As the resizing happens from the upper left corner downward and to the right, your mask will probably be displaced as it grows. It might even be pushed completely outside the frame. To get it back to the center, go to the preview panel (the panel showing a preview of your project on the right), select the Project Monitor tab (Figure 4), click on the hamburger menu icon (the icon with three vertical bars to the right of the time counter), and mark the Zoom checkbox.
A new toolbar will appear in the upper left-hand corner of the preview panel (in Kdenlive's development version, this bar appears when you mouse over the upper right-hand corner of the preview panel). Use the slide at the bottom of the bar to zoom out from the visible frame. At some point, you will see a red rectangle with a red square in its center. This is the frame of your mask. The visible frame also has a square in its center, and both squares are joined by a line.
Place your cursor over the square in the center of your mask frame, click, hold, and drag the square over the visible frame's square. This will recenter your mask in the visible frame.
Also notice that you have four handles (again in the shape of red squares) in each corner of you mask's frame. You can drag on these to change the size of your mask visually.
5. For good measure, add a Dissolve transition between the first and second clip (on the middle and bottom tracks), starting at the same position as the third keyframe you placed in the Composite and transform keyframe and ending at the same ending point of the Composite and transform transition. This will ensure any leftover bits from the first clip will have disappeared completely and gracefully by the end of your custom transition. Figure 5 shows how this will look on the project timeline.
Cartoons
Again, this is quite straightforward. After all, you are using Kdenlive's built-in tools as they were intended. I'll mix things up a bit, because things get a little more complex when you want to make a transition with an animated mask.
The complexity comes not so much from the theory, since the principles are the same. The problem is more logistic, because now you need not just one image, but a whole sequence of PNG images. If your transition is two seconds long, that is 50 images at least. You could work on each frame by hand, one by one, but I didn't do that for the animated Pacman I used in issue 209, and I have no regrets. Instead I used ImageMagick [4].
For starters I didn't even draw the Pacman in Inkscape or anything like that. Instead, I used ImageMagick's -draw
feature.
To generate each frame of the animated Pacman, you can use the commands shown in Listing 1. Line 1 draws Pacman with its mouth open. Here is a breakdown of how that line works:
Listing 1
Animating Pacman
01 convert -size 534x534 xc:none +antialias -fill none -stroke yellow -draw 'arc 0,0 534,534 225,135' -draw 'line 78,78 267,267' -draw 'line 78,456 267,267' -floodfill +269+269 yellow cc01.png 02 convert -size 534x534 xc:none +antialias -fill none -stroke yellow -draw 'arc 0,0 534,534 202,158' -draw 'line 20,164 267,267' -draw 'line 20,369 267,267' -floodfill +269+269 yellow cc02.png 03 convert -size 534x534 xc:none +antialias -fill yellow -stroke yellow -draw 'circle 267,267 0,267' cc03.png
convert
is ImageMagick's jack-of-all-trades command with which you can do most operations.-size 534x534 xc:none
makes an image that is 534 pixels wide by 534 pixels high and sets the background tonone
, which, in a PNG image, means transparent.+antialias -fill none -stroke yellow
switches anti-aliasing off (you want a 1980s pixelated vibe), sets the fill to transparent (otherwise everything you draw will be filled with the default color, black), and sets the stroke (i.e., the picture's outline) to yellow.-draw 'arc 0,0 534,534 225,135'
draws Pacman's "body." Thearc
option draws, as its name implies, arcs of ellipses. To figure out your ellipse's shape, you have to imagine it enclosed in a rectangle (or square, if you want to draw a circular arc). The first set of coordinates (0,0
) gives ImageMagick the upper left-hand corner of the rectangle surrounding the ellipse. In this case, it coincides with the upper left-hand corner of the image itself. The next set of coordinates gives ImageMagick the position of the lower right-hand corner of the rectangle. Again it coincides with the lower right-hand corner of the image. As the width and height are the same, this will be a circular arc. The last set of figures,225,135
, draws the arc itself from 225 degrees to 135 degrees. Note that, in ImageMagick, zero degrees is on the left, 90 degrees is pointing down, 180 degrees is on the right, and 270 degrees is pointing up.-draw 'line 78,78 267,267' -draw 'line 78,456 267,267'
draws the straight lines that make up Pacman's "jaws." You can figure out where to start each line with a bit of trigonometry. The endpoint in both cases is, of course, the center of Pacman's circular body.-floodfill +269+269 yellow
picks a spot within Pacman's body (two pixels off from his center) and floods the whole shape with yellow.- Finally, the resulting image is poured into
cc01.png
.
Line 2 does something similar, but draws Pacman with his mouth half closed and puts the resulting image into cc02.png
. Finally, line 3 draws a yellow circle, which is, of course, Pacman with his mouth completely closed (Figure 6)..
Now that you have the different frames for the animation, you can create the frames for the transition. As mentioned above, if you want to make your transition last two seconds, you have to draw 50 images, putting the first frame of your animation (cco1.png
) on the right of the frame and then, with each successive frame, move Pacman toward the left, as you cycle through each frame of the animation.
Instead of doing this by hand, you can write a Bash script (Listing 2) that uses ImageMagick instructions embedded in loops to do the repetitive work for you.
Listing 2
customtransition.sh
01 #!/bin/bash 02 03 mkdir -p transition/frames 04 mkdir transition/animation 05 06 f_w=`expr match "$2" '\(.[0-9]*\)'` 07 f_h=`expr match "$2" '.*x\(.[0-9]*\)'` 08 09 for i in $1*.png 10 do 11 convert $i -resize x$f_h transition/animation/${i##*/} 12 done 13 14 anim_frames=`ls $1|wc -l` 15 16 cc=(transition/animation/*.png) 17 color=$3 18 fs=$4 19 20 i_w=0 21 for i in $1/*.png 22 do 23 cfs=`convert $i -format "%w" info:` 24 25 if [ $cfs -gt $i_w ] 26 then 27 i_w=$cfs 28 fi 29 done 30 31 i_s=$[(($f_w+$i_w)/$fs)+1] 32 f_l_e=$[($i_s*$fs)-$f_w] 33 p_p=$[$i_s*$fs] 34 pf_w=$[($i_s*$fs)+$i_w+1] 35 36 f_c=0 37 for i in $(seq -f "%03g" 0 $fs) 38 do 39 np=$[$p_p-(10#$i*$i_s)] 40 41 convert -size ${pf_w}x${f_h} xc:none ${cc[$f_c]} -geometry +${np}+0 +antialias -composite transition/frames/frameNF.png 42 convert transition/frames/frameNF.png -floodfill +$[$pf_w-1]+1 $color transition/frames/frameUC.png 43 convert transition/frames/frameNF.png -crop ${f_w}x${f_h}+$f_l_e+0 transition/frames/frame$i.png 44 convert transition/frames/frameUC.png -crop ${f_w}x${f_h}+$f_l_e+0 transition/frames/chroma$i.png 45 46 let f_c++ 47 if [ $f_c -gt $((anim_frames-1)) ] 48 then 49 f_c=0 50 fi 51 done 52 53 rm transition/frames/frameNF.png 54 rm transition/frames/frameUC.png
The script takes four parameters:
1. The path to the directory containing the animation frames (e.g., animation/
)
2. The width and height you want for the resulting transition frames (e.g., 1280x720
)
3. Color for the chroma (e.g, "#0f0"
)
4. Number of frames you want for the transition (e.g., 50
)
An example command line would look like this:
customtransition.sh animation/ 1280x720 "#0f0" 50
From lines 3 to 34, you set up directories that the animation is going to land in and the variables you will later need to create the transition's frames. It is all about calculating the ideal sizes for the animation frames, the transition frames, and the initial positions of all the moving parts. The loop that runs from lines 9 to 12, for example, resizes the frames of your animation to make sure they are exactly the height of the transition clip.
The loop that runs from lines 21 to 29 finds the width of the widest animation frame. You do this because, before creating the final transition frames, you have to fit your animation image mostly outside the frame on the right in the first few transition frames and mostly outside the frame on the left in last few. You have to prepare for that, so the proto-frames are as wide as you tell them to be, but also with double the width of the widest animation frame added to the width. Don't worry: They are cropped later (see lines 43 and 44).
The real work happens in the loop from lines 37 to 51. Here, you insert the animation frame in its correct position for each transition frame (line 41) and create a chroma frame (in case you need it) by filling the empty area to the right of the animation frame with the chroma color (line 42). Then you crop both transitory frames and give them their final place in the sequence (lines 43 and 44).
Lines 46 to 50 cycle through the animation frames.
Although the example of a static image (as shown in Figure 1) used a black mask, the mask doesn't have to be black. Remember that the only condition to successfully XOR the mask with the underlying clip is that the mask contain transparent and opaque pixels. The color of the opaque pixels is irrelevant. That means the chroma frames of the transition will work perfectly well as masks.
Once you run the script, you will end up with a folder (called transition
) that contains two subfolders, animation/
and frames/
. The animation/
subfolder contains your resized animation frames, but the frames/
subfolder contains all the frames you need to create your transition in Kdenlive.
To apply your customized transition, open the two clips that you want to use the transition on in your Kdenlive project; then, load the frame and chroma sequence of images that the customtransition.sh
script built. To do that, click on the Add clip button in the project bin, navigate to the transition/frames/
folder created by customtransition.sh
, select the Import image sequence checkbox at the bottom of the file explorer window, and choose the first file in the frame sequence (frame001.png
). Then open the chroma sequence by doing the same, except now pick chroma001.png
.
Both sequences will load into Kdenlive and you will be able to work with them as if they were clips.
To set up your transition in Kdenlive, you'll need four video tracks: In the topmost track, you put the animation sequence (frame). On the second track, put the mask/chroma sequence (chroma) and align it with the animation on the top track. On the third track, put the first clip you want to transition from and align the end of that clip with the end of the animation sequence. Finally, on the bottom track, add the second clip you want to transition to, and make the beginning of that clip coincide with the beginning of the animation and chroma/mask sequences.
Add a Composite and transform to the chroma/mask sequence so that it affects the first clip, and change the Compositing method to Xor as shown in Figure 8.
Rendering your project will give you Pacman chomping up one scene and leading into the next.
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Wine 10 Includes Plenty to Excite Users
With its latest release, Wine has the usual crop of bug fixes and improvements, along with some exciting new features.
-
Linux Kernel 6.13 Offers Improvements for AMD/Apple Users
The latest Linux kernel is now available, and it includes plenty of improvements, especially for those who use AMD or Apple-based systems.
-
Gnome 48 Debuts New Audio Player
To date, the audio player found within the Gnome desktop has been meh at best, but with the upcoming release that all changes.
-
Plasma 6.3 Ready for Public Beta Testing
Plasma 6.3 will ship with KDE Gear 24.12.1 and KDE Frameworks 6.10, along with some new and exciting features.
-
Budgie 10.10 Scheduled for Q1 2025 with a Surprising Desktop Update
If Budgie is your desktop environment of choice, 2025 is going to be a great year for you.
-
Firefox 134 Offers Improvements for Linux Version
Fans of Linux and Firefox rejoice, as there's a new version available that includes some handy updates.
-
Serpent OS Arrives with a New Alpha Release
After months of silence, Ikey Doherty has released a new alpha for his Serpent OS.
-
HashiCorp Cofounder Unveils Ghostty, a Linux Terminal App
Ghostty is a new Linux terminal app that's fast, feature-rich, and offers a platform-native GUI while remaining cross-platform.
-
Fedora Asahi Remix 41 Available for Apple Silicon
If you have an Apple Silicon Mac and you're hoping to install Fedora, you're in luck because the latest release supports the M1 and M2 chips.
-
Systemd Fixes Bug While Facing New Challenger in GNU Shepherd
The systemd developers have fixed a really nasty bug amid the release of the new GNU Shepherd init system.