I'd like to use imagemagick or graphicsmagick to detect whether an image has basically no content.
Here is an example:
https://s3-us-west-2.amazonaws.com/idelog/token_page_images/120c6af0-73eb-11e4-9483-4d4827589112_embed.png
I've scoured Fred's imagemagick scripts, but I can't figure out if there is a way to do this:
http://www.fmwconcepts.com/imagemagick/
Easiest way would be to use -edge detection followed by histogram: & text:. This will generate a large list of pixel information that can be passed to another process for evaluation.
convert 120c6af0-73eb-11e4-9483-4d4827589112_embed.png \
-edge 1 histogram:text:- | cut -d ' ' -f 4 | sort | uniq -c
The above example will generate a nice report of:
50999 #000000
201 #FFFFFF
As the count of white pixels is less then 1% of black pixels, I can say the image is empty.
This can probably be simplified by passing -fx information to awk utility.
convert 120c6af0-73eb-11e4-9483-4d4827589112_embed.png \
-format '%[mean] %[max]' info:- | awk '{print $1/$2}'
#=> 0.00684814
If you are talking about the amount of opaque pixels vs the amount of transparent pixels, then the following will tell you the percentage of opaque pixels.
convert test.png -alpha extract -format "%[fx:100*mean]\n" info:
39.0626
Or if you want the percentage of transparent pixels, use
convert test.png -alpha extract -format "%[fx:100*(1-mean)]\n" info:
60.9374
Related
I would like to find the coordinates of the first appearance of a certain color, for example green, on an image so can be used in a bash script.
I've been trying to use Imagemagick but can't find a way to solve the problem.
Can this be done with Imagemagick or should I use anything else?
Here is one way in ImageMagick using sparse-color: (provided the image is fully opaque). Sparse-color will read out the x,y coordinates and color of all fully opaque pixels. Then you can use unix tools to get the first one.
Create red and blue image:
convert -size 10x10 xc:red xc:blue -append x.png
Find first rgb(0,0,255) i.e. blue colored pixel
convert x.png sparse-color: | tr " " "\n" | grep "srgb(0,0,255)" | head -n 1
Result
0,10,srgb(0,0,255)
Similar results can be achieved using txt: in place of sparse-color. But the unix commands for filtering would be a bit different.
I have a large image that I am using imagemagick to convert into tiles for use in a Google Earth KML as explained here
instructions on image pyramid construction
The idea is to chop up the images into 4 pieces, then 16, then 64, etc.
To keep things simple, I made the image canvas 4096x4096 so that dividing it in will produce equal size files. The basic command is very simple. For example:
convert large.png -crop 512x512 tiles.png
The issue is the convert command creates file names sequentially, while google needs a format of row column. For instance if there were four files output, the file names should be:
tiles00.png
tiles01.png
tiles10.png
tiles11.png
I brute forced renaming scripts for up to 64 files, but before doing the 256 file case, I'd like to know if there is a simpler way to generate the file names. I'm using linux.
Here is one way in Imagemagick 6 using for loops.
lena.png
The lena.png image is 256x256. I choose 128x128 size tiles. So there will be a total of 2 rows and 2 columns for four output images.
infile="lena.png"
tx=128
ty=128
ncols=`convert -ping "$infile" -format "%[fx:floor(w/$tx)]" info:`
nrows=`convert -ping "$infile" -format "%[fx:floor(h/$ty)]" info:`
for ((j=0; j<nrows; j++)); do
offy=$((j*ty))
for ((i=0; i<ncols; i++)); do
offx=$((i*tx))
convert lena.png -crop ${tx}x${ty}+${offx}+${offy} +repage lena_tile${j}${i}.png
done
done
lena_tile00
lena_tile01
lena_tile10
lena_tile11
An alternate, more compact way is to use -set filename command with fx calculations to name the files in the image chain.
infile="lena.png"
tx=128
ty=128
ncols=`convert -ping "$infile" -format "%[fx:floor(w/$tx)]" info:`
nrows=`convert -ping "$infile" -format "%[fx:floor(h/$ty)]" info:`
convert "$infile" -crop ${tx}x${ty} -set filename:row_col "%[fx:floor(t/$nrows)]%[fx:mod(t,$ncols)]" "lena_tile%[filename:row_col].png"
See:
https://imagemagick.org/Usage/basics/#set
https://imagemagick.org/script/fx.php
Are you trying to make your own in order to learn about the process? If not, existing tools like dzsave can build complete pyramids for you very quickly in a single command. For example:
$ vipsheader wtc.jpg
wtc.jpg: 10000x10000 uchar, 3 bands, srgb, jpegload
$ /usr/bin/time -f %M:%e vips dzsave wtc.jpg x --layout google
211224:1.52
$ ls -R x | wc
2404 2316 15186
So that's making a google-style pyramid of 2400 tiles in directory x from a 10,000 x 10,000 pixel JPG image. It takes about 1.5s and 210mb of ram.
There's a chapter in the manual introducing dzsave:
http://libvips.github.io/libvips/API/current/Making-image-pyramids.md.html
I have a JPG file which contains multiple photos over a white background.
I'm looking for a CLI tool which can extract photos from the source JPG (without supplying coordinates) into separate JPG files maintaining quality and photo resolution.
From some research I suspect ImageMagick can achieve this though unsure of the correct CLI command.
If useful, I'm on OSX 10.13.2 and have ImageMagick 7.0.7-28 installed.
Here are two ways to do this in Unix using Imagemagick. I just cropped out your base image from your diagram, since I was not sure it that was part of your image or not. If it is part of the image, then you would have to trim that off first using -trim.
Input:
The first is my script, multicrop2:
(-f 10 is the fuzz factor for extracting the background)
(-u 3 means no attempt to unrotated the results)
multicrop2 -f 10 -u 3 image.jpg resulta.jpg
Processing Image 0
Initial Crop Box: 113x84+81+89
Processing Image 1
Initial Crop Box: 113x67+144+10
Processing Image 2
Initial Crop Box: 113x66+10+11
The second is using Imagemagick -connected-componets (which is what I use in my script)
What this does is:
1) fuzzy flood fill the background to transparent (since jpg is loss and does not preserve a uniform background.
2) change the color under the transparent to white and remove the transparency
3) change anything not white to black
4) apply -connected-components to throw out areas smaller than 400 pixel area and extract each bounding box and color
5) if the color is gray(0), i.e. black, then crop the original image to the bounding box and save to disk
OLDIFS=$IFS
IFS=$'\n'
arr=(`convert image.jpg -fuzz 10% -fill none -draw "matte 0,0 floodfill" \
-background white -alpha background -alpha off \
-fill black +opaque white -type bilevel \
-define connected-components:verbose=true \
-define connected-components:mean-color=true \
-define connected-components:area-threshold=400 \
-connected-components 4 null: | tail -n +2 | sed 's/^[ ]*//'`)
IFS=$OLDIFS
num=${#arr[*]}
j=0
for ((i=0; i<num; i++)); do
bbox=`echo "${arr[$i]}" | cut -d\ -f2`
color=`echo "${arr[$i]}" | cut -d\ -f5`
if [ "$color" = "gray(0)" ]; then
convert image.jpg -crop $bbox +repage resultb_$j.jpg
j=$((j+1))
fi
done
EDIT: Add processing of your actual image
Input:
The first thing to note is that your actual two images are right at the right side, but there is a black edge there. Also one at the top. That black edge connects the two image so that they cannot easily be separated by the multicrop2 script. So you need to shave off the right side by enough pixels to remove that edge. There is also the edge at the top and you can shave that off if you want. If you do, you can reduce the -d argument. The -d argument needs to be smaller that the area of the smallest image you want to extract and larger than any other minor noise or the stripe at the top in area. So I clip off 20 pixels from the right side and then use multicrop2 with a very large value for -d. I have chosen a value for -f of 8, which is seems to be in a rather narrow range due to the non-constant background. You can add -m save to look at the mask the script creates to see that you get a good separation between your two images. I seed the processing at -c 20,20 to avoid the black border at the top of your image, so that the script gets a good measure of the background color for the flood fill step.
convert test.jpeg -gravity east -chop 20x0 tmp.png
multicrop2 -c 20,20 -f 8 -d 100000 tmp.png result.jpg
Processing Image 0
Initial Crop Box: 2319x1627+968+2153
Processing Image 1
Initial Crop Box: 2293x1611+994+436
I need to add a label onto a png picture, also I need to do a command substitution in order to get a number from a file.
I have something like
convert image.png -background red label:'input + `grep max numbers.txt | head -n 1 | awk '{print 2}'`' -gravity Center -append
but I have a very limited understanding of convert, I downloaded it just so I could do this one command
Thank-you
I suspect you need something like this:
convert -size 100x100 xc:red label:"input + $(awk '/max/{print $2; exit}' numbers.txt)" -gravity center -append result.png
You need to put the label: part in double (rather than single) quotes for the shell to expand and execute it. You do not need grep and head and awk. Awk alone is capable of finding the first occurrence of max and then printing the second field and exiting before finding any other instances.
I assume numbers.txt looks something like this:
a 34
max 32
max 33
I need to generate pictures with a certain size (in pixels). Each picture will have an incrementing number in it. That is all that will be in the picture, a number. I've been thinking of using photoshop but I have no idea how the scripting works. Any suggestions or examples I could use?
Try using ImageMagick (http://www.imagemagick.org) and its text handling feautures (http://www.imagemagick.org/Usage/text/).
Here is a way of doing that using ImageMagick:
#!/bin/bash
for i in {0..3}; do
echo Generating $i...
convert -size 256x256 xc:black \
-gravity south -background orange -splice 0x20 -annotate +0+2 "$i" image-$i.png
done
And the result: