Displaying tif files in jupyter notebook vie ipywidgets - jupyter-notebook

I am trying to display .tif images using the ipywidgets in jupyter-notebooks. The below code works for .png and .jpg files
from ipywidgets import Image
png_image_path = r"C:\Users\xxxxxxxx\Work\Exercises\images\000000000.png"
file = open(png_image_path, "rb")
im = file.read()
Image(
value=im,
width=300,
height=400,
)
type(im) # <class 'bytes'>
The ipywidget from the above code renders the desired image. For reading a tif file I am using gdal.
img = gdal.Open(tif_img_path).ReadAsArray()
print(img.shape) # (3, 1024, 1024)
print(img.transpose(1,2, 0).shape) # (1024, 1024, 3)
type(img.transpose(1,2,0).tobytes()) # <class 'bytes'>
Image(
value=img.transpose(1,2,0).tobytes(),
width=300,
height=400,
)
I get the following output, the image is not properly displayed in the ipywidget

The fact that you just do file.read() on the PNG image implies to me that Jupyter widgets expect a PNG or JPEG-encoded image, with a header and compressed pixel data.
If you open your TIFF with GDAL you will have a Numpy array, so you will need to encode it into an "in-memory" PNG or JPEG before passing to Jupyter widgets. You can do that with OpenCV like this:
import cv2
# Open TIFF image into Numpy array
img = gdal.Open(tif_img_path).ReadAsArray()
# Encode into in-memory PNG for Jupyter
_, PNG = cv2.imencode('.png', img)
As you rightly note in the comments, OpenCV uses BGR ordering so you would need to reverse the order of the colour channels with:
RGBimage = cv2.cvtColor(BGRimage, cv2.COLOR_BGR2RGB)
As an alternative to introducing the OpenCV dependency and its weird channel ordering, you could use PIL/Pillow which uses regular RGB ordering. In that case, you would convert a Numpy array you got from GDAL into a PNG with:
from io import BytesIO
im = ... read from GDAL ...
# Write Numpy array to in-memory PNG
membuf = BytesIO()
Image.fromarray(im).save(membuf, format="png")
... you can now use membuf.getvalue()
Note also, that in general TIFFs may contain float or float64 values that cannot be expressed in an 8-bit JPEG, so you may need to re-scale your data to fit the smaller range.

Related

Copy raster exif in GDAL

I have two images with the same size - first one is an image from a drone and the second - a mask. I need to subtract both images and of course translate the exif data from the original image into the resulting one. Is it possible in gdal or rasterio?
Thanks.
In my experience with DJI drones, the aerial imagery is often captured in JPEG format. The metadata can be accessed through GDAL like this:
from osgeo import gdal
im = gdal.Open('ImageName.jpg', 0)
exif = im.GetMetadata()
This returns a Python dictionary containing the EXIF metadata. To copy the metadata to a new image, you can simply do this:
outimg = im.GetDriver().CreateCopy('NewImageName.jpg', im, callback=gdal.TermProgress_nocb)
outimg.SetMetadata(exif)
del im, outimg, exif # close datasets to commit changes to disk
You can then edit the newly created image as required (e.g., multiply pixel values by binary mask).

convert hdf5 file to grayscale

How do I convert a .h5 file to grayscale in Julia?
I tried this
img = stack[:,:,100] #just some hdf5 file
img = convert(Image{Images.Gray}, img)
I get this error:
LoadError: PyError (:PyObject_Call) <type 'exceptions.TypeError'>
TypeError(u'Image data can not convert to float',)
My guess is you're also using some other package that defines Image, and this conflicts with the definition in Images.jl. Let's imagine that other package is called PythonImage. Try it like this:
using Colors # that way you don't have to say `Images.Gray`
import PythonImage, Images # `import` rather than `using` prevents conflicts
imgg = convert(Images.Image{Gray}, img)
# ...if you need the other one, use `PythonImage.Image`
Or you can using Images and import PythonImage (or vice versa). The only thing you can't do is using for both of them and expect everything to work.

Create a gif from a series of Leaflet maps in R

