Conversion of ENVI binary files to tiff - rstudio

I have a challenge in converting a batch of ENVI binary files(BSQ) temperature data(gotten from SAFARI 2000 AVHRR-Derived LST) to geotiff files. How can i read them and convert it to geotiff?
An example of one such file is 'afn_011-011_96.n14-LST_UL'

You would need to provide a proper sample dataset and the corresponding meta-data that tells you the image dimensions in pixels, the data type and so on, but in principle you can do it with ImageMagick which is included in most Linux distros and is available for macOS and Windows.
So, using the dataset here sample dataset and knowing the data is unsigned 8 bit and 360x180 pixels, you would run this command in Terminal (or Command Prompt if on Windows):
convert -size 360x180 -depth 8 gray:gl-latlong-1deg-landcover.bsq -auto-level result.tif
If your data is multi-band band-sequential, you may have to use:
convert -size 360x180 -depth 8 -interlace plane rgb:gl-latlong-1deg-landcover.bsq -auto-level result.tif
Or, if you cannot get that to work, you may need to extract each band separately using a byte offset and then combine them afterwards, something like:
convert -size 360x180 -depth 8 gray:image.bsq -auto-level red.tif
convert -size 360x180+64800 -depth 8 gray:image.bsq -auto-level green.tif
convert -size 360x180+129600 -depth 8 gray:image.bsq -auto-level blue.tif
convert red.tif green.tif blue.tif -combine RGB.tif
Note that if you install ImageMagick v7 or newer, the above commands change to:
magick -size ...
rather than:
convert -size ...
Keywords: ImageMagick, command-line, command line, image, image processing, satellite, ENVI, band-sequential, planar, imagery, AVHRR, convert

Related

ImageMagick: guess raw image height

I'm using convert utility from ImageMagick to convert raw image bytes to usable image format such as PNG. My raw files are generated by code, so there is no any headers, just pure pixels.
In order to convert my image I'm using command:
$ convert -depth 1 -size 576x391 -identify gray:image.raw image.png
gray:image.raw=>image.raw GRAY 576x391 576x391+0+0 1-bit Gray 28152B 0.010u 0:00.009
The width is fixed and pretty known for me. However I have to evaluate the height of the image from the file size each time which is annoying.
Without height specified or if wrong height is specified the utility compains:
$ convert -depth 1 -size 576 -identify gray:image.raw image.png
convert-im6.q16: must specify image size `image.raw' # error/gray.c/ReadGRAYImage/143.
convert-im6.q16: no images defined `image.png' # error/convert.c/ConvertImageCommand/3258.
$ convert -depth 1 -size 576x390 -identify gray:iphone.raw iphone.png
convert-im6.q16: unexpected end-of-file `image.raw': No such file or directory # error/gray.c/ReadGRAYImage/237.
convert-im6.q16: no images defined `image.png' # error/convert.c/ConvertImageCommand/3258.
So I wonder is there a way to automatically detect the image height based on the file/blob size?
A couple of ideas...
You may not be aware of the NetPBM format, but it is very simple and you may be able to change your software that creates the raw images so that it directly generates PBM format images which are readable and useable by OpenCV, Photoshop, GIMP, feh, eog and ImageMagick of course. It would not require any libraries or extra dependencies in your software, all you need to do is put a textual PBM header on the front, so your file looks like this:
P4
576 391
... YOUR EXISTING BINARY DATA ...
Do not forget to put newlines (i.e. linefeed character) after P4 and after 391.
You can try it for yourself and add a header onto one of your files like this and then view it with GIMP or other tool:
printf "P4\n576 391\n" > image.pbm
cat image.raw >> image.pbm
If you prefer a one-liner, just use a bash command grouping like this - which is equivalent to the 2 lines above:
{ printf "P4\n576 391\n"; cat image.raw; } > image.pbm
Be careful to have all the spaces and semi-colons exactly as I have them!
Another idea, just putting some meat on Fred's answer, might be the following one-liner which uses a bash arithmetic context and a bash command substitution, you can do this:
convert -depth 1 -size "576x$(($(stat -c "%s" image.raw)*8/576))" gray:image.raw image.png
Note that if you are on macOS, stat is a little different, so you may prefer the slightly less efficient, but more portable:
convert -depth 1 -size "576x$(($(wc -c < image.raw)*8/576))" gray:image.raw image.png
You have to know the -depth and width to compute the height for ImageMagick raw format. If depth is 1, then your image is binary (b/w). So height = 8 * file size (in B)/(width). 28152*8/391 = 576

mix single channel images into color image

