Преобразование 32-разрядного растра с плавающей запятой в 16-разрядный в R

#r #r-raster #sp #bit-depth

#r #r-растр #sp #разрядность

Вопрос:

У меня есть ~ 100 различных 4-полосных растров спутниковых изображений .tif, которые имеют 32-разрядную глубину с плавающей запятой. Мне нужно преобразовать их в 16-битный без знака в R при масштабировании значений пикселей (а не просто уничтожении высоких значений), но я понятия не имею, с чего начать даже для одного растра, не говоря уже о всей партии. Любая помощь будет высоко оценена!

Редактировать с дополнительной информацией: я искал в документации по пакету растров ключевые слова bit, pixel и depth без особой удачи. Судя по информации о минимальных / максимальных значениях пикселей, найденной в DataType(), я хочу перейти от FLT4S (32-разрядная плавающая точка) к INT2U (16 бит). Я попытался установить тип данных с помощью writeRaster (), как показано в примере, но на выходе было просто черно-белое изображение, а не обычные спутниковые снимки.

 image
class      : RasterStack 
dimensions : 4300, 8909, 38308700, 4  (nrow, ncol, ncell, nlayers)
resolution : 3, 3  (x, y)
extent     : 691032, 717759, 57492, 70392  (xmin, xmax, ymin, ymax)
crs        :  proj=utm  zone=17  datum=WGS84  units=m  no_defs  ellps=WGS84  towgs84=0,0,0 
names      :        image.1,        image.2,        image.3,        image.4 
min values : 7.244503e-02, 8.278998e-02, 2.286164e-05, 8.571137e-02 
max values :    0.5347134,    0.3522218,    0.4896736,    0.7308348 

dataType(image) #[1] "FLT4S" "FLT4S" "FLT4S" "FLT4S"
image2 = writeRaster(image, 'new.tif', datatype='INT2U', overwrite=TRUE, format="GTiff")
dataType(image2) #[1] "INT2U"

image2
class      : RasterBrick 
dimensions : 4300, 8909, 38308700, 4  (nrow, ncol, ncell, nlayers)
resolution : 3, 3  (x, y)
extent     : 691032, 717759, 57492, 70392  (xmin, xmax, ymin, ymax)
crs        :  proj=utm  zone=17  datum=WGS84  units=m  no_defs  ellps=WGS84  towgs84=0,0,0 
source     : new.tif 
names      : new.1, new.2, new.3, new.4 
min values :     0,     0,     0,     0 
max values :     1,     0,     0,     1 
 

Комментарии:

1. Можете ли вы улучшить свой вопрос? Что вы пробовали? как бы вы хотели масштабировать? Можете ли вы привести минимальный пример? Вы смотрели файлы справки пакета raster?

2. @RobertHijmans, дополнительная информация предоставлена в edit. Я не уверен, как работает механическое масштабирование, например, при преобразовании между разрядностью в ArcGIS или QGIS, но, по сути, я бы хотел, чтобы каждый пиксель, попадающий в 32-разрядный масштаб, был представлен в 16-разрядном масштабе 0-65,535.

Ответ №1:

В вашем примере у вас есть реальные значения от 0 до 1. При записи в целочисленный тип все они усекаются до 0. Если вы хотите выполнить запись в INT2U (байт без знака), вы можете сначала масштабировать значения в диапазоне от 0 до 255.

Пример данных

 library(raster)
b <- brick(system.file("external/rlogo.grd", package="raster"))
image <- clamp(b/255, 0, 0.6)
#class      : RasterBrick 
#dimensions : 77, 101, 7777, 3  (nrow, ncol, ncell, nlayers)
#resolution : 1, 1  (x, y)
#extent     : 0, 101, 0, 77  (xmin, xmax, ymin, ymax)
#crs        :  proj=merc  lon_0=0  k=1  x_0=0  y_0=0  datum=WGS84  units=m  no_defs 
#source     : memory
#names      : red, green, blue 
#min values :   0,     0,    0 
#max values : 0.6,   0.6,  0.6 
 

Что вы делаете (усечение)

 fname <- paste0(tempfile(), ".tif")      
x <- writeRaster(image, fname, datatype='INT2U', overwrite=TRUE)
x
#min values : 0, 0, 0 
#max values : 1, 1, 1 
 

Но обратите внимание на разницу при использовании округления

 fname <- paste0(tempfile(), ".tif")      
y <- round(image)
z <- writeRaster(y, fname, datatype='INT2U', overwrite=TRUE)

s <- stack(x[[1]], z[[1]]) 
plot(s)
 

Теперь с некоторым масштабированием

 maxv <- 65535
r <- round(image * maxv)
fname <- paste0(tempfile(), ".tif")
s <- writeRaster(r, fname, datatype='INT2U', overwrite=TRUE)

#s
#min values :     0,     0,     0 
#max values : 39321, 39321, 39321 
 

С вашими данными вы получите максимальные значения

 round(maxv * c(0.5347134, 0.3522218, 0.4896736, 0.7308348 ))
#[1] 35042 23083 32091 47895
 

Вы также можете установить максимальные значения для всех слоев maxv , чтобы сохранить больше вариаций (но сделать значения несопоставимыми с другими данными) — более релевантными, если вы использовали меньший диапазон, например 0-255.

 ss <- round(maxv * image / maxValue(image))
#names      :   red, green,  blue 
#min values :     0,     0,     0 
#max values : 65535, 65535, 65535 
 

вышеуказанное работает, потому что наименьшие значения равны нулю; если у вас отрицательные значения, вы бы сделали

 ss <- image - minValue(image)
ss <- round(maxv * ss / maxValue(ss))
 

В других случаях вы можете использовать clamp . Итак, вам нужно решить, как масштабировать

То, что я показал, — это линейное масштабирование. Есть и другие способы. Например, существует также scale метод, позволяющий улучшить статистическое распределение чисел. Это может иметь значение; но это зависит от ваших целей.

Примечание. Вы не говорите, почему вы это делаете, и это нормально. Но если это необходимо для экономии места на жестком диске, вместо этого можно использовать сжатие (см. ?writeRaster )

Комментарии:

1. Спасибо! Есть ли какая-либо конкретная причина, по которой вы бы предложили масштабирование до 0-255 (8 бит), а не непосредственно до 0-65,535? Я собираюсь использовать эти изображения для различных спектральных анализов.

2. Мой плохой —- я думал о INT1U (байтовых данных)! Я исправлю свой ответ