Imagemagick convert gif creation random image order - imagemagick

i have a folder of images with names foo<bar>.png where <bar> ranges from 0 to 100.
When i create a gif of these images with
convert -dispose previous -delay 10 -resize 25% -loop 0 *.png myimage.gif
it creates a gif with images in order like 0,1,2,3...
Is there a command to select images in random order?

If your PNG images are all the same dimensions, and if the number of images can be evenly divided into a grid, like 72 images would make a grid of 8 x 9 images, and if your images are small enough to read them all into a single ImageMagick command, here is a command that will randomize the order of a group of 72 input images...
convert *.png -virtual-pixel tile +append -crop 9x1# -append +repage ^
-crop 1x9# -distort affine "0,0 %[fx:floor(rand()*8)*(w/8)],0" -append +repage ^
-crop 8x1# -distort affine "0,0 0,%[fx:floor(rand()*9)*(h/9)]" +append +repage ^
-crop 8x9# +repage -set delay 10 -loop 0 image.gif
It basically makes a grid, randomly rolls all the rows, then randomly rolls all the columns. The shuffle scatters the images pretty well, but if you want a deeper shuffle, copy and paste those two "-crop ... -distort" lines, and add them below the first two...
convert *.png -virtual-pixel tile +append -crop 9x1# -append +repage ^
-crop 1x9# -distort affine "0,0 %[fx:floor(rand()*8)*(w/8)],0" -append +repage ^
-crop 8x1# -distort affine "0,0 0,%[fx:floor(rand()*9)*(h/9)]" +append +repage ^
-crop 1x9# -distort affine "0,0 %[fx:floor(rand()*8)*(w/8)],0" -append +repage ^
-crop 8x1# -distort affine "0,0 0,%[fx:floor(rand()*9)*(h/9)]" +append +repage ^
-crop 8x9# +repage -set delay 10 -loop 0 image.gif
Carefully replace the "8"s and "9"s with the width and height of the grid that holds the number of images you're using. I use it in a script that shuffles a deck of playing card images, 13 rows and 4 columns.
This uses ImageMagick v6 in Windows CMD syntax. In a BAT script double all the percent signs "%%". It would probably work on a *nix OS by changing all the continued-line carets "^" to backslashes "\". For ImageMagick v7 use "magick" instead of "convert".

I can tell you 2/3 of the answer on Windows, and hopefully some other kind soul can add the rest for you. Nobody said answers have to be complete.
Create a text file containing the names of the PNGs you want to animate. I believe that is:
DIR /B *.png > filelist.txt
Shuffle the lines in that file. I don't know how to do that in Windows. In Linux and macOS it is shuf. Here's a little Python equivalent:
python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," filelist.txt > shuffled.txt
Pass that file to ImageMagick like this:
convert -loop 0 -delay 80 #filelist.txt animation.gif
If you get that working, you can avoid the need for a temporary file by using this syntax:
DIR /B *.png | SHUFFLELINES | convert -loop 0 -delay 80 #- animation.gif

Related

Combining ImageMagick import/montage commands into one-liner

Long story short from the command line I need to take a screenshot, crop two areas of that screenshot and join them back together side-by-side.
The separate stages which work fine look like this:
$> import -window root -crop '1280x400+0+0' left.png
$> import -window root -crop '1280x400+0+400' right.png
$> montage -geometry 1280x400 left.png right.png out.png
However, I'm not sure how to combine this into one command.
OS is Linux (Raspbian) if that helps.
I'm not sure how to do any cropping as part of a magick import so I'll import and forward to a regular magick command for processing.
To mimic your approach, that would be:
magick import -window root png:- | magick png:- \
\( -clone 0 -crop 1280x400+0+0 \) \
\( -clone 0 -crop 1280x400+0+400 \) \
-delete 0 +append result.png
That first grabs the screen with import and pipes it on as a PNG to a second command that clones the image and crops the left half, clones it again and crops the right half, deletes the original and places the two crops side-by-side.
There is an easier way that works for you though. If you crop without an offset, all the cropped areas will remain in your stack:
magick import -window root png:- | magick png: -crop x50% +append result.png
Note: I am also using 50% of the height as the crop to save me having to do any maths 😀
Note: If you want a magenta gap between the two halves, add -background magenta near the start and replace +append with +smush 10 to place them 10 pixels apart.