each representing a channel and I want to merge them into a single one, like RGB image. The images are RAW, so no file header. I have managed to mix them with
cat imgPl0.raw imgPl1.raw imgPl2.raw >> img.rgb
but this is mixing the planes one after the other, but is there a way to do an interlaced mix ?
Maybe using imagemagick there is another way ?
Well, what I need at the output is a rgb image (not a png, sadly imagemagick is creating a png as output) containing the data interlaced. To be more explicit, cat-ing the images is going to make a rgb image plane-interlaced (that is rrrrrr...ggggggg...bbbbbbb). What I want is an operation that is creating a rgb image line-interlaced (that is rrr...ggg...bbb...rrr...ggg...bbb...rrr...ggg...bbb...). Sorry for not being explicit from the beginning.
About the data, it seems it is 12 bpp or 14 bpp little endian
ImageMagick offers a few techniques, but you'll need to be responsible for defining all the information missing from the headers. Stuff like image size, quantum depth, and colorspace.
One approach.
convert -size 70x46 -depth 8 \
r:imgPl0.raw g:imgPl1.raw b:imgPl2.raw \
-set colorspace RGB -combine -colorspace sRGB \
output.rgb
Another option is to create a blank canvas, and copy the data from the raw files over to the correct canvas channels.
convert -size 70x46 xc: -depth 8 \
r:imgPl0.raw -compose CopyRed -composite \
g:imgPl1.raw -compose CopyGreen -composite \
b:imgPl2.raw -compose CopyBlue -composite \
-colorspace sRGB output.rgb
Other examples can be found here.
Also note: I'm assuming that these .raw data files only contain single channel samples, are unsigned character color sizes, and have a 70x46 image size. YMMV
Update
Well, what I need at the output is a rgb image (not a png, sadly imagemagick is creating a png as output)
Sorry about that. Just switch output.png to output.rgb. ImageMagick will do the rest.
About the data, it seems it is 12 bpp or 14 bpp little endian
Adjust -depth from 8 to 12, or 14 bits-per-part.
There's also a -endian LSB option, but I don't think that's needed.
What I want is an operation that is creating a rgb image line-interlaced
Easy. Set the -interlace Line options.
So... My previous answer is still helpful, but just needs some additional options.
convert -size 70x46 -depth 12 \
r:imgPl0.raw g:imgPl1.raw b:imgPl2.raw \
-set colorspace RGB -combine -colorspace sRGB \
-interlace Line output.rgb
or
convert -size 70x46 xc: -depth 12 \
r:imgPl0.raw -compose CopyRed -composite \
g:imgPl1.raw -compose CopyGreen -composite \
b:imgPl2.raw -compose CopyBlue -composite \
-colorspace sRGB -interlace Line output.rgb
Hope that get's you close.
If your data is 8 bits per sample, you can do it like this which whilst not very efficient, doesn't require any code writing or compiling or anything:
#!/bin/bash
# Bytes per row
bpr=100
row=0
# Loop through all rows of file
while :; do
# Read a row from each channel and output on stdout redirected to result.rgb
for ((chan=0;chan<3;chan++)); do
dd if=imgPl${chan}.raw bs=$bpr count=1 skip=$row > row.tmp 2> /dev/null
[ ! -s row.tmp ] && exit
cat row.tmp
done
((row+=1))
done > result.rgb

graphicsmagick composite and crop in the same command

I need to get a specific crop of an image and put it over another image at a certain position and resized.
I can crop the first image and save it to a file in one command and then I can composite the 2 images in another command.
However, I would like to do it in a single command - is this possible with graphicsmagick and how?
Here are the 2 commands I am using atm:
gm convert -crop 1457x973+254+413 amber.jpg tmp.jpg
gm composite -geometry 6000x4000+600+600 tmp.jpg lux_bg.png out.jpg
The reason for wanting this is to avoid writing to disk then reading again when all this could be done in memory.
With ImageMagick, for example, the same 2 commands would be written in a single command like this:
convert lux_bg.png \( amber.jpg -crop 1457x973+254+413 \) -geometry 6000x4000+600+600 -composite out.jpg
I am doing this with ImageMagick for now but would love to do it with GraphicsMagick.
If your reason is simply to avoid creating a temporary file, you can still do it with two commands by constructing 'pipelines' (a great concept invented by, afaik, Douglas McIlroy around 1964):
gm convert -crop 1457x973+254+413 amber.jpg - | gm composite -geometry 6000x4000+600+600 - lux_bg.png out.jpg
hint: note the two - dashes in the two commands, and the | pipe
since the - can be used to mean the standard output and input in the two commands respectively.
This means that no file is created, all should happen in the memory.
You can find this in the help (gm -help convert | grep -i -e out -B 1):
Specify 'file' as '-' for standard input or output.
The use of - is common in unix-likes and must have been inspired by, or by something related to, the POSIX standard's Utility Syntax Guidelines.
Have you tried && operator? Your command should become:
gm convert -crop 1457x973+254+413 amber.jpg tmp.jpg && gm composite -geometry 6000x4000+600+600 tmp.jpg lux_bg.png out.jpg

Command line batch image cropping tool

