make all values but one in large raster file 0 - bash

I have a large raster file downloaded from Earth Engine. I want to turn it to a boolean file, keeping only one value (13) and make all other values either NA or 0. The file is so large it crashes QGIS and ArcMap when I try to process it, is there a way to do this using GDAL or bash? The file is a tif file.

You can do that with ImageMagick which is installed on most Linux distros and is available for macOS and Windows.
Make a test image at the command line - value 13 in the middle, red and blue around that:
convert -size 30x20 xc:"gray(13)" \
-bordercolor red -border 10 \
-bordercolor blue -border 10 start.tif
Now fill with black, everything that is not value 13:
convert start.tif -fill black +opaque "gray(13)" result.tif
Or, somewhat easier to see - fill everything that is not value 13 with cyan and change everything that is value 13 to yellow:
convert start.tif \
-fill cyan +opaque "gray(13)" \
-fill yellow -opaque "gray(13)" result.tif

Here's a gdal solution:
Your input is input.tif:
gdal_calc.py --calc="A==13" -A input.tif --type=Byte --outfile=output.tif

With R you can do
library(raster)
library(rgdal)
r <- raster("input.tif")
x <- calc(r, function(i){ i==13 }, filename="output.tif", datatype="INT1U")
Or use raster::reclassify

Related

ImageMagick to compare 2 images, marked with 2 different color on the output image

I want make 2 different colors on the output image when using Imagemagick. I have an original image with "Hello World" in it. And a modified image with "Hello Warcraft" in the same area. The default compare command will give me a image and mark all the differences with red.
Now I want to use 2 different colors like "orld" marked as red, and "arcraft" marked as another color, maybe blue. Is ImageMagick able to do this?
If not, how to use ImageMagick to transfer a specified color to another one?
Below are the sample.
Image A
Image B
Then I use the compare like: compare imageA.png imageB.png imageC.png
then the Image C will be:
Image C
But now I just know there are some differences between Image A and Image B. so I want to make some color-code on the Image C, it could be like below Image D:
Image D
from this I can know which parts are the same, and Green means what the difference on Image A and Red means what's the difference on Image B.
You can do this in ImageMagick 6 (Unix Syntax).
ImageA:
ImageB:
convert img1.png img2b.png \
-define compose:args="0,1,-1,0.5" \
-compose mathematics -composite -auto-level \
\( xc:red xc:blue +append \) -clut diff.png
This is a biased difference. Anything above 0.5 or mid gray (in normalized values) will be one color corresponding to one image and anything below 0.5 will be the other color corresponding to the other image.
See clut and compose mathematics
For ImageMagick 7, change convert to magick.
ADDITION:
Given your new input images. Here is how to do that:
imageA:
imageB:
convert imageA.png imageB.png -write mpr:img +delete -fill white -colorize 80% \
\( mpr:img -compose minus -composite -threshold 0 -background red -alpha shape \) \
\( mpr:img +swap -compose minus -composite -threshold 0 -background blue -alpha shape \) \
-background none -compose over -flatten result.png
Sorry, I used blue in stead of green. But you can change that if you want.

Use greek letters in adding annotation in convert imagemagick

I need to annotate some label/text containing greek letters on a figure using convert from imagemagick on linux.
What is the best option?
Trivial choices such as:
ii=1
label="α β $ii"
convert in.png -fill black -annotate "$label" out.png
won't work.
I am not familiar with font coding options.
One way that works for me in ImageMagick 6.9.9.23 Mac OSX Sierra is to use a Greek font. (The symbol font also works)
ii=1
label="a b $ii"
convert logo: -font GreekMathSymbols -pointsize 64 -gravity center -fill red -annotate +0+0 "$label" out.png
Alternately, use a UTF-8 compatible text editor and type your text using a font that supports those characters. For example I put your alpha beta one characters into a text file using the same GreekMathSymbols font.
Then
convert logo: -font GreekMathSymbols -pointsize 64 -gravity center -fill red -annotate +0+0 "#greek.txt" out2.png
See also http://www.imagemagick.org/Usage/text/#unicode

color pixel count with GraphicsMagick

I need to count pixels in an image that are not background color.
I am calling this from PHP (it's from ImageMagick):
gm convert test.png -fill black +opaque "rgb(255,255,255)" -fill white -opaque "rgb(255,255,255)" -print "pixels = %[fx:w*h*mean]\n"
But it does not give any result, nothing.
I tried using histogram instead:
gm convert test.png -define histogram:unique-colors=true -format %c histogram:info.txt
That works, but gives values for every color and more details, I just need a single number please.
You have got a couple of issues here. You seem to be trying to mix GraphicsMagick with ImageMagick when they are not the same thing.
Firstly, GraphicsMagick does not have the +opaque operator that ImageMagick has.
Secondly, it doesn't have the -fx operator that ImageMagick has for doing maths.
I would suggest you move to, the more powerful, ImageMagick. Then it will work as you expect:
# Create a test image
convert -size 200x200 xc:black xc:white xc:red +append image.png
# Count the white pixels
convert image.png -fill black +opaque "rgb(255,255,255)" -print "pixels = %[fx:w*h*mean]\n" nul:
pixels = 40000
If you really, really must do it with GraphicsMagick, I can only suggest the following - which is heavily based on #GlennRanders-Pehrson answer here:
gm convert image.png +matte -matte -transparent white -operator matte negate 1 result.png
gm identify -verbose result.png | grep -EA5 "Opacity:|Geometry:" | grep -E "Mean|Geometry"
Geometry: 600x200
Mean: 43690.00 (0.6667)
Mean: 43690.00 (0.6667)
And your answer will be:
600 * 200 * (1 - 0.667)

Count how many pixels with a specific color in an image?

I want to loop through a folder of images and output to console how many pixels are #333212, how many are #332211 etc. Is this possible in PHP? I found a package that manipulates images but not one that can detect colors of each pixel. Does such a tool or function exist in the PHP library?
EDIT: Doesn't have to be in PHP, the less packages I have to install the better.
You can do this quite easily with ImageMagick, like this. Say we want to count the red pixels...
# First create a little test strip with black, white, red, green and blue parts
convert -size 50x50 xc:black xc:white xc:red xc:lime xc:blue +append out.png
Now convert anything non-red to black so that only red pixels remain
convert out.png -fill black +opaque red n.png
Now count the red pixels by cloning the resulting picture and making the clone fully black (by setting everything to zero), and running a comparison to count how many pixels are not black
convert n.png \
\( +clone -evaluate set 0 \) \
-metric AE -compare \
-format "%[distortion]" info:
2500
And 2500 looks like 50px by 50px to me :-)
Note
The AE is the Absolute Error, i.e. a simple count of the number of differing pixels. The -format "%[distortion]" info: part causes ImageMagick to output the count (%distortion) as a number (info:) rather than as an image.
Obviously, you replace red with "#333212" for your problem.
You can also do all that in one visit, like this:
convert input.png \
-fill black +opaque red \
\( +clone -evaluate set 0 \) \
-metric AE -compare \
-format "%[distortion]" info:

Split a Bash script with ImageMagick instructions into smaller pieces?

I have this bash script, feeding drawing information into ImageMagick, which starts like this:
#!/bin/bash
convert -size 2200x2200 xc:white \
-fill '#FFFEFF' -draw 'point 1112,1111' \
-fill '#FFFEFE' -draw 'point 1112,1112' \
-fill '#FFFEFE' -draw 'point 1111,1112' \
-fill '#FFFEFE' -draw 'point 1110,1112' \
-fill '#FFFEFE' -draw 'point 1110,1111' \
******ON & ON 4.2 MILLION LINES MORE*******
spectrumspiral.png;
My problem is I keep getting warnings about argument list too long, terminal says 'Killed', warning about 'fork: cannot allocate memory etc.
I've tried adjusting ulimit -s to a much higher value to no avail. Really want to make this image. Any idea how I can feed the terminal chunks of this script at a time? Or something to that end.
I've heard xargs can be used for things like this, but I haven't been able to find a specific implementation that fits the nature of this problem.
If you create an image with 4 pixels in it (1 red, 1 white, 1 blue and 1 black), you can tell ImageMagick to output the resulting image as text file as follows:
convert -size 1x1 xc:red xc:white xc:blue xc:black +append -depth 8 -colorspace RGB image.txt
# ImageMagick pixel enumeration: 4,1,255,rgb
0,0: (255,0,0) #FF0000 rgb(255,0,0)
1,0: (255,255,255) #FFFFFF rgb(255,255,255)
2,0: (0,0,255) #0000FF rgb(0,0,255)
3,0: (0,0,0) #000000 rgb(0,0,0)
By the same token, if you feed that text file into ImageMagick, it can recreate the image:
cat image.txt | convert txt:- output.img
So, all we need to do is convert your -fill commands into a text file of the format that ImageMagick likes. So we can do this to yourFile
sed -E 's/.*(#[0-9A-F]+).* ([0-9]+)\,([0-9]+).*/\2,\3:\1/g' yourFile
and we will get something like this:
0,0:#3C4AD8
0,1:#269531
0,2:#CF2C7C
...
...
which we can then pipe into awk to rearrange how ImageMagick likes it:
awk -F: '
BEGIN{print "# ImageMagick pixel enumeration: 2200,2200,255,rgb"}
{
coords=$1;colour=$2
rh="0x" substr(colour,2,2);
gh="0x" substr(colour,4,2);
bh="0x" substr(colour,6,2);
r=strtonum(rh);
g=strtonum(gh);
b=strtonum(bh);
printf "%s: (%d,%d,%d) %s\n",coords,r,g,b,colour;
}'
So, if we put all that together, the following script should be able to create your beloved image into the file spectrumspiral.png:
#!/bin/bash
sed -E 's/.*(#[0-9A-F]+).* ([0-9]+)\,([0-9]+).*/\2,\3:\1/g' yourFile | awk -F: '
BEGIN{print "# ImageMagick pixel enumeration: 2200,2200,255,rgb"}
{
coords=$1;colour=$2
rh="0x" substr(colour,2,2);
gh="0x" substr(colour,4,2);
bh="0x" substr(colour,6,2);
r=strtonum(rh);
g=strtonum(gh);
b=strtonum(bh);
printf "%s: (%d,%d,%d) %s\n",coords,r,g,b,colour;
}' | convert txt:- spectrumspiral.png
Try using the shell's here-document
#!/bin/bash
convert - <<EOS spectrumspiral.png
-size 2200x2200 xc:white
-fill '#FFFEFF' -draw point '1112,1111'
-fill '#FFFEFE' -draw 'point 1112,1112'
-fill '#FFFEFE' -draw 'point 1111,1112'
-fill '#FFFEFE' -draw 'point 1110,1112'
-fill '#FFFEFE' -draw 'point 1110,1111'
# ******ON & ON 4.2 MILLION LINES MORE*****
EOS
My system doesn't have convert so I can test that this works.
Most linux programs (including convert) can accept input from StdIn, which in the cmd-line above is represented by the - char. The - tells the command to expect input, not from file, but as if it was being typed at the keyboard, ie StdIn. The <<EOS .... EOS is the here-doc, and it represents bash 'typing' in all of that text into the commands stdIn input.
You may or may not need all of the quoting, if you already have there, I don't think it will hurt. If this doesn't work as is, use a small sample file of input (like above) and test various scenarios until it creates a file for you.
IHTH

Resources