Splitting OpenEXR into different exposure images

I'm trying to use this dataset to do Exposure Meging (Fusion) in Python. Each image in the dataset has an OpenEXR file that can be downloaded (i don't have much experience with this file format).
I want to extract different samples (jpg or png) from the OpenEXR file with different exposures .
I managed to do that in Darktable :
Open the OpenEXR file (image)
Change the Exposure
Save as jpg
redo for each exposure value (-3EV, -2EV, -1EV, 0EV, 1EV, 2EV, 3EV).
The problem : I have 100 images and i want to automate this process. any idea on how to do that ?
Thank you in advance
Since each increment of EV ("Exposure Value") corresponds to doubling the exposure, and EXR files are in linear light (not gamma-encoded), you would expect that you can double the pixel values in an EXR file to add 1EV and halve them to do -1EV...
So, I downloaded the Luxo EXR file from here. Then I went into Photoshop and clicked:
Image -> Mode -> 8-bits/channel
and selected Method = Exposure and Gamma and set exposure=+1 and saved the resulting file as a JPEG with +1 in its name. I repeated that for EV-3, EV-2, EV+0, EV+1, EV+2, EV+3.
I then looked at the resulting files with ImageMagick using commands like the following in the Terminal to examine the mean value of the combined RGB image:
magick identify -verbose image-EV+2.jpg
I then went about producing those same mean values, and found that the following works:
# To increase 1 EV
magick input.exr -evaluate multiply 2 result.jpg
# To increase 2 EV
magick input.exr -evaluate multiply 4 result.jpg
# To increase 3 EV
magick input.exr -evaluate multiply 8 result.jpg
And so on...
So, I wrote a bash script to do that as follows, which you could save in your HOME directory as adjust.sh:
#!/bin/bash
# Default file, if none specified
file=${1:-/Users/mark/Desktop/LuxoDoubleChecker.exr}
# Default EV of +1, if none specified
EV=${2:-1}
# Strip extension
base="${file%.*}"
# Apply given EV to file and save with new name
new="${base}EV${EV}.jpg"
echo "Applying EV $EV to $file, saving as $new"
magick "$file" -evaluate multiply $(bc -l <<< "2^$EV") "$new"
Then, just necessary once, make it executable:
chmod +x $HOME/adjust.sh
And then you run it like this to add +3EV to SomeImage.exr:
~/adjust.sh SomeImage.exr 3
Sample Output
Applying EV 3 to SomeImage.exr, saving as SomeImageEV3.jpg
Alternatively, if you save this script as allEVs.sh, it will load the specified image just once and generate all 7 exposures in one go without re-reading the input EXR file 7 times:
#!/bin/bash
# Default file, if none specified
file=${1:-/Users/mark/Desktop/LuxoDoubleChecker.exr}
# Strip extension to get base without extension
base="${file%.*}"
magick "$file" \
\( +clone -evaluate multiply 0.125 -write "${base}EV-3.jpg" +delete \) \
\( +clone -evaluate multiply 0.25 -write "${base}EV-2.jpg" +delete \) \
\( +clone -evaluate multiply 0.5 -write "${base}EV-1.jpg" +delete \) \
\( +clone -evaluate multiply 1 -write "${base}EV-0.jpg" +delete \) \
\( +clone -evaluate multiply 2 -write "${base}EV+1.jpg" +delete \) \
\( +clone -evaluate multiply 4 -write "${base}EV+2.jpg" +delete \) \
-evaluate multiply 8 "${base}EV+3.jpg"
Please check carefully that this works correctly for you before basing a lifetime's analysis on it...
Keywords: Image processing, HDR, High Dynamic Range, EXR, EV, Exposure Value, f-stop, stop, stops, exposure, increase, decrease, tone map, ImageMagick.