I am looking for an automated method to convert leaflet R Studio plots into image files.
Seems like exporting a leaflet widget to HTML is straightforward (Saving leaflet output as html). However I cannot find any answers or docs about how to save the image produced by a leaflet widget as an image. It seems strange that I can do this manually in R Studio but that there isn't some function within R Studio that can be called to do the same thing.
I've tried the usual suspects, variations on the following:
png("test_png.png")
map
dev.off()
But these all just print white or print a file that can't even be opened. IF I understand this Git discussion correctly, seems like something in leaflet is not available but is desired by users.
In the meantime, R Studio clearly has a way to render this image into an image file, making me press a button to do it. Is there a way to automate this? How can I export the images plotted in R Studio to image files? I need image files and I need this to be programmatic because I want to make a gif out of a few hundred maps.
Alternately, I'd welcome suggestions for a workaround. I might try this: Python - render HTML content to GIF image but if someone has alternatibve suggestions, please share.
I've been trying to do this with a combination of the webshot package and saveWidget from htmltools, although it's pretty slow. For a few hundred maps, it's probably not too bad if you're only doing it here and there. But, for real-time application it is too slow.
There are two external applications you need for this workflow. webshot takes screenshots of webpages and requires you to install PhantomJS first (it's tiny and easy). I also use ImageMagick (and needs to be accessible from the command line) to create the .gif files, but I'm sure there many other programs you could use to make gifs.
The idea is just to create the maps in a loop, save them to a temporary html file with saveWidget and use webshot to turn it into a png (slow). Then, once you have all the pngs, use ImageMagick to convert them to a gif (fast).
Here is an example, I also load ggmap, but only to get a location to zoom in on.
library(webshot)
library(leaflet)
library(htmlwidgets)
library(ggmap)
loc <- geocode('mt everest') # zoom in everest
zooms <- seq(2,14,3) # some zoom levels to animate
## Make the maps, this will make some pngs called 'Rplot%02d.png'
## in your current directory
for (i in seq_along(zooms)) {
m <- leaflet(data=loc) %>%
addProviderTiles('Esri.WorldImagery') %>%
setView(lng=loc$lon, lat=loc$lat, zoom=zooms[i])
if (i==1)
m <- m %>% addPopups(popup="Going to see Mt Everest")
if (i==length(zooms))
m <- m %>%
addCircleMarkers(radius=90, opacity = 0.5) %>%
addPopups(popup = 'Mt Everest')
## This is the png creation part
saveWidget(m, 'temp.html', selfcontained = FALSE)
webshot('temp.html', file=sprintf('Rplot%02d.png', i),
cliprect = 'viewport')
}
Then, it is just converting pngs to gif. I did this on a Windows, so command might be slightly different on a mac/linux (I think just single quotes instead of double quotes or something). These commands are from a command line/shell, but you could also use system/system2 to call from R or try the animation package that has some wrapper functions for ImageMagick. To make a simle gif with nothing fancy is simply, convert *.png animation.gif. I used a slightly longer code to make the pngs smaller/add some delays/and have the sequence go in and out.
convert Rplot%02d.png[1-5] -duplicate 1,-2-1, -resize "%50" gif:- | convert - -set delay "%[fx:(t==0||t==4)?240:40]" -quiet -layers OptimizePlus -loop 0 cycle.gif
You can create a series of PNG files as answered by jenesaisquoi (first answer). Then create gif with the png files using the below code with magick package.
library(magick)
png.files <- sprintf("Rplot%02d.png", 1:20) #Mention the number of files to read
GIF.convert <- function(x, output = "animation.gif")#Create a function to read, animate and convert the files to gif
{
image_read(x) %>%
image_animate(fps = 1) %>%
image_write(output)
}
GIF.convert(png.files)
You don't require to install ImageMagick software on PC.
Code Link: Animation.R
I have table with 3 columns: lat,lon,day (376 days).
The process is: create the map -> save the map as HTML -> save the map as PNG -> import the pic -> plot it (with plot + ggimage)
All this process, will be in a loop
library(leaflet)
library(animation)
library(png)
library(htmlwidgets)
library(webshot)
library(ggmap)
saveGIF({
for (i in 1:376) {
map = leaflet() %>%
addTiles() %>%
setView(lng = lon_lat[1,2], lat = lon_lat[1,1], zoom = 5)%>%
addMarkers(lng = lon_lat[lon_lat$day == i,2],lat = lon_lat[lon_lat$day == i,1])
saveWidget(map, 'temp.html', selfcontained = FALSE) ## save the html
webshot('temp.html', file=sprintf('Rplot%02d.png', 1),cliprect = 'viewport') ## save as png
img = readPNG("Rplot01.png") ### read the png
plot(ggimage(img)) ###reading png file
}
})

Export image from R to word with alpha channel (transparency)

I am wanting to export an R produced figure to Word. The figure contains transparency (alpha channel). Below is some example code - when exported to Windows metafile it throws an error:
Warning message:
In plot.xy(xy, type, ...) :
semi-transparency is not supported on this device: reported only once per page
Exporting to SVG produces the desired result, but this image format is not supported by MS Office. Is there a way around this? What image type could I use while retaining the alpha channel? PNG is possible, but this doesn't produce very crisp graphics - it loses the clear vectorized image.
# Get some colours with transparency (alpha = 0.6)
col.dot <- rainbow(5, alpha = .6)
# Save to svg file - OK
svg("test_fig.svg")
plot(1:5,col = col.dot, pch=15)
dev.off()
# Save to wmf - warning "semi-transparency is not supported on this device..."
win.metafile("test_fig.wmf")
plot(1:5,col = col.dot, pch=15)
dev.off()
I should add, this is on a Windows system (Windows 8 64 bit, with Word 2013)
I just made a new package export to easily export R graphs to Office (Word, Powerpoint), see
https://cran.r-project.org/web/packages/export/index.html and
for demo https://github.com/tomwenseleers/export.
Typical syntax is very easy, e.g.:
install.packages("export")
library(export)
library(ggplot2)
qplot(Sepal.Length, Petal.Length, data = iris, color = Species,
size = Petal.Width, alpha = I(0.7))
graph2ppt(file="ggplot2_plot.pptx", width=6, height=5)
Output is vector format and so fully editable after you ungroup your graph in Powerpoint. You can also use it to export to Word, Excel, Latex or HTML and you can also use it to export statistical output of various R stats objects.
This results in a fully editable, high quality Powerpoint graph in native Office vector-based DrawingML format, which you can also readily copy & paste as enhanced metafile if you like, and which unlike the EMFs exported from R also fully supports transparency.
From the help of win.metafile:
There is support for semi-transparent colours of lines, fills and text
on the screen devices. These work for saving (from the ‘File’ menu) to
PDF, PNG, BMP, JPEG and TIFF, but will be ignored if saving to
Metafile and PostScript.
So you cannot use transparency in a metafile. You can try saving as png and increasing the resolution of the output.

R: tiff( ) won't compress or set resolution to 300 ppi

I am trying to save some graphs using R for publication. I want to have them compressed with lzw and have the resolution at 300. For some reason it won't allow me to do this. In fact, it seems like R is ignoring some of the variables I set.
For the code example,
tiff(file="file.tiff",
width=6.83, height=6.83, units="in",
pointsize="12", compression = "lzw",
bg="white", res=300, antialias = "none" )
outputs an uncompressed file of size 28 x 28 inches and a resolution of 72 ppi.
A reproducable example would be
hist(rnorm(1000))
dev.off()
Here is the output of ImageMagick for file.tiff
Image: file.tiff
Format: TIFF (Tagged Image File Format)
Class: DirectClass
Geometry: 2049x2049+0+0
Units: PixelsPerInch
Type: PaletteAlpha
Base type: TrueColor
Endianess: MSB
Colorspace: sRGB
...
Compression: None
...
Filesize: 16.8MB
I tested this on another Apple running 10.7 and get the same results. As can be seen, even when using the options to compress and set the resolution at 300 dpi, the output does not follow the options.
I verified your example with R 2.15.1 on GNU/Linux by appending
hist(rnorm(1000))
dev.off()
to your tiff() call and checked the resulting file "file.tiff" with ImageMagick's command line tool identify (most output omitted):
Image: file.tiff
Format: TIFF (Tagged Image File Format)
Class: DirectClass
Geometry: 2049x2049+0+0
Resolution: 300x300
Print size: 6.83x6.83
[...]
Compression: LZW
[...]
Filesize: 70KB
[...]
The R command seems to do exactly what you intend to do. I suspect that either you create the TIFF file not in the manner you describe or the tool you use to check the TIFF file's properties is faulty.

Resources