Perspective + montage with overlap of multiple images at the command-line - imagemagick

I have a collection (of variable size) of rectangular images (frames extracted from a source video file with ffmpeg), and am trying to find a way to automatically generate a "filmstrip" at the command line, ideally one in which each image is rotated to give it a perspective, and then partly overlayed with the previous one.
The output would be something like this (with transparent background)
(Note: Numbers in the corner would be a plus...)
I imagine ImageMagick has the tools for this, but so far I've not found any obvious way of achieving this...
Any pointer?

Here's something that worked quite nicely for me:
-virtual-pixel transparent +distort Perspective '0,0 0,0 0,110 0,110 200,0 100,20 200,110 100,80' \
-gravity South -background transparent -splice 0x15 \
-font Arial -pointsize 12 -gravity southwest -annotate +2+0 "%[p]" \
miff:- | \
montage -geometry 100x\>-20+2 -tile x1 -background none - montage_test.png```
![montage](https://i.stack.imgur.com/ezplh.png)

Related

Practical Imagemagick stack (combined) complex commands

I want a combined command that can perform the following task in single execution. I searched the internet, but hardly found any tutorial that guide us to write any stack command. I can found single command for each operation, such as -composite, -blur, etc, and I know I can pipe the command as such
convert ... mpr:- | convert ... mpr:- | ... | convert ... png:-
However, I want a combined command that use \( ... \) and mpr:{label} since this will increase the performance as all operations are executed in single process (pipeline in shell can degrade the performance, and the process sequence is required to be in order).
The process sequence as such:
put flower.png on top of the frame.png -> mpr:framedFlower
put mpr:framedFlower on top of the background.png -> mpr:out2
blur the heart.png, right-gradient-transparent the smiley.png and put both image on top of mpr:out2 -> mpr:out3
annotate the mpr:out3 with "Hello world" (placement=bottom) -> png:-
I don't include the commands that I have tried because they are too messy and it will be an insult to those users who read it. I tried for many hours, but can't get it done. Please advise.
I haven't spent ages futzing with the exact coordinates as I am only using sample pictures, but this one-liner contains every technique you need to do what you are asking.
There is basically one line of code per element in the final image:
convert frame.png -resize 500x400\! \( flower.png -resize 400x300\! \) -gravity center -composite \
background.png +swap -gravity northwest -geometry +100+150 -composite \
\( heart.png -resize 200x200 -blur 0x8 \) -geometry +1200+250 -composite \
-gravity south -pointsize 72 -fill red -annotate +0+60 'Hello world' \
\( emoji.png -resize 250x250 -channel a -fx "u.a*(1-(i/w))" \) -gravity northwest -geometry +1200+500 -composite result.png
The first line reads in the picture frame and the flower and resizes them each independently because of the parentheses and then composites the flower into the frame.
The next line loads the background and then uses +swap to put it behind the framed picture from the previous line. It then sets -gravity to northwest as the origin for the ensuing -geometry before compositing the framed picture onto the background.
The next line loads the heart and resizes and blurs just the heart before compositing that onto the main picture at your specified position.
Next up is the annotation - the only interesting thing is that I set the -geometry to south which means that the offsets to -annotate are relative to the bottom centre of the background.
Finally, I load the emoji-thing and resize just it in parentheses before compositing over the main image. The only interesting thing is that I use -fx to alter the alpha channel (-channel a) and I multiply the existing transparency (u.a) by the fraction of the inverse of the distance we are across the image, namely (1-(i/w)).
Hope that is fairly clear!
Start Images

Start path relative to corner of image

I have written the following script which uses the ImageMagick* convert utility to append axis labels to an existing image.
LEFT_="l -30,0 +2,+2 -6,-2 +6,-2 -2,+2 z"
RIGHT_="l 30,0 -2,+2 +6,-2 -6,-2 +2,+2 z"
convert -size 240x160 pattern:SMALLFISHSCALES \
-pointsize 16 -fill black -background white \
-gravity SouthEast -splice 0x20 \
-draw "translate 40,0 text 0,0 'Time' stroke red path 'm 5,2 $RIGHT_'" \
-gravity NorthWest -splice 20x0 \
-draw "rotate +90 translate 40,-10 text 0,0 'Value' path 'm -5,2 $LEFT_'" \
example.png
Which produces the following image:
This is almost exactly what I am after, except that the red arrow is out of place. I expected the red arrow to appear next to the Time label, since its start point is specified as a relative position in the same draw command. Unfortunately, it looks like the -gravity option is affecting the text primitive, but not the path primitive.
Is there a way to reference the SouthEast corner, or the Time text label when specifying the start position of the red arrow? I can't use absolute coordinates, because the size of the image varies.
*ImageMagick 6.7.8-9 on CentOS 7
Updated Answer
Maybe you can make Unicode text arrows like this then they will be affected by gravity...
perl -e 'binmode(STDOUT,":utf8"); print "Time ... \x{2192}\x{2191}";'|
convert -font TimesNewRoman -pointsize 36 label:#- arrows.png
Depending on your OS, the following may do as a replacement for the Perl above...
printf "%b" "\u2192" | convert ...
Original Answer
I am not at all familiar with paths, but I can suggest a way to achieve what you want that doesn't use gravity at all, and maybe that will help.
Rather than use -splice, you can clone your original image and crop it to the size you planned to splice on, and then -append the strips that label the axes. It is easier to show you the command than explain it!
convert -size 240x160 pattern:SMALLFISHSCALES \
\( +clone -crop x20+0+0 -fill blue -colorize 100% \) \
-append \
\( +clone -crop 20x+0+0 -fill red -colorize 100% \) \
+swap +append result.png
I have filled the x-axis blue, but remove that and add whatever labelling and arrows you need, and I filled the y-axis red, but likewise remove that and add labelling and arrows - rotating as necessary.
Two tricky things to note...
-append will append the second image below the first
+append will append the second image to the right of the first, so I +swap beforehand to put it on the left side.

Apply watermark with text / image using GraphicsMagick

I need to be able to apply watermark on an image, using either text or another image.
Getting it to work with an image was quite straight forward, using the following command:
gm composite -dissolve 15 -tile logo.png image.jpg wmark_tiled.jpg
Now, I also want to be able to use text for watermarking (in other cases). The only thing that I found close to it, is a command from ImageMagick tutorial which is the following :
convert -size 140x80 xc:none -fill grey -gravity NorthWest -draw "text 10,10 'copyrigh text'" -gravity SouthEast -draw "text 5,15 'copyright text'" miff:- | gm composite -tile - image.jpg copyrightImage.jpg
Although its not working in GM, and I would rather avoid using pipe as it causes some headaches managing it from Java.
What I thought I could do, is generate an image from a given text, and then use that image as logo.png is used on my first command. Although I cannot find how to generate an image out of text, all I find is putting text on top of an image.
Ideally I will generate a transparent image with the text, and from what I see modifying font/color etc should be quite flexible.
Any suggestions on how to achieve this, or any better solutions are welcome.
(I added imagemagick tag as the interfaces are often same/similar)
I'm not sure I fully understand your query, so apologies if I've misunderstood, but are you trying to create a transparent image, with some text in the corner? If so, would this not work?
convert -background transparent -fill grey -font Calibri -size 140x80 -pointsize 14 -gravity southeast label:'copyright text' output.png
Obviously adjusting the font, pointsize, output image name etc. That would create the following:
http://oi42.tinypic.com/14j1bvp.jpg
P.S. that was written for ImageMagick. I don't know how GM differs or whether it would still work.
To be able to get the watermark text into the same image I had to use the -annotate parameter.
So Moogle's code snippet would look like this in my case:
convert original_image.jpg -background transparent -fill grey -font Calibri -size 140x80 -pointsize 14 -gravity southeast -annotate +0+0 'copyright text' output.jpg

Add gradient overlay under a photo label using imagemagick

I'm trying to convert a bunch of photos using imagemagick. However, I hadn't figured out how to overlay an image with gradient and write some text on it. I know the text part though:
convert IMG_8408.jpg \
-font URWChanceryMediumI \
-pointsize 250 \
-draw "gravity south
fill black text 0,40 'Some text stuff here'" \
test.jpg
Is there a way to add a white gradient to the bottom? Note, that the image size may vary.
What I have:
What I want:
I picked the colors so that it's clearly visible what I want to achieve
You can achieve desired output with 3 commands:
a. create the upper part of your image (a solid rectangle with your selected background color):
convert -size 640x200 xc:#A02B2B background.jpg
b. create another image containing the text over a gradient:
convert -size 640x110 gradient:#A02B2B-#126B27 -pointsize 25 -draw "gravity south fill black text 0,40 'Some text stuff here'" text.jpg
c. combine the images to obtain the final output:
montage background.jpg text.jpg -tile 1x2 -geometry +0+0 output.jpg
Note: I modified text creation parameters in step 2 to keep the command short, but you can add back your original settings
Use the following command:
magick -size 640x310 -define gradient:vector="0,107 0,0" gradient:"#a02b2b-#126b27" -flip -gravity south -font script-mt-bold -pointsize 48 -annotate +0+24 "Some text stuff here" output.png

Overlaying an image's filename using ImageMagick (or similar)

I know ImageMagick's annotate command can superimpose some text over an image, but can it use the image's filename as this text? I would've assumed so, but can't seem to find direct documentation that confirms this.
No doubt some combination of parameters can manage this, or is there a better way of doing this in a script?
Eric L.'s answer is correct -- +1 from me for it! -- but -annotate doesn't give you much control over the appearance of the text.
If you look for prettyness, then rather go for something that uses -composite. You can use an IM command to construct an overlay image first (which uses a semi-transparent background) and then overlay it over the original image.
Here is an example how to do it with -composite instead of -annotate, using a scripted approach that processes every PNG file in the current directory. This one even automatically adapts the font size and fits it into the available "width * 90%" -- it is a Bash script (see comments for Win equivalent):
for img in *.png; do
width=$(identify -format %W ${img})
width=$(( ${width} * 9 / 10 ))
convert \
-background '#0008' \
-gravity center \
-fill white \
-size ${width}x100 \
caption:"${img}" \
"${img}" \
+swap \
-gravity south \
-composite \
"with-caption-${img}"
done
An example illustration for one original and the respective output are below:
!
Here is a command that uses -annotate, trying to set a few things beyond the default parameters:
for img in so#12231624-right.png; do
convert \
"${img}" \
-fill red \
-undercolor '#0008' \
-pointsize 24 \
-gravity south \
-annotate +0+5 "${img}" \
"with-annotate-${img}"
done
It's a very old entry but I find it each time I search for this topic, and it doesn't work (for me at least). Here something that works for me:
convert input.jpg -gravity South -annotate 0 '%f' output.jpg
Hope this helps someone...
You can also use mogrify to add text to bunch of images at once.
mogrify -gravity South -annotate 0 '%f' -pointsize 24 -fill white *.png
This will overwrite existing images, so make sure you have a backup before you execute this.
Building on Steve Czetty's solution, it looks like you can set the text size and color of the annotation, using -pointsize and -fill, respectively.
Here's an example:
convert input.jpg -gravity south -pointsize 24 -fill yellow -annotate 0 '%f' output.jpg
Obviously, you can change the text size from 24 points to something else, as well the color, from 'yellow' to some other color, as per your preference.

Resources