Hello I want to add a same image to the left side of multiple images. First image is a legend and it common for all the 6 images which I later want to montage 3x2.
I tried this command below before montaging and it did not work. I wanted to see if I could make it work without adding a for loop, which slows down the code.
convert +append image_3_1.png image_1_[1-6].png -geometry +10+0 test.png
I want the image_3_1 added to all the 6 images starting with image_1. Any ideas?
Your question is unclear about:
what your input and expected output images look like or how big they are,
whether you actually need the intermediate images or just the montage,
what the actual issue is with for loops
So here are some ideas...
Option 1
This one avoids for loops and multiple invocations of magick by using a single magick and loading the side image just once and cloning it in memory:
magick side.png \
\( +clone image_1.png +append -write out_1.png +delete \) \
\( +clone image_2.png +append -write out_2.png +delete \) \
\( +clone image_3.png +append -write out_3.png +delete \) \
\( +clone image_4.png +append -write out_4.png +delete \) \
\( +clone image_5.png +append -write out_5.png +delete \) \
image_6.png +append out_6.png
It produces 6 output files as follows:
Option 2
This one avoids for loops by running 6 copies of magick in parallel:
magick side.png image_1.png +append out_1.png &
magick side.png image_2.png +append out_2.png &
magick side.png image_3.png +append out_3.png &
magick side.png image_4.png +append out_4.png &
magick side.png image_5.png +append out_5.png &
magick side.png image_6.png +append out_6.png &
wait
It produces the same 6 output files as above.
Option 3
This does the same by using GNU Parallel to do it more succinctly:
parallel magick side.png image_{}.png +append out_{}.png ::: {1..6}
Option 4
If you don't need the intermediate files, and just want the montage:
parallel -k magick side.png {} +append ppm:- ::: image_*png | magick montage -tile 2x3 -geometry +5+5 ppm:- montage.png
Option 5
This is much the same, avoiding producing the intermediate output files, and also avoiding using GNU Parallel:
magick side.png \
\( +clone image_1.png +append -write ppm:- +delete \) \
\( +clone image_2.png +append -write ppm:- +delete \) \
\( +clone image_3.png +append -write ppm:- +delete \) \
\( +clone image_4.png +append -write ppm:- +delete \) \
\( +clone image_5.png +append -write ppm:- +delete \) \
image_6.png +append ppm:- | magick montage -background black -geometry +5+10 -tile 2x3 ppm:- montage.png
Option 6
This one uses no for loops, a single process, no separate montage command and generates no intermediate files:
magick side.png -write MPR:side +delete \
\( MPR:side image_1.png MPR:side image_2.png +append \) \
\( MPR:side image_3.png MPR:side image_4.png +append \) \
\( MPR:side image_5.png MPR:side image_6.png +append \) \
-append montage.png
Replace the +append and -append with -smush for more layout and inter-image spacing flexibility.
Option 7
Maybe something like this with -smush:
magick side.png -write MPR:side +delete -background cyan \
\( MPR:side image_1.png MPR:side image_2.png +smush 10 \) \
\( MPR:side image_3.png MPR:side image_4.png +smush 10 \) \
\( MPR:side image_5.png MPR:side image_6.png +smush 10 \) \
-smush 30 montage.png
My guess is that option 6 would be the fastest on most machines in most circumstances, if it is flexible enough for you. If you need more flexibility, go with option 7 or 5.
Keywords: ImageMagick, image processing, montage, layout, parallel, smush.
Related
I am trying to run below command from my command prompt and it gives me following error:
magick billadd1.jpg -type TrueColorAlpha billadd2.jpg -type TrueColorAlpha \( -clone 0,1 -compose difference -composite -morphology dilate disk:10 \) \( -clone 0 -fill yellow -colorize 100 -channel a -evaluate set 50% +channel \) \( -clone 0,3,2 -compose over -composite +write 1.jpg \) \( -clone 1,3,2 -compose over -composite +write 2.jpg \) null:
magick: unable to open image '\(': No such file or directory # error/blob.c/OpenBlob/3537.
magick: no decode delegate for this image format `' # error/constitute.c/ReadImage/562.
Also, how to run this command from java using im4java?
Note i am using imagemagick veriosn7
The Windows syntax is different from Unix/Linux syntax. Your command is currently in Unix/Linux syntax:
magick billadd1.jpg -type TrueColorAlpha billadd2.jpg -type TrueColorAlpha \
\( -clone 0,1 -compose difference -composite -morphology dilate disk:10 \) \
\( -clone 0 -fill yellow -colorize 100 -channel a -evaluate set 50% +channel \) \
\( -clone 0,3,2 -compose over -composite +write 1.jpg \) \
\( -clone 1,3,2 -compose over -composite +write 2.jpg \) null:
Which, when converted to Windows, probably becomes:
magick billadd1.jpg -type TrueColorAlpha billadd2.jpg -type TrueColorAlpha ^
( -clone 0,1 -compose difference -composite -morphology dilate disk:10 ) ^
( -clone 0 -fill yellow -colorize 100 -channel a -evaluate set 50%% +channel ) ^
( -clone 0,3,2 -compose over -composite +write 1.jpg ) ^
( -clone 1,3,2 -compose over -composite +write 2.jpg ) null:
So, the rules are something like this to go from Linux to Windows:
remove backslashes before parentheses
change backslash line-continuation character to caret (^)
double up any percent signs
change any single quotes to double-quotes
There are some more detailed notes here.
A possible history for this question: Eliminate slow speed factor in ffmpeg and image-magic commands
I am creating a GIF using this command with wiper effect,
convert -gravity southeast logo.png -write MPR:logo \
\( before.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:before \) \
\( after.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:after \) \
-delete 0--1 \
MPR:before \( MPR:after -set delay 25 -crop 15x0 -reverse \) \
MPR:after \( MPR:before -set delay 27 -crop 15x0 \) \
-set delay 2 -loop 0 temp.gif -delete 1--1 -resize 640x thumb.jpg
Which is working all fine, but it creates a gif of size 3MB+, as there are more than 100 frames in wiper effect.
How can we decrease the number of frames for the wiper effect as well as the quality remains the same, but size decreases? I tried to attach different parameters with different loop values but nothing worked.
Here are 3 Imageamagick commands. The first is yours above. In the second I create a common color map image from the two input images (before and after) and apply that to each frame. In the third, I do the same color map processing, but reduce the number of frames. I took all the images from the web site and animation referenced and put the new logo in the bottom left corner, since there was already one in the bottom right corner. Note that I added -layers optimize to all, which decreased the file size considerably.
logo:
before:
after:
Method 1 (original):
convert -gravity southwest everlogo.png -write MPR:logo \
\( before.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:before \) \
\( after.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:after \) \
-delete 0--1 \
MPR:before \( MPR:after -set delay 25 -crop 15x0 -reverse \) \
MPR:after \( MPR:before -set delay 27 -crop 15x0 \) \
-set delay 2 -layers optimize -loop 0 temp1a.gif
2,246,665 bytes
174 frames
Result is too large to upload here.
Method2 (common color map):
convert -gravity southwest \
everlogo.png -write MPR:logo +delete \
\( before.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:before \) \
\( after.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:after \) \
-delete 0--1 \
\( MPR:before MPR:after +append +dither -colors 255 -unique-colors -write MPR:colors +delete \) \
MPR:before +dither -remap MPR:colors \( MPR:after +dither -remap MPR:colors -set delay 25 -crop 15x0 -reverse \) \
MPR:after+dither -remap MPR:colors \( MPR:before +dither -remap MPR:colors -set delay 27 -crop 15x0 \) \
-set delay 2 -layers optimize -loop 0 temp1b.gif
2,004,345 bytes
173 frames
Method 3 (common color map; twice the crop width and four times the delay; adjust the delay as desired to match better Method 2)
convert -gravity southwest \
everlogo.png -write MPR:logo +delete \
\( before.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:before \) \
\( after.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:after \) \
-delete 0--1 \
\( MPR:before MPR:after +append +dither -colors 255 -unique-colors -write MPR:colors +delete \) \
MPR:before +dither -remap MPR:colors \( MPR:after +dither -remap MPR:colors -set delay 100 -crop 30x0 -reverse \) \
MPR:after+dither -remap MPR:colors \( MPR:before +dither -remap MPR:colors -set delay 108 -crop 30x0 \) \
-set delay 4 -layers optimize -loop 0 temp1c.gif
1,927,359 bytes
87 frames
I am bit surprised that reducing the number of frames so significantly does not make a commensurate decrease in animation file size. But I suspect that is due to the -layers optimize.
ADDITION:
Also in all the code above, I do not understand the use of setting the delay of 25 and 27 inside the parentheses and then setting it again to 2 afterwards. I do not think animated gifs can have different delays. The only one that matters is the final one.
So just in terms of delays and number of frames, these two do the same. The first uses -crop 15x0 and -set delay 4 and the second use -crop 30x0 and -set delay 8. This produces the same speed animation, but the second has fewer frames. The first is 174 and the second is 88 and so more coarse steps. But the file sizes are about the same. So it seems that the common color map causes the largest decrease in file size.
convert -gravity southwest everlogo.png -write MPR:logo \
\( before.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:before \) \
\( after.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:after \) \
-delete 0--1 \
MPR:before \( MPR:after -crop 15x0 -reverse \) \
MPR:after \( MPR:before -crop 15x0 \) \
-set delay 4 -layers optimize -loop 0 temp3.gif
frames 174
2,246,665 bytes
convert -gravity southwest everlogo.png -write MPR:logo \
\( before.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:before \) \
\( after.jpg -resize '1280x720!' MPR:logo -geometry +15+15 -composite -write MPR:after \) \
-delete 0--1 \
MPR:before \( MPR:after -crop 30x0 -reverse \) \
MPR:after \( MPR:before -crop 30x0 \) \
-set delay 8 -layers optimize -loop 0 temp2.gif
frames 88
2,174,954 bytes
I have a jpeg containing alpha blended text. Knowing the font and size, I deduced a png file representing the text
Using ImageMagick, can I get an approximation of the original picture?
One way to do this is with a technique called inpainting. You can find that in (Python) Skimage at
http://scikit-image.org/docs/dev/api/skimage.restoration.html#inpaint-biharmonic
or in OpenCV at
https://docs.opencv.org/3.0-beta/modules/photo/doc/inpainting.html
https://docs.opencv.org/3.4.0/df/d3d/tutorial_py_inpainting.html
Here is the Python Skimage inpainting processing:
kitty image:
watermark image:
The Skimage inpainting requires a binary mask image. So I can convert your watermark to such a mask by:
convert watermark.png -alpha extract -threshold 0 mask.png
mask image:
Here is the Python code:
#!/opt/local/bin/python3.6
import numpy as np
import skimage.io
import skimage.restoration
import skimage.exposure
img = skimage.io.imread('/Users/fred/desktop/kitty.png')
msk = skimage.io.imread('/Users/fred/desktop/mask.png')
msk = skimage.exposure.rescale_intensity(msk, in_range='image', out_range=(0,1))
newimg = skimage.restoration.inpaint_biharmonic(img, msk, multichannel=True)
skimage.io.imsave('/Users/fred/desktop/kitty_inpaint_biharmonic.png', newimg)
Imagemagick does not have an official version of that. But user snibgo on the Imagemagick forum has implemented a custom version he calls 'hole filling' at http://im.snibgo.com/fillholespri.htm. He shows an example at https://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=28640#p127233.
Furthermore, on the same page, he shows some clever Imagemagick code that does repeated small amounts of resizing. This achieves a somewhat similar result to inpainting. But in general, it will not be quite as good as inpainting. Nevertheless, it does work moderately well for your image.
kitty image:
watermark image:
First, I have to take your watermark image and extract a binary image from it where the text is white and the background black. Then I use it to make the kitty image transparent where the text resides. Then I crop out the area of the text just to make the subsequent processing faster.
convert kitty.png \
\( watermark.png -alpha extract -threshold 0 -negate \) \
-alpha off -compose copy_opacity -composite \
-crop 490x102+235+150 +repage tmp1.png
Then I run his rather long sequence of successive resizing of the image followed by merging all the layers and resizing back to the original size.
convert tmp1.png \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
\( +clone -resize 90.9091% \) \
-layers RemoveDups \
-filter Gaussian -resize 490x102! \
-background None \
-compose DstOver -layers merge \
-alpha opaque \
tmp2.png
Then finally, I composite this result back into the place on the kitty image from which I had cropped it.
convert kitty.png tmp2.png -geometry +235+150 -compose over -composite kitty2.png
At full resolution, you can still make out the very faint text residual in this image. The Skimage result is better as can be seen by rapidly alternating the two images.
Albert Myšák has the proper technique here, since one knows the exact alpha channel values for the text and the equation that describes how the alpha channel is blended with the image. Kudos!
My earlier methods are better suited to when one only knows the positions of the text pixels in the image, so that one can make a binary mask or convert the text to transparency or some other color needed by whatever inpainting software is used.
Here is the equivalent one line Imagemagick command broken into several continuation lines for easier reading and explaining.
Line1 - read the kitty image
Line2 - copy it and make it all white rgb(255,255,255), save it into memory and delete the copy image from the image sequence
Line3 - read the watermark image and extract the alpha channel. Then subtract it from white
Line4 - divide the result of line 3 by the white image
Line5 - divide the kitty image by the result of line 4
Line6 - save the result to disk
convert kitty.png \
\( -clone 0 -fill white -colorize 100 -write mpr:white +delete \) \
\( watermark.png -alpha extract mpr:white -compose minus -composite \
mpr:white +swap -compose divide -composite \) \
+swap -compose divide -composite \
kitty_restored.png
you can do this in two lines of code.
import numpy as np
import cv2
import matplotlib.pyplot as plt
source_image = cv2.imread("6LfDs.png") #Image of cat with text watermark
text = cv2.imread("gJAAx.png", cv2.IMREAD_UNCHANGED) #Image of text
correcting_matrix = ((255 -text[:,:,3]) /255) #Matrix of "how much this pixel was darkened by applying text overlay"
original_image = (source_image / correcting_matrix[:,:,np.newaxis]).astype(np.uint8)
cv2.imwrite("original_image.png", original_image)
How does this work? Lets say you have pixel of cat with text with value of 15 and you know that alpha channel of text has value of 64.
If alpha channel has value of 64, we know that original pixel was multiplied by (255-64)/255, which is 0.75. Original value is 15/0.75 = 20
We can do this for every pixel and get original image
I want resize, crop and concatenate really many images.
I don't want to write the intermediate results to disk, just the final result only.
My script is :
montage -mode concatenate \
\( test.jpg -thumbnail "150x100>" -background white -gravity center -extent 150x100 -page 150x100+0+0 \) \
\( -clone 0 -crop 23x16+80+0 -background white -extent 23x16 \) \
\( -clone 0 -crop 23x16+16+87 -background white -extent 23x16 \) \
...
-delete 0 -quality 100% thumb.jpg
I got always the following error:
montage.im6: geometry does not contain image `test.jpg' # warning/transform.c/CropImage/574.
I tried to use the "repage" and "page" parameters, but I was unsuccessful with them.
Any idea?
Update
Mark asked for examples. So I try to write down the different steps which I would like to merge in one single step:
convert logo: test.jpg
convert test.jpg -thumbnail "150x100>" -background white -gravity center -extent 150x100 -page 150x100+0+0 test.resized.jpg
montage -mode concatenate test.resized.jpg \
\( -clone 0 -crop 23x16+80+20 -background white -extent 23x16 \) \
\( -clone 0 -crop 23x16+92+74 -background white -extent 23x16 \) \
\( -clone 0 -crop 23x16+100+80 -background white -extent 23x16 \) \
-delete 0 -quality 100% result.thumb.jpg
And the results:
you can see here the expected result.
http://phspring.nl/stackoverflow28101334.jpg
I must admit this one has me mystified! I cannot get it to work how you tried, or how I would want to do it at all. I found that I can only make it work if I add a +repage but if I do that it forgets the -extent, so I keep ending up with 2 commands. I also find that +clone refuses to work in place of -clone 0 for this example, which also mystifies me.
The only way I can make it work, and avoid the intermediate file is to stream the output of the first convert to the second one.
convert logo: -resize "150x100>" -background white -gravity center -extent 150x100 JPG:- | \
convert JPG:- \
\( -clone 0 -crop 23x16+80+20 \) \
\( -clone 0 -crop 23x16+92+74 \) \
\( -clone 0 -crop 23x16+100+80 \) \
-delete 0 +append out.jpg
I'd like to render a single file say 1.jpg to multiple Read/Write formats ImageMagick supports for eg. 1.png, 1.tif, 1.pdf etc. on a Windows machine. Is there a quick command to do that or do I have to run convert each time to render 1.jpg to each new output format I want?
Like this:
convert 1.jpg \
\( +clone -write 1.gif +delete \) \
\( +clone -write 1.png +delete \) \
1.tif
To make it create only one copy of GIF, PNG and other written files, use this command (asumuing, you want to convert myinputfile.jpg):
name=myinputfile
convert \
${name}.jpg \
-resize 50% \
\( +write ${name}.png \) \
\( +write ${name}.ppm \) \
\( +write ${name}.tif \) \
\( +write ${name}.gif \) \
\( +write ${name}.pdf \) \
${name}.pnm