Only cropping/appending a subset of images from an image sequence - bash

I have a numbered image sequence that I need to crop and append, but only certain frame ranges.
Example, sequence of 100 images named as follows:
frame001.jpg
frame002.jpg
frame003.jpg
...
Sometimes might only need to crop and append images 20-30, or other time, 5-75.
How can I specify a range? Simply outputting to a PNG.

For examle, if you want to pick the jpg files in the range of 20-30
and generate a png file appending them, would you please try:
#!/bin/bash
declare -a input # an array to store jpg filenames
for i in $(seq 20 30); do # loop between 20 and 30
input+=( "$(printf "frame%03d.jpg" "$i")" ) # append the filename one by one to the array
done
echo convert -append "${input[#]}" "output.png" # generate a png file appending the files
If the output command looks good, drop echo.
If you are unsure how to run a bash script and prefer a one-liner, please try instead:
declare -a input; for i in $(seq 20 30); do input+=( "$(printf "frame%03d.jpg" "$i")" ); done; echo convert -append "${input[#]}" "output.png"
[Edit]
If you want to crop the images with e.g. 720x480+300+200,
then please try:
#!/bin/bash
declare -a input
for i in $(seq 20 30); do
input+=( "$(printf "frame%03d.jpg" "$i")" )
done
convert "${input[#]}" -crop 720x480+300+200 -append "output.png"
The order of options and filenames doesn't matter here, but I have followed
the modern style of ImageMagick usage to place the input filenames first.

Related

Bash script not working with string variable, runs fine in directly in terminal