How to split an image with a grid and preserve transparency bounding box

I have some png images that I want to split it into parts, like by grid or size.
But each part should have the same bounding box (transparency) as original image.
Example:
Splitting image into 2 parts.
Original: 200 × 89
Output:
part_1.png, 200 × 89
part_2.png, 200 × 89
Can ImageMagick do this? Or any other app or method.
My actual goal is to split into 100+ slices images.
EDIT:
Another goal to have an indents for each slice. Say indent = 10px.
Example:
Input: 200 x 100
Output:
part_1.png, 200 x 100
part_2.png, 200 x 100
And just as example, to visually compare input and output: combined output images in Photoshop as layer added one onto another
200 x 100 :
Also this is showing input image added onto combined(so it's better to see what was cropped and how):
In ImageMagick, you can split an image into many parts with the -crop command. For your example above with two parts, you can do that with the following commands. ImageMagick will append -0, -1 ... to the output file names.
ImageMagick 6:
dim=`convert image.png -format "%wx%h" info:`
convert \( -size $dim xc:none \) null: \( image.png -crop 50x100% \) -layers composite result.png
ImageMagick 7:
magick \( image.png -set option:dim "%wx%h" -crop 50x100% \) null: \( -size "%[dim]" xc:none \) -reverse -layers composite result.png
The results are:
See
http://www.imagemagick.org/Usage/crop/#crop
http://www.imagemagick.org/Usage/crop/#crop_percent
http://www.imagemagick.org/Usage/crop/#crop_tile
http://www.imagemagick.org/Usage/crop/#crop_quad
http://www.imagemagick.org/Usage/crop/#crop_equal
http://www.imagemagick.org/script/command-line-options.php#layers
Note that -crop keeps the virtual canvas information if you do not add +repage afterwards. So to put the individual images back into their original placement, you have to composite them onto a transparent background the size of the input. That is done in one command using -layers composite using the null: separator.
Here is another way to add transparent areas between parts of a crop in ImageMagick. Crop the image into pieces, chop off the parts you want to remove, then pipe to montage to add the spacing back.
Input:
Here I make this into a 4x4 grid of images with 10 pixel spacing:
convert lena.png -crop 25%x25% +repage -gravity east -chop 10x0 -gravity south -chop 0x10 +repage miff:- | montage - -background none -tile 4x4 -geometry +5+5 result.png
To answer your new question, you can do that with a script loop. On a Unix-like platform, assuming your images do not have spaces, you can do the following:
cd path/to/current_folder
list=`ls *.png`
for img in $list; do
name=`convert $img -format "%t" info:`
dim=`convert $img -format "%wx%h" info:`
convert \( -size $dim xc:none \) null: \( $img -crop 50x100% \) -layers composite -scene 1 path/to/new_folder/${name}_%d.png
done
If you want leading 0s in the output, say 3, use path/to/new_folder/${name}_%03d.png.
Note that to start with 1 rather than 0, I have added -scene 1.
Sorry, I do not know how to script for Windows.
Please always provide your ImageMagick version and platform.
In ImageMagick, the best way to put transparent areas into your image is with a binary mask that is put into the alpha channel of your image.
convert input.png \( -size 200x89 xc:white -size 10x89 xc:black -gravity center -composite \) -alpha off -compose copy_opacity -composite result.png
You can add as many blank areas as you want by adding more white areas to the mask or by tiling out one region of black and one region of white to create the mask with regular spacing of black and white.
Edited to add this ImageMagick 6 example which splits the input image into 4 pieces, 25% of the original width and 100% of its height, then creates a transparent canvas for each piece the same dimensions of the input image, and locates the pieces at their original offsets on those canvases.
convert input.png -set option:distort:viewport %[w]x%[h] -crop 25x100% \
-virtual-pixel none -distort affine "0,0 %[fx:s.page.x],%[fx:s.page.y]" out%03d.png
The output file names will be numbered starting from zero like "out000.png", etc.
Original message...
Here's a simple command using ImageMagick 7 that can crop an image into any number of pieces, and output all the pieces at their original offsets on transparent backgrounds of the original input dimensions...
magick input.png -crop 100x1# -background none \
-extent "%[fx:s.page.width]x%[fx:s.page.height]-%[fx:s.page.x]-%[fx:s.page.y]" out%03d.png
That "-crop 100x1#" tells it to split the image into a grid 100 pieces wide by 1 piece high. You could just as well specify the crop sizes as percents or numbers of pixels.
Edited again to add:
This following command will split the input image into the individual pieces specified with the "-crop" operator, then shave 5 pixels from every side of each piece, then apply a 5 pixel transparent border to every side of each piece. It will still remember the original locations of the pieces within the input canvas, so the "-distort affine ..." can extend the canvases and place the pieces where they were in the input image.
convert input.png -set option:distort:viewport %[w]x%[h] \
-bordercolor none -background none -virtual-pixel none \
-crop 25x100% -shave 5x5 -border 5x5 \
-distort affine "0,0 %[fx:s.page.x],%[fx:s.page.y]" out%03d.png
To use this command with IM7 you need to change "convert" to "magick".
Given the changes of requirements provided by Kamikaze, here is one way to achieve the split with indent in ImageMagick, assuming I understand correctly.
dim=`convert image.png -format "%wx%h" info:`
convert \( -size $dim xc:none \) null: \( image.png -crop 50x100% -shave 5x5 \) -geometry +5+5 -layers composite result.png
To check, I flatten over a blue background:
convert result-0.png result-1.png -background blue -flatten result.png

How to trim animated gif (using imagemagick)?

Given an animated gif over a solid background color
I'd like to trim away the padding. Concretely, I'd like to crop the image to the maximum extent of the foreground object over all frames:
I can't seem to find the right combination of -alpha, -background to achieve this with a single convert command. For example, if I issue
convert -dispose 2 input.gif -trim -layers TrimBounds fail.gif
I get random "background" colors for frames whose individual trimmed extents are smaller than the maximum extent over all frames:
I can achieve the correct output with a long string of commands:
convert input.gif -trim -layers TrimBounds out-%03d.miff
mogrify -background "rgb(20%,30%,80%)" -layers flatten out-*.miff
convert out-*.miff output.gif
rm out-*.miff
This is slow, writes a bunch of temporary files, and requires me to know the background color ("rgb(20%,30%,80%)") explicitly.
Is there a simpler way to trim an animated gif?
This related question considers explicit cropping rather than automatic trimming.
Finally, this seems to work in ImageMagick with one line to get the background color and one line of processing. No temp files are needed.
bgcolor=`convert input.gif[0] -format "%[pixel:u.p{0,0}]" info:`
convert -dispose previous -delay 10 -background "$bgcolor" input.gif -trim -layers TrimBounds -coalesce -layers optimize -loop 0 output.gif
You can accomplish this sort of trimming using IM's "-distort" with a defined viewport.
convert oHBWq.gif -coalesce +repage -background none \
\( -clone 0--1 -trim -flatten -trim \) \
-set option:distort:viewport %[fx:u[-1].w]x%[fx:u[-1].h]+%[fx:u[-1].page.x]+%[fx:u[-1].page.y] \
-delete -1 -distort SRT 0 +repage output.gif
That clones the input frames, trims them individually, and flattens them keeping their original alignment. Then it trims that flattened one again to get rid of the excess transparent background. The result will be the right size and have the correct page offsets for the finished images. You don't have to know the background color.
Now you can easily get those dimensions and offsets into a distort viewport setting and do a no-op distort. Delete the cloned flattened one that was used to get the measurements, "+repage" the rest, and finish with whatever other GIF settings you need.
This is an interesting question. At the moment, I do not see how to improve it so that extra file(s) are not needed. But I will consider it further. But I can clean your code up a bit and make it easier for you and make the output.gif look correct.
bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
convert oHBWq.gif -trim -layers TrimBounds out-%03d.miff
mogrify -background "$bgcolor" -layers flatten out-*.miff
convert -dispose previous -delay 10 out-*.miff -loop 0 output.gif
rm out-*.miff
This does the same thing as above, but only requires saving 1 multi-frame miff file. The subshell loop processing does similar to your mogrify.
bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
num=`convert oHBWq.gif -format "%n\n" info: | head -n 1`
convert oHBWq.gif -trim -layers TrimBounds tmp.miff
(for ((i=0; i<num; i++)); do
convert tmp.miff[$i] -background "$bgcolor" -layers flatten miff:-
done ) |\
convert -dispose previous -delay 10 - -loop 0 output2.gif
rm tmp.miff
This also works without having to save any temp files, but is has to repeat the -trim -layers trim bounds for each loop iteration.
bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
num=`convert oHBWq.gif -format "%n\n" info: | head -n 1`
echo "num=$num"
(for ((i=0; i<num; i++)); do
convert oHBWq.gif -trim -layers TrimBounds miff:- |\
convert -[$i] -background "$bgcolor" -layers flatten miff:-
done ) |\
convert -dispose previous -delay 10 - -loop 0 output3.gif
This is close but for one frame:
bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
convert -dispose previous -delay 10 oHBWq.gif -trim -layers TrimBounds -background "$bgcolor" -layers optimize -loop 0 output5.gif

Extracting data digitally

I have 200 copies of this page(15 * 10 matrix) and i have to write all the numbers from 0 - 9 in each corresponding cell and then extract those digits digitally in a seperate image of (32*32 pixels) for each digit, after scanning each page once. How can i achieve this? This is required for my research purpose. I am a CS student so i can code too.
Update:
For mark : Here is one of the scanned image
This is for some local language ( 0 - 9) ..
Update 2:
The commands for the previous image are working fine but on new images,something is getting wrong(some kind of offsets)..
I am attaching the image below
What changes do u suggest ?
Updated Answer
I have taken your feedback and improved the algorithm to the following bash script now...
#!/bin/bash
################################################################################
# dice
#
# Trim borders off an image (twice) and then dice into 10x15 cells.
#
# Usage: ./dice image
################################################################################
# Pick up image name from first parameter
image="$1"
echo DEBUG: Processing image $image...
# Apply median filter to remove noisy black dots around image and then get the
# dimensions of the "trim box" - note we don't use the (degraded) median-filtered image in
# later steps.
trimbox=$(convert "$image" -median 9x9 -fuzz 50% -format %# info:)
echo DEBUG: trimbox $trimbox
# Now trim original unfiltered image into stage1-$$.png (for debug)
convert "$1" -crop $trimbox +repage stage1-$$.png
echo DEBUG: Trimmed outer: stage1-$$.png
# Now trim column headings
convert stage1-$$.png -crop 2000x2590+120+190 +repage stage2-$$.png
echo DEBUG: Trimmed inner: stage2-$$.png
# Now slice into 10x15 rectangles
echo DEBUG: Slicing and dicing
convert stage2-$$.png -crop 10x15# +repage rectangles-%03d.png
# Now trim the edges off the rectangles and resize all to a constant size
for f in rectangles*png; do
echo DEBUG: Trimming and resizing $f
trimbox=$(convert "$f" -median 9x9 -shave 15x15 -bordercolor black -border 15 -threshold 50% -floodfill +0+0 white -fuzz 50% -format %# info:)
echo DEBUG: Cell trimbox $trimbox
convert "$f" -crop $trimbox +repage -resize 32x32! "$f"
done
Here are the resulting cells - i.e. 150 separate image files. I have put a red border around the individual cells/files so you can see their extent:
Original Answer
I would do that with ImageMagick which is free and installed on most Linux distros and is available for OSX and Windows too. There are Perl, PHP, Java, node, .NET, Ruby, C/C++ bindings too if you prefer those languages. Here I am using the command line in Terminal.
First job is to get rid of noise and trim the outer edges:
convert scan.jpg -median 3x3 -fuzz 50% -trim +repage trimmed1.png
Now, trim again to get rid of outer frame and column titles across the top:
convert trimmed1.png -crop 2000x2590+120+190 +repage trimmed2.png
Now divide into 10 cells by 15 cells and save as rectangles-nnn.png
convert trimmed2.png -crop 10x15# rectangles-%03d.png
Check what we got - yes, 150 images:
ls -l rect*
rectangles-000.png rectangles-022.png rectangles-044.png rectangles-066.png rectangles-088.png rectangles-110.png rectangles-132.png
rectangles-001.png rectangles-023.png rectangles-045.png rectangles-067.png rectangles-089.png rectangles-111.png rectangles-133.png
rectangles-002.png rectangles-024.png rectangles-046.png rectangles-068.png rectangles-090.png rectangles-112.png rectangles-134.png
rectangles-003.png rectangles-025.png rectangles-047.png rectangles-069.png rectangles-091.png rectangles-113.png rectangles-135.png
rectangles-004.png rectangles-026.png rectangles-048.png rectangles-070.png rectangles-092.png rectangles-114.png rectangles-136.png
rectangles-005.png rectangles-027.png rectangles-049.png rectangles-071.png rectangles-093.png rectangles-115.png rectangles-137.png
rectangles-006.png rectangles-028.png rectangles-050.png rectangles-072.png rectangles-094.png rectangles-116.png rectangles-138.png
rectangles-007.png rectangles-029.png rectangles-051.png rectangles-073.png rectangles-095.png rectangles-117.png rectangles-139.png
rectangles-008.png rectangles-030.png rectangles-052.png rectangles-074.png rectangles-096.png rectangles-118.png rectangles-140.png
rectangles-009.png rectangles-031.png rectangles-053.png rectangles-075.png rectangles-097.png rectangles-119.png rectangles-141.png
rectangles-010.png rectangles-032.png rectangles-054.png rectangles-076.png rectangles-098.png rectangles-120.png rectangles-142.png
rectangles-011.png rectangles-033.png rectangles-055.png rectangles-077.png rectangles-099.png rectangles-121.png rectangles-143.png
rectangles-012.png rectangles-034.png rectangles-056.png rectangles-078.png rectangles-100.png rectangles-122.png rectangles-144.png
rectangles-013.png rectangles-035.png rectangles-057.png rectangles-079.png rectangles-101.png rectangles-123.png rectangles-145.png
rectangles-014.png rectangles-036.png rectangles-058.png rectangles-080.png rectangles-102.png rectangles-124.png rectangles-146.png
rectangles-015.png rectangles-037.png rectangles-059.png rectangles-081.png rectangles-103.png rectangles-125.png rectangles-147.png
rectangles-016.png rectangles-038.png rectangles-060.png rectangles-082.png rectangles-104.png rectangles-126.png rectangles-148.png
rectangles-017.png rectangles-039.png rectangles-061.png rectangles-083.png rectangles-105.png rectangles-127.png rectangles-149.png
rectangles-018.png rectangles-040.png rectangles-062.png rectangles-084.png rectangles-106.png rectangles-128.png
rectangles-019.png rectangles-041.png rectangles-063.png rectangles-085.png rectangles-107.png rectangles-129.png
rectangles-020.png rectangles-042.png rectangles-064.png rectangles-086.png rectangles-108.png rectangles-130.png
rectangles-021.png rectangles-043.png rectangles-065.png rectangles-087.png rectangles-109.png rectangles-131.png
Look at first couple:
You can do those 3 steps in 1 like this:
convert scan.jpg -median 3x3 -fuzz 50% -trim +repage \
-crop 2000x2590+120+190 +repage \
-crop 10x15# rectangles-%03d.png
You may want to shave a few pixels off each side of each image and resize to 32x32 with something like (untested):
mogrify -shave 3x3 -resize 32x32! rectangles*png

Resources