is there any lightweight command line batch image cropping tool(Linux or Windows) which can handle a variety of the formats ?
In Linux you can use
mogrify -crop {Width}x{Height}+{X}+{Y} +repage image.png
for CLI image manipulation
Imagemagick's convert does the trick for me (and much more than cropping):
convert -crop +100+10 in.jpg out.jpg
crops 100 pixels off the left border, 10 pixels from the top.
convert -crop -100+0 in.jpg out.jpg
crops 100 pixels off the right, and so on. The Imagemagick website knows more:
http://www.imagemagick.org/Usage/crop/#crop
Imagemagick is what you want -- tried and true.
I found nconvert pretty handy so far.
for f in final/**/*;
do
convert -crop 950x654+0+660 "$f" "${f%.jpg}".jpg
done
This script loops through all the sub-folders and crops the .jpg files.
macOS has sips image processing tool integrated. Cropping functions available are:
-c, --cropToHeightWidth pixelsH pixelsW
--cropOffset offsetY offsetH
Easy with sips: just set the offset to start the cropping:
sips --cropOffset 1 1 -c <height> <width> -o output.png input.png
I have scanned some pages and all ~130 pages needs the lower ~1/8 of the page cut off.
Using mogrify didn't work for me,
a#a-NC210-NC110:/media/a/LG/AC/Learn/Math/Calculus/Workshop/clockwise/aa$ mogrify -quality 100 -crop 2592×1850+0+0 *.jpg
mogrify.im6: invalid argument for option `2592×1850+0+0': -crop # error/mogrify.c/MogrifyImageCommand/4232.
However convert did:
a#a-NC210-NC110:~/Pictures/aa$ convert '*.jpg[2596x1825+0+0]' letter%01d.jpg
a#a-NC210-NC110:~/Pictures/aa$
I learnt this here under the Inline Image Crop section.
Notice my syntax: I had to put my geometry in brackets: [].
Using the successful syntax above but with mogrify simply didn't work, producing:
a#a-NC210-NC110:~/Pictures/aa$ mogrify '*.jpg[2596x1825+0+0]' letter%01d.jpg
mogrify.im6: unable to open image `letter%01d.jpg': No such file or directory # error/blob.c/OpenBlob/2638.
Linux a-NC210-NC110 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:12 UTC 2014 i686 i686 i686 GNU/Linux
Lubuntu 14.04 LTS

Can ImageMagick return the image size?

I'm using ImageMagick from the command line to resize images:
convert -size 320x240 image.jpg
However, I don't know how to determine the size of the final image. Since this is a proportional image scale, it's very possible that new image is 100x240 or 320x90 in size (not 320x240).
Can I call the 'convert' command to resize the image and return the new image dimensions? For example, pseudo code:
convert -size 320x240 -return_new_image_dimension image.jpg // returns the new resized image dimensions
-ping option
This option is also recommended as it prevents the entire image from being loaded to memory, as mentioned at: https://stackoverflow.com/a/22393926/895245:
identify -ping -format '%w %h' image.jpg
man identify says:
-ping efficiently determine image attributes
We can for example test it out with some of the humongous images present on Wikimedia's "Large image" category e.g. this ultra high resolution image of Van Gogh's Starry Night which Wikimedia claims is 29,696 × 29,696 pixels, file size: 175.67 MB:
wget -O image.jpg https://upload.wikimedia.org/wikipedia/commons/e/e8/Van_Gogh_-_Starry_Night_-_Google_Art_Project-x0-y0.jpg
time identify -ping -format '%w %h' image.jpg
time identify -format '%w %h' image.jpg
I however observed that -ping at least in this case did not make any difference on the time, maybe it only matters for other image formats?
Tested on ImageMagick 6.9.10, Ubuntu 20.04.
See also: Fast way to get image dimensions (not filesize)
You could use an extra call to identify:
convert -size 320x240 image.jpg; identify -format "%[fx:w]x%[fx:h]" image.jpg
I'm not sure with the %w and %h format. While Photoshop says my picture is 2678x3318 (and I really trust Photoshop), identify gives me:
identify -ping -format '=> %w %h' image.jpg
=> 643x796
(so does [fx:w] and [fx:h])
I had to use
identify -ping -format '=> %[width] %[height]' image.jpg
=> 2678x3318
I don't know what's going on here, but you can see both values on standard output (where the width and height before the => are the correct ones)
identify -ping image.jpg
image.jpg PAM 2678x3318=>643x796 643x796+0+0 16-bit ColorSeparation CMYK 2.047MB 0.000u 0:00.000
The documentation says %w is the current width and %[width] is original width. Confusing.
%w and %h may be correct for most uses, but not for every picture.
If you specify option -verbose, convert prints:
original.jpg=>scaled.jpg JPEG 800x600=>100x75 100x75+0+0 8-bit sRGB 4.12KB 0.020u 0:00.009
^^^^^^

Resources