I am relatively new to Bash. I wrote a script to generate montage of images using montage utility from imagemagick, by reading list of png files from a text file:
IFS=$'\n'
count=1
for line in `cat pngListGr4`;
do
montage -tile 4x0 $line $(printf "%03d" $count).png
((count=count + 1))
done
unset IFS
where pngListGr4 file looks like this:
01.png 02.png 03.png 04.png
05.png 06.png 07.png 08.png
...
Hence I was expecting to generate file 001.png and 002.png as the montage of files 1-4 and 5-8.
But instead I am getting error:
montage-im6.q16: missing an image filename `001.png' # error/montage.c/MontageImageCommand/1795.
However following code works fine in terminal:
$ string_="01.png 02.png 03.png 04.png"
$ montage -tile 4x0 $string_ $(printf "%03d" $count).png
Why my string substitution in my bash script giving such issues?
You are setting IFS to \n to try to read lines, but that means that $string_ will no longer break on spaces in your montage command. The better solution is to use a while read loop which can both get lines and split them up into fields:
count=1
while IFS= read -ra line
do
montage -tile 4x0 "${line[#]}" "$(printf "%03d" "$count").png"
((count++))
done < pngListGr4

How to automate file transformation with simultanous execution?

I am working on transforming a lot of image files (png) into text files. I have the basic code to do this one by one, which is really time consuming. My process involves converting the image files into a black and white format and then using tesseract to transform those into a text file. This process works great but it would take days for me to acomplisyh my task if done file by file.
Here is my code:
for f in $1
do
echo "Processing $f file..."
convert $f -resample 200 -colorspace Gray ${f%.*}BW.png
echo "OCR'ing $f"
tesseract ${f.*}BW.png ${f%.*} -l tla -psm 6
echo "Removing black and white for $f"
rn ${f%.*}BW.png
done
echo "Done!"
Is there a way to perform this process to each file at the same time, that is, how would I be able to run this process simultaneously instead of one by one? My goal is to significantly reduce the amount of time it would take for me to transform these images into text files.
Thanks in advance.
You could make the content for your for loop a function then call the function multiple times but send each all to the background so you could execute another.
function my_process{
echo "Processing $1 file..."
convert $1 -resample 200 -colorspace Gray ${1%.*}BW.png
echo "OCR'ing $1"
tesseract ${1.*}BW.png ${1%.*} -l tla -psm 6
echo "Removing black and white for $1"
rn ${1%.*}BW.png
}
for file in ${files[#]}
do
# & at the end send it to the background.
my_process "$file" &
done
I want to thank contributors #Songy and #shellter.
To answer my question... I ended up using GNU Parallel in order to make these processes run in intervals of 5. Here is the code that I used:
parallel -j 5 convert {} "-resample 200 -colorspace Gray" {.}BW.png ::: *.png ; parallel -j 5 tesseract {} {} -l tla -psm 6 ::: *BW.png ; rm *BW.png
I am now in the process of splitting my dataset in order to run this command simultaneously with different subgroups of my (very large) pool of images.
Cheers

Unix: Combine PDF -files and images into PDF -file?

My friend is asking this question, he is using Mac and cannot get PdfLatex working (having no dev CD, related here). Anyway my first idea:
$ pdftk 1.pdf 2.pdf 3.pdf cat output 123.pdf [only pdfs]
$ convert 1.png 2.png myfile.pdf [only images]
Now I don't know without LaTex or iPad's Notes Plus how to combine images and PDF -files. So how can I combine pdf -files and images in Unix?
You could run a loop, identifying PDF and images, and converting images to PDF with ImageMagick. When you're done, you assemble it all with pdftk.
This is a Bash-only script.
#!/bin/bash
# Convert arguments into list
N=0
for file in $*; do
files[$N]=$file
N=$[ $N + 1 ]
done
# Last element of list is our destination filename
N=$[ $N - 1 ]
LAST=$files[$N]
unset files[$N]
N=$[ $N - 1 ]
# Check all files in the input array, converting image types
T=0
for i in $( seq 0 $N ); do
file=${files[$i]}
case ${file##*.} in
jpg|png|gif|tif)
temp="tmpfile.$T.pdf"
convert $file $temp
tmp[$T]=$temp
uses[$i]=$temp
T=$[ $T + 1 ]
# Or also: tmp=("${tmp[#]}" "$temp")
;;
pdf)
uses[$i]=$file
;;
esac
done
# Now assemble PDF files
pdftk ${uses[#]} cat output $LAST
# Destroy all temporary file names. Disabled because you never know :-)
echo "I would remove ${tmp[#]}"
# rm ${tmp[#]}
I am gathering here some info.
Unix Commandline
More about Pdftk here.
Merging png images into one pdf file
Combine all files in a folder as pdf
Mac
Because the moderator in Apple SE removed the useful thread "Merge PDF files and images to single PDF file in Mac?"
here
-- I collect the tips here for Mac -- sorry but the moderator is very intolerant about collecting Newbie -things.
https://apple.stackexchange.com/questions/16226/what-software-is-available-preferably-free-to-create-and-edit-pdf-files-on-mac
https://apple.stackexchange.com/questions/812/how-can-i-combine-two-pdfs-in-preview
https://apple.stackexchange.com/questions/11163/how-do-i-combine-two-or-more-images-to-get-a-single-pdf-file
https://apple.stackexchange.com/questions/69659/ipad-pdf-software-to-edit-merge-annotate-etc-well-pdf-documents-like-in-deskto

How can I save files with wget to numbered files with leading zeros?

I'm trying to download a list of .jpg files using wget. The file names on the server are all random alphanumeric strings; I want to save them to new, numbered file names, e.g. 000.jpg, 001.jpg, etc. based on the order that they're listed in the input file.
The problem I'm having is that BASH strips out the leading zeros, so I get 000.jpg, 1.jpg, etc.
Here's my script:
picnum=000
for i in `cat $imglist`; do
wget -O $picnum.jpg $i
let picnum++
done
All of the techniques that I've been able to find for preserving leading zeros look like they wouldn't work in this situation, so I'd really appreciate any assistance.
You need to zero-pad your number.
Try this:
wget -O `printf "%03d" $picnum`.jpg $i
You should not use for i in cat. For your example, it may work, but you should use read from within a while loop to iterate over the lines in a file. See this link for more information: http://mywiki.wooledge.org/BashFAQ/001.
You can use printf to pad your number with 0s.
picnum=0
while read -r image; do
wget -O $(printf '%03d.jpg' "$picnum") "$image"
(( picnum++ ))
done < "$imglist"

Generating the output file name from the input file in bash

I have a bash script:
#!/bin/bash
convert "$1" -resize 50% "$2"
Instead of passing two arguments while the script is run I want to mention just the source (or input file name) and the output file name should be auto-genarated from the source file name. Something like this "$1" | cut -d'.' -f1".jpg". If the input file name was myimage.png, the output name should be myimage.jpg. .jpg should be appended to the fist part of the source file name. It should also work if the argument is: *.png. So how can I modify my script?
The expansion ${X%pattern} removes pattern of the end of $X.
convert "$1" -resize 50% "${1%.*}.jpg"
To work on multiple files:
for filename ; do
convert "$filename" -resize 50% "${filename%.*}.jpg"
done
This will iterate over each of the command line arguments and is shorthand for for filename in "$#". You do not need to worry about checking whether the argument is *.png - the shell will expand that for you - you will simple receive the expanded list of filenames.
convert "$1" -resize 50% "${1%.*}.jpg"
The magic is in the %.* part, which removes everything after the last dot. If your file is missing an extension, it will still work (as long as you don't have a dot anywhere else in the path).
OUTFILE=`echo $1|sed 's/\(.*\)\..*/\1/'`.jpg
convert "$1" -resize 50% "$OUTFILE"

Resources