Skip to content

ImageMagick, four point perspective distortion in a video

Step 1) Download the video from Youtube using JDownloader. The best one was the original Japanese upload, The Game Awards 2014 出展映像 ゼルダの伝説 最新作, which is 720p. I saved this file as zelda_720p.mp4.

Step 2) Transform the video in a series of PNGs.

[bash]mplayer -nosound -vo png:z=9 zelda_720p.mp4[/bash]

This generated image files ranging from 00000001.png to 00007563.png.

Step 3)
Using Gimp, find the 2 sets of 4 points for the perspective. The first in red is the source and the one in blue is the destination.

zelda video four point perspective

Step 4) Apply ImageMagick’s four point perspective distortion in each image using a ShellScript.

for image in *.png;
convert $image -matte -virtual-pixel transparent \
-distort Perspective \
‘60,90 0,0 50,415 0,720 582,418 1280,720 589,147 1280,0’ \

Now I have images in the format p_00000001.png to p_00007563.png. Because PNG is a lossless format, the perspective lost less information in this step than it would if step 2 was outputting jpgs.

Step 5) Convert frames to jpgs using ImageMagick and ShellScript.

for image in p_*.png;
convert $image "${image/.png/}.jpg"

Where “${image/.png/}.jpg” removes the .png in the image string.

Ps: this step is not really necessary as you could use png as input to ffmpeg.

Step 6) Convert jpgs in a video.

ffmpeg -start_number 0 -i ‘%08d.jpg’ -c:v libx264 output.mp4

‘%08d.jpg’ means a 8 digits filled with zeros in the left followed by .jpg, in this case 00000001.jpg to 00007563.jpg.

With this, I have the output.mp4 video ready to upload.

The whole process took several hours and a total 13GiB, although the final video has only 96 MiB. This could be optimized using pipelines and parallelism if it was needed to repeat the process.

HackerNews discussion:

Published inenglish


  1. Thanks for this. It’s great to see that you can even edit videos from the command line.

    If you are indeed interested in parallelizing this, then I can recommend GNU Parallel. Step 5, for example, could then be rewritten as follows:

    $ ls p_*.png | parallel "convert {} {.}.jpg"

    It has many option, but the most interesting ones in this case are –jobs and –progress.



  2. Woah, amazing work cropping inside a video. Best of all, I think you could recreate all of that in javascript with canvas ( ofc, after you manually set the video file ).

    Either directly edit the video live, but I’m not sure how well will that work (usually freezes the browser ) or slow version with js workers ( but takes some time ).
    Or 2nd version to crop each frame from video with canvas and to animate it:
    either display each image with 1000 ms timeouts for each or convert somehow to gif (i’m not sure about this).

  3. Rich Rich

    Why convert to JPEG before encoding the video? That’s decreasing your quality since it’s going through a second encoding process with x264.

  4. In step 5 you could convert all fo the files to jpg by doing mogrify -format jpg *.png.

    Does your method have any benefits? Faster speed?

  5. Thank you 5 years later ha ha 🙂 . I am doing a stop motion animation of a rock band made of toothpicks and wire named Wood Zeppelin. I am working on their first music video, and this code will help me with the toothpick backgrounds i have made from toothpicks. I am on Facebook and my website is below. Good work! Keep it coming!

Leave a Reply

Your email address will not be published. Required fields are marked *