UCANR-IGIS / uasimg

The uasimg R package provides utilities for managing drone imagery, including creating data catalogs and utilities for single-image analysis.
https://ucanr-igis.github.io/uasimg/
GNU General Public License v3.0
16 stars 10 forks source link

Add the metadata to the DJI image in order to have a single georeferenced image #7

Closed Leprechault closed 1 year ago

Leprechault commented 1 year ago

Hi Everyone!

In my example, I have a single dji image in *JPG:

library(terra)
single.image <-stack("https://github.com/Leprechault/trash/raw/main/DJI_0274.JPG")
plotRGB(single.image,  r = 3, g = 2, b = 1, stretch = "lin")
# class      : RasterStack 
# dimensions : 3648, 4864, 17743872, 3  (nrow, ncol, ncell, nlayers)
# resolution : 1, 1  (x, y)
# extent     : 0, 4864, 0, 3648  (xmin, xmax, ymin, ymax)
# crs        : NA 
# names      : DJI_0274_1, DJI_0274_2, DJI_0274_3 

and the correspond Metadata in *jgw file:

single.image.mtd <- read.table("https://github.com/Leprechault/trash/raw/main/DJI_0274.jgw", header = FALSE)
single.image.mtd
#              V1
# 1 -3.532000e-07
# 2  2.600000e-09
# 3  3.100000e-09
# 4  2.976000e-07
# 5 -5.170865e+01
# 6 -1.973617e+01

I'd like to know if is possible to add the metadata to the image in order to have a single georeferenced image and save it in *tif format using uasimg package?

Thanks in advance!

Alexandre

ajlyons commented 1 year ago

Hi @Leprechault, the short answer is no. uasimg::uas_worldfile() can create the jgw file from a JPG, but there is no function at present to apply the transformation saved in the world file and export the result as a georeferenced, non-rotated, TIF image.

This should certainly be possible in R, perhaps by manually editing the parameters of the @rotation slot of the raster (or terra) object, and then using rectify(). Or maybe gdal can do it. If you do find a R workflow please let me know as I would love to add this functionality to the package.

If you just have one or two images to convert, the next place I would look would be convert or export tools in QGIS or ArcGIS.

Leprechault commented 1 year ago

Hi @ajlyons thank you so much for the answer. You give me valuable tips and if I have success in R to solved that I'll share with you. Best wishes!!

Leprechault commented 1 year ago

Hi @ajlyons, look this:

# load data with *.jgw copied to same directory 
r2 <- rast("DJI_0274.JPG")
#> Warning: [rast] the data in this file are rotated. 
r2
#> class       : SpatRaster 
#> dimensions  : 3648, 4864, 3  (nrow, ncol, nlyr)
#> resolution  : 3.532e-07, 2.976e-07  (x, y)
#> extent      : -51.70865, -51.70693, -19.73725, -19.73617  (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 
#> source      : DJI_0274.JPG 
#> colors RGB  : 1, 2, 3 
#> names       : DJI_0274_1, DJI_0274_2, DJI_0274_3

r_rect <- rectify(r2)
r_rect
#> class       : SpatRaster 
#> dimensions  : 3648, 4864, 3  (nrow, ncol, nlyr)
#> resolution  : 3.555963e-07, 3.011079e-07  (x, y)
#> extent      : -51.70865, -51.70692, -19.73725, -19.73616  (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 
#> source(s)   : memory
#> names       : DJI_0274_1, DJI_0274_2, DJI_0274_3 
#> min values  :          0,          0,          0 
#> max values  :        255,        255,        255

# write to disk as geoTIFF
writeRaster(r_rect, "DJI_0274_3.tif")

# Note that it was necessary to execute rectify() to adjust the rotated SpatRaster into a non-rotated object - otherwise R crashed when executing writeRaster().
ajlyons commented 1 year ago

Hi @Leprechault, thank you for sharing that very straightforward solution. Sometimes you get lucky (thank you terra)!

I replicated it myself and found that it worked well. The only difference I encountered was that terra::rast() did not detect the CRS of my test image. In your example above it figured out the image was lon/lat WGS 84. Maybe it guessed that from EXIF data or the jpw file.

The world files created by uas_worldfile() save a transformation matrix based on UTM. However the CRS doesn't get saved in the world file, so it will have to be assigned manually to the SpatRast object (easy enough). So a pipeline within uasimg may look something like:

my_image_collection_info |> uas_worldfile(wld = TRUE) |> uas_geotiff(output_dir = ".")

where uas_geotiff() will be a new function.

Leprechault commented 1 year ago

Thanks @ajlyons for you feedback and for the new function!!